|
|
@@ -1,3 +1,4 @@
|
|
|
+import { assert } from 'console';
|
|
|
import fs from 'fs';
|
|
|
import path from 'path';
|
|
|
import { promisify } from 'util';
|
|
|
@@ -7,7 +8,7 @@ import { GrowiPluginType } from '@growi/core/dist/consts';
|
|
|
import type { GrowiPluginValidationData, GrowiTemplatePluginValidationData } from '~/model';
|
|
|
import { GrowiPluginValidationError } from '~/model';
|
|
|
|
|
|
-import type { TemplateStatus, TemplateSummaries } from '../../../interfaces/v4';
|
|
|
+import { isTemplateStatusValid, type TemplateStatus, type TemplateSummary } from '../../../interfaces/v4';
|
|
|
|
|
|
import { importPackageJson, validatePackageJson } from './package-json';
|
|
|
|
|
|
@@ -43,12 +44,11 @@ export const validateTemplatePluginPackageJson = async(projectDirRoot: string):
|
|
|
};
|
|
|
|
|
|
|
|
|
-type TemplateDirStatus = {
|
|
|
- isTemplateExists: boolean,
|
|
|
- isMetaDataFileExists: boolean,
|
|
|
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
- meta?: any,
|
|
|
-}
|
|
|
+type TemplateDirStatus = { isTemplateExists: boolean } &
|
|
|
+ (
|
|
|
+ { isMetaDataFileExists: false } |
|
|
|
+ { isMetaDataFileExists: true, meta: { [key: string]: string } }
|
|
|
+ )
|
|
|
|
|
|
async function getStats(tplDir: string): Promise<TemplateDirStatus> {
|
|
|
const markdownPath = path.resolve(tplDir, 'template.md');
|
|
|
@@ -62,17 +62,21 @@ async function getStats(tplDir: string): Promise<TemplateDirStatus> {
|
|
|
const result: TemplateDirStatus = {
|
|
|
isTemplateExists,
|
|
|
isMetaDataFileExists,
|
|
|
+ meta: isMetaDataFileExists ? await import(metaDataPath) : undefined,
|
|
|
};
|
|
|
|
|
|
- if (isMetaDataFileExists) {
|
|
|
- result.meta = await import(metaDataPath);
|
|
|
- }
|
|
|
-
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
|
|
|
-export const scanTemplateStatus = async(projectDirRoot: string, templateId: string, data: GrowiTemplatePluginValidationData): Promise<TemplateStatus[]> => {
|
|
|
+export const scanTemplateStatus = async(
|
|
|
+ projectDirRoot: string,
|
|
|
+ templateId: string,
|
|
|
+ data: GrowiTemplatePluginValidationData,
|
|
|
+ opts?: {
|
|
|
+ namespace?: string,
|
|
|
+ },
|
|
|
+): Promise<TemplateStatus[]> => {
|
|
|
const status: TemplateStatus[] = [];
|
|
|
|
|
|
const tplRootDirPath = path.resolve(projectDirRoot, 'dist', templateId);
|
|
|
@@ -82,26 +86,34 @@ export const scanTemplateStatus = async(projectDirRoot: string, templateId: stri
|
|
|
const tplDir = path.resolve(tplRootDirPath, locale);
|
|
|
|
|
|
try {
|
|
|
+ const stats = await getStats(tplDir);
|
|
|
const {
|
|
|
- isTemplateExists, isMetaDataFileExists, meta,
|
|
|
- } = await getStats(tplDir);
|
|
|
+ isTemplateExists, isMetaDataFileExists,
|
|
|
+ } = stats;
|
|
|
|
|
|
if (!isTemplateExists) throw new Error("'template.md does not exist.");
|
|
|
if (!isMetaDataFileExists) throw new Error("'meta.md does not exist.");
|
|
|
- if (meta?.title == null) throw new Error("'meta.md does not contain the title.");
|
|
|
+
|
|
|
+ assert(isMetaDataFileExists);
|
|
|
+ const { meta } = stats;
|
|
|
+
|
|
|
+ if (meta?.title) throw new Error("'meta.md does not contain the title.");
|
|
|
|
|
|
const isDefault = !isDefaultPushed;
|
|
|
status.push({
|
|
|
+ namespace: opts?.namespace,
|
|
|
id: templateId,
|
|
|
locale,
|
|
|
isValid: true,
|
|
|
isDefault,
|
|
|
title: meta.title,
|
|
|
+ desc: meta.desc,
|
|
|
});
|
|
|
isDefaultPushed = true;
|
|
|
}
|
|
|
catch (err) {
|
|
|
status.push({
|
|
|
+ namespace: opts?.namespace,
|
|
|
id: templateId,
|
|
|
locale,
|
|
|
isValid: false,
|
|
|
@@ -120,35 +132,36 @@ export const scanAllTemplateStatus = async(
|
|
|
projectDirRoot: string,
|
|
|
opts?: {
|
|
|
data?: GrowiTemplatePluginValidationData,
|
|
|
+ namespace?: string,
|
|
|
returnsInvalidTemplates?: boolean,
|
|
|
},
|
|
|
-): Promise<TemplateSummaries> => {
|
|
|
+): Promise<TemplateSummary[]> => {
|
|
|
|
|
|
const data = opts?.data ?? await validateTemplatePluginPackageJson(projectDirRoot);
|
|
|
|
|
|
- const summaries = {};
|
|
|
+ const summaries: TemplateSummary[] = [];
|
|
|
|
|
|
const distDirPath = path.resolve(projectDirRoot, 'dist');
|
|
|
const distDirFiles = fs.readdirSync(distDirPath);
|
|
|
|
|
|
for await (const templateId of distDirFiles) {
|
|
|
- const status = (await scanTemplateStatus(projectDirRoot, templateId, data))
|
|
|
+ const status = (await scanTemplateStatus(projectDirRoot, templateId, data, { namespace: opts?.namespace }))
|
|
|
// omit invalid templates if `returnsInvalidTemplates` is true
|
|
|
.filter(s => (opts?.returnsInvalidTemplates ? true : s.isValid));
|
|
|
|
|
|
// determine default locale
|
|
|
const defaultTemplateStatus = status.find(s => 'isDefault' in s && s.isDefault);
|
|
|
|
|
|
- if (defaultTemplateStatus == null) {
|
|
|
+ if (defaultTemplateStatus == null || !isTemplateStatusValid(defaultTemplateStatus)) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- summaries[templateId] = Object.assign(
|
|
|
+ summaries.push({
|
|
|
// for the 'default' key
|
|
|
- { default: defaultTemplateStatus },
|
|
|
+ default: defaultTemplateStatus,
|
|
|
// for each locale keys
|
|
|
- Object.fromEntries(status.map(templateStatus => [templateStatus.locale, templateStatus])),
|
|
|
- );
|
|
|
+ ...Object.fromEntries(status.map(templateStatus => [templateStatus.locale, templateStatus])),
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
return summaries;
|
|
|
@@ -167,8 +180,8 @@ export const validateTemplatePlugin = async(projectDirRoot: string): Promise<boo
|
|
|
// key: id
|
|
|
// value: isValid properties
|
|
|
const idValidMap: { [id: string]: boolean[] } = {};
|
|
|
- Object.entries(results).forEach(([templateId, status]) => {
|
|
|
- idValidMap[templateId] = Object.values(status).map(s => s?.isValid ?? false);
|
|
|
+ Object.entries(results).forEach(([index, summary]) => {
|
|
|
+ idValidMap[summary.default.id] = Object.values(summary).map(s => s?.isValid ?? false);
|
|
|
});
|
|
|
|
|
|
for (const [id, validMap] of Object.entries(idValidMap)) {
|