correctly 0.0.0 → 0.1.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/AGENTS.md +6 -2
- package/README.md +21 -15
- package/dist/ajv.d.mts +11 -0
- package/dist/ajv.d.mts.map +1 -0
- package/dist/ajv.mjs +221 -0
- package/dist/ajv.mjs.map +1 -0
- package/dist/check-BI7U3ZLc.mjs +88 -0
- package/dist/check-BI7U3ZLc.mjs.map +1 -0
- package/dist/cli.mjs +14 -62
- package/dist/cli.mjs.map +1 -1
- package/dist/config-Bx1-XXeo.d.mts +189 -0
- package/dist/config-Bx1-XXeo.d.mts.map +1 -0
- package/dist/config-Cb6o4YnJ.mjs +348 -0
- package/dist/config-Cb6o4YnJ.mjs.map +1 -0
- package/dist/core.d.mts +27 -125
- package/dist/core.d.mts.map +1 -1
- package/dist/core.mjs +5 -2
- package/dist/diagnostics-BqD1WOy4.mjs +70 -0
- package/dist/diagnostics-BqD1WOy4.mjs.map +1 -0
- package/dist/engine-VST0hoSk.mjs +111 -0
- package/dist/engine-VST0hoSk.mjs.map +1 -0
- package/dist/extensions-ClclWslY.d.mts +11 -0
- package/dist/extensions-ClclWslY.d.mts.map +1 -0
- package/dist/hints-HvSIhuMM.mjs +57 -0
- package/dist/hints-HvSIhuMM.mjs.map +1 -0
- package/dist/lsp.mjs +40 -91
- package/dist/lsp.mjs.map +1 -1
- package/dist/renovate.d.mts +5 -0
- package/dist/renovate.d.mts.map +1 -0
- package/dist/renovate.mjs +11 -0
- package/dist/renovate.mjs.map +1 -0
- package/dist/schemas-UxCtIdo2.mjs +265 -0
- package/dist/schemas-UxCtIdo2.mjs.map +1 -0
- package/dist/session-DCFav56x.mjs +113 -0
- package/dist/session-DCFav56x.mjs.map +1 -0
- package/dist/worker.mjs +80 -0
- package/dist/worker.mjs.map +1 -0
- package/docs/guide.md +166 -34
- package/examples/basic/correctly.config.ts +13 -0
- package/package.json +69 -60
- package/src/cli/check.ts +41 -11
- package/src/cli/main.ts +3 -2
- package/src/cli/readable.ts +24 -5
- package/src/cli/vsix.ts +1 -0
- package/src/core/adapters.ts +54 -0
- package/src/core/config.ts +201 -64
- package/src/core/engine.ts +118 -218
- package/src/core/extensions.ts +144 -0
- package/src/core/index.ts +3 -0
- package/src/core/parse.ts +26 -2
- package/src/core/parsers.ts +22 -0
- package/src/core/schema-walk.ts +43 -0
- package/src/core/schemas.ts +21 -41
- package/src/core/types.ts +33 -6
- package/src/extensions/renovate.ts +4 -0
- package/src/lsp/hints.ts +22 -12
- package/src/lsp/server.ts +9 -2
- package/src/lsp/workspace.ts +49 -54
- package/src/runtime/session.ts +173 -0
- package/src/runtime/worker.ts +99 -0
- package/src/validators/ajv.ts +257 -0
- package/src/vscode/README.md +1 -1
- package/src/vscode/extension.ts +2 -4
- package/src/vscode/package.json +9 -2
- package/dist/engine-BgWBnb1A.mjs +0 -746
- package/dist/engine-BgWBnb1A.mjs.map +0 -1
- package/examples/basic/correctly.config.json +0 -10
- package/src/core/config.schema.json +0 -47
package/dist/engine-BgWBnb1A.mjs
DELETED
|
@@ -1,746 +0,0 @@
|
|
|
1
|
-
import { mkdir, readFile, rename, stat, writeFile } from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
|
-
import { Ajv } from "ajv";
|
|
5
|
-
import picomatch from "picomatch";
|
|
6
|
-
import { findNodeAtLocation, getNodePath, getNodeValue, parseTree, printParseErrorCode } from "jsonc-parser";
|
|
7
|
-
import { Ajv2020 } from "ajv/dist/2020.js";
|
|
8
|
-
import addFormats from "ajv-formats";
|
|
9
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
10
|
-
//#region src/core/config.schema.json
|
|
11
|
-
var config_schema_default = {
|
|
12
|
-
$schema: "http://json-schema.org/draft-07/schema#",
|
|
13
|
-
type: "object",
|
|
14
|
-
additionalProperties: false,
|
|
15
|
-
required: ["associations"],
|
|
16
|
-
properties: {
|
|
17
|
-
"$schema": { "type": "string" },
|
|
18
|
-
"files": { "$ref": "#/definitions/patterns" },
|
|
19
|
-
"exclude": { "$ref": "#/definitions/patterns" },
|
|
20
|
-
"associations": {
|
|
21
|
-
"type": "array",
|
|
22
|
-
"items": {
|
|
23
|
-
"type": "object",
|
|
24
|
-
"additionalProperties": false,
|
|
25
|
-
"required": ["files", "schema"],
|
|
26
|
-
"properties": {
|
|
27
|
-
"name": {
|
|
28
|
-
"type": "string",
|
|
29
|
-
"minLength": 1
|
|
30
|
-
},
|
|
31
|
-
"files": { "$ref": "#/definitions/patterns" },
|
|
32
|
-
"schema": {
|
|
33
|
-
"type": ["string", "null"],
|
|
34
|
-
"minLength": 1
|
|
35
|
-
},
|
|
36
|
-
"mode": { "enum": ["json", "jsonc"] }
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
},
|
|
40
|
-
"remote": {
|
|
41
|
-
"type": "object",
|
|
42
|
-
"additionalProperties": false,
|
|
43
|
-
"properties": {
|
|
44
|
-
"offline": { "type": "boolean" },
|
|
45
|
-
"cacheDir": {
|
|
46
|
-
"type": "string",
|
|
47
|
-
"minLength": 1
|
|
48
|
-
},
|
|
49
|
-
"timeoutMs": {
|
|
50
|
-
"type": "integer",
|
|
51
|
-
"minimum": 1,
|
|
52
|
-
"maximum": 6e4
|
|
53
|
-
},
|
|
54
|
-
"maxBytes": {
|
|
55
|
-
"type": "integer",
|
|
56
|
-
"minimum": 1,
|
|
57
|
-
"maximum": 16777216
|
|
58
|
-
},
|
|
59
|
-
"maxRequests": {
|
|
60
|
-
"type": "integer",
|
|
61
|
-
"minimum": 1,
|
|
62
|
-
"maximum": 256
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
definitions: { "patterns": {
|
|
68
|
-
"type": "array",
|
|
69
|
-
"minItems": 1,
|
|
70
|
-
"items": {
|
|
71
|
-
"type": "string",
|
|
72
|
-
"minLength": 1,
|
|
73
|
-
"pattern": "^(?![/!])(?![A-Za-z]:)(?!.*(?:^|/)\\.\\.(?:/|$)).+"
|
|
74
|
-
}
|
|
75
|
-
} }
|
|
76
|
-
};
|
|
77
|
-
//#endregion
|
|
78
|
-
//#region src/core/parse.ts
|
|
79
|
-
function pointer(parts) {
|
|
80
|
-
return parts.map((p) => `/${String(p).replace(/~/g, "~0").replace(/\//g, "~1")}`).join("");
|
|
81
|
-
}
|
|
82
|
-
function positionAt(text, offset) {
|
|
83
|
-
const end = Math.min(Math.max(0, offset), text.length);
|
|
84
|
-
let line = 0;
|
|
85
|
-
let start = 0;
|
|
86
|
-
for (let i = 0; i < end; i++) if (text[i] === "\r") {
|
|
87
|
-
if (text[i + 1] === "\n" && i + 1 < end) i++;
|
|
88
|
-
line++;
|
|
89
|
-
start = i + 1;
|
|
90
|
-
} else if (text[i] === "\n") {
|
|
91
|
-
line++;
|
|
92
|
-
start = i + 1;
|
|
93
|
-
}
|
|
94
|
-
return {
|
|
95
|
-
line,
|
|
96
|
-
character: end - start
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
function diagnostic(text, code, message, jsonPointer = "", offset = 0, length = 1) {
|
|
100
|
-
const start = Math.min(offset, text.length);
|
|
101
|
-
const size = Math.min(Math.max(1, length), text.length - start);
|
|
102
|
-
return {
|
|
103
|
-
code,
|
|
104
|
-
message,
|
|
105
|
-
pointer: jsonPointer,
|
|
106
|
-
offset: start,
|
|
107
|
-
length: size,
|
|
108
|
-
range: {
|
|
109
|
-
start: positionAt(text, start),
|
|
110
|
-
end: positionAt(text, start + size)
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
function parseDocument(text, mode) {
|
|
115
|
-
const errors = [];
|
|
116
|
-
const root = parseTree(text, errors, {
|
|
117
|
-
disallowComments: mode === "json",
|
|
118
|
-
allowTrailingComma: mode === "jsonc",
|
|
119
|
-
allowEmptyContent: false
|
|
120
|
-
});
|
|
121
|
-
const diagnostics = errors.map((e) => diagnostic(text, "syntax", printParseErrorCode(e.error), "", e.offset, e.length));
|
|
122
|
-
function visit(node) {
|
|
123
|
-
if (node.type === "object") {
|
|
124
|
-
const keys = /* @__PURE__ */ new Set();
|
|
125
|
-
for (const property of node.children ?? []) {
|
|
126
|
-
const key = property.children?.[0];
|
|
127
|
-
if (!key || typeof key.value !== "string") continue;
|
|
128
|
-
if (keys.has(key.value)) diagnostics.push(diagnostic(text, "duplicate-key", `Duplicate key ${JSON.stringify(key.value)}`, pointer([...getNodePath(node), key.value]), key.offset, key.length));
|
|
129
|
-
keys.add(key.value);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
if (node.type === "number" && !Number.isFinite(node.value)) diagnostics.push(diagnostic(text, "syntax", "Number exceeds the supported finite range", pointer(getNodePath(node)), node.offset, node.length));
|
|
133
|
-
for (const child of node.children ?? []) visit(child);
|
|
134
|
-
}
|
|
135
|
-
if (root) visit(root);
|
|
136
|
-
function value(node) {
|
|
137
|
-
if (node.type === "object") return Object.fromEntries((node.children ?? []).flatMap((property) => {
|
|
138
|
-
const key = property.children?.[0];
|
|
139
|
-
const child = property.children?.[1];
|
|
140
|
-
return key && child ? [[String(key.value), value(child)]] : [];
|
|
141
|
-
}));
|
|
142
|
-
if (node.type === "array") return (node.children ?? []).map(value);
|
|
143
|
-
return getNodeValue(node);
|
|
144
|
-
}
|
|
145
|
-
return {
|
|
146
|
-
root,
|
|
147
|
-
value: root ? value(root) : void 0,
|
|
148
|
-
diagnostics,
|
|
149
|
-
locate: (jsonPointer, key = false) => {
|
|
150
|
-
const node = locate(root, jsonPointer, key);
|
|
151
|
-
return node ? {
|
|
152
|
-
offset: node.offset,
|
|
153
|
-
length: node.length
|
|
154
|
-
} : void 0;
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
function locate(root, jsonPointer, key = false) {
|
|
159
|
-
if (!root) return void 0;
|
|
160
|
-
const parts = jsonPointer === "" ? [] : jsonPointer.slice(1).split("/").map((p) => p.replace(/~1/g, "/").replace(/~0/g, "~"));
|
|
161
|
-
let current = root;
|
|
162
|
-
for (const part of parts) {
|
|
163
|
-
const next = findNodeAtLocation(current, [current.type === "array" ? Number(part) : part]);
|
|
164
|
-
if (!next) break;
|
|
165
|
-
current = next;
|
|
166
|
-
}
|
|
167
|
-
return key && current.parent?.type === "property" ? current.parent.children?.[0] ?? current : current;
|
|
168
|
-
}
|
|
169
|
-
//#endregion
|
|
170
|
-
//#region src/core/types.ts
|
|
171
|
-
var CorrectlyError = class extends Error {
|
|
172
|
-
code;
|
|
173
|
-
constructor(code, message) {
|
|
174
|
-
super(message);
|
|
175
|
-
this.name = "CorrectlyError";
|
|
176
|
-
this.code = code;
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
function failure(error, file) {
|
|
180
|
-
return {
|
|
181
|
-
code: error instanceof CorrectlyError ? error.code : "execution",
|
|
182
|
-
message: error instanceof Error ? error.message : String(error),
|
|
183
|
-
...file === void 0 ? {} : { file }
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
//#endregion
|
|
187
|
-
//#region src/core/config.ts
|
|
188
|
-
const CONFIG_NAME = "correctly.config.json";
|
|
189
|
-
const DEFAULT_EXCLUDES = [
|
|
190
|
-
"**/node_modules/**",
|
|
191
|
-
"**/.git/**",
|
|
192
|
-
"**/dist/**",
|
|
193
|
-
"**/artifacts/**",
|
|
194
|
-
"**/.correctly-cache/**"
|
|
195
|
-
];
|
|
196
|
-
const readText = (uri) => readFile(fileURLToPath(uri), "utf8");
|
|
197
|
-
const validateConfig = new Ajv({
|
|
198
|
-
allErrors: true,
|
|
199
|
-
strict: true
|
|
200
|
-
}).compile(config_schema_default);
|
|
201
|
-
function contains(root, file) {
|
|
202
|
-
const relative = path.relative(root, file);
|
|
203
|
-
return relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
|
204
|
-
}
|
|
205
|
-
async function discoverConfig(start, boundary, virtualFiles = /* @__PURE__ */ new Set()) {
|
|
206
|
-
let directory = path.resolve(start);
|
|
207
|
-
if (boundary && !contains(boundary, directory)) throw new CorrectlyError("config", `Path is outside workspace ${boundary}`);
|
|
208
|
-
while (true) {
|
|
209
|
-
const candidate = path.join(directory, CONFIG_NAME);
|
|
210
|
-
if (virtualFiles.has(candidate)) return candidate;
|
|
211
|
-
try {
|
|
212
|
-
if ((await stat(candidate)).isFile()) return candidate;
|
|
213
|
-
} catch (error) {
|
|
214
|
-
if (error.code !== "ENOENT") throw error;
|
|
215
|
-
}
|
|
216
|
-
const parent = path.dirname(directory);
|
|
217
|
-
if (directory === boundary || parent === directory) break;
|
|
218
|
-
directory = parent;
|
|
219
|
-
}
|
|
220
|
-
throw new CorrectlyError("config", `No ${CONFIG_NAME} found from ${start}${boundary ? ` within ${boundary}` : ""}`);
|
|
221
|
-
}
|
|
222
|
-
async function loadProject(configPath, read = readText) {
|
|
223
|
-
const resolved = path.resolve(configPath);
|
|
224
|
-
let text;
|
|
225
|
-
try {
|
|
226
|
-
text = await read(pathToFileURL(resolved).href);
|
|
227
|
-
} catch (error) {
|
|
228
|
-
throw new CorrectlyError("config", `Cannot read configuration ${resolved}: ${String(error)}`);
|
|
229
|
-
}
|
|
230
|
-
const parsed = parseDocument(text, "json");
|
|
231
|
-
if (parsed.diagnostics.length) {
|
|
232
|
-
const d = parsed.diagnostics[0];
|
|
233
|
-
throw new CorrectlyError("config", `${resolved}:${d.range.start.line + 1}:${d.range.start.character + 1}: ${d.message}`);
|
|
234
|
-
}
|
|
235
|
-
if (!validateConfig(parsed.value)) throw new CorrectlyError("config", `${resolved}: ${validateConfig.errors?.map((e) => `${e.instancePath || "/"} ${e.message}`).join("; ")}`);
|
|
236
|
-
const config = parsed.value;
|
|
237
|
-
for (const pattern of [
|
|
238
|
-
...config.files ?? [],
|
|
239
|
-
...config.exclude ?? [],
|
|
240
|
-
...config.associations.flatMap((a) => a.files)
|
|
241
|
-
]) if (pattern.includes("\\")) throw new CorrectlyError("config", `Use forward slashes in patterns: ${pattern}`);
|
|
242
|
-
return {
|
|
243
|
-
configPath: resolved,
|
|
244
|
-
root: path.dirname(resolved),
|
|
245
|
-
config
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
function schemaUri(value, root) {
|
|
249
|
-
if (/^[A-Za-z][A-Za-z\d+.-]*:/.test(value) && !/^[A-Za-z]:[\\/]/.test(value)) {
|
|
250
|
-
const uri = new URL(value);
|
|
251
|
-
if (![
|
|
252
|
-
"file:",
|
|
253
|
-
"http:",
|
|
254
|
-
"https:"
|
|
255
|
-
].includes(uri.protocol)) throw new CorrectlyError("schema", `Unsupported schema protocol: ${uri.protocol}`);
|
|
256
|
-
return uri.href;
|
|
257
|
-
}
|
|
258
|
-
const hash = value.indexOf("#");
|
|
259
|
-
const filename = hash === -1 ? value : value.slice(0, hash);
|
|
260
|
-
const uri = pathToFileURL(path.resolve(root, filename));
|
|
261
|
-
if (hash !== -1) uri.hash = value.slice(hash + 1);
|
|
262
|
-
return uri.href;
|
|
263
|
-
}
|
|
264
|
-
function exclusions(project) {
|
|
265
|
-
const cachePath = path.resolve(project.root, project.config.remote?.cacheDir ?? ".correctly-cache");
|
|
266
|
-
const relative = path.relative(project.root, cachePath).split(path.sep).join("/");
|
|
267
|
-
return [
|
|
268
|
-
...DEFAULT_EXCLUDES,
|
|
269
|
-
...project.config.exclude ?? [],
|
|
270
|
-
...relative && contains(project.root, cachePath) ? [`${relative}/**`] : []
|
|
271
|
-
];
|
|
272
|
-
}
|
|
273
|
-
function isIncluded(project, file) {
|
|
274
|
-
if (!contains(project.root, file)) return false;
|
|
275
|
-
const relative = path.relative(project.root, file).split(path.sep).join("/");
|
|
276
|
-
const options = { dot: true };
|
|
277
|
-
return picomatch(project.config.files ?? ["**/*.json", "**/*.jsonc"], options)(relative) && !picomatch(exclusions(project), options)(relative);
|
|
278
|
-
}
|
|
279
|
-
function associationFor(project, file) {
|
|
280
|
-
const relative = path.relative(project.root, file).split(path.sep).join("/");
|
|
281
|
-
for (let index = project.config.associations.length - 1; index >= 0; index--) {
|
|
282
|
-
const rule = project.config.associations[index];
|
|
283
|
-
if (picomatch(rule.files, { dot: true })(relative)) return {
|
|
284
|
-
index,
|
|
285
|
-
name: rule.name ?? `association ${index + 1}`,
|
|
286
|
-
schema: rule.schema === null ? null : schemaUri(rule.schema, project.root),
|
|
287
|
-
mode: rule.mode ?? modeFor(file)
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
return null;
|
|
291
|
-
}
|
|
292
|
-
function modeFor(file) {
|
|
293
|
-
return path.extname(file).toLowerCase() === ".jsonc" ? "jsonc" : "json";
|
|
294
|
-
}
|
|
295
|
-
//#endregion
|
|
296
|
-
//#region src/core/schemas.ts
|
|
297
|
-
const DIALECTS = {
|
|
298
|
-
draft7: "http://json-schema.org/draft-07/schema#",
|
|
299
|
-
"2020-12": "https://json-schema.org/draft/2020-12/schema"
|
|
300
|
-
};
|
|
301
|
-
const VOCABULARIES = new Set([
|
|
302
|
-
"core",
|
|
303
|
-
"applicator",
|
|
304
|
-
"unevaluated",
|
|
305
|
-
"validation",
|
|
306
|
-
"meta-data",
|
|
307
|
-
"format-annotation",
|
|
308
|
-
"content"
|
|
309
|
-
].map((name) => `https://json-schema.org/draft/2020-12/vocab/${name}`));
|
|
310
|
-
const SINGLE_SCHEMAS = [
|
|
311
|
-
"additionalItems",
|
|
312
|
-
"additionalProperties",
|
|
313
|
-
"contains",
|
|
314
|
-
"propertyNames",
|
|
315
|
-
"not",
|
|
316
|
-
"if",
|
|
317
|
-
"then",
|
|
318
|
-
"else",
|
|
319
|
-
"unevaluatedProperties",
|
|
320
|
-
"unevaluatedItems",
|
|
321
|
-
"contentSchema"
|
|
322
|
-
];
|
|
323
|
-
const MAP_SCHEMAS = [
|
|
324
|
-
"properties",
|
|
325
|
-
"patternProperties",
|
|
326
|
-
"definitions",
|
|
327
|
-
"$defs",
|
|
328
|
-
"dependentSchemas",
|
|
329
|
-
"dependencies"
|
|
330
|
-
];
|
|
331
|
-
const ARRAY_SCHEMAS = [
|
|
332
|
-
"allOf",
|
|
333
|
-
"anyOf",
|
|
334
|
-
"oneOf",
|
|
335
|
-
"prefixItems"
|
|
336
|
-
];
|
|
337
|
-
function isObject(value) {
|
|
338
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
339
|
-
}
|
|
340
|
-
function dialect(value, inherited) {
|
|
341
|
-
if (value === void 0) return inherited;
|
|
342
|
-
if (typeof value !== "string") throw new CorrectlyError("schema", "Schema $schema must be a string");
|
|
343
|
-
const id = value.replace(/#$/, "");
|
|
344
|
-
if (id === "http://json-schema.org/draft-07/schema" || id === "https://json-schema.org/draft-07/schema") return "draft7";
|
|
345
|
-
if (id === DIALECTS["2020-12"]) return "2020-12";
|
|
346
|
-
throw new CorrectlyError("unsupported-dialect", `Unsupported schema dialect: ${value}; supported: draft 7, draft 2020-12`);
|
|
347
|
-
}
|
|
348
|
-
var SchemaStore = class {
|
|
349
|
-
options;
|
|
350
|
-
resources = /* @__PURE__ */ new Map();
|
|
351
|
-
pending = /* @__PURE__ */ new Map();
|
|
352
|
-
cacheDir;
|
|
353
|
-
offline;
|
|
354
|
-
timeoutMs;
|
|
355
|
-
maxBytes;
|
|
356
|
-
maxRequests;
|
|
357
|
-
read;
|
|
358
|
-
request;
|
|
359
|
-
requests = 0;
|
|
360
|
-
constructor(project, options = {}) {
|
|
361
|
-
this.options = options;
|
|
362
|
-
const remote = project.config.remote;
|
|
363
|
-
this.cacheDir = path.resolve(project.root, remote?.cacheDir ?? ".correctly-cache");
|
|
364
|
-
this.offline = options.offline ?? remote?.offline ?? false;
|
|
365
|
-
this.timeoutMs = remote?.timeoutMs ?? 5e3;
|
|
366
|
-
this.maxBytes = remote?.maxBytes ?? 2097152;
|
|
367
|
-
this.maxRequests = remote?.maxRequests ?? 64;
|
|
368
|
-
this.read = options.read ?? readText;
|
|
369
|
-
this.request = options.fetch ?? fetch;
|
|
370
|
-
}
|
|
371
|
-
async load(value, inherited = "draft7") {
|
|
372
|
-
this.options.signal?.throwIfAborted();
|
|
373
|
-
const url = new URL(value);
|
|
374
|
-
url.hash = "";
|
|
375
|
-
const uri = url.href;
|
|
376
|
-
const known = this.resources.get(uri);
|
|
377
|
-
if (known) return known;
|
|
378
|
-
let promise = this.pending.get(uri);
|
|
379
|
-
if (!promise) {
|
|
380
|
-
promise = this.loadResource(uri, inherited);
|
|
381
|
-
this.pending.set(uri, promise);
|
|
382
|
-
}
|
|
383
|
-
return promise;
|
|
384
|
-
}
|
|
385
|
-
async loadResource(uri, inherited) {
|
|
386
|
-
if (++this.requests > this.maxRequests) throw new CorrectlyError("schema-limit", `Schema resource limit (${this.maxRequests}) exceeded`);
|
|
387
|
-
let text;
|
|
388
|
-
const url = new URL(uri);
|
|
389
|
-
try {
|
|
390
|
-
if (url.protocol === "file:") text = await this.read(uri);
|
|
391
|
-
else if (url.protocol === "https:" || url.protocol === "http:") text = await this.remote(uri);
|
|
392
|
-
else throw new CorrectlyError("schema", `Unsupported schema protocol: ${url.protocol}`);
|
|
393
|
-
} catch (error) {
|
|
394
|
-
if (error instanceof CorrectlyError) throw error;
|
|
395
|
-
throw new CorrectlyError("schema-load", `Cannot load schema ${uri}: ${error instanceof Error ? error.message : String(error)}`);
|
|
396
|
-
}
|
|
397
|
-
this.options.signal?.throwIfAborted();
|
|
398
|
-
if (Buffer.byteLength(text) > this.maxBytes) throw new CorrectlyError("schema-limit", `Schema ${uri} exceeds ${this.maxBytes} bytes`);
|
|
399
|
-
const parsed = parseDocument(text, "json");
|
|
400
|
-
if (parsed.diagnostics.length) {
|
|
401
|
-
const d = parsed.diagnostics[0];
|
|
402
|
-
throw new CorrectlyError("schema", `Invalid schema JSON at ${uri}:${d.range.start.line + 1}:${d.range.start.character + 1}: ${d.message}`);
|
|
403
|
-
}
|
|
404
|
-
if (typeof parsed.value !== "boolean" && !isObject(parsed.value)) throw new CorrectlyError("schema", `Schema must be an object or boolean: ${uri}`);
|
|
405
|
-
const rootDialect = dialect(isObject(parsed.value) ? parsed.value.$schema : void 0, inherited);
|
|
406
|
-
const schema = parsed.value;
|
|
407
|
-
const resource = {
|
|
408
|
-
uri,
|
|
409
|
-
schema,
|
|
410
|
-
dialect: rootDialect
|
|
411
|
-
};
|
|
412
|
-
this.normalize(schema, uri, rootDialect, resource);
|
|
413
|
-
if (isObject(schema) && schema.$id === void 0) schema.$id = uri;
|
|
414
|
-
this.register(uri, resource);
|
|
415
|
-
return resource;
|
|
416
|
-
}
|
|
417
|
-
register(uri, resource) {
|
|
418
|
-
const previous = this.resources.get(uri);
|
|
419
|
-
if (previous && previous.schema !== resource.schema) throw new CorrectlyError("schema", `Duplicate schema identifier: ${uri}`);
|
|
420
|
-
this.resources.set(uri, resource);
|
|
421
|
-
}
|
|
422
|
-
normalize(schema, base, expected, root) {
|
|
423
|
-
if (!isObject(schema)) return;
|
|
424
|
-
const ownDialect = dialect(schema.$schema, expected);
|
|
425
|
-
if (ownDialect !== expected) throw new CorrectlyError("unsupported-dialect", `Mixed schema dialects at ${base} are not supported`);
|
|
426
|
-
if (schema.$schema !== void 0) schema.$schema = DIALECTS[ownDialect];
|
|
427
|
-
if (schema.$async !== void 0) throw new CorrectlyError("schema", `Asynchronous data validation is not supported: ${base}`);
|
|
428
|
-
if (schema.$vocabulary !== void 0) {
|
|
429
|
-
if (!isObject(schema.$vocabulary)) throw new CorrectlyError("schema", `$vocabulary must be an object: ${base}`);
|
|
430
|
-
for (const [vocabulary, required] of Object.entries(schema.$vocabulary)) {
|
|
431
|
-
if (typeof required !== "boolean") throw new CorrectlyError("schema", `$vocabulary values must be boolean: ${base}`);
|
|
432
|
-
if (required && !VOCABULARIES.has(vocabulary)) throw new CorrectlyError("unsupported-vocabulary", `Unsupported required vocabulary: ${vocabulary}`);
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
let scope = base;
|
|
436
|
-
if (schema.$id !== void 0) {
|
|
437
|
-
if (typeof schema.$id !== "string") throw new CorrectlyError("schema", `$id must be a string: ${base}`);
|
|
438
|
-
scope = new URL(schema.$id, base).href;
|
|
439
|
-
schema.$id = scope;
|
|
440
|
-
this.register(scope.replace(/#$/, ""), {
|
|
441
|
-
...root,
|
|
442
|
-
schema
|
|
443
|
-
});
|
|
444
|
-
}
|
|
445
|
-
for (const anchor of [schema.$anchor, schema.$dynamicAnchor]) if (typeof anchor === "string") this.register(new URL(`#${anchor}`, scope).href, {
|
|
446
|
-
...root,
|
|
447
|
-
schema
|
|
448
|
-
});
|
|
449
|
-
for (const key of SINGLE_SCHEMAS) this.normalize(schema[key], scope, expected, root);
|
|
450
|
-
for (const key of MAP_SCHEMAS) if (isObject(schema[key])) for (const child of Object.values(schema[key])) this.normalize(child, scope, expected, root);
|
|
451
|
-
for (const key of [...ARRAY_SCHEMAS, "items"]) {
|
|
452
|
-
const children = schema[key];
|
|
453
|
-
if (Array.isArray(children)) for (const child of children) this.normalize(child, scope, expected, root);
|
|
454
|
-
else if (key === "items") this.normalize(children, scope, expected, root);
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
async remote(uri) {
|
|
458
|
-
const cacheFile = path.join(this.cacheDir, `${createHash("sha256").update(uri).digest("hex")}.json`);
|
|
459
|
-
let cached;
|
|
460
|
-
try {
|
|
461
|
-
const raw = await readFile(cacheFile, "utf8");
|
|
462
|
-
const entry = JSON.parse(raw);
|
|
463
|
-
if (!isObject(entry) || entry.uri !== uri || typeof entry.text !== "string") throw new Error("invalid cache entry");
|
|
464
|
-
cached = entry;
|
|
465
|
-
} catch (error) {
|
|
466
|
-
if (error.code !== "ENOENT") throw new CorrectlyError("schema-cache", `Cannot read schema cache ${cacheFile}: ${String(error)}`);
|
|
467
|
-
}
|
|
468
|
-
if (this.offline) {
|
|
469
|
-
if (!cached) throw new CorrectlyError("offline-miss", `Schema is not cached in offline mode: ${uri}`);
|
|
470
|
-
return cached.text;
|
|
471
|
-
}
|
|
472
|
-
const timeout = AbortSignal.timeout(this.timeoutMs);
|
|
473
|
-
const signal = this.options.signal ? AbortSignal.any([this.options.signal, timeout]) : timeout;
|
|
474
|
-
const headers = {};
|
|
475
|
-
if (cached?.etag) headers["If-None-Match"] = cached.etag;
|
|
476
|
-
if (cached?.lastModified) headers["If-Modified-Since"] = cached.lastModified;
|
|
477
|
-
let current = uri;
|
|
478
|
-
for (let redirects = 0; redirects <= 5; redirects++) {
|
|
479
|
-
const response = await this.request(current, {
|
|
480
|
-
signal,
|
|
481
|
-
headers,
|
|
482
|
-
redirect: "manual"
|
|
483
|
-
});
|
|
484
|
-
if ([
|
|
485
|
-
301,
|
|
486
|
-
302,
|
|
487
|
-
303,
|
|
488
|
-
307,
|
|
489
|
-
308
|
|
490
|
-
].includes(response.status)) {
|
|
491
|
-
await response.body?.cancel();
|
|
492
|
-
const location = response.headers.get("location");
|
|
493
|
-
if (!location) throw new CorrectlyError("schema-load", `Redirect without location: ${current}`);
|
|
494
|
-
current = new URL(location, current).href;
|
|
495
|
-
if (!["http:", "https:"].includes(new URL(current).protocol)) throw new CorrectlyError("schema-load", `Unsupported redirect: ${current}`);
|
|
496
|
-
continue;
|
|
497
|
-
}
|
|
498
|
-
if (response.status === 304 && cached) {
|
|
499
|
-
await response.body?.cancel();
|
|
500
|
-
return cached.text;
|
|
501
|
-
}
|
|
502
|
-
if (!response.ok || !response.body) {
|
|
503
|
-
await response.body?.cancel();
|
|
504
|
-
throw new CorrectlyError("schema-load", `HTTP ${response.status} loading schema ${uri}`);
|
|
505
|
-
}
|
|
506
|
-
const reader = response.body.getReader();
|
|
507
|
-
const chunks = [];
|
|
508
|
-
let size = 0;
|
|
509
|
-
try {
|
|
510
|
-
while (true) {
|
|
511
|
-
const { value, done } = await reader.read();
|
|
512
|
-
if (done) break;
|
|
513
|
-
size += value.byteLength;
|
|
514
|
-
if (size > this.maxBytes) throw new CorrectlyError("schema-limit", `Schema ${uri} exceeds ${this.maxBytes} bytes`);
|
|
515
|
-
chunks.push(value);
|
|
516
|
-
}
|
|
517
|
-
} finally {
|
|
518
|
-
await reader.cancel();
|
|
519
|
-
}
|
|
520
|
-
const text = Buffer.concat(chunks).toString("utf8");
|
|
521
|
-
const entry = {
|
|
522
|
-
uri,
|
|
523
|
-
text
|
|
524
|
-
};
|
|
525
|
-
const etag = response.headers.get("etag");
|
|
526
|
-
const lastModified = response.headers.get("last-modified");
|
|
527
|
-
if (etag) entry.etag = etag;
|
|
528
|
-
if (lastModified) entry.lastModified = lastModified;
|
|
529
|
-
signal.throwIfAborted();
|
|
530
|
-
await mkdir(this.cacheDir, { recursive: true });
|
|
531
|
-
const temporary = `${cacheFile}.${randomUUID()}.tmp`;
|
|
532
|
-
await writeFile(temporary, JSON.stringify(entry));
|
|
533
|
-
await rename(temporary, cacheFile);
|
|
534
|
-
return text;
|
|
535
|
-
}
|
|
536
|
-
throw new CorrectlyError("schema-limit", `Too many redirects loading schema ${uri}`);
|
|
537
|
-
}
|
|
538
|
-
};
|
|
539
|
-
function localSchemaPath(uri) {
|
|
540
|
-
const url = new URL(uri);
|
|
541
|
-
return url.protocol === "file:" ? fileURLToPath(url) : void 0;
|
|
542
|
-
}
|
|
543
|
-
//#endregion
|
|
544
|
-
//#region src/core/diagnostics.ts
|
|
545
|
-
function validationContexts(errors, diagnostics) {
|
|
546
|
-
const summaries = errors.flatMap((error, index) => {
|
|
547
|
-
if (error.keyword === "anyOf" || error.keyword === "oneOf") return [{
|
|
548
|
-
index,
|
|
549
|
-
error,
|
|
550
|
-
prefix: `${error.schemaPath}/`,
|
|
551
|
-
alternative: true
|
|
552
|
-
}];
|
|
553
|
-
if (error.keyword === "if" && ["then", "else"].includes(error.params.failingKeyword)) return [{
|
|
554
|
-
index,
|
|
555
|
-
error,
|
|
556
|
-
prefix: `${error.schemaPath.slice(0, -3)}/${error.params.failingKeyword}`,
|
|
557
|
-
alternative: false
|
|
558
|
-
}];
|
|
559
|
-
return [];
|
|
560
|
-
});
|
|
561
|
-
return diagnostics.map((diagnostic, index) => {
|
|
562
|
-
const error = errors[index];
|
|
563
|
-
const parent = summaries.filter((parent) => parent.index > index && (error.instancePath === parent.error.instancePath || error.instancePath.startsWith(`${parent.error.instancePath}/`)) && (parent.error.propertyName === void 0 || error.propertyName === parent.error.propertyName) && (parent.alternative ? error.schemaPath.startsWith(parent.prefix) : error.schemaPath === parent.prefix || error.schemaPath.startsWith(`${parent.prefix}/`))).toSorted((a, b) => b.prefix.length - a.prefix.length || a.index - b.index)[0];
|
|
564
|
-
if (!parent) return diagnostic;
|
|
565
|
-
const branch = parent.alternative ? error.schemaPath.slice(parent.prefix.length).split("/")[0] : parent.error.params.failingKeyword;
|
|
566
|
-
if (parent.alternative && !/^\d+$/.test(branch)) return diagnostic;
|
|
567
|
-
return {
|
|
568
|
-
...diagnostic,
|
|
569
|
-
context: {
|
|
570
|
-
parent: parent.index,
|
|
571
|
-
label: parent.alternative ? `Alternative ${Number(branch) + 1}` : branch === "then" ? "Then branch" : "Else branch"
|
|
572
|
-
}
|
|
573
|
-
};
|
|
574
|
-
});
|
|
575
|
-
}
|
|
576
|
-
function diagnosticViews(diagnostics) {
|
|
577
|
-
const views = diagnostics.map((diagnostic) => ({
|
|
578
|
-
...diagnostic,
|
|
579
|
-
branches: []
|
|
580
|
-
}));
|
|
581
|
-
const roots = [];
|
|
582
|
-
for (const [index, view] of views.entries()) {
|
|
583
|
-
const context = view.context;
|
|
584
|
-
const parent = context && Number.isInteger(context.parent) && context.parent > index ? views[context.parent] : void 0;
|
|
585
|
-
if (!parent) {
|
|
586
|
-
roots.push(view);
|
|
587
|
-
continue;
|
|
588
|
-
}
|
|
589
|
-
let branch = parent.branches.find((branch) => branch.label === context.label);
|
|
590
|
-
if (!branch) {
|
|
591
|
-
branch = {
|
|
592
|
-
label: context.label,
|
|
593
|
-
diagnostics: []
|
|
594
|
-
};
|
|
595
|
-
parent.branches.push(branch);
|
|
596
|
-
}
|
|
597
|
-
branch.diagnostics.push(view);
|
|
598
|
-
}
|
|
599
|
-
return roots;
|
|
600
|
-
}
|
|
601
|
-
function diagnosticDetails(view) {
|
|
602
|
-
return view.branches.flatMap((branch) => branch.diagnostics.flatMap((child) => [{
|
|
603
|
-
label: branch.label,
|
|
604
|
-
diagnostic: child
|
|
605
|
-
}, ...diagnosticDetails(child).map((detail) => ({
|
|
606
|
-
...detail,
|
|
607
|
-
label: `${branch.label} / ${detail.label}`
|
|
608
|
-
}))]));
|
|
609
|
-
}
|
|
610
|
-
//#endregion
|
|
611
|
-
//#region src/core/engine.ts
|
|
612
|
-
const ANNOTATIONS = [
|
|
613
|
-
"markdownDescription",
|
|
614
|
-
"enumDescriptions",
|
|
615
|
-
"markdownEnumDescriptions",
|
|
616
|
-
"defaultSnippets",
|
|
617
|
-
"errorMessage",
|
|
618
|
-
"patternErrorMessage",
|
|
619
|
-
"deprecationMessage",
|
|
620
|
-
"suggestSortText",
|
|
621
|
-
"doNotSuggest",
|
|
622
|
-
"allowComments",
|
|
623
|
-
"allowTrailingCommas",
|
|
624
|
-
"deprecated",
|
|
625
|
-
"$vocabulary"
|
|
626
|
-
];
|
|
627
|
-
function registerRootAnchors(ajv, schema, uri) {
|
|
628
|
-
if (typeof schema !== "object" || schema === null) return;
|
|
629
|
-
const object = schema;
|
|
630
|
-
for (const anchor of [object.$anchor, object.$dynamicAnchor]) if (typeof anchor === "string") ajv.refs[new URL(`#${anchor}`, object.$id ?? uri).href] = object.$id ?? uri;
|
|
631
|
-
}
|
|
632
|
-
function validationMessage(error) {
|
|
633
|
-
if (error.keyword === "anyOf") return "must match at least one alternative; none matched";
|
|
634
|
-
if (error.keyword === "if" && ["then", "else"].includes(error.params.failingKeyword)) return `must satisfy the ${error.params.failingKeyword} branch of the conditional schema`;
|
|
635
|
-
if (error.keyword === "uniqueItems") {
|
|
636
|
-
const { i, j } = error.params;
|
|
637
|
-
if (Number.isInteger(i) && Number.isInteger(j)) return `duplicates item at ${error.instancePath}${pointer([Math.min(i, j)])}; array items must be unique`;
|
|
638
|
-
}
|
|
639
|
-
if (error.keyword === "enum" && Array.isArray(error.params.allowedValues)) return `must be one of: ${error.params.allowedValues.map((value) => JSON.stringify(value)).join(", ")}`;
|
|
640
|
-
if (error.keyword === "const" && Object.hasOwn(error.params, "allowedValue")) return `must equal ${JSON.stringify(error.params.allowedValue)}`;
|
|
641
|
-
if (error.keyword === "oneOf") {
|
|
642
|
-
if (error.params.passingSchemas === null) return "must match exactly one alternative; none matched";
|
|
643
|
-
if (Array.isArray(error.params.passingSchemas)) return `must match exactly one alternative; multiple matched (alternatives ${error.params.passingSchemas.map((index) => index + 1).join(", ")})`;
|
|
644
|
-
}
|
|
645
|
-
return error.message ?? "Schema violation";
|
|
646
|
-
}
|
|
647
|
-
function validationDiagnostic(text, parsed, error) {
|
|
648
|
-
let jsonPointer = error.instancePath;
|
|
649
|
-
if (error.keyword === "uniqueItems" && Number.isInteger(error.params.i) && Number.isInteger(error.params.j)) jsonPointer += pointer([Math.max(error.params.i, error.params.j)]);
|
|
650
|
-
const property = error.params.additionalProperty ?? error.params.unevaluatedProperty ?? error.params.missingProperty ?? error.params.propertyName ?? error.propertyName;
|
|
651
|
-
if (typeof property === "string") jsonPointer += pointer([property]);
|
|
652
|
-
const node = parsed.locate(jsonPointer, error.keyword === "additionalProperties" || error.keyword === "unevaluatedProperties" || error.keyword === "propertyNames" || typeof error.propertyName === "string");
|
|
653
|
-
const rangeNode = error.keyword === "required" && error.propertyName === void 0 ? parsed.locate(error.instancePath) : node;
|
|
654
|
-
const length = error.keyword === "required" && error.propertyName === void 0 ? 1 : rangeNode?.length;
|
|
655
|
-
return diagnostic(text, `schema/${error.keyword}`, `${jsonPointer || "/"}: ${validationMessage(error)}`, jsonPointer, rangeNode?.offset ?? 0, length ?? 1);
|
|
656
|
-
}
|
|
657
|
-
var Engine = class {
|
|
658
|
-
project;
|
|
659
|
-
store;
|
|
660
|
-
compiled = /* @__PURE__ */ new Map();
|
|
661
|
-
constructor(project, options = {}) {
|
|
662
|
-
this.project = project;
|
|
663
|
-
this.store = new SchemaStore(project, options);
|
|
664
|
-
}
|
|
665
|
-
validator(uri) {
|
|
666
|
-
let compiled = this.compiled.get(uri);
|
|
667
|
-
if (!compiled) {
|
|
668
|
-
compiled = this.compile(uri);
|
|
669
|
-
this.compiled.set(uri, compiled);
|
|
670
|
-
}
|
|
671
|
-
return compiled;
|
|
672
|
-
}
|
|
673
|
-
async compile(uri) {
|
|
674
|
-
try {
|
|
675
|
-
const resource = await this.store.load(uri);
|
|
676
|
-
const options = {
|
|
677
|
-
allErrors: true,
|
|
678
|
-
strictSchema: true,
|
|
679
|
-
strictTypes: false,
|
|
680
|
-
strictTuples: false,
|
|
681
|
-
strictRequired: false,
|
|
682
|
-
coerceTypes: false,
|
|
683
|
-
useDefaults: false,
|
|
684
|
-
removeAdditional: false,
|
|
685
|
-
validateSchema: true,
|
|
686
|
-
loadSchema: async (ref) => {
|
|
687
|
-
const loaded = await this.store.load(ref, resource.dialect);
|
|
688
|
-
if (loaded.dialect !== resource.dialect) throw new CorrectlyError("unsupported-dialect", `Mixed schema dialects: ${uri} references ${ref}`);
|
|
689
|
-
registerRootAnchors(ajv, loaded.schema, loaded.uri);
|
|
690
|
-
return loaded.schema;
|
|
691
|
-
}
|
|
692
|
-
};
|
|
693
|
-
const ajv = resource.dialect === "2020-12" ? new Ajv2020(options) : new Ajv(options);
|
|
694
|
-
addFormats(ajv);
|
|
695
|
-
for (const keyword of ANNOTATIONS) if (!ajv.RULES.keywords[keyword]) ajv.addKeyword({
|
|
696
|
-
keyword,
|
|
697
|
-
valid: true
|
|
698
|
-
});
|
|
699
|
-
if (resource.dialect === "2020-12") ajv.addKeyword({
|
|
700
|
-
keyword: "$anchor",
|
|
701
|
-
schemaType: "string",
|
|
702
|
-
valid: true
|
|
703
|
-
});
|
|
704
|
-
ajv.addSchema(resource.schema, resource.uri);
|
|
705
|
-
registerRootAnchors(ajv, resource.schema, resource.uri);
|
|
706
|
-
return await ajv.compileAsync({
|
|
707
|
-
$schema: DIALECTS[resource.dialect],
|
|
708
|
-
$ref: uri
|
|
709
|
-
});
|
|
710
|
-
} catch (error) {
|
|
711
|
-
if (error instanceof CorrectlyError) throw error;
|
|
712
|
-
throw new CorrectlyError("schema", `Cannot compile schema ${uri}: ${error instanceof Error ? error.message : String(error)}`);
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
async prepare() {
|
|
716
|
-
for (const association of this.project.config.associations) if (association.schema !== null) await this.store.load(schemaUri(association.schema, this.project.root));
|
|
717
|
-
for (const association of this.project.config.associations) if (association.schema !== null) await this.validator(schemaUri(association.schema, this.project.root));
|
|
718
|
-
}
|
|
719
|
-
async validate(file, text) {
|
|
720
|
-
const association = associationFor(this.project, file);
|
|
721
|
-
const mode = association?.mode ?? modeFor(file);
|
|
722
|
-
const result = {
|
|
723
|
-
file,
|
|
724
|
-
mode,
|
|
725
|
-
association,
|
|
726
|
-
coverage: "excluded",
|
|
727
|
-
diagnostics: [],
|
|
728
|
-
failures: []
|
|
729
|
-
};
|
|
730
|
-
if (!isIncluded(this.project, file)) return result;
|
|
731
|
-
result.coverage = association?.schema ? "schema" : "syntax-only";
|
|
732
|
-
const parsed = parseDocument(text, mode);
|
|
733
|
-
result.diagnostics.push(...parsed.diagnostics);
|
|
734
|
-
if (association?.schema) try {
|
|
735
|
-
const validate = await this.validator(association.schema);
|
|
736
|
-
if (parsed.diagnostics.length === 0 && !validate(parsed.value)) result.diagnostics.push(...validationContexts(validate.errors ?? [], (validate.errors ?? []).map((e) => validationDiagnostic(text, parsed, e))));
|
|
737
|
-
} catch (error) {
|
|
738
|
-
result.failures.push(failure(error, file));
|
|
739
|
-
}
|
|
740
|
-
return result;
|
|
741
|
-
}
|
|
742
|
-
};
|
|
743
|
-
//#endregion
|
|
744
|
-
export { pointer as C, parseDocument as S, schemaUri as _, SchemaStore as a, diagnostic as b, DEFAULT_EXCLUDES as c, discoverConfig as d, exclusions as f, readText as g, modeFor as h, DIALECTS as i, associationFor as l, loadProject as m, diagnosticDetails as n, localSchemaPath as o, isIncluded as p, diagnosticViews as r, CONFIG_NAME as s, Engine as t, contains as u, CorrectlyError as v, positionAt as w, locate as x, failure as y };
|
|
745
|
-
|
|
746
|
-
//# sourceMappingURL=engine-BgWBnb1A.mjs.map
|