@schalkneethling/miyagi-core 4.6.2 → 4.7.0
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/frontend/views/component_variation.twig.miyagi +2 -2
- package/frontend/views/iframe_component.twig.miyagi +9 -0
- package/lib/build/index.js +1 -0
- package/lib/data-json/index.js +69 -0
- package/lib/helpers.js +10 -2
- package/lib/init/router.js +1 -0
- package/lib/init/watcher.js +17 -0
- package/lib/render/views/iframe/component.js +25 -1
- package/lib/render/views/iframe/variation.standalone.js +8 -1
- package/lib/state/components.js +4 -0
- package/lib/state/file-contents.js +1 -0
- package/package.json +1 -1
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
{% if assets.js %}
|
|
25
25
|
<script src="{{ assets.js }}"></script>
|
|
26
26
|
{% endif %}
|
|
27
|
-
{% if
|
|
28
|
-
<script type="application/json" id="
|
|
27
|
+
{% if dataJson is defined and dataJson %}
|
|
28
|
+
<script type="application/json" id="{{ dataJsonId }}">{{ dataJson|replace({'</script>': '<\\/script>'})|raw }}</script>
|
|
29
29
|
{% endif %}
|
|
30
30
|
<script>
|
|
31
31
|
{{ theme.js }}
|
|
@@ -34,6 +34,12 @@
|
|
|
34
34
|
<div id="json-tree-resolved-mocks" data-jsontree-js="jsontree.mocks"></div>
|
|
35
35
|
</details>
|
|
36
36
|
{% endif %}
|
|
37
|
+
{% if dataJson %}
|
|
38
|
+
<details class="Tabs-tab">
|
|
39
|
+
<summary>Data</summary>
|
|
40
|
+
<div id="json-tree-resolved-data" data-jsontree-js="jsontree.data"></div>
|
|
41
|
+
</details>
|
|
42
|
+
{% endif %}
|
|
37
43
|
{% if template %}
|
|
38
44
|
<details class="Tabs-tab">
|
|
39
45
|
<summary>Template</summary>
|
|
@@ -135,6 +141,9 @@
|
|
|
135
141
|
},
|
|
136
142
|
"mocks": {
|
|
137
143
|
"data": {{ mocks|default({})|replace({'</script>': '<\\/script>'})|raw }}
|
|
144
|
+
},
|
|
145
|
+
"data": {
|
|
146
|
+
"data": {{ dataJson|default({})|replace({'</script>': '<\\/script>'})|raw }}
|
|
138
147
|
}
|
|
139
148
|
};
|
|
140
149
|
</script>
|
package/lib/build/index.js
CHANGED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { getVariationData, getComponentData } from "../mocks/index.js";
|
|
2
|
+
import log from "../logger.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Resolves the data.json content for a component.
|
|
6
|
+
*
|
|
7
|
+
* If no data.json exists, returns null values (no JSON exposed in DOM).
|
|
8
|
+
* If data.json has useMocks: true, uses the mocks pipeline as the data source.
|
|
9
|
+
* Otherwise, uses the data.json content directly (stripping the useMocks key).
|
|
10
|
+
* @param {object} component - the component route object
|
|
11
|
+
* @param {object} options
|
|
12
|
+
* @param {string} [options.variation] - the variation name (used when useMocks is true)
|
|
13
|
+
* @returns {Promise<{ json: string|null, id: string }>}
|
|
14
|
+
*/
|
|
15
|
+
export async function resolveDataJson(component, { variation } = {}) {
|
|
16
|
+
const dataJsonPath = component.paths.data.full;
|
|
17
|
+
const dataJsonContent = global.state.fileContents[dataJsonPath];
|
|
18
|
+
|
|
19
|
+
if (!dataJsonContent) {
|
|
20
|
+
return { json: null, id: "miyagi-mock-data" };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (dataJsonContent.useMocks === true) {
|
|
24
|
+
return resolveFromMocks(component, variation);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return resolveFromDataJson(dataJsonContent);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Uses the mocks pipeline to produce the JSON content.
|
|
32
|
+
* @param {object} component
|
|
33
|
+
* @param {string} [variation]
|
|
34
|
+
* @returns {Promise<{ json: string|null, id: string }>}
|
|
35
|
+
*/
|
|
36
|
+
async function resolveFromMocks(component, variation) {
|
|
37
|
+
try {
|
|
38
|
+
let data;
|
|
39
|
+
|
|
40
|
+
if (variation) {
|
|
41
|
+
data = await getVariationData(component, variation);
|
|
42
|
+
} else {
|
|
43
|
+
const allData = await getComponentData(component);
|
|
44
|
+
data = allData?.[0] ?? null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const resolved = data?.resolved ?? {};
|
|
48
|
+
return { json: JSON.stringify(resolved), id: "miyagi-mock-data" };
|
|
49
|
+
} catch (err) {
|
|
50
|
+
log(
|
|
51
|
+
"error",
|
|
52
|
+
`Error resolving mock data for data.json in ${component.paths.dir.short}`,
|
|
53
|
+
err,
|
|
54
|
+
);
|
|
55
|
+
return { json: null, id: "miyagi-mock-data" };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Uses the data.json content directly, stripping internal properties.
|
|
61
|
+
* @param {object} dataJsonContent - parsed data.json object
|
|
62
|
+
* @returns {{ json: string, id: string }}
|
|
63
|
+
*/
|
|
64
|
+
function resolveFromDataJson(dataJsonContent) {
|
|
65
|
+
const clone = structuredClone(dataJsonContent);
|
|
66
|
+
delete clone.useMocks;
|
|
67
|
+
|
|
68
|
+
return { json: JSON.stringify(clone), id: "miyagi-mock-data" };
|
|
69
|
+
}
|
package/lib/helpers.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import v8 from "v8";
|
|
2
1
|
import path from "path";
|
|
3
2
|
|
|
4
3
|
/**
|
|
@@ -69,7 +68,7 @@ export const getResolvedFileName = function (nameInConfig, fileName) {
|
|
|
69
68
|
* @returns {object} clone of rhe given object
|
|
70
69
|
*/
|
|
71
70
|
export const cloneDeep = function (obj) {
|
|
72
|
-
return
|
|
71
|
+
return structuredClone(obj);
|
|
73
72
|
};
|
|
74
73
|
|
|
75
74
|
/**
|
|
@@ -133,6 +132,15 @@ export const fileIsSchemaFile = function (filePath) {
|
|
|
133
132
|
);
|
|
134
133
|
};
|
|
135
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Accepts a file path and checks if it is a data.json file
|
|
137
|
+
* @param {string} filePath - path to any type of file
|
|
138
|
+
* @returns {boolean} is true if the given file is a data.json file
|
|
139
|
+
*/
|
|
140
|
+
export const fileIsDataJsonFile = function (filePath) {
|
|
141
|
+
return path.basename(filePath) === "data.json";
|
|
142
|
+
};
|
|
143
|
+
|
|
136
144
|
/**
|
|
137
145
|
* Accepts a file path and checks if it is component js or css file
|
|
138
146
|
* @param {string} filePath - path to any type of file
|
package/lib/init/router.js
CHANGED
package/lib/init/watcher.js
CHANGED
|
@@ -298,6 +298,7 @@ async function updateFileContents(events) {
|
|
|
298
298
|
fs.lstatSync(fullPath).isFile() &&
|
|
299
299
|
(helpers.fileIsTemplateFile(relativePath) ||
|
|
300
300
|
helpers.fileIsDataFile(relativePath) ||
|
|
301
|
+
helpers.fileIsDataJsonFile(relativePath) ||
|
|
301
302
|
helpers.fileIsDocumentationFile(relativePath) ||
|
|
302
303
|
helpers.fileIsSchemaFile(relativePath))
|
|
303
304
|
) {
|
|
@@ -357,6 +358,9 @@ async function handleFileChange(events) {
|
|
|
357
358
|
const schemaEvents = events.filter(({ relativePath }) =>
|
|
358
359
|
helpers.fileIsSchemaFile(relativePath),
|
|
359
360
|
);
|
|
361
|
+
const dataJsonEvents = events.filter(({ relativePath }) =>
|
|
362
|
+
helpers.fileIsDataJsonFile(relativePath),
|
|
363
|
+
);
|
|
360
364
|
const componentAssetEvents = events.filter(({ relativePath }) =>
|
|
361
365
|
helpers.fileIsAssetFile(relativePath),
|
|
362
366
|
);
|
|
@@ -532,6 +536,19 @@ async function handleFileChange(events) {
|
|
|
532
536
|
return;
|
|
533
537
|
}
|
|
534
538
|
|
|
539
|
+
if (dataJsonEvents.length > 0) {
|
|
540
|
+
await setState({
|
|
541
|
+
fileContents: await updateFileContents(dataJsonEvents),
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
sendReload(watchRules.data, {
|
|
545
|
+
reason: "data-json",
|
|
546
|
+
paths: dataJsonEvents.map(({ relativePath }) => relativePath),
|
|
547
|
+
});
|
|
548
|
+
log("success", `${t("updatingDone")}\n`);
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
|
|
535
552
|
if (componentAssetEvents.length > 0) {
|
|
536
553
|
sendReload(watchRules.componentAsset, {
|
|
537
554
|
reason: "component-asset",
|
|
@@ -32,6 +32,8 @@ export default async function renderIframeComponent({
|
|
|
32
32
|
global.state.fileContents[path.join(component.paths.dir.full, "README.md")];
|
|
33
33
|
const componentSchema =
|
|
34
34
|
global.state.fileContents[component.paths.schema.full];
|
|
35
|
+
const componentDataJson =
|
|
36
|
+
global.state.fileContents[component.paths.data.full] ?? null;
|
|
35
37
|
const componentTemplate = hasTemplate
|
|
36
38
|
? global.state.fileContents[component.paths.tpl.full]
|
|
37
39
|
: null;
|
|
@@ -103,6 +105,16 @@ export default async function renderIframeComponent({
|
|
|
103
105
|
),
|
|
104
106
|
}
|
|
105
107
|
: null,
|
|
108
|
+
data: componentDataJson
|
|
109
|
+
? {
|
|
110
|
+
string: JSON.stringify(componentDataJson, null, 2),
|
|
111
|
+
type: "json",
|
|
112
|
+
file: path.join(
|
|
113
|
+
global.config.components.folder,
|
|
114
|
+
component.paths.data.short,
|
|
115
|
+
),
|
|
116
|
+
}
|
|
117
|
+
: null,
|
|
106
118
|
};
|
|
107
119
|
|
|
108
120
|
await renderVariations({
|
|
@@ -205,13 +217,24 @@ async function renderVariations({
|
|
|
205
217
|
}
|
|
206
218
|
}
|
|
207
219
|
|
|
220
|
+
let dataJson;
|
|
221
|
+
|
|
222
|
+
if (fileContents?.data?.string) {
|
|
223
|
+
try {
|
|
224
|
+
dataJson = JSON.stringify(JSON.parse(fileContents.data.string));
|
|
225
|
+
} catch (err) {
|
|
226
|
+
log("error", null, err);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
208
230
|
return Promise.all(promises)
|
|
209
231
|
.then(async () => {
|
|
210
232
|
const themeMode = getThemeMode(cookies);
|
|
211
233
|
const renderFileTabs = !!(
|
|
212
234
|
fileContents.schema ||
|
|
213
235
|
fileContents.mocks ||
|
|
214
|
-
fileContents.template
|
|
236
|
+
fileContents.template ||
|
|
237
|
+
fileContents.data
|
|
215
238
|
);
|
|
216
239
|
const componentsEntry = global.state.components.find(
|
|
217
240
|
({ shortPath }) => shortPath === component.paths.dir.short,
|
|
@@ -259,6 +282,7 @@ async function renderVariations({
|
|
|
259
282
|
? validatedMocks[0].data.map((error) => error.message).join("\n")
|
|
260
283
|
: null,
|
|
261
284
|
mocks: mocksJson,
|
|
285
|
+
dataJson,
|
|
262
286
|
template: fileContents.template,
|
|
263
287
|
renderInformation: renderFileTabs || variations.length > 0,
|
|
264
288
|
renderFileTabs,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import config from "../../../default-config.js";
|
|
3
|
+
import { resolveDataJson } from "../../../data-json/index.js";
|
|
3
4
|
import { getUserUiConfig } from "../../helpers.js";
|
|
4
5
|
import resolveAssets from "../../helpers/resolve-assets.js";
|
|
5
6
|
import applyOverrides from "../../helpers/apply-overrides.js";
|
|
@@ -13,6 +14,7 @@ import applyOverrides from "../../helpers/apply-overrides.js";
|
|
|
13
14
|
* @param {Function} [object.cb] - callback function
|
|
14
15
|
* @param {object} [object.cookies]
|
|
15
16
|
* @param {object} [object.overrides] - query-param override values
|
|
17
|
+
* @param {string} [object.variation] - the variation name
|
|
16
18
|
* @returns {Promise} gets resolved when the variation has been rendered
|
|
17
19
|
*/
|
|
18
20
|
export default async function renderIframeVariationStandalone({
|
|
@@ -23,6 +25,7 @@ export default async function renderIframeVariationStandalone({
|
|
|
23
25
|
cb,
|
|
24
26
|
cookies,
|
|
25
27
|
overrides,
|
|
28
|
+
variation,
|
|
26
29
|
}) {
|
|
27
30
|
if (overrides) {
|
|
28
31
|
const schema =
|
|
@@ -31,6 +34,9 @@ export default async function renderIframeVariationStandalone({
|
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
const directoryPath = component.paths.dir.short;
|
|
37
|
+
const { json: dataJson, id: dataJsonId } = await resolveDataJson(component, {
|
|
38
|
+
variation,
|
|
39
|
+
});
|
|
34
40
|
|
|
35
41
|
return new Promise((resolve, reject) => {
|
|
36
42
|
global.app.render(
|
|
@@ -58,7 +64,8 @@ export default async function renderIframeVariationStandalone({
|
|
|
58
64
|
"component_variation.twig.miyagi",
|
|
59
65
|
{
|
|
60
66
|
html: result,
|
|
61
|
-
|
|
67
|
+
dataJson,
|
|
68
|
+
dataJsonId,
|
|
62
69
|
cssFiles,
|
|
63
70
|
jsFilesHead,
|
|
64
71
|
jsFilesBody,
|
package/lib/state/components.js
CHANGED
|
@@ -116,6 +116,10 @@ function addToRoutes({ name, shortPath, fullPath }, partials = []) {
|
|
|
116
116
|
full: path.join(fullPath, "README.md"),
|
|
117
117
|
short: path.join(shortPath, "README.md"),
|
|
118
118
|
},
|
|
119
|
+
data: {
|
|
120
|
+
full: path.join(fullPath, "data.json"),
|
|
121
|
+
short: path.join(shortPath, "data.json"),
|
|
122
|
+
},
|
|
119
123
|
},
|
|
120
124
|
type: "components",
|
|
121
125
|
};
|
|
@@ -69,6 +69,7 @@ async function getFilePaths(sourceTree) {
|
|
|
69
69
|
`${files.mocks.name}.${files.mocks.extension[0]}`,
|
|
70
70
|
`${files.mocks.name}.${files.mocks.extension[1]}`,
|
|
71
71
|
`${files.schema.name}.${files.schema.extension}`,
|
|
72
|
+
"data.json",
|
|
72
73
|
]) ||
|
|
73
74
|
helpers.fileIsDocumentationFile(entry.path)
|
|
74
75
|
) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@schalkneethling/miyagi-core",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.7.0",
|
|
4
4
|
"description": "miyagi is a component development tool for JavaScript template engines.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"author": "Schalk Neethling <schalkneethling@duck.com>, Michael Großklaus <mail@mgrossklaus.de> (https://www.mgrossklaus.de)",
|