@schalkneethling/miyagi-core 4.0.2
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/LICENSE.md +21 -0
- package/README.md +43 -0
- package/api/app.js +39 -0
- package/api/index.js +236 -0
- package/bin/miyagi.js +2 -0
- package/dist/css/iframe.css +31 -0
- package/dist/css/main.css +1 -0
- package/dist/js/_iframe-links-DdifIr4P.js +1 -0
- package/dist/js/_mock-data-Dypo4Bl_.js +1 -0
- package/dist/js/_prism-By3NMwUd.js +1 -0
- package/dist/js/iframe.build.js +1 -0
- package/dist/js/iframe.js +1 -0
- package/dist/js/index-BKDKaBC6.js +1 -0
- package/dist/js/jsontree.js +1 -0
- package/dist/js/main.build.js +1 -0
- package/dist/js/main.js +1 -0
- package/frontend/assets/css/iframe/accordion-tabs.css +77 -0
- package/frontend/assets/css/iframe/jsontree.js.css +325 -0
- package/frontend/assets/css/iframe/prism.css +132 -0
- package/frontend/assets/css/iframe/styleguide/colors.css +61 -0
- package/frontend/assets/css/iframe/styleguide/fonts.css +37 -0
- package/frontend/assets/css/iframe/styleguide/index.css +109 -0
- package/frontend/assets/css/iframe/styleguide/spacings.css +21 -0
- package/frontend/assets/css/iframe.css +410 -0
- package/frontend/assets/css/main/menu/config-switcher.css +49 -0
- package/frontend/assets/css/main/menu/config-switchers.css +67 -0
- package/frontend/assets/css/main/menu/goto.css +24 -0
- package/frontend/assets/css/main/menu/nav.css +113 -0
- package/frontend/assets/css/main/menu/search.css +64 -0
- package/frontend/assets/css/main/menu/title.css +40 -0
- package/frontend/assets/css/main/menu.css +114 -0
- package/frontend/assets/css/main/reset.css +217 -0
- package/frontend/assets/css/main.css +71 -0
- package/frontend/assets/css/shared.css +34 -0
- package/frontend/assets/css/tokens.css +112 -0
- package/frontend/assets/favicon.ico +0 -0
- package/frontend/assets/js/_accordion-tabs.js +403 -0
- package/frontend/assets/js/_goto.js +63 -0
- package/frontend/assets/js/_iframe-links.js +19 -0
- package/frontend/assets/js/_is-triggered.js +15 -0
- package/frontend/assets/js/_main.js +379 -0
- package/frontend/assets/js/_mock-data.js +13 -0
- package/frontend/assets/js/_prism.js +1098 -0
- package/frontend/assets/js/_search.js +190 -0
- package/frontend/assets/js/_socket.js +9 -0
- package/frontend/assets/js/config-switcher/development-mode.js +49 -0
- package/frontend/assets/js/config-switcher/index.js +63 -0
- package/frontend/assets/js/config-switcher/text-direction.js +30 -0
- package/frontend/assets/js/config-switcher/theme.js +87 -0
- package/frontend/assets/js/iframe.build.js +43 -0
- package/frontend/assets/js/iframe.js +52 -0
- package/frontend/assets/js/jsontree.js +979 -0
- package/frontend/assets/js/main.build.js +40 -0
- package/frontend/assets/js/main.js +42 -0
- package/frontend/assets/js/styleguide/color-converter.js +741 -0
- package/frontend/assets/js/styleguide/index.js +119 -0
- package/frontend/views/component_variation.twig.miyagi +57 -0
- package/frontend/views/design-tokens/colors.twig.miyagi +43 -0
- package/frontend/views/design-tokens/sizes.twig.miyagi +35 -0
- package/frontend/views/design-tokens/typography.twig.miyagi +38 -0
- package/frontend/views/iframe_component.twig.miyagi +141 -0
- package/frontend/views/iframe_component_variation.twig.miyagi +55 -0
- package/frontend/views/iframe_index.twig.miyagi +14 -0
- package/frontend/views/layouts/iframe_default.twig.miyagi +22 -0
- package/frontend/views/main.twig.miyagi +24 -0
- package/frontend/views/menu/config-switchers.twig.miyagi +83 -0
- package/frontend/views/menu/goto.twig.miyagi +9 -0
- package/frontend/views/menu/menu.twig.miyagi +21 -0
- package/frontend/views/menu/nav.twig.miyagi +95 -0
- package/frontend/views/menu/search.twig.miyagi +13 -0
- package/frontend/views/menu/title.twig.miyagi +24 -0
- package/index.js +3 -0
- package/lib/build/index.js +1020 -0
- package/lib/cli/app.js +38 -0
- package/lib/cli/component.js +56 -0
- package/lib/cli/index.js +5 -0
- package/lib/cli/lint.js +180 -0
- package/lib/config.js +74 -0
- package/lib/default-config.js +105 -0
- package/lib/generator/component.js +199 -0
- package/lib/generator/mocks.js +201 -0
- package/lib/helpers.js +184 -0
- package/lib/i18n/en.js +91 -0
- package/lib/i18n/index.js +17 -0
- package/lib/index.js +166 -0
- package/lib/init/args.js +55 -0
- package/lib/init/config.js +330 -0
- package/lib/init/engines.js +65 -0
- package/lib/init/index.js +102 -0
- package/lib/init/rendering.js +12 -0
- package/lib/init/router.js +249 -0
- package/lib/init/static.js +133 -0
- package/lib/init/twing/cache.js +34 -0
- package/lib/init/twing/functions.js +51 -0
- package/lib/init/views.js +19 -0
- package/lib/init/watcher.js +402 -0
- package/lib/logger.js +94 -0
- package/lib/mocks/get.js +111 -0
- package/lib/mocks/index.js +9 -0
- package/lib/mocks/resolve/ref.js +484 -0
- package/lib/mocks/resolve/tpl.js +246 -0
- package/lib/mocks/resolve.js +205 -0
- package/lib/render/helpers.js +51 -0
- package/lib/render/index.js +38 -0
- package/lib/render/views/iframe/component.docs.js +77 -0
- package/lib/render/views/iframe/component.js +338 -0
- package/lib/render/views/iframe/design-tokens/colors.js +52 -0
- package/lib/render/views/iframe/design-tokens/index.js +9 -0
- package/lib/render/views/iframe/design-tokens/sizes.js +49 -0
- package/lib/render/views/iframe/design-tokens/typography.js +52 -0
- package/lib/render/views/iframe/docs.js +68 -0
- package/lib/render/views/iframe/index.js +44 -0
- package/lib/render/views/iframe/variation.js +116 -0
- package/lib/render/views/iframe/variation.standalone.js +89 -0
- package/lib/render/views/main/component.docs.js +53 -0
- package/lib/render/views/main/component.js +74 -0
- package/lib/render/views/main/design-tokens.js +53 -0
- package/lib/render/views/main/docs.js +47 -0
- package/lib/render/views/main/index.js +46 -0
- package/lib/state/components.js +132 -0
- package/lib/state/css.js +50 -0
- package/lib/state/docs.js +111 -0
- package/lib/state/file-contents.js +207 -0
- package/lib/state/helpers.js +86 -0
- package/lib/state/index.js +56 -0
- package/lib/state/menu/index.js +275 -0
- package/lib/state/menu/structure.js +146 -0
- package/lib/state/partials.js +23 -0
- package/lib/state/source-tree.js +75 -0
- package/lib/styleguide/color-names.js +150 -0
- package/lib/styleguide/colors.js +135 -0
- package/lib/styleguide/helpers.js +37 -0
- package/lib/styleguide/index.js +17 -0
- package/lib/styleguide/media-queries.js +26 -0
- package/lib/styleguide/spacings.js +35 -0
- package/lib/styleguide/typography.js +61 -0
- package/lib/validator/mocks.js +105 -0
- package/package.json +117 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import config from "../../../default-config.js";
|
|
2
|
+
import { getUserUiConfig, getThemeMode } from "../../helpers.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {object} object - parameter object
|
|
6
|
+
* @param {object} object.res - the express response object
|
|
7
|
+
* @param {object} object.doc
|
|
8
|
+
* @param {Function} [object.cb] - callback function
|
|
9
|
+
* @param {object} [object.cookies]
|
|
10
|
+
*/
|
|
11
|
+
export default async function renderMainDocs({ res, doc, cb, cookies }) {
|
|
12
|
+
const themeMode = getThemeMode(cookies);
|
|
13
|
+
|
|
14
|
+
await res.render(
|
|
15
|
+
"main.twig.miyagi",
|
|
16
|
+
{
|
|
17
|
+
lang: global.config.ui.lang,
|
|
18
|
+
folders: global.state.menu,
|
|
19
|
+
components: global.state.components,
|
|
20
|
+
flatUrlPattern: global.config.isBuild
|
|
21
|
+
? "/show-{{component}}.html"
|
|
22
|
+
: "/show?file={{component}}",
|
|
23
|
+
iframeSrc: doc.route.embedded,
|
|
24
|
+
requestedComponent: doc.paths.dir.short,
|
|
25
|
+
projectName: config.projectName,
|
|
26
|
+
userProjectName: global.config.projectName,
|
|
27
|
+
indexPath: global.config.indexPath.embedded,
|
|
28
|
+
miyagiDev: !!process.env.MIYAGI_DEVELOPMENT,
|
|
29
|
+
isBuild: global.config.isBuild,
|
|
30
|
+
userUiConfig: getUserUiConfig(cookies),
|
|
31
|
+
theme: themeMode
|
|
32
|
+
? Object.assign(global.config.ui.theme, { mode: themeMode })
|
|
33
|
+
: global.config.ui.theme,
|
|
34
|
+
basePath: global.config.isBuild ? global.config.build.basePath : "/",
|
|
35
|
+
uiTextDirection: global.config.ui.textDirection,
|
|
36
|
+
},
|
|
37
|
+
(html) => {
|
|
38
|
+
if (res.send) {
|
|
39
|
+
res.send(html);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (cb) {
|
|
43
|
+
cb(null, html);
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
);
|
|
47
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import config from "../../../default-config.js";
|
|
2
|
+
import { getUserUiConfig, getThemeMode } from "../../helpers.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {object} object - parameter object
|
|
6
|
+
* @param {object} object.res - the express response object
|
|
7
|
+
* @param {Function} [object.cb] - callback function
|
|
8
|
+
* @param {object} [object.cookies]
|
|
9
|
+
*/
|
|
10
|
+
export default function renderMainIndex({ res, cb, cookies }) {
|
|
11
|
+
const themeMode = getThemeMode(cookies);
|
|
12
|
+
|
|
13
|
+
res.render(
|
|
14
|
+
"main.twig.miyagi",
|
|
15
|
+
{
|
|
16
|
+
lang: global.config.ui.lang,
|
|
17
|
+
folders: global.state.menu,
|
|
18
|
+
components: global.state.components,
|
|
19
|
+
flatUrlPattern: global.config.isBuild
|
|
20
|
+
? "/show-{{component}}.html"
|
|
21
|
+
: "/show?file={{component}}",
|
|
22
|
+
iframeSrc: global.config.indexPath.default,
|
|
23
|
+
showAll: true,
|
|
24
|
+
projectName: config.projectName,
|
|
25
|
+
userProjectName: global.config.projectName,
|
|
26
|
+
indexPath: global.config.indexPath.embedded,
|
|
27
|
+
miyagiDev: !!process.env.MIYAGI_DEVELOPMENT,
|
|
28
|
+
isBuild: global.config.isBuild,
|
|
29
|
+
userUiConfig: getUserUiConfig(cookies),
|
|
30
|
+
theme: themeMode
|
|
31
|
+
? Object.assign(global.config.ui.theme, { mode: themeMode })
|
|
32
|
+
: global.config.ui.theme,
|
|
33
|
+
basePath: global.config.isBuild ? global.config.build.basePath : "/",
|
|
34
|
+
uiTextDirection: global.config.ui.textDirection,
|
|
35
|
+
},
|
|
36
|
+
(html) => {
|
|
37
|
+
if (res.send) {
|
|
38
|
+
res.send(html);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (cb) {
|
|
42
|
+
cb(null, html);
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
import * as helpers from "../helpers.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @param {Array} menu
|
|
8
|
+
* @param {boolean} isBuild
|
|
9
|
+
* @returns {Array}
|
|
10
|
+
*/
|
|
11
|
+
export default function getComponents(menu, isBuild) {
|
|
12
|
+
if (!menu) return [];
|
|
13
|
+
|
|
14
|
+
const components = [];
|
|
15
|
+
|
|
16
|
+
const partials = Object.keys(global.state.partials || []);
|
|
17
|
+
|
|
18
|
+
(function iterate(arr) {
|
|
19
|
+
arr.forEach((entry) => {
|
|
20
|
+
if (entry.shortPath && entry.normalizedShortPath) {
|
|
21
|
+
const componentName = path.basename(entry.shortPath);
|
|
22
|
+
const assetNames = {
|
|
23
|
+
css: `${componentName}.miyagi.css`,
|
|
24
|
+
js: `${componentName}.miyagi.js`,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
components.push({
|
|
28
|
+
shortPath: entry.shortPath,
|
|
29
|
+
value: isBuild ? entry.normalizedShortPath : entry.shortPath,
|
|
30
|
+
assets: {
|
|
31
|
+
css: fs.existsSync(path.join(entry.fullPath, assetNames.css))
|
|
32
|
+
? path.relative(
|
|
33
|
+
process.cwd(),
|
|
34
|
+
path.join(entry.fullPath, assetNames.css),
|
|
35
|
+
)
|
|
36
|
+
: false,
|
|
37
|
+
js: fs.existsSync(path.join(entry.fullPath, assetNames.js))
|
|
38
|
+
? path.relative(
|
|
39
|
+
process.cwd(),
|
|
40
|
+
path.join(entry.fullPath, assetNames.js),
|
|
41
|
+
)
|
|
42
|
+
: false,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
addToRoutes(
|
|
47
|
+
{
|
|
48
|
+
name: componentName,
|
|
49
|
+
shortPath: entry.shortPath,
|
|
50
|
+
fullPath: entry.fullPath,
|
|
51
|
+
},
|
|
52
|
+
partials,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (entry.children && entry.children.length > 0) {
|
|
57
|
+
iterate(entry.children);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
})(menu);
|
|
61
|
+
|
|
62
|
+
return components;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @param {object} item
|
|
67
|
+
* @param {string} item.name
|
|
68
|
+
* @param {string} item.shortPath
|
|
69
|
+
* @param {string} item.fullPath
|
|
70
|
+
* @param {Array} partials
|
|
71
|
+
*/
|
|
72
|
+
function addToRoutes({ name, shortPath, fullPath }, partials = []) {
|
|
73
|
+
if (!global.state.routes.includes(shortPath)) {
|
|
74
|
+
const fileName = `${path.basename(shortPath)}.${
|
|
75
|
+
global.config.files.templates.extension
|
|
76
|
+
}`;
|
|
77
|
+
|
|
78
|
+
const tplShortPath = path.join(shortPath, fileName);
|
|
79
|
+
const schemaFileName = `${global.config.files.schema.name}.${global.config.files.schema.extension}`;
|
|
80
|
+
|
|
81
|
+
const component = {
|
|
82
|
+
name,
|
|
83
|
+
route: {
|
|
84
|
+
default: global.config.isBuild
|
|
85
|
+
? `component-${helpers.normalizeString(shortPath)}.html`
|
|
86
|
+
: `/component?file=${shortPath}`,
|
|
87
|
+
embedded: global.config.isBuild
|
|
88
|
+
? `component-${helpers.normalizeString(shortPath)}-embedded.html`
|
|
89
|
+
: `/component?file=${shortPath}&embedded=true`,
|
|
90
|
+
},
|
|
91
|
+
alias: shortPath,
|
|
92
|
+
paths: {
|
|
93
|
+
dir: {
|
|
94
|
+
full: fullPath,
|
|
95
|
+
short: shortPath,
|
|
96
|
+
},
|
|
97
|
+
mocks: {
|
|
98
|
+
full(fileType) {
|
|
99
|
+
return path.join(
|
|
100
|
+
fullPath,
|
|
101
|
+
`${global.config.files.mocks.name}.${fileType}`,
|
|
102
|
+
);
|
|
103
|
+
},
|
|
104
|
+
short(fileType) {
|
|
105
|
+
return path.join(
|
|
106
|
+
shortPath,
|
|
107
|
+
`${global.config.files.mocks.name}.${fileType}`,
|
|
108
|
+
);
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
schema: {
|
|
112
|
+
full: path.join(fullPath, schemaFileName),
|
|
113
|
+
short: path.join(shortPath, schemaFileName),
|
|
114
|
+
},
|
|
115
|
+
docs: {
|
|
116
|
+
full: path.join(fullPath, "README.md"),
|
|
117
|
+
short: path.join(shortPath, "README.md"),
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
type: "components",
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
if (partials.includes(tplShortPath)) {
|
|
124
|
+
component.paths.tpl = {
|
|
125
|
+
short: tplShortPath,
|
|
126
|
+
full: path.join(fullPath, fileName),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
global.state.routes.push(component);
|
|
131
|
+
}
|
|
132
|
+
}
|
package/lib/state/css.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import css from "@adobe/css-tools";
|
|
2
|
+
import deepMerge from "deepmerge";
|
|
3
|
+
import log from "../logger.js";
|
|
4
|
+
import { t } from "../i18n/index.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @param {object} fileContents
|
|
8
|
+
* @returns {object}
|
|
9
|
+
*/
|
|
10
|
+
export default function getCSS(fileContents) {
|
|
11
|
+
const { assets } = global.config;
|
|
12
|
+
let cssObject = {};
|
|
13
|
+
|
|
14
|
+
if (assets?.customProperties?.files.length > 0) {
|
|
15
|
+
if (assets.customProperties.files.length > 1) {
|
|
16
|
+
cssObject = deepMerge.all(
|
|
17
|
+
assets.customProperties.files.map((file) => {
|
|
18
|
+
const fileContent = fileContents[file];
|
|
19
|
+
|
|
20
|
+
if (fileContent) {
|
|
21
|
+
return css.parse(fileContent);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
log(
|
|
25
|
+
"warn",
|
|
26
|
+
t("customPropertyFileNotFound").replace("{{filePath}}", file),
|
|
27
|
+
);
|
|
28
|
+
return {};
|
|
29
|
+
}),
|
|
30
|
+
);
|
|
31
|
+
} else {
|
|
32
|
+
const fileContent = fileContents[assets.customProperties.files[0]];
|
|
33
|
+
|
|
34
|
+
if (fileContent) {
|
|
35
|
+
return css.parse(fileContents[assets.customProperties.files[0]]);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
log(
|
|
39
|
+
"warn",
|
|
40
|
+
t("customPropertyFileNotFound").replace(
|
|
41
|
+
"{{filePath}}",
|
|
42
|
+
assets.customProperties.files[0],
|
|
43
|
+
),
|
|
44
|
+
);
|
|
45
|
+
return {};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return cssObject;
|
|
50
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import PATH from "path";
|
|
2
|
+
|
|
3
|
+
import * as helpers from "../helpers.js";
|
|
4
|
+
|
|
5
|
+
export const getMenu = (sourceTree) => {
|
|
6
|
+
if (!sourceTree) return null;
|
|
7
|
+
|
|
8
|
+
return getMenuItem(sourceTree, {});
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {object} sourceItem
|
|
13
|
+
* @param {string} sourceItem.name
|
|
14
|
+
* @param {string} sourceItem.type
|
|
15
|
+
* @param {string} sourceItem.path
|
|
16
|
+
* @param {Array} sourceItem.children
|
|
17
|
+
* @param {object} item
|
|
18
|
+
* @returns {object}
|
|
19
|
+
*/
|
|
20
|
+
function getMenuItem({ name, type, path, children }, item) {
|
|
21
|
+
const shortPath = PATH.relative(
|
|
22
|
+
process.cwd(),
|
|
23
|
+
type === "file"
|
|
24
|
+
? PATH.join(PATH.dirname(path), PATH.basename(path, PATH.extname(path)))
|
|
25
|
+
: path,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
item.topLevel = shortPath == global.config.docs.folder;
|
|
29
|
+
item.id = shortPath;
|
|
30
|
+
item.shortPath = shortPath;
|
|
31
|
+
item.name = type === "file" ? PATH.basename(name, PATH.extname(name)) : name;
|
|
32
|
+
item.type = type;
|
|
33
|
+
item.section = "docs";
|
|
34
|
+
item.route = {
|
|
35
|
+
default: global.config.isBuild
|
|
36
|
+
? `component-${helpers.normalizeString(shortPath)}.html`
|
|
37
|
+
: `/component?file=${shortPath}`,
|
|
38
|
+
embedded: global.config.isBuild
|
|
39
|
+
? `component-${helpers.normalizeString(shortPath)}-embedded.html`
|
|
40
|
+
: `/component?file=${shortPath}&embedded=true`,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* if the current item in the tree is a directory, we check if any of
|
|
45
|
+
* its children is a README.md or index.md. In that case, we want
|
|
46
|
+
* this directory to be linked, not the file.
|
|
47
|
+
*/
|
|
48
|
+
if (item.type === "directory") {
|
|
49
|
+
if (children) {
|
|
50
|
+
const indexFile = children.find(
|
|
51
|
+
(child) => child.name === "README.md" || child.name === "index.md",
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
item.isLink = !!indexFile;
|
|
55
|
+
|
|
56
|
+
if (indexFile) {
|
|
57
|
+
item.file = indexFile.path;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (item.isLink) {
|
|
61
|
+
addToRoutes(item);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
item.isLink = true;
|
|
66
|
+
item.shortPath = shortPath;
|
|
67
|
+
item.file = path;
|
|
68
|
+
|
|
69
|
+
addToRoutes(item);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (children) {
|
|
73
|
+
item.children = [];
|
|
74
|
+
|
|
75
|
+
children.forEach((child) => {
|
|
76
|
+
const fileName = PATH.basename(child.path);
|
|
77
|
+
|
|
78
|
+
if (
|
|
79
|
+
child.type === "directory" ||
|
|
80
|
+
!["README.md", "index.md"].includes(fileName)
|
|
81
|
+
) {
|
|
82
|
+
item.children.push(getMenuItem(child, {}));
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return item;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @param {object} item
|
|
92
|
+
* @param {string} item.name
|
|
93
|
+
* @param {string} item.shortPath
|
|
94
|
+
* @param {string} item.file
|
|
95
|
+
* @param {string} item.route
|
|
96
|
+
*/
|
|
97
|
+
function addToRoutes({ name, shortPath, file, route }) {
|
|
98
|
+
if (!global.state.routes.includes(shortPath)) {
|
|
99
|
+
global.state.routes.push({
|
|
100
|
+
name,
|
|
101
|
+
route,
|
|
102
|
+
paths: {
|
|
103
|
+
dir: {
|
|
104
|
+
full: file,
|
|
105
|
+
short: shortPath,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
type: "docs",
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module for getting the content of all relevant files
|
|
3
|
+
* @module stateFilecontents
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readFile as readFileFs } from "node:fs/promises";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import anymatch from "anymatch";
|
|
9
|
+
import yaml from "js-yaml";
|
|
10
|
+
import { marked as Markdown } from "marked";
|
|
11
|
+
import * as helpers from "../helpers.js";
|
|
12
|
+
import log from "../logger.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Checks if a given array of file paths includes a given file path
|
|
16
|
+
* @param {string} file - file path string
|
|
17
|
+
* @param {Array} fileNames - array of file path string
|
|
18
|
+
* @returns {boolean} is true if given array includes given file path
|
|
19
|
+
*/
|
|
20
|
+
function checkIfFileNamesIncludeFile(file, fileNames) {
|
|
21
|
+
return fileNames.includes(path.basename(file));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Returns all component and docs file from components.folder
|
|
26
|
+
* @param {object} sourceTree
|
|
27
|
+
* @returns {Promise<string[]>}
|
|
28
|
+
*/
|
|
29
|
+
async function getFilePaths(sourceTree) {
|
|
30
|
+
const { assets, components, files } = global.config;
|
|
31
|
+
|
|
32
|
+
const paths = [...assets.customProperties.files];
|
|
33
|
+
|
|
34
|
+
if (sourceTree.components) {
|
|
35
|
+
(function getPaths(entry) {
|
|
36
|
+
if (!anymatch(components.ignores, entry.path)) {
|
|
37
|
+
if (entry.type === "file") {
|
|
38
|
+
if (
|
|
39
|
+
checkIfFileNamesIncludeFile(entry.path, [
|
|
40
|
+
`${helpers.getResolvedFileName(
|
|
41
|
+
files.templates.name,
|
|
42
|
+
path.basename(entry.path, `.${files.templates.extension}`),
|
|
43
|
+
)}.${files.templates.extension}`,
|
|
44
|
+
`${files.mocks.name}.${files.mocks.extension[0]}`,
|
|
45
|
+
`${files.mocks.name}.${files.mocks.extension[1]}`,
|
|
46
|
+
`${files.schema.name}.${files.schema.extension}`,
|
|
47
|
+
]) ||
|
|
48
|
+
helpers.fileIsDocumentationFile(entry.path)
|
|
49
|
+
) {
|
|
50
|
+
paths.push(entry.path);
|
|
51
|
+
}
|
|
52
|
+
} else if (entry.type === "directory") {
|
|
53
|
+
entry.children.forEach((item) => getPaths(item));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
})(sourceTree.components);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (sourceTree.docs) {
|
|
60
|
+
(function getPaths(entry) {
|
|
61
|
+
if (entry.type === "file") {
|
|
62
|
+
paths.push(entry.path);
|
|
63
|
+
} else if (entry.type === "directory") {
|
|
64
|
+
entry.children.forEach((item) => getPaths(item));
|
|
65
|
+
}
|
|
66
|
+
})(sourceTree.docs);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return paths;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Calls the default export of an ES module and returns its return value
|
|
74
|
+
* or returns the return value directly if it is not a function
|
|
75
|
+
* @param {string} fileName - file path string
|
|
76
|
+
* @returns {Promise<string>} - the default export of the ES module
|
|
77
|
+
*/
|
|
78
|
+
async function getJsFileContent(fileName) {
|
|
79
|
+
const file = await import(path.resolve(`${fileName}?time=${Date.now()}`));
|
|
80
|
+
|
|
81
|
+
return file.default();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Returns the content of a YAML file parsed as JSON object
|
|
86
|
+
* @param {string} fileName - path to a yaml file
|
|
87
|
+
* @returns {Promise<object>} the content of the given file as an object
|
|
88
|
+
*/
|
|
89
|
+
async function getYamlFileContent(fileName) {
|
|
90
|
+
try {
|
|
91
|
+
const result = await readFileFs(fileName, "utf8");
|
|
92
|
+
return yaml.load(result);
|
|
93
|
+
} catch (err) {
|
|
94
|
+
return Promise.reject(err);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Returns the parsed content of a JSON file.
|
|
100
|
+
* @param {string} fileName - path to a json file
|
|
101
|
+
* @returns {Promise<object>} the parsed content of the given file
|
|
102
|
+
*/
|
|
103
|
+
async function getParsedJsonFileContent(fileName) {
|
|
104
|
+
try {
|
|
105
|
+
const result = await readFileFs(fileName, "utf8");
|
|
106
|
+
return JSON.parse(result);
|
|
107
|
+
} catch (err) {
|
|
108
|
+
return Promise.reject(err);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Returns the as HTML rendered content of markdown files.
|
|
114
|
+
* @param {string} fileName - path to a markdown file
|
|
115
|
+
* @returns {Promise<string>} the markdown of the given file converted into HTML
|
|
116
|
+
*/
|
|
117
|
+
async function getConvertedMarkdownFileContent(fileName) {
|
|
118
|
+
try {
|
|
119
|
+
const result = await readFileFs(fileName, "utf8");
|
|
120
|
+
return Markdown.parse(result);
|
|
121
|
+
} catch (err) {
|
|
122
|
+
return Promise.reject(err);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Calls different functions getting the file's content based on its type
|
|
128
|
+
* and returns the (converted) file content.
|
|
129
|
+
* @param {string} fileName - path to a file of any type
|
|
130
|
+
* @returns {Promise<string|object|Array>} content of the given file based on its type
|
|
131
|
+
*/
|
|
132
|
+
export const readFile = async function (fileName) {
|
|
133
|
+
switch (true) {
|
|
134
|
+
case [".yaml", ".yml"].includes(path.extname(fileName)):
|
|
135
|
+
{
|
|
136
|
+
try {
|
|
137
|
+
return await getYamlFileContent(fileName);
|
|
138
|
+
} catch (err) {
|
|
139
|
+
log("error", `Error when reading file ${fileName}`, err);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
break;
|
|
143
|
+
case helpers.fileIsDocumentationFile(fileName):
|
|
144
|
+
{
|
|
145
|
+
try {
|
|
146
|
+
return await getConvertedMarkdownFileContent(fileName);
|
|
147
|
+
} catch (err) {
|
|
148
|
+
log("error", `Error when reading file ${fileName}`, err);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
break;
|
|
152
|
+
case helpers.fileIsDataFile(fileName) &&
|
|
153
|
+
[".js", ".mjs"].includes(path.extname(fileName)):
|
|
154
|
+
{
|
|
155
|
+
try {
|
|
156
|
+
return await getJsFileContent(fileName);
|
|
157
|
+
} catch (err) {
|
|
158
|
+
log("error", `Error when reading file ${fileName}`, err);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
break;
|
|
162
|
+
case fileName.endsWith(".json"):
|
|
163
|
+
{
|
|
164
|
+
try {
|
|
165
|
+
return await getParsedJsonFileContent(fileName);
|
|
166
|
+
} catch (err) {
|
|
167
|
+
log("error", `Error when reading file ${fileName}`, err);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
break;
|
|
171
|
+
default: {
|
|
172
|
+
try {
|
|
173
|
+
return await readFileFs(fileName, { encoding: "utf8" });
|
|
174
|
+
} catch (err) {
|
|
175
|
+
log("error", `Error when reading file ${fileName}`, err);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Returns a promise which will be resolved with an object,
|
|
183
|
+
* including all component files (except for template files)
|
|
184
|
+
* and their content.
|
|
185
|
+
* @param {object} sourceTree
|
|
186
|
+
* @returns {Promise} gets resolved with the content of all docs, mocks, schema files
|
|
187
|
+
*/
|
|
188
|
+
export const getFileContents = async function (sourceTree) {
|
|
189
|
+
const fileContents = {};
|
|
190
|
+
const paths = await getFilePaths(sourceTree);
|
|
191
|
+
|
|
192
|
+
if (paths) {
|
|
193
|
+
await Promise.all(
|
|
194
|
+
paths.map(async (fullPath) => {
|
|
195
|
+
try {
|
|
196
|
+
fileContents[fullPath] = await readFile(fullPath.replace(/\0/g, ""));
|
|
197
|
+
} catch (err) {
|
|
198
|
+
return err;
|
|
199
|
+
}
|
|
200
|
+
}),
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
return fileContents;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return {};
|
|
207
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper functions for all state modules
|
|
3
|
+
* @module stateHelpers
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import path from "path";
|
|
7
|
+
import log from "../logger.js";
|
|
8
|
+
import { t } from "../i18n/index.js";
|
|
9
|
+
import { readdir } from "node:fs/promises";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {string|null} dir - the directory in which to look for files
|
|
13
|
+
* @param {string[]} ignores - an array of folders which should be ignored
|
|
14
|
+
* @param {string} configPath
|
|
15
|
+
* @param {string} type
|
|
16
|
+
* @param {Function} check - checks if the file should be returned, returns null or the file path
|
|
17
|
+
* @returns {Promise<string[]>} an array with file paths
|
|
18
|
+
*/
|
|
19
|
+
async function getFiles(dir, ignores, configPath, type, check) {
|
|
20
|
+
if (dir === null) return [];
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
var entries = await readdir(path.join(process.cwd(), dir), {
|
|
24
|
+
withFileTypes: true,
|
|
25
|
+
});
|
|
26
|
+
} catch (error) {
|
|
27
|
+
if (error.code === "ENOENT") {
|
|
28
|
+
log(
|
|
29
|
+
"error",
|
|
30
|
+
t("srcFolderNotFound")
|
|
31
|
+
.replaceAll("{{directory}}", dir)
|
|
32
|
+
.replaceAll("{{type}}", type)
|
|
33
|
+
.replaceAll("{{config}}", configPath),
|
|
34
|
+
);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
} else {
|
|
37
|
+
log("error", error.toString(), error);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const files = await Promise.all(
|
|
43
|
+
entries.map(async (entry) => {
|
|
44
|
+
const res = path.resolve(dir, entry.name);
|
|
45
|
+
|
|
46
|
+
if (isNotIgnored(res, ignores)) {
|
|
47
|
+
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
48
|
+
return await getFiles(
|
|
49
|
+
path.join(dir, entry.name),
|
|
50
|
+
ignores,
|
|
51
|
+
configPath,
|
|
52
|
+
type,
|
|
53
|
+
check,
|
|
54
|
+
);
|
|
55
|
+
} else {
|
|
56
|
+
return check(res);
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}),
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return Array.prototype.concat(...files).filter((file) => file !== null);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Checks if a given file is not in one of the ignored folders
|
|
69
|
+
* @param {string} file - file path
|
|
70
|
+
* @param {Array} ignoredFolders - folders that should be ignored
|
|
71
|
+
* @returns {boolean} returns true if the given file is not inside any of the given ignoredFolders
|
|
72
|
+
*/
|
|
73
|
+
function isNotIgnored(file, ignoredFolders) {
|
|
74
|
+
for (let i = 0; i < ignoredFolders.length; i += 1) {
|
|
75
|
+
if (file.includes(ignoredFolders[i])) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export default {
|
|
84
|
+
getFiles,
|
|
85
|
+
isNotIgnored,
|
|
86
|
+
};
|