template.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import fs from 'fs';
  2. import path from 'path';
  3. import { promisify } from 'util';
  4. import { GrowiPluginType } from '../../../consts';
  5. import type { GrowiPluginValidationData, GrowiTemplatePluginValidationData } from '../../../model';
  6. import { GrowiPluginValidationError } from '../../../model';
  7. import { importPackageJson, validatePackageJson } from './package-json';
  8. const statAsync = promisify(fs.stat);
  9. /**
  10. * An utility for template plugin which wrap 'validatePackageJson' of './package-json.ts' module
  11. * @param projectDirRoot
  12. */
  13. export const validateTemplatePluginPackageJson = async(projectDirRoot: string): Promise<GrowiTemplatePluginValidationData> => {
  14. const data = await validatePackageJson(projectDirRoot, GrowiPluginType.TEMPLATE);
  15. const pkg = await importPackageJson(projectDirRoot);
  16. // check supporting locales
  17. const supportingLocales: string[] | undefined = pkg.growiPlugin.locales;
  18. if (supportingLocales == null || supportingLocales.length === 0) {
  19. throw new GrowiPluginValidationError<GrowiPluginValidationData & { supportingLocales?: string[] }>(
  20. "Template plugin must have 'supportingLocales' and that must have one or more locales",
  21. {
  22. ...data,
  23. supportingLocales,
  24. },
  25. );
  26. }
  27. return {
  28. ...data,
  29. supportingLocales,
  30. };
  31. };
  32. export type TemplateStatus = {
  33. id: string,
  34. locale: string,
  35. isValid: boolean,
  36. invalidReason?: string,
  37. }
  38. type TemplateDirStatus = {
  39. isTemplateExists: boolean,
  40. isMetaDataFileExists: boolean,
  41. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  42. meta?: any,
  43. }
  44. async function getStats(tplDir: string): Promise<TemplateDirStatus> {
  45. const markdownPath = path.resolve(tplDir, 'template.md');
  46. const statForMarkdown = await statAsync(markdownPath);
  47. const isTemplateExists = statForMarkdown.isFile();
  48. const metaDataPath = path.resolve(tplDir, 'meta.json');
  49. const statForMetaDataFile = await statAsync(metaDataPath);
  50. const isMetaDataFileExists = statForMetaDataFile.isFile();
  51. const result: TemplateDirStatus = {
  52. isTemplateExists,
  53. isMetaDataFileExists,
  54. };
  55. if (isMetaDataFileExists) {
  56. result.meta = await import(metaDataPath);
  57. }
  58. return result;
  59. }
  60. export const scanTemplateStatus = async(projectDirRoot: string, templateId: string, data: GrowiTemplatePluginValidationData): Promise<TemplateStatus[]> => {
  61. const status: TemplateStatus[] = [];
  62. const tplRootDirPath = path.resolve(projectDirRoot, 'dist', templateId);
  63. for await (const locale of data.supportingLocales) {
  64. const tplDir = path.resolve(tplRootDirPath, locale);
  65. try {
  66. const {
  67. isTemplateExists, isMetaDataFileExists, meta,
  68. } = await getStats(tplDir);
  69. if (!isTemplateExists) throw new Error("'template.md does not exist.");
  70. if (!isMetaDataFileExists) throw new Error("'meta.md does not exist.");
  71. if (meta?.title == null) throw new Error("'meta.md does not contain the title.");
  72. status.push({ id: templateId, locale, isValid: true });
  73. }
  74. catch (err) {
  75. status.push({
  76. id: templateId,
  77. locale,
  78. isValid: false,
  79. invalidReason: err.message,
  80. });
  81. }
  82. }
  83. // eslint-disable-next-line no-console
  84. console.debug({ status });
  85. return status;
  86. };
  87. export const scanAllTemplateStatus = async(projectDirRoot: string): Promise<TemplateStatus[]> => {
  88. const data = await validateTemplatePluginPackageJson(projectDirRoot);
  89. const status: TemplateStatus[] = [];
  90. const distDirPath = path.resolve(projectDirRoot, 'dist');
  91. const distDirFiles = fs.readdirSync(distDirPath);
  92. for await (const templateId of distDirFiles) {
  93. status.push(...await scanTemplateStatus(projectDirRoot, templateId, data));
  94. }
  95. return status;
  96. };