@schalkneethling/miyagi-core 4.0.2 → 4.2.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/api/index.js +98 -10
- package/lib/build/index.js +16 -0
- package/lib/cli/drupal-assets.js +159 -0
- package/lib/cli/index.js +2 -0
- package/lib/cli/lint.js +142 -94
- package/lib/constants/lint-log-levels.js +11 -0
- package/lib/default-config.js +10 -0
- package/lib/drupal/load-assets-config.js +94 -0
- package/lib/drupal/resolve-library-assets.js +189 -0
- package/lib/i18n/en.js +4 -0
- package/lib/index.js +27 -4
- package/lib/init/args.js +38 -0
- package/lib/init/config.js +26 -0
- package/lib/init/router.js +1 -0
- package/lib/init/static.js +30 -0
- package/lib/init/watcher.js +21 -0
- package/lib/logger.js +37 -2
- package/lib/mocks/get.js +4 -0
- package/lib/render/helpers/resolve-assets.js +58 -0
- package/lib/render/views/iframe/component.js +9 -7
- package/lib/render/views/iframe/variation.standalone.js +9 -7
- package/lib/state/file-contents.js +46 -3
- package/lib/state/index.js +1 -0
- package/lib/validator/mocks.js +31 -26
- package/lib/validator/schemas.js +234 -0
- package/package.json +10 -8
|
@@ -6,6 +6,7 @@ import * as helpers from "../../../helpers.js";
|
|
|
6
6
|
import validateMocks from "../../../validator/mocks.js";
|
|
7
7
|
import { getComponentData } from "../../../mocks/index.js";
|
|
8
8
|
import { getUserUiConfig, getThemeMode } from "../../helpers.js";
|
|
9
|
+
import resolveAssets from "../../helpers/resolve-assets.js";
|
|
9
10
|
import log from "../../../logger.js";
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -216,18 +217,19 @@ async function renderVariations({
|
|
|
216
217
|
({ shortPath }) => shortPath === component.paths.dir.short,
|
|
217
218
|
);
|
|
218
219
|
|
|
220
|
+
const componentDeclaredAssets =
|
|
221
|
+
context.length > 0 ? context[0].$assets || null : null;
|
|
222
|
+
const { cssFiles, jsFilesHead, jsFilesBody } =
|
|
223
|
+
resolveAssets(componentDeclaredAssets);
|
|
224
|
+
|
|
219
225
|
await res.render(
|
|
220
226
|
"iframe_component.twig.miyagi",
|
|
221
227
|
{
|
|
222
228
|
lang: global.config.ui.lang,
|
|
223
229
|
variations,
|
|
224
|
-
cssFiles
|
|
225
|
-
jsFilesHead
|
|
226
|
-
|
|
227
|
-
),
|
|
228
|
-
jsFilesBody: global.config.assets.js.filter(
|
|
229
|
-
(entry) => entry.position === "body",
|
|
230
|
-
),
|
|
230
|
+
cssFiles,
|
|
231
|
+
jsFilesHead,
|
|
232
|
+
jsFilesBody,
|
|
231
233
|
assets: {
|
|
232
234
|
css: componentsEntry
|
|
233
235
|
? componentsEntry.assets.css
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import config from "../../../default-config.js";
|
|
3
3
|
import { getUserUiConfig } from "../../helpers.js";
|
|
4
|
+
import resolveAssets from "../../helpers/resolve-assets.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* @param {object} object - parameter object
|
|
7
8
|
* @param {object} [object.res] - the express response object
|
|
8
9
|
* @param {object} object.component
|
|
9
10
|
* @param {object} object.componentData
|
|
11
|
+
* @param {object|null} [object.componentDeclaredAssets] - $assets from mocks
|
|
10
12
|
* @param {Function} [object.cb] - callback function
|
|
11
13
|
* @param {object} [object.cookies]
|
|
12
14
|
* @returns {Promise} gets resolved when the variation has been rendered
|
|
@@ -15,6 +17,7 @@ export default async function renderIframeVariationStandalone({
|
|
|
15
17
|
res,
|
|
16
18
|
component,
|
|
17
19
|
componentData,
|
|
20
|
+
componentDeclaredAssets = null,
|
|
18
21
|
cb,
|
|
19
22
|
cookies,
|
|
20
23
|
}) {
|
|
@@ -38,17 +41,16 @@ export default async function renderIframeVariationStandalone({
|
|
|
38
41
|
({ shortPath }) => shortPath === directoryPath,
|
|
39
42
|
);
|
|
40
43
|
|
|
44
|
+
const { cssFiles, jsFilesHead, jsFilesBody } =
|
|
45
|
+
resolveAssets(componentDeclaredAssets);
|
|
46
|
+
|
|
41
47
|
await res.render(
|
|
42
48
|
"component_variation.twig.miyagi",
|
|
43
49
|
{
|
|
44
50
|
html: result,
|
|
45
|
-
cssFiles
|
|
46
|
-
jsFilesHead
|
|
47
|
-
|
|
48
|
-
),
|
|
49
|
-
jsFilesBody: global.config.assets.js.filter(
|
|
50
|
-
(entry) => entry.position === "body",
|
|
51
|
-
),
|
|
51
|
+
cssFiles,
|
|
52
|
+
jsFilesHead,
|
|
53
|
+
jsFilesBody,
|
|
52
54
|
assets: {
|
|
53
55
|
css: componentsEntry
|
|
54
56
|
? componentsEntry.assets.css
|
|
@@ -11,6 +11,31 @@ import { marked as Markdown } from "marked";
|
|
|
11
11
|
import * as helpers from "../helpers.js";
|
|
12
12
|
import log from "../logger.js";
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* @param {string} fileName
|
|
16
|
+
* @returns {boolean}
|
|
17
|
+
*/
|
|
18
|
+
function isSchemaFile(fileName) {
|
|
19
|
+
const schemaFileName = `${global.config.files.schema.name}.${global.config.files.schema.extension}`;
|
|
20
|
+
return path.basename(fileName) === schemaFileName;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {string} fileName
|
|
25
|
+
* @param {Error & { code?: string }} err
|
|
26
|
+
*/
|
|
27
|
+
function markFileReadError(fileName, err) {
|
|
28
|
+
if (!global.state?.fileReadErrors || !isSchemaFile(fileName)) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
global.state.fileReadErrors[fileName] = {
|
|
33
|
+
type: "schema-parse",
|
|
34
|
+
code: err?.code || null,
|
|
35
|
+
message: err?.message || String(err),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
14
39
|
/**
|
|
15
40
|
* Checks if a given array of file paths includes a given file path
|
|
16
41
|
* @param {string} file - file path string
|
|
@@ -134,8 +159,13 @@ export const readFile = async function (fileName) {
|
|
|
134
159
|
case [".yaml", ".yml"].includes(path.extname(fileName)):
|
|
135
160
|
{
|
|
136
161
|
try {
|
|
137
|
-
|
|
162
|
+
const content = await getYamlFileContent(fileName);
|
|
163
|
+
if (global.state?.fileReadErrors) {
|
|
164
|
+
delete global.state.fileReadErrors[fileName];
|
|
165
|
+
}
|
|
166
|
+
return content;
|
|
138
167
|
} catch (err) {
|
|
168
|
+
markFileReadError(fileName, err);
|
|
139
169
|
log("error", `Error when reading file ${fileName}`, err);
|
|
140
170
|
}
|
|
141
171
|
}
|
|
@@ -153,8 +183,13 @@ export const readFile = async function (fileName) {
|
|
|
153
183
|
[".js", ".mjs"].includes(path.extname(fileName)):
|
|
154
184
|
{
|
|
155
185
|
try {
|
|
156
|
-
|
|
186
|
+
const content = await getJsFileContent(fileName);
|
|
187
|
+
if (global.state?.fileReadErrors) {
|
|
188
|
+
delete global.state.fileReadErrors[fileName];
|
|
189
|
+
}
|
|
190
|
+
return content;
|
|
157
191
|
} catch (err) {
|
|
192
|
+
markFileReadError(fileName, err);
|
|
158
193
|
log("error", `Error when reading file ${fileName}`, err);
|
|
159
194
|
}
|
|
160
195
|
}
|
|
@@ -162,8 +197,13 @@ export const readFile = async function (fileName) {
|
|
|
162
197
|
case fileName.endsWith(".json"):
|
|
163
198
|
{
|
|
164
199
|
try {
|
|
165
|
-
|
|
200
|
+
const content = await getParsedJsonFileContent(fileName);
|
|
201
|
+
if (global.state?.fileReadErrors) {
|
|
202
|
+
delete global.state.fileReadErrors[fileName];
|
|
203
|
+
}
|
|
204
|
+
return content;
|
|
166
205
|
} catch (err) {
|
|
206
|
+
markFileReadError(fileName, err);
|
|
167
207
|
log("error", `Error when reading file ${fileName}`, err);
|
|
168
208
|
}
|
|
169
209
|
}
|
|
@@ -187,6 +227,9 @@ export const readFile = async function (fileName) {
|
|
|
187
227
|
*/
|
|
188
228
|
export const getFileContents = async function (sourceTree) {
|
|
189
229
|
const fileContents = {};
|
|
230
|
+
if (global.state) {
|
|
231
|
+
global.state.fileReadErrors = {};
|
|
232
|
+
}
|
|
190
233
|
const paths = await getFilePaths(sourceTree);
|
|
191
234
|
|
|
192
235
|
if (paths) {
|
package/lib/state/index.js
CHANGED
package/lib/validator/mocks.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import jsYaml from "js-yaml";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
2
3
|
import deepMerge from "deepmerge";
|
|
3
4
|
import log from "../logger.js";
|
|
4
5
|
import { t } from "../i18n/index.js";
|
|
@@ -9,31 +10,19 @@ import { t } from "../i18n/index.js";
|
|
|
9
10
|
* @param {object} component
|
|
10
11
|
* @param {Array} dataArray - an array with mock data
|
|
11
12
|
* @param {boolean} [noCli]
|
|
13
|
+
* @param {Array<object>} [validSchemas]
|
|
12
14
|
* @returns {null|object[]} null if there is no schema or an array with booleans defining the validity of the entries in the data array
|
|
13
15
|
*/
|
|
14
|
-
export default function validateMockData(
|
|
16
|
+
export default function validateMockData(
|
|
17
|
+
component,
|
|
18
|
+
dataArray,
|
|
19
|
+
noCli,
|
|
20
|
+
validSchemas = [],
|
|
21
|
+
) {
|
|
15
22
|
const componentSchema =
|
|
16
23
|
global.state.fileContents[component.paths.schema.full];
|
|
17
24
|
|
|
18
25
|
if (componentSchema) {
|
|
19
|
-
const schemas = [];
|
|
20
|
-
|
|
21
|
-
Object.entries(global.state.fileContents).forEach(([key, value]) => {
|
|
22
|
-
if (
|
|
23
|
-
key.endsWith(
|
|
24
|
-
`${global.config.files.schema.name}.${global.config.files.schema.extension}`,
|
|
25
|
-
)
|
|
26
|
-
) {
|
|
27
|
-
const arr = Array.isArray(value) ? value : [value];
|
|
28
|
-
|
|
29
|
-
arr.forEach((schema) => {
|
|
30
|
-
if (schema && componentSchema.$id !== schema.$id) {
|
|
31
|
-
schemas.push(schema);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
|
|
37
26
|
const validity = [];
|
|
38
27
|
let validate;
|
|
39
28
|
let jsonSchemaValidator;
|
|
@@ -43,16 +32,19 @@ export default function validateMockData(component, dataArray, noCli) {
|
|
|
43
32
|
deepMerge(
|
|
44
33
|
{
|
|
45
34
|
allErrors: true,
|
|
46
|
-
schemas: schemas.map((schema, i) => {
|
|
47
|
-
if (!schema.$id) {
|
|
48
|
-
schema.$id = i.toString();
|
|
49
|
-
}
|
|
50
|
-
return schema;
|
|
51
|
-
}),
|
|
52
35
|
},
|
|
53
36
|
global.config.schema.options || {},
|
|
54
37
|
),
|
|
55
38
|
);
|
|
39
|
+
|
|
40
|
+
validSchemas.forEach((entry) => {
|
|
41
|
+
// Preload only other validated schemas for cross-component $ref resolution.
|
|
42
|
+
// The current component schema is compiled below and must not be added twice.
|
|
43
|
+
if (entry?.schemaFile !== component.paths.schema.full && entry?.schema) {
|
|
44
|
+
jsonSchemaValidator.addSchema(entry.schema);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
56
48
|
validate = jsonSchemaValidator.compile(componentSchema);
|
|
57
49
|
} catch (e) {
|
|
58
50
|
const message = e.toString();
|
|
@@ -95,9 +87,22 @@ export default function validateMockData(component, dataArray, noCli) {
|
|
|
95
87
|
}
|
|
96
88
|
|
|
97
89
|
if (!global.config.isBuild && !noCli) {
|
|
90
|
+
const parseError = global.state.fileReadErrors?.[component.paths.schema.full];
|
|
91
|
+
const schemaExistsOnDisk = existsSync(component.paths.schema.full);
|
|
92
|
+
const warningMessage = parseError
|
|
93
|
+
? t("validator.mocks.schemaParseFailed")
|
|
94
|
+
.replace("{{schemaFile}}", component.paths.schema.short)
|
|
95
|
+
.replace("{{format}}", "JSON or YAML")
|
|
96
|
+
: schemaExistsOnDisk
|
|
97
|
+
? t("validator.mocks.schemaParseFailed")
|
|
98
|
+
.replace("{{schemaFile}}", component.paths.schema.short)
|
|
99
|
+
.replace("{{format}}", "JSON or YAML")
|
|
100
|
+
: t("validator.mocks.schemaMissing")
|
|
101
|
+
.replace("{{component}}", component.paths.dir.short)
|
|
102
|
+
.replace("{{schemaFile}}", component.paths.schema.short);
|
|
98
103
|
log(
|
|
99
104
|
"warn",
|
|
100
|
-
|
|
105
|
+
warningMessage,
|
|
101
106
|
);
|
|
102
107
|
}
|
|
103
108
|
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import deepMerge from "deepmerge";
|
|
4
|
+
|
|
5
|
+
const DEFAULT_SCHEMA_VALIDATION_MODE = "collect-all";
|
|
6
|
+
const ALLOWED_SCHEMA_VALIDATION_MODES = new Set(["collect-all", "fail-fast"]);
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @returns {"collect-all"|"fail-fast"}
|
|
10
|
+
*/
|
|
11
|
+
export function getSchemaValidationMode() {
|
|
12
|
+
const mode = global.config.schemaValidationMode ?? DEFAULT_SCHEMA_VALIDATION_MODE;
|
|
13
|
+
|
|
14
|
+
if (!ALLOWED_SCHEMA_VALIDATION_MODES.has(mode)) {
|
|
15
|
+
return DEFAULT_SCHEMA_VALIDATION_MODE;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return mode;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {object} options
|
|
23
|
+
* @param {Array<object>} [options.components]
|
|
24
|
+
* @returns {{ valid: boolean, errors: Array<object>, validSchemas: Array<object> }}
|
|
25
|
+
*/
|
|
26
|
+
export function validateSchemas({ components } = {}) {
|
|
27
|
+
const validSchemas = [];
|
|
28
|
+
const errors = [];
|
|
29
|
+
const componentRoutes =
|
|
30
|
+
components ??
|
|
31
|
+
global.state.routes.filter((route) => route.type === "components" && route.paths.tpl);
|
|
32
|
+
const validator = new global.config.schema.ajv(
|
|
33
|
+
deepMerge(
|
|
34
|
+
{
|
|
35
|
+
allErrors: true,
|
|
36
|
+
},
|
|
37
|
+
global.config.schema.options || {},
|
|
38
|
+
),
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
let pendingSchemas = componentRoutes
|
|
42
|
+
.map((component, index) => {
|
|
43
|
+
// Absolute schema file path.
|
|
44
|
+
const schemaFile = component.paths.schema.full;
|
|
45
|
+
// Parsed schema from in-memory state cache.
|
|
46
|
+
const schemaFromState = global.state.fileContents[schemaFile];
|
|
47
|
+
|
|
48
|
+
if (!schemaFromState) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const schema = structuredClone(schemaFromState);
|
|
53
|
+
if (!schema.$id) {
|
|
54
|
+
schema.$id = component.paths.schema.short || schemaFile || index.toString();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
component: component.paths.dir.short,
|
|
59
|
+
schemaFile,
|
|
60
|
+
rawSchema: schemaFromState,
|
|
61
|
+
schema,
|
|
62
|
+
};
|
|
63
|
+
})
|
|
64
|
+
.filter(Boolean);
|
|
65
|
+
|
|
66
|
+
while (pendingSchemas.length > 0) {
|
|
67
|
+
let progress = false;
|
|
68
|
+
const retrySchemas = [];
|
|
69
|
+
|
|
70
|
+
pendingSchemas.forEach((entry) => {
|
|
71
|
+
try {
|
|
72
|
+
validator.compile(entry.schema);
|
|
73
|
+
if (!validator.getSchema(entry.schema.$id)) {
|
|
74
|
+
validator.addSchema(entry.schema);
|
|
75
|
+
}
|
|
76
|
+
validSchemas.push({
|
|
77
|
+
component: entry.component,
|
|
78
|
+
schemaFile: entry.schemaFile,
|
|
79
|
+
schema: entry.schema,
|
|
80
|
+
});
|
|
81
|
+
progress = true;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
if (isUnresolvedRefError(error)) {
|
|
84
|
+
retrySchemas.push(entry);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
errors.push(
|
|
89
|
+
buildSchemaValidationError({
|
|
90
|
+
error,
|
|
91
|
+
component: entry.component,
|
|
92
|
+
schemaFile: entry.schemaFile,
|
|
93
|
+
rawSchema: entry.rawSchema,
|
|
94
|
+
}),
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
if (!progress) {
|
|
100
|
+
retrySchemas.forEach((entry) => {
|
|
101
|
+
const error = new Error(
|
|
102
|
+
`can't resolve reference while validating schema ${entry.schemaFile}`,
|
|
103
|
+
);
|
|
104
|
+
errors.push(
|
|
105
|
+
buildSchemaValidationError({
|
|
106
|
+
error,
|
|
107
|
+
component: entry.component,
|
|
108
|
+
schemaFile: entry.schemaFile,
|
|
109
|
+
rawSchema: entry.rawSchema,
|
|
110
|
+
}),
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
pendingSchemas = retrySchemas;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
valid: errors.length === 0,
|
|
121
|
+
errors,
|
|
122
|
+
validSchemas,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @param {object} obj
|
|
128
|
+
* @param {Error & { errors?: Array<object> }} obj.error
|
|
129
|
+
* @param {string} obj.component
|
|
130
|
+
* @param {string} obj.schemaFile
|
|
131
|
+
* @param {object} obj.rawSchema
|
|
132
|
+
* @returns {object}
|
|
133
|
+
*/
|
|
134
|
+
function buildSchemaValidationError({ error, component, schemaFile, rawSchema }) {
|
|
135
|
+
const ajvErrors = Array.isArray(error?.errors) ? error.errors : [];
|
|
136
|
+
const [firstAjvError] = ajvErrors;
|
|
137
|
+
const hint = getSchemaHint(rawSchema, ajvErrors);
|
|
138
|
+
const type = isUnresolvedRefError(error) ? "schema-ref" : "schema";
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
type,
|
|
142
|
+
component,
|
|
143
|
+
schemaFile,
|
|
144
|
+
message: error?.toString?.() || "Unknown schema validation error",
|
|
145
|
+
schemaPath: firstAjvError?.schemaPath || "",
|
|
146
|
+
instancePath: firstAjvError?.instancePath || "",
|
|
147
|
+
hint,
|
|
148
|
+
details: ajvErrors.map((entry) => ({
|
|
149
|
+
keyword: entry.keyword,
|
|
150
|
+
message: entry.message,
|
|
151
|
+
schemaPath: entry.schemaPath,
|
|
152
|
+
instancePath: entry.instancePath,
|
|
153
|
+
params: entry.params,
|
|
154
|
+
})),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* @param {object} schema
|
|
160
|
+
* @param {Array<object>} ajvErrors
|
|
161
|
+
* @returns {string|undefined}
|
|
162
|
+
*/
|
|
163
|
+
function getSchemaHint(schema, ajvErrors) {
|
|
164
|
+
if (schema?.properties === null) {
|
|
165
|
+
return "Hint: `properties` resolves to null. In YAML this often means `properties:` has no nested keys.";
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (
|
|
169
|
+
ajvErrors.some(
|
|
170
|
+
(error) =>
|
|
171
|
+
error?.schemaPath?.endsWith("/properties/type") &&
|
|
172
|
+
error?.instancePath?.includes("/properties/"),
|
|
173
|
+
)
|
|
174
|
+
) {
|
|
175
|
+
return "Hint: check each field `type` value; it must be a valid JSON Schema type.";
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* @param {Error & { message?: string, missingRef?: string, missingSchema?: string, code?: string }} error
|
|
183
|
+
* @returns {boolean}
|
|
184
|
+
*/
|
|
185
|
+
function isUnresolvedRefError(error) {
|
|
186
|
+
if (typeof error?.missingRef === "string" && error.missingRef.length > 0) {
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (
|
|
191
|
+
typeof error?.missingSchema === "string" &&
|
|
192
|
+
error.missingSchema.length > 0
|
|
193
|
+
) {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (error?.code === "ERR_MISSING_REF") {
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return /can't resolve reference|missing ref|missing schema/i.test(
|
|
202
|
+
error?.message || "",
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* @param {object} schemaError
|
|
208
|
+
* @param {object} [options]
|
|
209
|
+
* @param {boolean} [options.verbose]
|
|
210
|
+
* @returns {{ type: "schema"|"schema-ref", data: Array<object> }}
|
|
211
|
+
*/
|
|
212
|
+
export function toSchemaValidationResult(schemaError, options = {}) {
|
|
213
|
+
const useVerbose =
|
|
214
|
+
options.verbose ?? global.config?.schema?.verbose === true;
|
|
215
|
+
const formattedError = {
|
|
216
|
+
message: schemaError.message,
|
|
217
|
+
component: schemaError.component,
|
|
218
|
+
schemaFile: schemaError.schemaFile,
|
|
219
|
+
hint: schemaError.hint,
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
if (useVerbose) {
|
|
223
|
+
formattedError.schemaPath = schemaError.schemaPath;
|
|
224
|
+
formattedError.instancePath = schemaError.instancePath;
|
|
225
|
+
formattedError.details = schemaError.details;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return {
|
|
229
|
+
type: schemaError.type || "schema",
|
|
230
|
+
data: [
|
|
231
|
+
formattedError,
|
|
232
|
+
],
|
|
233
|
+
};
|
|
234
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@schalkneethling/miyagi-core",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.2.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)",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"bugs": "https://github.com/miyagi-dev/miyagi/issues",
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
12
|
-
"url": "
|
|
12
|
+
"url": "https://github.com/schalkneethling/miyagi.git"
|
|
13
13
|
},
|
|
14
14
|
"type": "module",
|
|
15
15
|
"keywords": [
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"frontend"
|
|
21
21
|
],
|
|
22
22
|
"engines": {
|
|
23
|
-
"node": ">=
|
|
23
|
+
"node": ">=24"
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
26
|
"api",
|
|
@@ -43,9 +43,10 @@
|
|
|
43
43
|
"directory-tree": "^3.5.2",
|
|
44
44
|
"express": "^5.1.0",
|
|
45
45
|
"js-yaml": "^4.1.0",
|
|
46
|
-
"marked": "^
|
|
46
|
+
"marked": "^17.0.2",
|
|
47
47
|
"node-watch": "^0.7.4",
|
|
48
|
-
"twing": "7.
|
|
48
|
+
"twing": "7.3.1",
|
|
49
|
+
"valibot": "^1.2.0",
|
|
49
50
|
"ws": "^8.18.3",
|
|
50
51
|
"yargs": "^18.0.0"
|
|
51
52
|
},
|
|
@@ -53,11 +54,13 @@
|
|
|
53
54
|
"@eslint/js": "^9.39.2",
|
|
54
55
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
55
56
|
"@rollup/plugin-terser": "^0.4.4",
|
|
57
|
+
"@types/js-yaml": "^4.0.9",
|
|
56
58
|
"@types/node": "^24.10.0",
|
|
59
|
+
"@types/yargs": "^17.0.35",
|
|
57
60
|
"@vitest/coverage-v8": "^4.0.6",
|
|
58
61
|
"cssnano": "^7.1.2",
|
|
59
62
|
"eslint": "^9.39.0",
|
|
60
|
-
"eslint-plugin-jsdoc": "^
|
|
63
|
+
"eslint-plugin-jsdoc": "^62.5.4",
|
|
61
64
|
"globals": "^15.15.0",
|
|
62
65
|
"gulp": "^5.0.1",
|
|
63
66
|
"gulp-postcss": "^10.0.0",
|
|
@@ -75,8 +78,7 @@
|
|
|
75
78
|
"build": "gulp build",
|
|
76
79
|
"test": "vitest run --coverage --coverage.include=api --coverage.include=lib",
|
|
77
80
|
"lint": "stylelint frontend/assets/css/ && eslint lib/ && eslint frontend/assets/js/",
|
|
78
|
-
"fix": "eslint lib/ --fix && eslint frontend/assets/js/ --fix"
|
|
79
|
-
"release": "standard-version"
|
|
81
|
+
"fix": "eslint lib/ --fix && eslint frontend/assets/js/ --fix"
|
|
80
82
|
},
|
|
81
83
|
"browserslist": [
|
|
82
84
|
"last 2 versions",
|