@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
package/lib/cli/app.js ADDED
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Module for initializing miyagi
3
+ * @module init
4
+ */
5
+
6
+ import express from "express";
7
+
8
+ import setEngines from "../init/engines.js";
9
+ import setRouter from "../init/router.js";
10
+ import setState from "../state/index.js";
11
+ import setStatic from "../init/static.js";
12
+ import setViews from "../init/views.js";
13
+
14
+ /**
15
+ * @param {object} mergedConfig
16
+ * @returns {Promise<object>}
17
+ */
18
+ export default async function init(mergedConfig) {
19
+ global.app = express();
20
+ global.config = mergedConfig;
21
+ global.app.set("view cache", false);
22
+ global.app.set("cache", false);
23
+
24
+ await setEngines();
25
+ await setState({
26
+ sourceTree: true,
27
+ menu: true,
28
+ partials: true,
29
+ fileContents: true,
30
+ css: true,
31
+ });
32
+
33
+ setStatic();
34
+ setRouter();
35
+ setViews();
36
+
37
+ return global.app;
38
+ }
@@ -0,0 +1,56 @@
1
+ import generateComponent from "../generator/component.js";
2
+ import log from "../logger.js";
3
+ import appConfig from "../default-config.js";
4
+ import { t } from "../i18n/index.js";
5
+
6
+ /**
7
+ * @param {object} cliParams
8
+ * @returns {Promise<void>}
9
+ */
10
+ export default async function createComponentViaCli(cliParams) {
11
+ const commands = cliParams._.slice(1);
12
+
13
+ if (commands.length === 0) {
14
+ log("error", t("generator.noComponentNameDefined"));
15
+
16
+ return;
17
+ }
18
+
19
+ const [component] = commands;
20
+ const fileTypes = getFileTypesFromCliArgs(
21
+ cliParams,
22
+ Object.values(appConfig.defaultUserConfig.files).map((file) => file.abbr),
23
+ );
24
+
25
+ try {
26
+ const result = await generateComponent({ component, fileTypes });
27
+ log("success", result);
28
+ } catch (message) {
29
+ log("error", message);
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Returns an array with file names, if necessary filtered based on args
35
+ * @param {object} args - the cli args
36
+ * @param {Array} fileTypes
37
+ * @returns {Array} all file paths that should be created
38
+ */
39
+ function getFileTypesFromCliArgs(args, fileTypes) {
40
+ if (args) {
41
+ if (args.skip) {
42
+ const files = [];
43
+ for (const fileType of fileTypes) {
44
+ if (!args.skip.includes(fileType)) {
45
+ files.push(fileType);
46
+ }
47
+ }
48
+ return files;
49
+ }
50
+ if (args.only) {
51
+ return args.only;
52
+ }
53
+ return fileTypes;
54
+ }
55
+ return fileTypes;
56
+ }
@@ -0,0 +1,5 @@
1
+ import lintImport from "./lint.js";
2
+ import componentImport from "./component.js";
3
+
4
+ export const lint = lintImport;
5
+ export const component = componentImport;
@@ -0,0 +1,180 @@
1
+ import path from "path";
2
+ import init from "./app.js";
3
+ import getConfig from "../config.js";
4
+ import log from "../logger.js";
5
+ import { getComponentData } from "../mocks/index.js";
6
+ import validateMockData from "../validator/mocks.js";
7
+ import { t } from "../i18n/index.js";
8
+
9
+ /**
10
+ * @param {object} args
11
+ */
12
+ export default async function lint(args) {
13
+ process.env.NODE_ENV = "development";
14
+
15
+ const componentArg = args._.slice(1)[0];
16
+ const config = await getConfig(args);
17
+ global.app = await init(config);
18
+
19
+ if (componentArg) {
20
+ const component = global.state.routes.find(
21
+ ({ alias }) =>
22
+ alias === path.relative(config.components.folder, componentArg),
23
+ );
24
+
25
+ if (component) {
26
+ await validateComponentMockData({
27
+ component,
28
+ });
29
+ } else {
30
+ log("error", `The component ${componentArg} does not seem to exist.`);
31
+ process.exit(1);
32
+ }
33
+ } else {
34
+ await validateAllMockData();
35
+ }
36
+ }
37
+
38
+ /**
39
+ * @param {boolean} exitProcess
40
+ */
41
+ async function validateAllMockData(exitProcess = true) {
42
+ log("info", t("linter.all.start"));
43
+
44
+ const promises = [];
45
+
46
+ global.state.routes.forEach((route) => {
47
+ if (route.type === "components") {
48
+ promises.push(
49
+ new Promise((resolve, reject) => {
50
+ validateComponentMockData({
51
+ component: route,
52
+ silent: true,
53
+ exitProcess: false,
54
+ })
55
+ .then((result) => resolve(result))
56
+ .catch((err) => {
57
+ console.error(err);
58
+ reject();
59
+ });
60
+ }),
61
+ );
62
+ }
63
+ });
64
+
65
+ Promise.all(promises)
66
+ .then((results) => {
67
+ const mockInvalidResults = results.filter(
68
+ (result) => result?.valid === false && result.type === "mocks",
69
+ );
70
+ const schemaInvalidResults = results.filter(
71
+ (result) => result?.valid === false && result.type === "schema",
72
+ );
73
+
74
+ if (
75
+ mockInvalidResults.length === 0 &&
76
+ schemaInvalidResults.length === 0
77
+ ) {
78
+ log("success", t("linter.all.valid"));
79
+ if (exitProcess) {
80
+ process.exit(0);
81
+ }
82
+ }
83
+
84
+ if (schemaInvalidResults.length > 0) {
85
+ log(
86
+ "error",
87
+ schemaInvalidResults.length === 1
88
+ ? t("linter.all.schema.invalid.one")
89
+ : t("linter.all.schema.invalid.other").replace(
90
+ "{{amount}}",
91
+ schemaInvalidResults.length,
92
+ ),
93
+ );
94
+ }
95
+
96
+ if (mockInvalidResults.length > 0) {
97
+ log(
98
+ "error",
99
+ mockInvalidResults.length === 1
100
+ ? t("linter.all.mocks.invalid.one")
101
+ : t("linter.all.mocks.invalid.other").replace(
102
+ "{{amount}}",
103
+ mockInvalidResults.length,
104
+ ),
105
+ );
106
+ }
107
+
108
+ if (exitProcess) {
109
+ process.exit(1);
110
+ }
111
+ })
112
+ .catch((err) => {
113
+ console.error(err);
114
+ if (exitProcess) {
115
+ process.exit(1);
116
+ }
117
+ });
118
+ }
119
+
120
+ /**
121
+ * @param {object} obj
122
+ * @param {object} obj.component
123
+ * @param {boolean} [obj.silent]
124
+ * @param {boolean} [obj.exitProcess]
125
+ * @returns {Promise<object|null>}
126
+ */
127
+ async function validateComponentMockData({
128
+ component,
129
+ silent,
130
+ exitProcess = true,
131
+ }) {
132
+ if (!silent) {
133
+ log(
134
+ "info",
135
+ t("linter.component.start").replace(
136
+ "{{component}}",
137
+ component.paths.dir.short,
138
+ ),
139
+ );
140
+ }
141
+
142
+ const data = await getComponentData(component);
143
+
144
+ if (data) {
145
+ for (const { messages } of data) {
146
+ for (const { type, text, verbose } of messages) {
147
+ log(type, text, verbose);
148
+ }
149
+ }
150
+
151
+ const results = validateMockData(component, data);
152
+
153
+ if (!results) return null;
154
+
155
+ if (results.length === 0) {
156
+ if (!silent) {
157
+ log("success", t("linter.component.valid"));
158
+ }
159
+
160
+ if (exitProcess) {
161
+ process.exit(0);
162
+ } else {
163
+ return {
164
+ valid: true,
165
+ };
166
+ }
167
+ } else {
168
+ if (exitProcess) {
169
+ process.exit(0);
170
+ } else {
171
+ return {
172
+ valid: false,
173
+ type: results[0].type,
174
+ };
175
+ }
176
+ }
177
+ }
178
+
179
+ return null;
180
+ }
package/lib/config.js ADDED
@@ -0,0 +1,74 @@
1
+ import path from "path";
2
+ import deepMerge from "deepmerge";
3
+
4
+ import getMergedConfig from "./init/config.js";
5
+ import log from "./logger.js";
6
+
7
+ /**
8
+ * @param {object} args
9
+ * @param {boolean} [isBuild]
10
+ * @param {boolean} [isComponentGenerator]
11
+ * @returns {Promise<object>}
12
+ */
13
+ export default async function getConfig(args, isBuild, isComponentGenerator) {
14
+ let userFile = {};
15
+ let userFileName;
16
+
17
+ try {
18
+ userFileName = ".miyagi.js";
19
+ userFile = await import(
20
+ path.resolve(process.cwd(), `${userFileName}?time=${Date.now()}`)
21
+ );
22
+ } catch (e) {
23
+ log("warn", null, e);
24
+ try {
25
+ userFileName = ".miyagi.mjs";
26
+ userFile = await import(
27
+ path.resolve(process.cwd(), `${userFileName}?time=${Date.now()}`)
28
+ );
29
+ } catch (err) {
30
+ userFileName = null;
31
+ log("warn", null, err);
32
+ }
33
+ }
34
+
35
+ let userConfig =
36
+ (args ? deepMerge(userFile.default, getCliArgs(args)) : userFile.default) ??
37
+ {};
38
+
39
+ userConfig.userFileName = userFileName;
40
+ userConfig.isBuild = isBuild;
41
+ userConfig.isComponentGenerator = isComponentGenerator;
42
+ userConfig.indexPath = {
43
+ default: isBuild ? "component-all.html" : "/component?file=all",
44
+ embedded: isBuild
45
+ ? "component-all-embedded.html"
46
+ : "/component?file=all&embedded=true",
47
+ };
48
+
49
+ delete userConfig._;
50
+
51
+ return getMergedConfig(userConfig);
52
+ }
53
+
54
+ /**
55
+ * Converts and removes unnecessary cli args
56
+ * @param {object} args - the cli args
57
+ * @returns {object} configuration object based on cli args
58
+ */
59
+ function getCliArgs(args) {
60
+ const cliArgs = { ...args };
61
+ const buildArgs = {};
62
+
63
+ delete cliArgs._;
64
+ delete cliArgs.$0;
65
+
66
+ if (cliArgs.folder) {
67
+ buildArgs.folder = cliArgs.folder;
68
+ delete cliArgs.folder;
69
+ }
70
+
71
+ cliArgs.build = buildArgs;
72
+
73
+ return cliArgs;
74
+ }
@@ -0,0 +1,105 @@
1
+ import AJV from "ajv";
2
+
3
+ export default {
4
+ defaultUserConfig: {
5
+ assets: {
6
+ root: "",
7
+ css: [],
8
+ customProperties: {
9
+ files: [],
10
+ prefixes: {
11
+ typo: "typo",
12
+ color: "color",
13
+ spacing: "spacing",
14
+ },
15
+ },
16
+ folder: [],
17
+ js: [],
18
+ manifest: null,
19
+ },
20
+ build: {
21
+ basePath: "/",
22
+ folder: "build",
23
+ },
24
+ docs: {
25
+ folder: "docs",
26
+ },
27
+ components: {
28
+ folder: "src",
29
+ ignores: [
30
+ "node_modules",
31
+ ".git",
32
+ "package.json",
33
+ "package-lock.json",
34
+ ".miyagi.js",
35
+ ".miyagi.mjs",
36
+ ],
37
+ lang: "en",
38
+ textDirection: "ltr",
39
+ },
40
+ engine: {
41
+ render: null,
42
+ options: {},
43
+ },
44
+ extensions: [],
45
+ files: {
46
+ css: {
47
+ abbr: "css",
48
+ name: "index",
49
+ extension: "css",
50
+ },
51
+ js: {
52
+ abbr: "js",
53
+ name: "index",
54
+ extension: "js",
55
+ },
56
+ mocks: {
57
+ abbr: "mocks",
58
+ name: "mocks",
59
+ extension: ["json", "js"],
60
+ },
61
+ schema: {
62
+ abbr: "schema",
63
+ name: "schema",
64
+ extension: "json",
65
+ },
66
+ templates: {
67
+ abbr: "tpl",
68
+ name: "index",
69
+ },
70
+ },
71
+ namespaces: {},
72
+ projectName: "miyagi",
73
+ ui: {
74
+ mode: "light",
75
+ lang: "en",
76
+ reload: true,
77
+ reloadAfterChanges: {
78
+ componentAssets: false,
79
+ },
80
+ textDirection: "ltr",
81
+ theme: {
82
+ css: null,
83
+ favicon: null,
84
+ js: null,
85
+ logo: {
86
+ light: null,
87
+ dark: null,
88
+ },
89
+ },
90
+ watchConfigFile: true,
91
+ },
92
+ schema: {
93
+ ajv: AJV,
94
+ },
95
+ },
96
+ projectName: "miyagi",
97
+ defaultPort: 5000,
98
+ folders: {
99
+ assets: {
100
+ development: "frontend/assets",
101
+ production: "dist",
102
+ },
103
+ },
104
+ defaultVariationName: "default",
105
+ };
@@ -0,0 +1,199 @@
1
+ import { writeFile, mkdir } from "node:fs/promises";
2
+ import path from "path";
3
+ import jsonToYaml from "js-yaml";
4
+ import * as helpers from "../helpers.js";
5
+ import { t } from "../i18n/index.js";
6
+
7
+ /**
8
+ * Module for creating component files based on the configuration cli params
9
+ * @param {object} root
10
+ * @param {object} root.component
11
+ * @param {Array} root.fileTypes
12
+ * @returns {Promise<string>}
13
+ */
14
+ export default async function componentGenerator({ component, fileTypes }) {
15
+ try {
16
+ await createComponentFolder(component);
17
+ await createComponentFiles(
18
+ global.config.files,
19
+ component,
20
+ fileTypes,
21
+ global.config.components.folder,
22
+ );
23
+
24
+ return Promise.resolve(
25
+ t("generator.component.done").replace("{{component}}", component),
26
+ );
27
+ } catch (err) {
28
+ return Promise.reject(err);
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Returns an array with file names
34
+ * @param {object} fileNames - an object with file names for the component
35
+ * @param {Array} fileTypes
36
+ * @returns {Array} all file paths that should be created
37
+ */
38
+ function getFiles(fileNames, fileTypes) {
39
+ return fileTypes.map((fileType) => fileNames[fileType]);
40
+ }
41
+
42
+ /**
43
+ * Returns the dummy content for a component file
44
+ * @param {string} fileType - the file type that should be created
45
+ * @param {object} filesConfig - the files object from the user congiguration object
46
+ * @param {string} componentPath
47
+ * @returns {string} dummy file content based on the given file type
48
+ */
49
+ function getDummyFileContent(fileType, filesConfig, componentPath) {
50
+ let str;
51
+
52
+ switch (fileType) {
53
+ case "mocks":
54
+ {
55
+ const data = {
56
+ $variants: [
57
+ {
58
+ $name: "",
59
+ },
60
+ ],
61
+ };
62
+
63
+ if (["yaml", "yml"].includes(filesConfig.mocks.extension[0])) {
64
+ str = jsonToYaml.dump(data);
65
+ } else {
66
+ str = `${JSON.stringify(data, null, 2)}\n`;
67
+ }
68
+ }
69
+ break;
70
+ case "schema":
71
+ {
72
+ const id = path.join("/", componentPath);
73
+
74
+ if (["yaml", "yml"].includes(filesConfig.schema.extension)) {
75
+ str = `$schema: "http://json-schema.org/draft-07/schema"
76
+ $id: "${id}"
77
+ additionalProperties: false
78
+ properties:
79
+ required:
80
+ `;
81
+ } else {
82
+ str = `${JSON.stringify(
83
+ {
84
+ $schema: "http://json-schema.org/draft-07/schema",
85
+ $id: id,
86
+ additionalProperties: false,
87
+ properties: {},
88
+ required: [],
89
+ },
90
+ null,
91
+ 2,
92
+ )}\n`;
93
+ }
94
+ }
95
+ break;
96
+ default:
97
+ str = "";
98
+ }
99
+
100
+ return str;
101
+ }
102
+
103
+ /**
104
+ * Creates the component files
105
+ * @param {object} filesConfig - the files configuration from the user configuration object
106
+ * @param {string} componentPath - the path of the component folder
107
+ * @param {Array} fileTypes
108
+ * @param {string} componentFolder
109
+ * @returns {Promise} gets resolved when all files have been created
110
+ */
111
+ async function createComponentFiles(
112
+ filesConfig,
113
+ componentPath,
114
+ fileTypes,
115
+ componentFolder,
116
+ ) {
117
+ const componentName = path.basename(componentPath);
118
+ const fileNames = getFileNames(filesConfig, componentName);
119
+ const files = getFiles(fileNames, fileTypes);
120
+ const entries = Object.entries(fileNames);
121
+
122
+ for (const [type, file] of entries) {
123
+ if (files.includes(file)) {
124
+ const fullFilePath = path.join(
125
+ process.env.INIT_CWD || process.cwd(),
126
+ componentPath,
127
+ file,
128
+ );
129
+
130
+ try {
131
+ await writeFile(
132
+ fullFilePath,
133
+ getDummyFileContent(
134
+ type,
135
+ filesConfig,
136
+ path.relative(componentFolder, componentPath),
137
+ ),
138
+ { flag: "wx" },
139
+ );
140
+ } catch (err) {
141
+ return Promise.reject(err.message);
142
+ }
143
+ }
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Returns an object with the file names for a given component name
149
+ * @param {object} filesConfig - the files configuration from the user configuration object
150
+ * @param {string} componentName - the name of the component
151
+ * @returns {object} all file names based on the user configuration
152
+ */
153
+ function getFileNames(filesConfig, componentName) {
154
+ return {
155
+ tpl: `${helpers.getResolvedFileName(
156
+ filesConfig.templates.name,
157
+ componentName,
158
+ )}.${filesConfig.templates.extension}`,
159
+ mocks: `${filesConfig.mocks.name}.${filesConfig.mocks.extension[0]}`,
160
+ docs: "README.md",
161
+ css: `${helpers.getResolvedFileName(filesConfig.css.name, componentName)}.${
162
+ filesConfig.css.extension
163
+ }`,
164
+ js: `${helpers.getResolvedFileName(filesConfig.js.name, componentName)}.${
165
+ filesConfig.js.extension
166
+ }`,
167
+ schema: `${filesConfig.schema.name}.${filesConfig.schema.extension}`,
168
+ };
169
+ }
170
+
171
+ /**
172
+ * Creates the component folder
173
+ * @param {string} folder - component folder path that should be created
174
+ * @returns {Promise} gets resolved when the folder has been created
175
+ */
176
+ async function createComponentFolder(folder) {
177
+ try {
178
+ await mkdir(
179
+ /*
180
+ * When using `pnpm/yarn/npm miyagi new …`, `process.env.INIT_CWD` equals
181
+ * the current working directory, so also subdirectories of where
182
+ * the package.json is located. In this case `process.cwd()` always
183
+ * equals the root directory though.
184
+ * When using node directly, `process.env.INIT_CWD` is not available,
185
+ * but `process.cwd()` is always the current working directory, so
186
+ * also subdirectories.
187
+ * So, if INIT_CWD is available, we know it is the directory the user
188
+ * cd'ed into, if it not available, then we use process.cwd(), which
189
+ * in that case is also the directory the user cd'ed into.
190
+ * It is important that we let the user create a component from their
191
+ * current working directory, so they can benefit from autocompletion.
192
+ */
193
+ path.join(process.env.INIT_CWD || process.cwd(), folder),
194
+ { recursive: true },
195
+ );
196
+ } catch (err) {
197
+ return err;
198
+ }
199
+ }