nodoku-core 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/bin/generate-component-default-theme.js +23 -0
- package/dist/esm/bin/generate-component-resolver.js +26 -75
- package/dist/esm/bin/generate-content-schema.js +1 -1
- package/dist/esm/bin/{generate-visual-schema.js → generate-skin-schema.js} +50 -62
- package/dist/esm/bin/import-load-hooks.js +1 -1
- package/dist/esm/bin/manifest-loader.js +49 -0
- package/dist/esm/bin/manifest.js +24 -0
- package/dist/esm/bin/mustache/component-resolver.ts.hbs +16 -0
- package/dist/esm/bin/mustache/content-schema.json.hbs +132 -0
- package/dist/esm/bin/mustache/visual-schema.json.hbs +165 -0
- package/dist/esm/content/nd-content.js +95 -0
- package/dist/esm/core/dummy-comp.jsx +80 -55
- package/dist/esm/core/rendering-page-props.js +16 -9
- package/dist/esm/core/rendering-page.jsx +187 -143
- package/dist/esm/index.js +11 -4
- package/dist/esm/providers/content/content-markdown-provider.js +374 -0
- package/dist/esm/providers/skin/skin-yaml-provider.js +52 -0
- package/dist/esm/skin/nd-skin.js +138 -0
- package/dist/esm/theme-utils/extended-theme-style.js +4 -0
- package/dist/esm/theme-utils/theme-merger.js +117 -0
- package/dist/esm/theme-utils/theme-style.js +8 -0
- package/dist/schemas/content-common-schema.json +89 -47
- package/dist/schemas/manifest-schema.json +21 -1
- package/dist/schemas/skin-common-schema.json +100 -0
- package/dist/types/bin/generate-component-default-theme.d.ts +2 -0
- package/dist/types/bin/generate-skin-schema.d.ts +2 -0
- package/dist/types/bin/manifest-loader.d.ts +2 -0
- package/dist/types/bin/manifest.d.ts +15 -0
- package/dist/types/content/nd-content.d.ts +51 -0
- package/dist/types/core/dummy-comp.d.ts +2 -2
- package/dist/types/core/providers.d.ts +12 -0
- package/dist/types/core/rendering-page-props.d.ts +14 -7
- package/dist/types/index.d.ts +13 -6
- package/dist/types/providers/content/content-markdown-provider.d.ts +3 -0
- package/dist/types/providers/skin/skin-yaml-provider.d.ts +3 -0
- package/dist/types/skin/nd-skin.d.ts +75 -0
- package/dist/types/theme-utils/extended-theme-style.d.ts +8 -0
- package/dist/types/theme-utils/theme-merger.d.ts +1 -0
- package/dist/types/theme-utils/theme-style.d.ts +5 -0
- package/package.json +14 -9
- package/dist/esm/bin/mustache/content-schema.json.mtl +0 -92
- package/dist/esm/bin/mustache/default-component-resolver.ts.mtl +0 -16
- package/dist/esm/bin/mustache/visual-schema.json.mtl +0 -40
- package/dist/esm/content/lb-content-block.js +0 -81
- package/dist/esm/content/manifest.js +0 -16
- package/dist/schemas/visual-common-schema.json +0 -29
- package/dist/types/bin/generate-visual-schema.d.ts +0 -2
- package/dist/types/content/lb-content-block.d.ts +0 -60
- package/dist/types/content/manifest.d.ts +0 -11
- package/dist/types/content/providers.d.ts +0 -9
- /package/dist/esm/{content → core}/providers.js +0 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import yaml from "js-yaml";
|
|
5
|
+
async function generateComponentDefaultTheme() {
|
|
6
|
+
console.log("generating default theme");
|
|
7
|
+
const dir = path.resolve("./dist/esm/components");
|
|
8
|
+
const dirSchema = path.resolve("./dist/schemas/components");
|
|
9
|
+
const components = fs.readdirSync(dir);
|
|
10
|
+
console.log("components", components);
|
|
11
|
+
Promise.all(components.map(async (compo) => {
|
|
12
|
+
const defaultTheme = (await import(`file:${path.resolve(dir, compo, compo + "-theme.js")}`)).default;
|
|
13
|
+
console.log("defaultTheme", defaultTheme);
|
|
14
|
+
const yamlContent = yaml.dump(defaultTheme, {
|
|
15
|
+
indent: 4,
|
|
16
|
+
lineWidth: 5000
|
|
17
|
+
});
|
|
18
|
+
console.log("yaml default theme", compo, yamlContent);
|
|
19
|
+
fs.writeFileSync(path.resolve(dirSchema, compo, "default-theme.yml"), yamlContent);
|
|
20
|
+
return null;
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
await generateComponentDefaultTheme();
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { register } from 'node:module';
|
|
3
|
-
import { ComponentDef, Manifest } from "../content/manifest.js";
|
|
4
3
|
import fs from "node:fs";
|
|
5
4
|
import path from "path";
|
|
6
5
|
import Mustache from "mustache";
|
|
6
|
+
import { loadManifestsFromFolder } from "./manifest-loader.js";
|
|
7
7
|
register('./import-load-hooks.js', import.meta.url);
|
|
8
8
|
/*
|
|
9
9
|
* we need to use a dynamic import here since otherwise we have no guarantee that the template
|
|
@@ -11,94 +11,45 @@ register('./import-load-hooks.js', import.meta.url);
|
|
|
11
11
|
* we register hooks, and only then use dynamic import to load custom template file
|
|
12
12
|
*/
|
|
13
13
|
// @ts-ignore
|
|
14
|
-
const template = (await import("./mustache/
|
|
15
|
-
function loadComponents(dir) {
|
|
16
|
-
const comps = new Map();
|
|
17
|
-
const files = fs.readdirSync(dir);
|
|
18
|
-
console.log("reading ...", dir);
|
|
19
|
-
for (const f of files) {
|
|
20
|
-
const stat = fs.statSync(`${dir}/${f}`);
|
|
21
|
-
if (stat.isDirectory()) {
|
|
22
|
-
const m = loadComponentsByManifest(`${dir}/${f}`, f);
|
|
23
|
-
if (m) {
|
|
24
|
-
comps.set(f, m);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return comps;
|
|
29
|
-
}
|
|
30
|
-
function loadComponentsByManifest(dir, moduleName) {
|
|
31
|
-
const files = fs.readdirSync(dir);
|
|
32
|
-
for (const f of files) {
|
|
33
|
-
const stat = fs.statSync(`${dir}/${f}`);
|
|
34
|
-
if (stat.isFile()) {
|
|
35
|
-
if (f == "nodoku.manifest.json") {
|
|
36
|
-
const manifest = new Manifest(moduleName);
|
|
37
|
-
console.log("found manifest ", `${dir}/${f}`, "reading...");
|
|
38
|
-
let json;
|
|
39
|
-
if (stat.isSymbolicLink()) {
|
|
40
|
-
json = JSON.parse(fs.readlinkSync(`${dir}/nodoku.manifest.json`));
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
json = JSON.parse(fs.readFileSync(`${dir}/nodoku.manifest.json`).toString());
|
|
44
|
-
}
|
|
45
|
-
console.log("loaded manifest ", path.resolve(dir, f));
|
|
46
|
-
console.log("found manifest json ", json);
|
|
47
|
-
manifest.namespace = json.namespace;
|
|
48
|
-
Object.keys(json.components).forEach((k) => {
|
|
49
|
-
const v = json.components[k];
|
|
50
|
-
console.log("adding ", k, v);
|
|
51
|
-
// comps.set(k, Manifest.from(k, moduleName, v));
|
|
52
|
-
manifest.components.set(k, new ComponentDef(v.implementation, v.schema));
|
|
53
|
-
});
|
|
54
|
-
return manifest;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return undefined;
|
|
59
|
-
}
|
|
14
|
+
const template = (await import("./mustache/component-resolver.ts.hbs")).default;
|
|
60
15
|
class TemplateView {
|
|
61
|
-
modules =
|
|
62
|
-
|
|
16
|
+
modules = [];
|
|
17
|
+
comps = [];
|
|
63
18
|
}
|
|
64
|
-
function calculateTemplateView(
|
|
65
|
-
if (!
|
|
66
|
-
|
|
19
|
+
function calculateTemplateView(dirNodeModules = undefined) {
|
|
20
|
+
if (!dirNodeModules) {
|
|
21
|
+
dirNodeModules = `${path.resolve()}/node_modules`;
|
|
67
22
|
}
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
console.log("adding ", m.moduleName);
|
|
73
|
-
tv.modules.set(m.moduleName, []);
|
|
74
|
-
}
|
|
23
|
+
const manifests = loadManifestsFromFolder(dirNodeModules);
|
|
24
|
+
const view = new TemplateView();
|
|
25
|
+
manifests.forEach((m, k) => {
|
|
26
|
+
let prefix = "";
|
|
75
27
|
if (m.namespace) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
tv.names.set(cn, `${m.namespace}.${cd.implementation}`);
|
|
79
|
-
});
|
|
28
|
+
view.modules.push({ module: m.moduleName, comps: [m.namespace] });
|
|
29
|
+
prefix = `${m.namespace}.`;
|
|
80
30
|
}
|
|
81
31
|
else {
|
|
82
|
-
m.components.
|
|
83
|
-
tv.modules.get(m.moduleName).push(cd.implementation);
|
|
84
|
-
tv.names.set(cn, cd.implementation);
|
|
85
|
-
});
|
|
32
|
+
view.modules.push({ module: m.moduleName, comps: Array.from(m.components.entries()).map(c => c[1].implementation) });
|
|
86
33
|
}
|
|
34
|
+
m.components.forEach((cd, cn) => {
|
|
35
|
+
let nb;
|
|
36
|
+
if (typeof cd.numBlocks == "string") {
|
|
37
|
+
nb = `"${cd.numBlocks}"`;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
nb = `${cd.numBlocks}`;
|
|
41
|
+
}
|
|
42
|
+
view.comps.push({ name: cn, impl: `${prefix}${cd.implementation}`, defaultThemeFile: "./" + path.relative(path.resolve("."), path.resolve("./schemas", m.moduleName, cd.defaultThemeFile)).replaceAll("\\", "/"), numBlocks: nb });
|
|
43
|
+
});
|
|
87
44
|
});
|
|
88
|
-
return
|
|
45
|
+
return view;
|
|
89
46
|
}
|
|
90
47
|
export function generateComponentResolver() {
|
|
91
48
|
const args = process.argv.slice(2);
|
|
92
49
|
const dir = path.resolve();
|
|
93
50
|
const src = args[0] ? args[0] : "./src";
|
|
94
51
|
console.log("generating component resolver");
|
|
95
|
-
const
|
|
96
|
-
const view = {
|
|
97
|
-
modules: Array.from(tv.modules.entries()).map((e) => {
|
|
98
|
-
return { "module": e[0], "comps": e[1].join(", ") };
|
|
99
|
-
}),
|
|
100
|
-
names: Array.from(tv.names.entries()).map((n) => { return { n: n[0], c: n[1] }; })
|
|
101
|
-
};
|
|
52
|
+
const view = calculateTemplateView();
|
|
102
53
|
console.log("view", JSON.stringify(view));
|
|
103
54
|
const output = Mustache.render(template, view);
|
|
104
55
|
const fileName = `${dir}/${src}/nodoku-component-resolver.ts`;
|
|
@@ -10,7 +10,7 @@ register('./import-load-hooks.js', import.meta.url);
|
|
|
10
10
|
* we register hooks, and only then use dynamic import to load custom template file
|
|
11
11
|
*/
|
|
12
12
|
// @ts-ignore
|
|
13
|
-
const template = (await import("./mustache/content-schema.json.
|
|
13
|
+
const template = (await import("./mustache/content-schema.json.hbs")).default;
|
|
14
14
|
const linkRegexPattern = "^((http|https)?:\\\\/\\\\/)?\\\\/?([-a-zA-Z0-9._\\\\+~#=]{1,256})([-a-zA-Z0-9@:%._\\\\+~#=]{1,256})([-a-zA-Z0-9()@:%_\\\\+.~#?&\\\\/\\\\/=]*)$";
|
|
15
15
|
export function generateContentSchema() {
|
|
16
16
|
const args = process.argv.slice(2);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { register } from 'node:module';
|
|
3
|
-
import { ComponentDef, Manifest } from "../content/manifest.js";
|
|
4
3
|
import fs from "node:fs";
|
|
5
4
|
import path from "path";
|
|
6
5
|
import Mustache from "mustache";
|
|
6
|
+
import { loadManifestsFromFolder } from "./manifest-loader.js";
|
|
7
7
|
register('./import-load-hooks.js', import.meta.url);
|
|
8
8
|
/*
|
|
9
9
|
* we need to use a dynamic import here since otherwise we have no guarantee that the template
|
|
@@ -11,79 +11,66 @@ register('./import-load-hooks.js', import.meta.url);
|
|
|
11
11
|
* we register hooks, and only then use dynamic import to load custom template file
|
|
12
12
|
*/
|
|
13
13
|
// @ts-ignore
|
|
14
|
-
const template = (await import("./mustache/visual-schema.json.
|
|
15
|
-
function loadComponents(dir) {
|
|
16
|
-
const comps = new Map();
|
|
17
|
-
const files = fs.readdirSync(dir);
|
|
18
|
-
console.log("reading ...", dir);
|
|
19
|
-
for (const f of files) {
|
|
20
|
-
const stat = fs.statSync(`${dir}/${f}`);
|
|
21
|
-
if (stat.isDirectory()) {
|
|
22
|
-
const m = loadComponentsByManifest(`${dir}/${f}`, f);
|
|
23
|
-
if (m) {
|
|
24
|
-
comps.set(f, m);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return comps;
|
|
29
|
-
}
|
|
30
|
-
function loadComponentsByManifest(dir, moduleName) {
|
|
31
|
-
const files = fs.readdirSync(dir);
|
|
32
|
-
for (const f of files) {
|
|
33
|
-
const stat = fs.statSync(`${dir}/${f}`);
|
|
34
|
-
if (stat.isFile()) {
|
|
35
|
-
if (f == "nodoku.manifest.json") {
|
|
36
|
-
const manifest = new Manifest(moduleName);
|
|
37
|
-
console.log("found manifest ", `${dir}/${f}`, "reading...");
|
|
38
|
-
let json;
|
|
39
|
-
if (stat.isSymbolicLink()) {
|
|
40
|
-
json = JSON.parse(fs.readlinkSync(`${dir}/nodoku.manifest.json`));
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
json = JSON.parse(fs.readFileSync(`${dir}/nodoku.manifest.json`).toString());
|
|
44
|
-
}
|
|
45
|
-
console.log("loaded manifest ", path.resolve(dir, f));
|
|
46
|
-
console.log("found manifest json ", json);
|
|
47
|
-
manifest.namespace = json.namespace;
|
|
48
|
-
Object.keys(json.components).forEach((k) => {
|
|
49
|
-
const v = json.components[k];
|
|
50
|
-
console.log("adding ", k, v);
|
|
51
|
-
// comps.set(k, Manifest.from(k, moduleName, v));
|
|
52
|
-
manifest.components.set(k, new ComponentDef(v.implementation, v.schemaFile));
|
|
53
|
-
});
|
|
54
|
-
return manifest;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return undefined;
|
|
59
|
-
}
|
|
14
|
+
const template = (await import("./mustache/visual-schema.json.hbs")).default;
|
|
60
15
|
class TemplateView {
|
|
61
16
|
components = new Map();
|
|
62
17
|
}
|
|
63
18
|
function calculateTemplateView(schemaDestinationDir, dirNodeModules = undefined) {
|
|
64
19
|
if (!dirNodeModules) {
|
|
65
|
-
dirNodeModules =
|
|
20
|
+
dirNodeModules = path.resolve("./node_modules");
|
|
66
21
|
}
|
|
67
|
-
const components =
|
|
22
|
+
const components = loadManifestsFromFolder(dirNodeModules);
|
|
68
23
|
const tv = new TemplateView();
|
|
69
24
|
components.forEach((m) => {
|
|
70
25
|
m.components.forEach((cd, cn) => {
|
|
71
26
|
const moduleDir = `${dirNodeModules}/${m.moduleName}`;
|
|
72
|
-
const
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
27
|
+
const themeSchema = resolveSchema(schemaDestinationDir, m.moduleName, moduleDir, cd.themeSchema, dirNodeModules);
|
|
28
|
+
const optionsSchema = resolveSchema(schemaDestinationDir, m.moduleName, moduleDir, cd.optionsSchema, dirNodeModules);
|
|
29
|
+
tv.components.set(cn, { themeSchema: themeSchema, optionsSchema: optionsSchema });
|
|
30
|
+
/*
|
|
31
|
+
* copy default-theme.yml
|
|
32
|
+
*/
|
|
33
|
+
const compSchema = cd.themeSchema;
|
|
34
|
+
const moduleSchemaFile = path.resolve(stripTrailingSlash(moduleDir), stripLeadingSlash(compSchema));
|
|
35
|
+
const compDefaultYaml = cd.defaultThemeFile;
|
|
36
|
+
// const moduleDefaultYamlFile = path.resolve(path.dirname(moduleSchemaFile), stripLeadingSlash(compDefaultYaml));
|
|
37
|
+
const moduleDefaultYamlFile = path.resolve(stripTrailingSlash(moduleDir), stripLeadingSlash(compDefaultYaml));
|
|
38
|
+
let stat = undefined;
|
|
39
|
+
try {
|
|
40
|
+
stat = fs.statSync(moduleDefaultYamlFile);
|
|
41
|
+
console.log("defaultYamlFilePath", moduleDefaultYamlFile);
|
|
42
|
+
if (stat.isFile()) {
|
|
43
|
+
let destSchemaFile = path.resolve(m.moduleName, compSchema);
|
|
44
|
+
console.log("compSchema", compSchema);
|
|
45
|
+
const dest = path.resolve(schemaDestinationDir, themeSchema);
|
|
46
|
+
const yamlFileName = path.basename(moduleDefaultYamlFile);
|
|
47
|
+
console.log("copying default-theme.yml", yamlFileName, schemaDestinationDir, destSchemaFile, moduleDefaultYamlFile, dest, path.dirname(dest));
|
|
48
|
+
fs.copyFile(moduleDefaultYamlFile, path.resolve(path.dirname(dest), yamlFileName), (err) => { });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
console.log("defaultYamlFilePath file not found ", moduleDefaultYamlFile);
|
|
53
|
+
}
|
|
77
54
|
});
|
|
78
55
|
});
|
|
79
56
|
const compSchemas = [];
|
|
80
57
|
let i = 0;
|
|
81
58
|
tv.components.forEach((v, k) => {
|
|
82
|
-
compSchemas.push({ name: k, schema: v, isLast: i == tv.components.size - 1 });
|
|
59
|
+
compSchemas.push({ name: k, schema: v.themeSchema, options: v.optionsSchema, isLast: i == tv.components.size - 1 });
|
|
83
60
|
i++;
|
|
84
61
|
});
|
|
85
62
|
return { components: compSchemas };
|
|
86
63
|
}
|
|
64
|
+
function resolveSchema(schemaDestinationDir, moduleName, moduleDir, schemaFileLoc, dirNodeModules) {
|
|
65
|
+
if (!schemaFileLoc) {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
const { content, dest } = readSchema(schemaDestinationDir, moduleName, moduleDir, schemaFileLoc);
|
|
69
|
+
const resolvedContent = resolveRefsInSchema(content, moduleName, dirNodeModules, schemaDestinationDir, schemaFileLoc);
|
|
70
|
+
const schemaFile = writeSchema(dest, resolvedContent);
|
|
71
|
+
const res = schemaFile.startsWith(schemaDestinationDir) ? schemaFile.replace(stripTrailingSlash(schemaDestinationDir), ".") : schemaFile;
|
|
72
|
+
return res;
|
|
73
|
+
}
|
|
87
74
|
function resolveRefsInSchema(schemaFileContent, moduleName, dirNodeModules, schemaDestinationDir, schemaFileRelativeToModuleDir) {
|
|
88
75
|
const regex = /\s*"\$ref": "(.*)"/;
|
|
89
76
|
const refs = [];
|
|
@@ -143,10 +130,11 @@ function resolveRef(ref, moduleName, dirNodeModules, schemaDestinationDir, schem
|
|
|
143
130
|
console.log("returning ref", ref);
|
|
144
131
|
return ref;
|
|
145
132
|
}
|
|
146
|
-
function readSchema(schemaDestinationDir, moduleName, moduleDir,
|
|
147
|
-
const moduleSchemaFile = `${stripTrailingSlash(moduleDir)}/${stripLeadingSlash(
|
|
133
|
+
function readSchema(schemaDestinationDir, moduleName, moduleDir, schemaFileLoc) {
|
|
134
|
+
// const moduleSchemaFile = `${stripTrailingSlash(moduleDir)}/${stripLeadingSlash(schemaFileLoc)}`;
|
|
135
|
+
const moduleSchemaFile = path.resolve(moduleDir, schemaFileLoc);
|
|
148
136
|
console.log("module dir", moduleDir);
|
|
149
|
-
let destSchemaFile = `${moduleName}/${stripLeadingSlash(
|
|
137
|
+
let destSchemaFile = `${moduleName}/${stripLeadingSlash(schemaFileLoc)}`;
|
|
150
138
|
const dest = `${schemaDestinationDir}/${destSchemaFile}`;
|
|
151
139
|
const moduleSchemaFilePath = moduleSchemaFile.replaceAll("/", "\\");
|
|
152
140
|
const stat = fs.statSync(moduleSchemaFilePath);
|
|
@@ -174,15 +162,15 @@ function stripTrailingSlash(path) {
|
|
|
174
162
|
return path;
|
|
175
163
|
}
|
|
176
164
|
function stripLeadingSlash(path) {
|
|
177
|
-
if (path.startsWith("/")) {
|
|
165
|
+
if (path && path.startsWith("/")) {
|
|
178
166
|
return path.substring(1);
|
|
179
167
|
}
|
|
180
|
-
else if (path.startsWith("./")) {
|
|
168
|
+
else if (path && path.startsWith("./")) {
|
|
181
169
|
return path.substring(2);
|
|
182
170
|
}
|
|
183
171
|
return path;
|
|
184
172
|
}
|
|
185
|
-
export function
|
|
173
|
+
export function generateSkinSchema() {
|
|
186
174
|
const args = process.argv.slice(2);
|
|
187
175
|
const dir = path.resolve();
|
|
188
176
|
const schemaSrc = args[0] ? args[0] : "./schemas";
|
|
@@ -197,4 +185,4 @@ export function generateVisualSchema() {
|
|
|
197
185
|
console.log(`${fileName}: File created!`);
|
|
198
186
|
});
|
|
199
187
|
}
|
|
200
|
-
|
|
188
|
+
generateSkinSchema();
|
|
@@ -10,7 +10,7 @@ export async function resolve(specifier, context, nextResolve) {
|
|
|
10
10
|
}
|
|
11
11
|
export async function load(url, context, nextLoad) {
|
|
12
12
|
console.log("Take a resolved URL and return the source code to be evaluated.", url, context, nextLoad);
|
|
13
|
-
if (url.endsWith(".
|
|
13
|
+
if (url.endsWith(".hbs")) {
|
|
14
14
|
const prefix = path.resolve("./");
|
|
15
15
|
const filePath = nodeUrl.fileURLToPath(url);
|
|
16
16
|
const file = await open(filePath);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ComponentDef, Manifest } from "./manifest.js";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
export function loadManifestsFromFolder(dir) {
|
|
5
|
+
const comps = new Map();
|
|
6
|
+
const files = fs.readdirSync(dir);
|
|
7
|
+
console.log("reading ...", dir);
|
|
8
|
+
for (const f of files) {
|
|
9
|
+
const stat = fs.statSync(`${dir}/${f}`);
|
|
10
|
+
if (stat.isDirectory()) {
|
|
11
|
+
const m = loadComponentsByManifest(`${dir}/${f}`, f);
|
|
12
|
+
if (m) {
|
|
13
|
+
comps.set(f, m);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return comps;
|
|
18
|
+
}
|
|
19
|
+
function loadComponentsByManifest(dir, moduleName) {
|
|
20
|
+
const files = fs.readdirSync(dir);
|
|
21
|
+
for (const f of files) {
|
|
22
|
+
const moduleDir = path.resolve(dir, f);
|
|
23
|
+
const stat = fs.statSync(moduleDir);
|
|
24
|
+
if (stat.isFile()) {
|
|
25
|
+
if (f == "nodoku.manifest.json") {
|
|
26
|
+
const manifest = new Manifest(moduleName, moduleDir);
|
|
27
|
+
console.log("found manifest ", `${dir}/${f}`, "reading...");
|
|
28
|
+
let json;
|
|
29
|
+
if (stat.isSymbolicLink()) {
|
|
30
|
+
json = JSON.parse(fs.readlinkSync(`${dir}/nodoku.manifest.json`).toString());
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
json = JSON.parse(fs.readFileSync(`${dir}/nodoku.manifest.json`).toString());
|
|
34
|
+
}
|
|
35
|
+
console.log("loaded manifest ", path.resolve(dir, f));
|
|
36
|
+
console.log("found manifest json ", json);
|
|
37
|
+
manifest.namespace = json.namespace;
|
|
38
|
+
Object.keys(json.components).forEach((k) => {
|
|
39
|
+
const v = json.components[k];
|
|
40
|
+
console.log("adding ", k, v);
|
|
41
|
+
// comps.set(k, Manifest.from(k, moduleName, v));
|
|
42
|
+
manifest.components.set(k, new ComponentDef(v.implementation, v.schemaFile, v.optionsFile, v.defaultThemeFile, v.numBlocks));
|
|
43
|
+
});
|
|
44
|
+
return manifest;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export class ComponentDef {
|
|
2
|
+
implementation;
|
|
3
|
+
themeSchema;
|
|
4
|
+
optionsSchema;
|
|
5
|
+
defaultThemeFile;
|
|
6
|
+
numBlocks;
|
|
7
|
+
constructor(componentImplementation, componentSchema, optionsSchema, defaultThemeFile, numBlocks) {
|
|
8
|
+
this.implementation = componentImplementation;
|
|
9
|
+
this.themeSchema = componentSchema;
|
|
10
|
+
this.optionsSchema = optionsSchema;
|
|
11
|
+
this.defaultThemeFile = defaultThemeFile;
|
|
12
|
+
this.numBlocks = numBlocks;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export class Manifest {
|
|
16
|
+
moduleName;
|
|
17
|
+
moduleDir;
|
|
18
|
+
namespace = undefined;
|
|
19
|
+
components = new Map();
|
|
20
|
+
constructor(moduleName, moduleDir) {
|
|
21
|
+
this.moduleName = moduleName;
|
|
22
|
+
this.moduleDir = moduleDir;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {AsyncFunctionComponent, DummyComp, NdComponentDefinition} from "nodoku-core";
|
|
2
|
+
|
|
3
|
+
{{#modules}}
|
|
4
|
+
import { {{comps}} } from "{{module}}";
|
|
5
|
+
{{/modules}}
|
|
6
|
+
|
|
7
|
+
const components: Map<string, {compo: AsyncFunctionComponent, compoDef: NdComponentDefinition}> = new Map<string, {compo: AsyncFunctionComponent, compoDef: NdComponentDefinition}>();
|
|
8
|
+
|
|
9
|
+
{{#comps}}
|
|
10
|
+
components.set("{{{name}}}", {compo: {{impl}}, compoDef: new NdComponentDefinition({{{numBlocks}}}, "{{{defaultThemeFile}}}")});
|
|
11
|
+
{{/comps}}
|
|
12
|
+
|
|
13
|
+
export function defaultComponentProvider(componentName: string): Promise<{compo: AsyncFunctionComponent, compoDef: NdComponentDefinition}> {
|
|
14
|
+
const f: {compo: AsyncFunctionComponent, compoDef: NdComponentDefinition} | undefined = components.get(componentName);
|
|
15
|
+
return Promise.resolve(f ? f : {compo: DummyComp, compoDef: new NdComponentDefinition(1)});
|
|
16
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Landing buddy content page schema",
|
|
3
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
|
+
"definitions": {
|
|
5
|
+
"Link": {
|
|
6
|
+
"type": "string",
|
|
7
|
+
"pattern": "{{{linkRegexPattern}}}"
|
|
8
|
+
},
|
|
9
|
+
"ClickableText": {
|
|
10
|
+
"oneOf": [
|
|
11
|
+
{
|
|
12
|
+
"type": "string"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"type": "object",
|
|
16
|
+
"properties": {
|
|
17
|
+
"text": {
|
|
18
|
+
"type": "string"
|
|
19
|
+
},
|
|
20
|
+
"link": {
|
|
21
|
+
"$ref": "#/definitions/Link"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
"Image": {
|
|
28
|
+
"oneOf": [
|
|
29
|
+
{
|
|
30
|
+
"type": "object",
|
|
31
|
+
"properties": {
|
|
32
|
+
"title": {
|
|
33
|
+
"type": "string"
|
|
34
|
+
},
|
|
35
|
+
"url": {
|
|
36
|
+
"type": "string"
|
|
37
|
+
},
|
|
38
|
+
"alt": {
|
|
39
|
+
"type": "string"
|
|
40
|
+
},
|
|
41
|
+
"link": {
|
|
42
|
+
"$ref": "#/definitions/Link"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"required": [
|
|
46
|
+
"url"
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"type": "string"
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
"ContentBlock": {
|
|
55
|
+
"type": "object",
|
|
56
|
+
"properties": {
|
|
57
|
+
"id": {
|
|
58
|
+
"type": "string"
|
|
59
|
+
},
|
|
60
|
+
"title": {
|
|
61
|
+
"$ref": "#/definitions/ClickableText"
|
|
62
|
+
},
|
|
63
|
+
"subTitle": {
|
|
64
|
+
"$ref": "#/definitions/ClickableText"
|
|
65
|
+
},
|
|
66
|
+
"h3": {
|
|
67
|
+
"$ref": "#/definitions/ClickableText"
|
|
68
|
+
},
|
|
69
|
+
"h4": {
|
|
70
|
+
"$ref": "#/definitions/ClickableText"
|
|
71
|
+
},
|
|
72
|
+
"h5": {
|
|
73
|
+
"$ref": "#/definitions/ClickableText"
|
|
74
|
+
},
|
|
75
|
+
"h6": {
|
|
76
|
+
"$ref": "#/definitions/ClickableText"
|
|
77
|
+
},
|
|
78
|
+
"footer": {
|
|
79
|
+
"$ref": "#/definitions/ClickableText"
|
|
80
|
+
},
|
|
81
|
+
"images": {
|
|
82
|
+
"type": "array",
|
|
83
|
+
"items": {
|
|
84
|
+
"$ref": "#/definitions/Image"
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"paragraphs": {
|
|
88
|
+
"type": "array",
|
|
89
|
+
"items": {
|
|
90
|
+
"$ref": "#/definitions/ClickableText"
|
|
91
|
+
},
|
|
92
|
+
"additionalItems": false
|
|
93
|
+
},
|
|
94
|
+
"bgImage": {
|
|
95
|
+
"$ref": "#/definitions/Image"
|
|
96
|
+
},
|
|
97
|
+
"namespace": {
|
|
98
|
+
"type": "string"
|
|
99
|
+
},
|
|
100
|
+
"tags": {
|
|
101
|
+
"type": "array",
|
|
102
|
+
"items": {
|
|
103
|
+
"type": "string"
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"attributes": {
|
|
107
|
+
"type": "object",
|
|
108
|
+
"additionalProperties": {
|
|
109
|
+
"type": "string"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
},
|
|
114
|
+
"additionalItems": false,
|
|
115
|
+
"additionalProperties": false
|
|
116
|
+
},
|
|
117
|
+
"SectionBlock": {
|
|
118
|
+
"type": "array",
|
|
119
|
+
"items": {
|
|
120
|
+
"$ref": "#/definitions/ContentBlock"
|
|
121
|
+
},
|
|
122
|
+
"additionalItems": false,
|
|
123
|
+
"additionalProperties": false
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
"type": "array",
|
|
127
|
+
"items": {
|
|
128
|
+
"$ref": "#/definitions/ContentBlock"
|
|
129
|
+
},
|
|
130
|
+
"additionalItems": false,
|
|
131
|
+
"additionalProperties": false
|
|
132
|
+
}
|