@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.
Files changed (138) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +43 -0
  3. package/api/app.js +39 -0
  4. package/api/index.js +236 -0
  5. package/bin/miyagi.js +2 -0
  6. package/dist/css/iframe.css +31 -0
  7. package/dist/css/main.css +1 -0
  8. package/dist/js/_iframe-links-DdifIr4P.js +1 -0
  9. package/dist/js/_mock-data-Dypo4Bl_.js +1 -0
  10. package/dist/js/_prism-By3NMwUd.js +1 -0
  11. package/dist/js/iframe.build.js +1 -0
  12. package/dist/js/iframe.js +1 -0
  13. package/dist/js/index-BKDKaBC6.js +1 -0
  14. package/dist/js/jsontree.js +1 -0
  15. package/dist/js/main.build.js +1 -0
  16. package/dist/js/main.js +1 -0
  17. package/frontend/assets/css/iframe/accordion-tabs.css +77 -0
  18. package/frontend/assets/css/iframe/jsontree.js.css +325 -0
  19. package/frontend/assets/css/iframe/prism.css +132 -0
  20. package/frontend/assets/css/iframe/styleguide/colors.css +61 -0
  21. package/frontend/assets/css/iframe/styleguide/fonts.css +37 -0
  22. package/frontend/assets/css/iframe/styleguide/index.css +109 -0
  23. package/frontend/assets/css/iframe/styleguide/spacings.css +21 -0
  24. package/frontend/assets/css/iframe.css +410 -0
  25. package/frontend/assets/css/main/menu/config-switcher.css +49 -0
  26. package/frontend/assets/css/main/menu/config-switchers.css +67 -0
  27. package/frontend/assets/css/main/menu/goto.css +24 -0
  28. package/frontend/assets/css/main/menu/nav.css +113 -0
  29. package/frontend/assets/css/main/menu/search.css +64 -0
  30. package/frontend/assets/css/main/menu/title.css +40 -0
  31. package/frontend/assets/css/main/menu.css +114 -0
  32. package/frontend/assets/css/main/reset.css +217 -0
  33. package/frontend/assets/css/main.css +71 -0
  34. package/frontend/assets/css/shared.css +34 -0
  35. package/frontend/assets/css/tokens.css +112 -0
  36. package/frontend/assets/favicon.ico +0 -0
  37. package/frontend/assets/js/_accordion-tabs.js +403 -0
  38. package/frontend/assets/js/_goto.js +63 -0
  39. package/frontend/assets/js/_iframe-links.js +19 -0
  40. package/frontend/assets/js/_is-triggered.js +15 -0
  41. package/frontend/assets/js/_main.js +379 -0
  42. package/frontend/assets/js/_mock-data.js +13 -0
  43. package/frontend/assets/js/_prism.js +1098 -0
  44. package/frontend/assets/js/_search.js +190 -0
  45. package/frontend/assets/js/_socket.js +9 -0
  46. package/frontend/assets/js/config-switcher/development-mode.js +49 -0
  47. package/frontend/assets/js/config-switcher/index.js +63 -0
  48. package/frontend/assets/js/config-switcher/text-direction.js +30 -0
  49. package/frontend/assets/js/config-switcher/theme.js +87 -0
  50. package/frontend/assets/js/iframe.build.js +43 -0
  51. package/frontend/assets/js/iframe.js +52 -0
  52. package/frontend/assets/js/jsontree.js +979 -0
  53. package/frontend/assets/js/main.build.js +40 -0
  54. package/frontend/assets/js/main.js +42 -0
  55. package/frontend/assets/js/styleguide/color-converter.js +741 -0
  56. package/frontend/assets/js/styleguide/index.js +119 -0
  57. package/frontend/views/component_variation.twig.miyagi +57 -0
  58. package/frontend/views/design-tokens/colors.twig.miyagi +43 -0
  59. package/frontend/views/design-tokens/sizes.twig.miyagi +35 -0
  60. package/frontend/views/design-tokens/typography.twig.miyagi +38 -0
  61. package/frontend/views/iframe_component.twig.miyagi +141 -0
  62. package/frontend/views/iframe_component_variation.twig.miyagi +55 -0
  63. package/frontend/views/iframe_index.twig.miyagi +14 -0
  64. package/frontend/views/layouts/iframe_default.twig.miyagi +22 -0
  65. package/frontend/views/main.twig.miyagi +24 -0
  66. package/frontend/views/menu/config-switchers.twig.miyagi +83 -0
  67. package/frontend/views/menu/goto.twig.miyagi +9 -0
  68. package/frontend/views/menu/menu.twig.miyagi +21 -0
  69. package/frontend/views/menu/nav.twig.miyagi +95 -0
  70. package/frontend/views/menu/search.twig.miyagi +13 -0
  71. package/frontend/views/menu/title.twig.miyagi +24 -0
  72. package/index.js +3 -0
  73. package/lib/build/index.js +1020 -0
  74. package/lib/cli/app.js +38 -0
  75. package/lib/cli/component.js +56 -0
  76. package/lib/cli/index.js +5 -0
  77. package/lib/cli/lint.js +180 -0
  78. package/lib/config.js +74 -0
  79. package/lib/default-config.js +105 -0
  80. package/lib/generator/component.js +199 -0
  81. package/lib/generator/mocks.js +201 -0
  82. package/lib/helpers.js +184 -0
  83. package/lib/i18n/en.js +91 -0
  84. package/lib/i18n/index.js +17 -0
  85. package/lib/index.js +166 -0
  86. package/lib/init/args.js +55 -0
  87. package/lib/init/config.js +330 -0
  88. package/lib/init/engines.js +65 -0
  89. package/lib/init/index.js +102 -0
  90. package/lib/init/rendering.js +12 -0
  91. package/lib/init/router.js +249 -0
  92. package/lib/init/static.js +133 -0
  93. package/lib/init/twing/cache.js +34 -0
  94. package/lib/init/twing/functions.js +51 -0
  95. package/lib/init/views.js +19 -0
  96. package/lib/init/watcher.js +402 -0
  97. package/lib/logger.js +94 -0
  98. package/lib/mocks/get.js +111 -0
  99. package/lib/mocks/index.js +9 -0
  100. package/lib/mocks/resolve/ref.js +484 -0
  101. package/lib/mocks/resolve/tpl.js +246 -0
  102. package/lib/mocks/resolve.js +205 -0
  103. package/lib/render/helpers.js +51 -0
  104. package/lib/render/index.js +38 -0
  105. package/lib/render/views/iframe/component.docs.js +77 -0
  106. package/lib/render/views/iframe/component.js +338 -0
  107. package/lib/render/views/iframe/design-tokens/colors.js +52 -0
  108. package/lib/render/views/iframe/design-tokens/index.js +9 -0
  109. package/lib/render/views/iframe/design-tokens/sizes.js +49 -0
  110. package/lib/render/views/iframe/design-tokens/typography.js +52 -0
  111. package/lib/render/views/iframe/docs.js +68 -0
  112. package/lib/render/views/iframe/index.js +44 -0
  113. package/lib/render/views/iframe/variation.js +116 -0
  114. package/lib/render/views/iframe/variation.standalone.js +89 -0
  115. package/lib/render/views/main/component.docs.js +53 -0
  116. package/lib/render/views/main/component.js +74 -0
  117. package/lib/render/views/main/design-tokens.js +53 -0
  118. package/lib/render/views/main/docs.js +47 -0
  119. package/lib/render/views/main/index.js +46 -0
  120. package/lib/state/components.js +132 -0
  121. package/lib/state/css.js +50 -0
  122. package/lib/state/docs.js +111 -0
  123. package/lib/state/file-contents.js +207 -0
  124. package/lib/state/helpers.js +86 -0
  125. package/lib/state/index.js +56 -0
  126. package/lib/state/menu/index.js +275 -0
  127. package/lib/state/menu/structure.js +146 -0
  128. package/lib/state/partials.js +23 -0
  129. package/lib/state/source-tree.js +75 -0
  130. package/lib/styleguide/color-names.js +150 -0
  131. package/lib/styleguide/colors.js +135 -0
  132. package/lib/styleguide/helpers.js +37 -0
  133. package/lib/styleguide/index.js +17 -0
  134. package/lib/styleguide/media-queries.js +26 -0
  135. package/lib/styleguide/spacings.js +35 -0
  136. package/lib/styleguide/typography.js +61 -0
  137. package/lib/validator/mocks.js +105 -0
  138. 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
+ }
@@ -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
+ };