@terrazzo/parser 2.0.0-alpha.3 → 2.0.0-alpha.4
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/dist/index.d.ts +35 -30
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +445 -343
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/build/index.ts +2 -2
- package/src/lib/resolver-utils.ts +35 -0
- package/src/lint/index.ts +4 -3
- package/src/parse/index.ts +30 -17
- package/src/parse/load.ts +20 -110
- package/src/parse/process.ts +124 -0
- package/src/parse/token.ts +6 -6
- package/src/resolver/create-synthetic-resolver.ts +86 -0
- package/src/resolver/load.ts +90 -35
- package/src/resolver/normalize.ts +18 -11
- package/src/resolver/validate.ts +10 -6
- package/src/types.ts +11 -12
package/dist/index.js
CHANGED
|
@@ -1,42 +1,11 @@
|
|
|
1
1
|
import wcmatch from "wildcard-match";
|
|
2
2
|
import * as momoa from "@humanwhocodes/momoa";
|
|
3
|
-
import { evaluate } from "@humanwhocodes/momoa";
|
|
4
3
|
import pc from "picocolors";
|
|
5
4
|
import { merge } from "merge-anything";
|
|
6
5
|
import { BORDER_REQUIRED_PROPERTIES, COLORSPACE, FONT_WEIGHTS, GRADIENT_REQUIRED_STOP_PROPERTIES, SHADOW_REQUIRED_PROPERTIES, STROKE_STYLE_LINE_CAP_VALUES, STROKE_STYLE_OBJECT_REQUIRED_PROPERTIES, STROKE_STYLE_STRING_VALUES, TRANSITION_REQUIRED_PROPERTIES, isAlias, parseAlias, parseColor, pluralize, tokenToCulori } from "@terrazzo/token-tools";
|
|
7
6
|
import { clampChroma, wcagContrast } from "culori";
|
|
8
|
-
import { bundle, getObjMember, getObjMembers, isPure$ref, maybeRawJSON, parseRef, replaceNode,
|
|
7
|
+
import { bundle, getObjMember, getObjMembers, isPure$ref, maybeRawJSON, parseRef, replaceNode, traverse } from "@terrazzo/json-schema-tools";
|
|
9
8
|
|
|
10
|
-
//#region rolldown:runtime
|
|
11
|
-
var __create = Object.create;
|
|
12
|
-
var __defProp = Object.defineProperty;
|
|
13
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
14
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
15
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
16
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
17
|
-
var __commonJS = (cb, mod) => function() {
|
|
18
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
19
|
-
};
|
|
20
|
-
var __copyProps = (to, from, except, desc) => {
|
|
21
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
22
|
-
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
23
|
-
key = keys[i];
|
|
24
|
-
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
25
|
-
__defProp(to, key, {
|
|
26
|
-
get: ((k) => from[k]).bind(null, key),
|
|
27
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return to;
|
|
33
|
-
};
|
|
34
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
35
|
-
value: mod,
|
|
36
|
-
enumerable: true
|
|
37
|
-
}) : target, mod));
|
|
38
|
-
|
|
39
|
-
//#endregion
|
|
40
9
|
//#region src/lib/code-frame.ts
|
|
41
10
|
/**
|
|
42
11
|
* Extract what lines should be marked and highlighted.
|
|
@@ -2489,40 +2458,8 @@ async function lintRunner({ tokens, filename, config = {}, sources, logger }) {
|
|
|
2489
2458
|
});
|
|
2490
2459
|
}
|
|
2491
2460
|
|
|
2492
|
-
//#endregion
|
|
2493
|
-
//#region ../../node_modules/.pnpm/fast-deep-equal@3.1.3/node_modules/fast-deep-equal/index.js
|
|
2494
|
-
var require_fast_deep_equal = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/fast-deep-equal@3.1.3/node_modules/fast-deep-equal/index.js": ((exports, module) => {
|
|
2495
|
-
module.exports = function equal(a, b) {
|
|
2496
|
-
if (a === b) return true;
|
|
2497
|
-
if (a && b && typeof a == "object" && typeof b == "object") {
|
|
2498
|
-
if (a.constructor !== b.constructor) return false;
|
|
2499
|
-
var length, i, keys;
|
|
2500
|
-
if (Array.isArray(a)) {
|
|
2501
|
-
length = a.length;
|
|
2502
|
-
if (length != b.length) return false;
|
|
2503
|
-
for (i = length; i-- !== 0;) if (!equal(a[i], b[i])) return false;
|
|
2504
|
-
return true;
|
|
2505
|
-
}
|
|
2506
|
-
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
|
|
2507
|
-
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
|
|
2508
|
-
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
|
|
2509
|
-
keys = Object.keys(a);
|
|
2510
|
-
length = keys.length;
|
|
2511
|
-
if (length !== Object.keys(b).length) return false;
|
|
2512
|
-
for (i = length; i-- !== 0;) if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
|
|
2513
|
-
for (i = length; i-- !== 0;) {
|
|
2514
|
-
var key = keys[i];
|
|
2515
|
-
if (!equal(a[key], b[key])) return false;
|
|
2516
|
-
}
|
|
2517
|
-
return true;
|
|
2518
|
-
}
|
|
2519
|
-
return a !== a && b !== b;
|
|
2520
|
-
};
|
|
2521
|
-
}) });
|
|
2522
|
-
|
|
2523
2461
|
//#endregion
|
|
2524
2462
|
//#region src/lib/momoa.ts
|
|
2525
|
-
var import_fast_deep_equal = /* @__PURE__ */ __toESM(require_fast_deep_equal(), 1);
|
|
2526
2463
|
/** Momoa’s default parser, with preferred settings. */
|
|
2527
2464
|
function toMomoa(srcRaw) {
|
|
2528
2465
|
return momoa.parse(typeof srcRaw === "string" ? srcRaw : JSON.stringify(srcRaw, void 0, 2), {
|
|
@@ -2532,6 +2469,32 @@ function toMomoa(srcRaw) {
|
|
|
2532
2469
|
});
|
|
2533
2470
|
}
|
|
2534
2471
|
|
|
2472
|
+
//#endregion
|
|
2473
|
+
//#region src/lib/resolver-utils.ts
|
|
2474
|
+
/**
|
|
2475
|
+
* If tokens are found inside a resolver, strip out the resolver paths (don’t
|
|
2476
|
+
* include "sets"/"modifiers" in the token ID etc.)
|
|
2477
|
+
*/
|
|
2478
|
+
function filterResolverPaths(path) {
|
|
2479
|
+
switch (path[0]) {
|
|
2480
|
+
case "sets": return path.slice(4);
|
|
2481
|
+
case "modifiers": return path.slice(5);
|
|
2482
|
+
case "resolutionOrder":
|
|
2483
|
+
switch (path[2]) {
|
|
2484
|
+
case "sources": return path.slice(4);
|
|
2485
|
+
case "contexts": return path.slice(5);
|
|
2486
|
+
}
|
|
2487
|
+
break;
|
|
2488
|
+
}
|
|
2489
|
+
return path;
|
|
2490
|
+
}
|
|
2491
|
+
/**
|
|
2492
|
+
* Make a deterministic string from an object
|
|
2493
|
+
*/
|
|
2494
|
+
function makeInputKey(input) {
|
|
2495
|
+
return JSON.stringify(Object.fromEntries(Object.entries(input).sort((a, b) => a[0].localeCompare(b[0], "en-us", { numeric: true }))));
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2535
2498
|
//#endregion
|
|
2536
2499
|
//#region src/resolver/validate.ts
|
|
2537
2500
|
/**
|
|
@@ -2910,204 +2873,6 @@ function validateModifier(node, isInline = false, { src }) {
|
|
|
2910
2873
|
return errors;
|
|
2911
2874
|
}
|
|
2912
2875
|
|
|
2913
|
-
//#endregion
|
|
2914
|
-
//#region src/resolver/normalize.ts
|
|
2915
|
-
/** Normalize resolver (assuming it’s been validated) */
|
|
2916
|
-
async function normalizeResolver(node, { filename, req, src, logger, yamlToMomoa }) {
|
|
2917
|
-
const resolverSource = evaluate(node);
|
|
2918
|
-
const resolutionOrder = getObjMember(node.body, "resolutionOrder");
|
|
2919
|
-
return {
|
|
2920
|
-
name: resolverSource.name,
|
|
2921
|
-
version: resolverSource.version,
|
|
2922
|
-
description: resolverSource.description,
|
|
2923
|
-
sets: resolverSource.sets,
|
|
2924
|
-
modifiers: resolverSource.modifiers,
|
|
2925
|
-
resolutionOrder: await Promise.all(resolutionOrder.elements.map(async (element, i) => {
|
|
2926
|
-
const layer = element.value;
|
|
2927
|
-
const members = getObjMembers(layer);
|
|
2928
|
-
let item = layer;
|
|
2929
|
-
if (members.$ref) {
|
|
2930
|
-
const entry = {
|
|
2931
|
-
group: "parser",
|
|
2932
|
-
label: "init",
|
|
2933
|
-
node: members.$ref,
|
|
2934
|
-
src
|
|
2935
|
-
};
|
|
2936
|
-
const { url, subpath } = parseRef(members.$ref.value);
|
|
2937
|
-
if (url === ".") if (!subpath?.[0]) logger.error({
|
|
2938
|
-
...entry,
|
|
2939
|
-
message: "$ref can’t refer to the root document."
|
|
2940
|
-
});
|
|
2941
|
-
else if (subpath[0] !== "sets" && subpath[0] !== "modifiers") logger.error({
|
|
2942
|
-
...entry,
|
|
2943
|
-
message: "Local $ref in resolutionOrder must point to either #/sets/[set] or #/modifiers/[modifiers]."
|
|
2944
|
-
});
|
|
2945
|
-
else {
|
|
2946
|
-
const resolvedItem = resolverSource[subpath[0]]?.[subpath[1]];
|
|
2947
|
-
if (!resolvedItem) logger.error({
|
|
2948
|
-
...entry,
|
|
2949
|
-
message: "Invalid $ref"
|
|
2950
|
-
});
|
|
2951
|
-
else item = {
|
|
2952
|
-
type: subpath[0] === "sets" ? "set" : "modifier",
|
|
2953
|
-
...resolvedItem
|
|
2954
|
-
};
|
|
2955
|
-
}
|
|
2956
|
-
else {
|
|
2957
|
-
const result = await bundle([{
|
|
2958
|
-
filename: new URL(url, filename),
|
|
2959
|
-
src: resolverSource.resolutionOrder[i]
|
|
2960
|
-
}], {
|
|
2961
|
-
req,
|
|
2962
|
-
yamlToMomoa
|
|
2963
|
-
});
|
|
2964
|
-
if (result.document.body.type === "Object") {
|
|
2965
|
-
const type = getObjMember(result.document.body, "type");
|
|
2966
|
-
if (type?.type === "String" && type.value === "set") {
|
|
2967
|
-
validateSet(result.document.body, true, src);
|
|
2968
|
-
item = evaluate(result.document.body);
|
|
2969
|
-
} else if (type?.type === "String" && type.value === "modifier") {
|
|
2970
|
-
validateModifier(result.document.body, true, src);
|
|
2971
|
-
item = evaluate(result.document.body);
|
|
2972
|
-
}
|
|
2973
|
-
}
|
|
2974
|
-
logger.error({
|
|
2975
|
-
...entry,
|
|
2976
|
-
message: "$ref did not resolve to a valid Set or Modifier."
|
|
2977
|
-
});
|
|
2978
|
-
}
|
|
2979
|
-
}
|
|
2980
|
-
return evaluate((await bundle([{
|
|
2981
|
-
filename,
|
|
2982
|
-
src: item
|
|
2983
|
-
}], {
|
|
2984
|
-
req,
|
|
2985
|
-
yamlToMomoa
|
|
2986
|
-
})).document.body);
|
|
2987
|
-
}))
|
|
2988
|
-
};
|
|
2989
|
-
}
|
|
2990
|
-
|
|
2991
|
-
//#endregion
|
|
2992
|
-
//#region src/resolver/load.ts
|
|
2993
|
-
/** Quick-parse input sources and find a resolver */
|
|
2994
|
-
async function loadResolver(inputs, { logger, req, yamlToMomoa }) {
|
|
2995
|
-
let resolverDoc;
|
|
2996
|
-
const entry = {
|
|
2997
|
-
group: "parser",
|
|
2998
|
-
label: "init"
|
|
2999
|
-
};
|
|
3000
|
-
for (const input of inputs) {
|
|
3001
|
-
let document;
|
|
3002
|
-
if (typeof input.src === "string") if (maybeRawJSON(input.src)) document = toMomoa(input.src);
|
|
3003
|
-
else if (yamlToMomoa) document = yamlToMomoa(input.src);
|
|
3004
|
-
else logger.error({
|
|
3005
|
-
...entry,
|
|
3006
|
-
message: `Install yaml-to-momoa package to parse YAML, and pass in as option, e.g.:
|
|
3007
|
-
|
|
3008
|
-
import { bundle } from '@terrazzo/json-schema-tools';
|
|
3009
|
-
import yamlToMomoa from 'yaml-to-momoa';
|
|
3010
|
-
|
|
3011
|
-
bundle(yamlString, { yamlToMomoa });`
|
|
3012
|
-
});
|
|
3013
|
-
else if (input.src && typeof input.src === "object") document = toMomoa(JSON.stringify(input.src, void 0, 2));
|
|
3014
|
-
else logger.error({
|
|
3015
|
-
...entry,
|
|
3016
|
-
message: `Could not parse ${input.filename}. Is this valid JSON or YAML?`
|
|
3017
|
-
});
|
|
3018
|
-
if (!document || !isLikelyResolver(document)) continue;
|
|
3019
|
-
if (inputs.length > 1) logger.error({
|
|
3020
|
-
...entry,
|
|
3021
|
-
message: `Resolver must be the only input, found ${inputs.length} sources.`
|
|
3022
|
-
});
|
|
3023
|
-
resolverDoc = document;
|
|
3024
|
-
break;
|
|
3025
|
-
}
|
|
3026
|
-
if (resolverDoc) {
|
|
3027
|
-
validateResolver(resolverDoc, {
|
|
3028
|
-
logger,
|
|
3029
|
-
src: inputs[0].src
|
|
3030
|
-
});
|
|
3031
|
-
return createResolver(await normalizeResolver(resolverDoc, {
|
|
3032
|
-
filename: inputs[0].filename,
|
|
3033
|
-
logger,
|
|
3034
|
-
req,
|
|
3035
|
-
src: inputs[0].src,
|
|
3036
|
-
yamlToMomoa
|
|
3037
|
-
}), { logger });
|
|
3038
|
-
}
|
|
3039
|
-
}
|
|
3040
|
-
/** Create an interface to resolve permutations */
|
|
3041
|
-
function createResolver(resolverSource, { logger }) {
|
|
3042
|
-
const inputDefaults = {};
|
|
3043
|
-
const modifierPermutations = [];
|
|
3044
|
-
for (const [name, m] of Object.entries(resolverSource.modifiers ?? {})) {
|
|
3045
|
-
if (typeof m.default === "string") inputDefaults[name] = m.default;
|
|
3046
|
-
modifierPermutations.push([name, Object.keys(m.contexts)]);
|
|
3047
|
-
}
|
|
3048
|
-
for (const m of resolverSource.resolutionOrder) {
|
|
3049
|
-
if (!("type" in m) || m.type !== "modifier") continue;
|
|
3050
|
-
if (typeof m.default === "string") inputDefaults[m.name] = m.default;
|
|
3051
|
-
modifierPermutations.push([m.name, Object.keys(m.contexts)]);
|
|
3052
|
-
}
|
|
3053
|
-
const permutations = calculatePermutations(modifierPermutations);
|
|
3054
|
-
return {
|
|
3055
|
-
apply(inputRaw) {
|
|
3056
|
-
let tokens = {};
|
|
3057
|
-
const input = {
|
|
3058
|
-
...inputDefaults,
|
|
3059
|
-
...inputRaw
|
|
3060
|
-
};
|
|
3061
|
-
for (const item of resolverSource.resolutionOrder) switch (item.type) {
|
|
3062
|
-
case "set":
|
|
3063
|
-
for (const s of item.sources) tokens = merge(tokens, s);
|
|
3064
|
-
break;
|
|
3065
|
-
case "modifier": {
|
|
3066
|
-
const context = input[item.name];
|
|
3067
|
-
const sources = item.contexts[context];
|
|
3068
|
-
if (!sources) logger.error({
|
|
3069
|
-
group: "parser",
|
|
3070
|
-
label: "resolver",
|
|
3071
|
-
message: `Modifier ${item.name} has no context ${JSON.stringify(context)}.`
|
|
3072
|
-
});
|
|
3073
|
-
for (const s of sources ?? []) tokens = merge(tokens, s);
|
|
3074
|
-
break;
|
|
3075
|
-
}
|
|
3076
|
-
}
|
|
3077
|
-
return tokens;
|
|
3078
|
-
},
|
|
3079
|
-
source: resolverSource,
|
|
3080
|
-
permutations,
|
|
3081
|
-
isValidInput(inputRaw) {
|
|
3082
|
-
if (!inputRaw || typeof inputRaw !== "object") logger.error({
|
|
3083
|
-
group: "parser",
|
|
3084
|
-
label: "resolver",
|
|
3085
|
-
message: `Invalid input: ${JSON.stringify(inputRaw)}.`
|
|
3086
|
-
});
|
|
3087
|
-
const input = {
|
|
3088
|
-
...inputDefaults,
|
|
3089
|
-
...inputRaw
|
|
3090
|
-
};
|
|
3091
|
-
return permutations.findIndex((p) => (0, import_fast_deep_equal.default)(input, p)) !== -1;
|
|
3092
|
-
}
|
|
3093
|
-
};
|
|
3094
|
-
}
|
|
3095
|
-
/** Calculate all permutations */
|
|
3096
|
-
function calculatePermutations(options) {
|
|
3097
|
-
const permutationCount = [1];
|
|
3098
|
-
for (const [_name, contexts] of options) permutationCount.push(contexts.length * (permutationCount.at(-1) || 1));
|
|
3099
|
-
const permutations = [];
|
|
3100
|
-
for (let i = 0; i < permutationCount.at(-1); i++) {
|
|
3101
|
-
const input = {};
|
|
3102
|
-
for (let j = 0; j < options.length; j++) {
|
|
3103
|
-
const [name, contexts] = options[j];
|
|
3104
|
-
input[name] = contexts[Math.floor(i / permutationCount[j]) % contexts.length];
|
|
3105
|
-
}
|
|
3106
|
-
permutations.push(input);
|
|
3107
|
-
}
|
|
3108
|
-
return permutations.length ? permutations : [{}];
|
|
3109
|
-
}
|
|
3110
|
-
|
|
3111
2876
|
//#endregion
|
|
3112
2877
|
//#region src/parse/normalize.ts
|
|
3113
2878
|
/**
|
|
@@ -3234,7 +2999,7 @@ function tokenFromNode(node, { groups, path, source, ignore }) {
|
|
|
3234
2999
|
const group = groups[`#/${path.slice(0, -1).join("/")}`];
|
|
3235
3000
|
if (group?.tokens && !group.tokens.includes(id)) group.tokens.push(id);
|
|
3236
3001
|
const nodeSource = {
|
|
3237
|
-
filename: source.filename
|
|
3002
|
+
filename: source.filename.href,
|
|
3238
3003
|
node
|
|
3239
3004
|
};
|
|
3240
3005
|
const token = {
|
|
@@ -3579,68 +3344,20 @@ function resolveAliases(tokens, { logger, refMap, sources }) {
|
|
|
3579
3344
|
}
|
|
3580
3345
|
|
|
3581
3346
|
//#endregion
|
|
3582
|
-
//#region src/parse/
|
|
3583
|
-
|
|
3584
|
-
async function loadSources(inputs, { config, logger, req, continueOnError, yamlToMomoa, transform }) {
|
|
3347
|
+
//#region src/parse/process.ts
|
|
3348
|
+
function processTokens(rootSource, { config, logger, sourceByFilename, refMap }) {
|
|
3585
3349
|
const entry = {
|
|
3586
3350
|
group: "parser",
|
|
3587
3351
|
label: "init"
|
|
3588
3352
|
};
|
|
3589
|
-
const firstLoad = performance.now();
|
|
3590
|
-
let document = {};
|
|
3591
|
-
/** The original user inputs, in original order, with parsed ASTs */
|
|
3592
|
-
const sources = inputs.map((input, i) => ({
|
|
3593
|
-
...input,
|
|
3594
|
-
document: {},
|
|
3595
|
-
filename: input.filename || new URL(`virtual:${i}`)
|
|
3596
|
-
}));
|
|
3597
|
-
/** The sources array, indexed by filename */
|
|
3598
|
-
let sourceByFilename = {};
|
|
3599
|
-
/** Mapping of all final $ref resolutions. This will be used to generate the graph later. */
|
|
3600
|
-
let refMap = {};
|
|
3601
|
-
try {
|
|
3602
|
-
const result = await bundle(sources, {
|
|
3603
|
-
req,
|
|
3604
|
-
parse: transform ? transformer(transform) : void 0,
|
|
3605
|
-
yamlToMomoa
|
|
3606
|
-
});
|
|
3607
|
-
document = result.document;
|
|
3608
|
-
sourceByFilename = result.sources;
|
|
3609
|
-
refMap = result.refMap;
|
|
3610
|
-
for (const [filename, source] of Object.entries(result.sources)) {
|
|
3611
|
-
const i = sources.findIndex((s) => s.filename.href === filename);
|
|
3612
|
-
if (i === -1) sources.push(source);
|
|
3613
|
-
else {
|
|
3614
|
-
sources[i].src = source.src;
|
|
3615
|
-
sources[i].document = source.document;
|
|
3616
|
-
}
|
|
3617
|
-
}
|
|
3618
|
-
} catch (err) {
|
|
3619
|
-
let src = sources.find((s) => s.filename.href === err.filename)?.src;
|
|
3620
|
-
if (src && typeof src !== "string") src = JSON.stringify(src, void 0, 2);
|
|
3621
|
-
logger.error({
|
|
3622
|
-
...entry,
|
|
3623
|
-
continueOnError,
|
|
3624
|
-
message: err.message,
|
|
3625
|
-
node: err.node,
|
|
3626
|
-
src
|
|
3627
|
-
});
|
|
3628
|
-
}
|
|
3629
|
-
logger.debug({
|
|
3630
|
-
...entry,
|
|
3631
|
-
message: `JSON loaded`,
|
|
3632
|
-
timing: performance.now() - firstLoad
|
|
3633
|
-
});
|
|
3634
|
-
const artificialSource = {
|
|
3635
|
-
src: momoa.print(document, { indent: 2 }),
|
|
3636
|
-
document
|
|
3637
|
-
};
|
|
3638
3353
|
const firstPass = performance.now();
|
|
3639
3354
|
const tokens = {};
|
|
3640
3355
|
const tokenIDs = [];
|
|
3641
3356
|
const groups = {};
|
|
3642
|
-
|
|
3357
|
+
const isResolver = isLikelyResolver(rootSource.document);
|
|
3358
|
+
traverse(rootSource.document, { enter(node, _parent, rawPath) {
|
|
3643
3359
|
if (node.type !== "Object") return;
|
|
3360
|
+
const path = isResolver ? filterResolverPaths(rawPath) : rawPath;
|
|
3644
3361
|
groupFromNode(node, {
|
|
3645
3362
|
path,
|
|
3646
3363
|
groups
|
|
@@ -3649,10 +3366,7 @@ async function loadSources(inputs, { config, logger, req, continueOnError, yamlT
|
|
|
3649
3366
|
groups,
|
|
3650
3367
|
ignore: config.ignore,
|
|
3651
3368
|
path,
|
|
3652
|
-
source:
|
|
3653
|
-
src: artificialSource,
|
|
3654
|
-
document
|
|
3655
|
-
}
|
|
3369
|
+
source: rootSource
|
|
3656
3370
|
});
|
|
3657
3371
|
if (token) {
|
|
3658
3372
|
tokenIDs.push(token.jsonID);
|
|
@@ -3665,7 +3379,7 @@ async function loadSources(inputs, { config, logger, req, continueOnError, yamlT
|
|
|
3665
3379
|
timing: performance.now() - firstPass
|
|
3666
3380
|
});
|
|
3667
3381
|
const secondPass = performance.now();
|
|
3668
|
-
for (const source of Object.values(sourceByFilename))
|
|
3382
|
+
for (const source of Object.values(sourceByFilename)) traverse(source.document, { enter(node, _parent, path) {
|
|
3669
3383
|
if (node.type !== "Object") return;
|
|
3670
3384
|
const tokenRawValues = tokenRawValuesFromNode(node, {
|
|
3671
3385
|
filename: source.filename.href,
|
|
@@ -3722,17 +3436,386 @@ async function loadSources(inputs, { config, logger, req, continueOnError, yamlT
|
|
|
3722
3436
|
tokensSorted[id] = tokens[path];
|
|
3723
3437
|
}
|
|
3724
3438
|
for (const group of Object.values(groups)) group.tokens.sort((a, b) => a.localeCompare(b, "en-us", { numeric: true }));
|
|
3725
|
-
return
|
|
3726
|
-
tokens: tokensSorted,
|
|
3727
|
-
sources
|
|
3728
|
-
};
|
|
3439
|
+
return tokensSorted;
|
|
3729
3440
|
}
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3441
|
+
|
|
3442
|
+
//#endregion
|
|
3443
|
+
//#region src/resolver/normalize.ts
|
|
3444
|
+
/** Normalize resolver (assuming it’s been validated) */
|
|
3445
|
+
async function normalizeResolver(node, { filename, req, src, logger, yamlToMomoa }) {
|
|
3446
|
+
const resolverSource = momoa.evaluate(node);
|
|
3447
|
+
const resolutionOrder = getObjMember(node.body, "resolutionOrder");
|
|
3448
|
+
return {
|
|
3449
|
+
name: resolverSource.name,
|
|
3450
|
+
version: resolverSource.version,
|
|
3451
|
+
description: resolverSource.description,
|
|
3452
|
+
sets: resolverSource.sets,
|
|
3453
|
+
modifiers: resolverSource.modifiers,
|
|
3454
|
+
resolutionOrder: await Promise.all(resolutionOrder.elements.map(async (element, i) => {
|
|
3455
|
+
const layer = element.value;
|
|
3456
|
+
const members = getObjMembers(layer);
|
|
3457
|
+
let item = layer;
|
|
3458
|
+
if (members.$ref) {
|
|
3459
|
+
const entry = {
|
|
3460
|
+
group: "parser",
|
|
3461
|
+
label: "init",
|
|
3462
|
+
node: members.$ref,
|
|
3463
|
+
src
|
|
3464
|
+
};
|
|
3465
|
+
const { url, subpath } = parseRef(members.$ref.value);
|
|
3466
|
+
if (url === ".") if (!subpath?.[0]) logger.error({
|
|
3467
|
+
...entry,
|
|
3468
|
+
message: "$ref can’t refer to the root document."
|
|
3469
|
+
});
|
|
3470
|
+
else if (subpath[0] !== "sets" && subpath[0] !== "modifiers") logger.error({
|
|
3471
|
+
...entry,
|
|
3472
|
+
message: "Local $ref in resolutionOrder must point to either #/sets/[set] or #/modifiers/[modifiers]."
|
|
3473
|
+
});
|
|
3474
|
+
else {
|
|
3475
|
+
const resolvedItem = resolverSource[subpath[0]]?.[subpath[1]];
|
|
3476
|
+
if (!resolvedItem) logger.error({
|
|
3477
|
+
...entry,
|
|
3478
|
+
message: "Invalid $ref"
|
|
3479
|
+
});
|
|
3480
|
+
else item = {
|
|
3481
|
+
type: subpath[0] === "sets" ? "set" : "modifier",
|
|
3482
|
+
name: subpath[1],
|
|
3483
|
+
...resolvedItem
|
|
3484
|
+
};
|
|
3485
|
+
}
|
|
3486
|
+
else {
|
|
3487
|
+
const result = await bundle([{
|
|
3488
|
+
filename: new URL(url, filename),
|
|
3489
|
+
src: resolverSource.resolutionOrder[i]
|
|
3490
|
+
}], {
|
|
3491
|
+
req,
|
|
3492
|
+
yamlToMomoa
|
|
3493
|
+
});
|
|
3494
|
+
if (result.document.body.type === "Object") {
|
|
3495
|
+
const type = getObjMember(result.document.body, "type");
|
|
3496
|
+
if (type?.type === "String" && type.value === "set") {
|
|
3497
|
+
validateSet(result.document.body, true, src);
|
|
3498
|
+
item = momoa.evaluate(result.document.body);
|
|
3499
|
+
} else if (type?.type === "String" && type.value === "modifier") {
|
|
3500
|
+
validateModifier(result.document.body, true, src);
|
|
3501
|
+
item = momoa.evaluate(result.document.body);
|
|
3502
|
+
}
|
|
3503
|
+
}
|
|
3504
|
+
logger.error({
|
|
3505
|
+
...entry,
|
|
3506
|
+
message: "$ref did not resolve to a valid Set or Modifier."
|
|
3507
|
+
});
|
|
3508
|
+
}
|
|
3509
|
+
}
|
|
3510
|
+
const finalResult = await bundle([{
|
|
3511
|
+
filename,
|
|
3512
|
+
src: item
|
|
3513
|
+
}], {
|
|
3514
|
+
req,
|
|
3515
|
+
yamlToMomoa
|
|
3516
|
+
});
|
|
3517
|
+
return momoa.evaluate(finalResult.document.body);
|
|
3518
|
+
})),
|
|
3519
|
+
_source: {
|
|
3520
|
+
filename,
|
|
3521
|
+
node
|
|
3522
|
+
}
|
|
3523
|
+
};
|
|
3524
|
+
}
|
|
3525
|
+
|
|
3526
|
+
//#endregion
|
|
3527
|
+
//#region src/resolver/load.ts
|
|
3528
|
+
/** Quick-parse input sources and find a resolver */
|
|
3529
|
+
async function loadResolver(inputs, { config, logger, req, yamlToMomoa }) {
|
|
3530
|
+
let resolverDoc;
|
|
3531
|
+
let tokens = {};
|
|
3532
|
+
const entry = {
|
|
3533
|
+
group: "parser",
|
|
3534
|
+
label: "init"
|
|
3535
|
+
};
|
|
3536
|
+
for (const input of inputs) {
|
|
3537
|
+
let document;
|
|
3538
|
+
if (typeof input.src === "string") if (maybeRawJSON(input.src)) document = toMomoa(input.src);
|
|
3539
|
+
else if (yamlToMomoa) document = yamlToMomoa(input.src);
|
|
3540
|
+
else logger.error({
|
|
3541
|
+
...entry,
|
|
3542
|
+
message: `Install yaml-to-momoa package to parse YAML, and pass in as option, e.g.:
|
|
3543
|
+
|
|
3544
|
+
import { bundle } from '@terrazzo/json-schema-tools';
|
|
3545
|
+
import yamlToMomoa from 'yaml-to-momoa';
|
|
3546
|
+
|
|
3547
|
+
bundle(yamlString, { yamlToMomoa });`
|
|
3548
|
+
});
|
|
3549
|
+
else if (input.src && typeof input.src === "object") document = toMomoa(JSON.stringify(input.src, void 0, 2));
|
|
3550
|
+
else logger.error({
|
|
3551
|
+
...entry,
|
|
3552
|
+
message: `Could not parse ${input.filename}. Is this valid JSON or YAML?`
|
|
3553
|
+
});
|
|
3554
|
+
if (!document || !isLikelyResolver(document)) continue;
|
|
3555
|
+
if (inputs.length > 1) logger.error({
|
|
3556
|
+
...entry,
|
|
3557
|
+
message: `Resolver must be the only input, found ${inputs.length} sources.`
|
|
3558
|
+
});
|
|
3559
|
+
resolverDoc = document;
|
|
3560
|
+
break;
|
|
3561
|
+
}
|
|
3562
|
+
let resolver;
|
|
3563
|
+
if (resolverDoc) {
|
|
3564
|
+
validateResolver(resolverDoc, {
|
|
3565
|
+
logger,
|
|
3566
|
+
src: inputs[0].src
|
|
3567
|
+
});
|
|
3568
|
+
resolver = createResolver(await normalizeResolver(resolverDoc, {
|
|
3569
|
+
filename: inputs[0].filename,
|
|
3570
|
+
logger,
|
|
3571
|
+
req,
|
|
3572
|
+
src: inputs[0].src,
|
|
3573
|
+
yamlToMomoa
|
|
3574
|
+
}), {
|
|
3575
|
+
config,
|
|
3576
|
+
logger,
|
|
3577
|
+
sources: [{
|
|
3578
|
+
...inputs[0],
|
|
3579
|
+
document: resolverDoc
|
|
3580
|
+
}]
|
|
3581
|
+
});
|
|
3582
|
+
const firstInput = {};
|
|
3583
|
+
for (const m of resolver.source.resolutionOrder) {
|
|
3584
|
+
if (m.type !== "modifier") continue;
|
|
3585
|
+
firstInput[m.name] = typeof m.default === "string" ? m.default : Object.keys(m.contexts)[0];
|
|
3586
|
+
}
|
|
3587
|
+
tokens = resolver.apply(firstInput);
|
|
3588
|
+
}
|
|
3589
|
+
return {
|
|
3590
|
+
resolver,
|
|
3591
|
+
tokens,
|
|
3592
|
+
sources: [{
|
|
3593
|
+
...inputs[0],
|
|
3594
|
+
document: resolverDoc
|
|
3595
|
+
}]
|
|
3596
|
+
};
|
|
3597
|
+
}
|
|
3598
|
+
/** Create an interface to resolve permutations */
|
|
3599
|
+
function createResolver(resolverSource, { config, logger, sources }) {
|
|
3600
|
+
const inputDefaults = {};
|
|
3601
|
+
const validContexts = {};
|
|
3602
|
+
const allPermutations = [];
|
|
3603
|
+
const resolverCache = {};
|
|
3604
|
+
for (const m of resolverSource.resolutionOrder) if (m.type === "modifier") {
|
|
3605
|
+
if (typeof m.default === "string") inputDefaults[m.name] = m.default;
|
|
3606
|
+
validContexts[m.name] = Object.keys(m.contexts);
|
|
3607
|
+
}
|
|
3608
|
+
return {
|
|
3609
|
+
apply(inputRaw) {
|
|
3610
|
+
let tokensRaw = {};
|
|
3611
|
+
const input = {
|
|
3612
|
+
...inputDefaults,
|
|
3613
|
+
...inputRaw
|
|
3614
|
+
};
|
|
3615
|
+
const inputKey = makeInputKey(input);
|
|
3616
|
+
if (resolverCache[inputKey]) return resolverCache[inputKey];
|
|
3617
|
+
for (const item of resolverSource.resolutionOrder) switch (item.type) {
|
|
3618
|
+
case "set":
|
|
3619
|
+
for (const s of item.sources) tokensRaw = merge(tokensRaw, s);
|
|
3620
|
+
break;
|
|
3621
|
+
case "modifier": {
|
|
3622
|
+
const context = input[item.name];
|
|
3623
|
+
const sources$1 = item.contexts[context];
|
|
3624
|
+
if (!sources$1) logger.error({
|
|
3625
|
+
group: "parser",
|
|
3626
|
+
label: "resolver",
|
|
3627
|
+
message: `Modifier ${item.name} has no context ${JSON.stringify(context)}.`
|
|
3628
|
+
});
|
|
3629
|
+
for (const s of sources$1 ?? []) tokensRaw = merge(tokensRaw, s);
|
|
3630
|
+
break;
|
|
3631
|
+
}
|
|
3632
|
+
}
|
|
3633
|
+
const src = JSON.stringify(tokensRaw, void 0, 2);
|
|
3634
|
+
const tokens = processTokens({
|
|
3635
|
+
filename: resolverSource._source.filename,
|
|
3636
|
+
document: toMomoa(src),
|
|
3637
|
+
src
|
|
3638
|
+
}, {
|
|
3639
|
+
config,
|
|
3640
|
+
logger,
|
|
3641
|
+
sourceByFilename: {},
|
|
3642
|
+
refMap: {},
|
|
3643
|
+
sources
|
|
3644
|
+
});
|
|
3645
|
+
resolverCache[inputKey] = tokens;
|
|
3646
|
+
return tokens;
|
|
3647
|
+
},
|
|
3648
|
+
source: resolverSource,
|
|
3649
|
+
listPermutations() {
|
|
3650
|
+
if (!allPermutations.length) allPermutations.push(...calculatePermutations(Object.entries(validContexts)));
|
|
3651
|
+
return allPermutations;
|
|
3652
|
+
},
|
|
3653
|
+
isValidInput(input) {
|
|
3654
|
+
if (!input || typeof input !== "object") logger.error({
|
|
3655
|
+
group: "parser",
|
|
3656
|
+
label: "resolver",
|
|
3657
|
+
message: `Invalid input: ${JSON.stringify(input)}.`
|
|
3658
|
+
});
|
|
3659
|
+
if (!Object.keys(input).every((k) => k in validContexts)) return false;
|
|
3660
|
+
for (const [name, contexts] of Object.entries(validContexts)) if (name in input) {
|
|
3661
|
+
if (!contexts.includes(input[name])) return false;
|
|
3662
|
+
} else if (!(name in inputDefaults)) return false;
|
|
3663
|
+
return true;
|
|
3664
|
+
}
|
|
3665
|
+
};
|
|
3666
|
+
}
|
|
3667
|
+
/** Calculate all permutations */
|
|
3668
|
+
function calculatePermutations(options) {
|
|
3669
|
+
const permutationCount = [1];
|
|
3670
|
+
for (const [_name, contexts] of options) permutationCount.push(contexts.length * (permutationCount.at(-1) || 1));
|
|
3671
|
+
const permutations = [];
|
|
3672
|
+
for (let i = 0; i < permutationCount.at(-1); i++) {
|
|
3673
|
+
const input = {};
|
|
3674
|
+
for (let j = 0; j < options.length; j++) {
|
|
3675
|
+
const [name, contexts] = options[j];
|
|
3676
|
+
input[name] = contexts[Math.floor(i / permutationCount[j]) % contexts.length];
|
|
3677
|
+
}
|
|
3678
|
+
permutations.push(input);
|
|
3679
|
+
}
|
|
3680
|
+
return permutations.length ? permutations : [{}];
|
|
3681
|
+
}
|
|
3682
|
+
|
|
3683
|
+
//#endregion
|
|
3684
|
+
//#region src/resolver/create-synthetic-resolver.ts
|
|
3685
|
+
/**
|
|
3686
|
+
* Interop layer upgrading legacy Terrazzo modes to resolvers
|
|
3687
|
+
*/
|
|
3688
|
+
async function createSyntheticResolver(tokens, { config, logger, req, sources }) {
|
|
3689
|
+
const contexts = {};
|
|
3690
|
+
for (const token of Object.values(tokens)) for (const [mode, value] of Object.entries(token.mode)) {
|
|
3691
|
+
if (mode === ".") continue;
|
|
3692
|
+
if (!(mode in contexts)) contexts[mode] = [{}];
|
|
3693
|
+
addToken(contexts[mode][0], {
|
|
3694
|
+
...token,
|
|
3695
|
+
$value: value.$value
|
|
3696
|
+
}, { logger });
|
|
3697
|
+
}
|
|
3698
|
+
const src = JSON.stringify({
|
|
3699
|
+
name: "Terrazzo",
|
|
3700
|
+
version: "2025.10",
|
|
3701
|
+
resolutionOrder: [{ $ref: "#/sets/allTokens" }, { $ref: "#/modifiers/tzMode" }],
|
|
3702
|
+
sets: { allTokens: { sources: [simpleFlatten(tokens, { logger })] } },
|
|
3703
|
+
modifiers: { tzMode: {
|
|
3704
|
+
description: "Automatically built from $extensions.mode",
|
|
3705
|
+
contexts
|
|
3706
|
+
} }
|
|
3707
|
+
}, void 0, 2);
|
|
3708
|
+
return createResolver(await normalizeResolver(momoa.parse(src), {
|
|
3709
|
+
filename: new URL("file:///virtual:resolver.json"),
|
|
3710
|
+
logger,
|
|
3711
|
+
req,
|
|
3712
|
+
src
|
|
3713
|
+
}), {
|
|
3714
|
+
config,
|
|
3715
|
+
logger,
|
|
3716
|
+
sources
|
|
3717
|
+
});
|
|
3718
|
+
}
|
|
3719
|
+
/** Add a normalized token back into an arbitrary, hierarchial structure */
|
|
3720
|
+
function addToken(structure, token, { logger }) {
|
|
3721
|
+
let node = structure;
|
|
3722
|
+
const parts = token.id.split(".");
|
|
3723
|
+
const localID = parts.pop();
|
|
3724
|
+
for (const part of parts) {
|
|
3725
|
+
if (!(part in node)) node[part] = {};
|
|
3726
|
+
node = node[part];
|
|
3727
|
+
}
|
|
3728
|
+
if (localID in node) logger.error({
|
|
3729
|
+
group: "parser",
|
|
3730
|
+
label: "resolver",
|
|
3731
|
+
message: `${localID} already exists!`
|
|
3732
|
+
});
|
|
3733
|
+
node[localID] = {
|
|
3734
|
+
$type: token.$type,
|
|
3735
|
+
$value: token.$value
|
|
3736
|
+
};
|
|
3737
|
+
}
|
|
3738
|
+
/** Downconvert normalized tokens back into a simplified, hierarchial shape. This is extremely lossy, and only done to build a resolver. */
|
|
3739
|
+
function simpleFlatten(tokens, { logger }) {
|
|
3740
|
+
const group = {};
|
|
3741
|
+
for (const token of Object.values(tokens)) addToken(group, token, { logger });
|
|
3742
|
+
return group;
|
|
3743
|
+
}
|
|
3744
|
+
|
|
3745
|
+
//#endregion
|
|
3746
|
+
//#region src/parse/load.ts
|
|
3747
|
+
/** Load from multiple entries, while resolving remote files */
|
|
3748
|
+
async function loadSources(inputs, { config, logger, req, continueOnError, yamlToMomoa, transform }) {
|
|
3749
|
+
const entry = {
|
|
3750
|
+
group: "parser",
|
|
3751
|
+
label: "init"
|
|
3752
|
+
};
|
|
3753
|
+
const firstLoad = performance.now();
|
|
3754
|
+
let document = {};
|
|
3755
|
+
/** The original user inputs, in original order, with parsed ASTs */
|
|
3756
|
+
const sources = inputs.map((input, i) => ({
|
|
3757
|
+
...input,
|
|
3758
|
+
document: {},
|
|
3759
|
+
filename: input.filename || new URL(`virtual:${i}`)
|
|
3760
|
+
}));
|
|
3761
|
+
/** The sources array, indexed by filename */
|
|
3762
|
+
let sourceByFilename = {};
|
|
3763
|
+
/** Mapping of all final $ref resolutions. This will be used to generate the graph later. */
|
|
3764
|
+
let refMap = {};
|
|
3765
|
+
try {
|
|
3766
|
+
const result = await bundle(sources, {
|
|
3767
|
+
req,
|
|
3768
|
+
parse: transform ? transformer(transform) : void 0,
|
|
3769
|
+
yamlToMomoa
|
|
3770
|
+
});
|
|
3771
|
+
document = result.document;
|
|
3772
|
+
sourceByFilename = result.sources;
|
|
3773
|
+
refMap = result.refMap;
|
|
3774
|
+
for (const [filename, source] of Object.entries(result.sources)) {
|
|
3775
|
+
const i = sources.findIndex((s) => s.filename.href === filename);
|
|
3776
|
+
if (i === -1) sources.push(source);
|
|
3777
|
+
else {
|
|
3778
|
+
sources[i].src = source.src;
|
|
3779
|
+
sources[i].document = source.document;
|
|
3780
|
+
}
|
|
3781
|
+
}
|
|
3782
|
+
} catch (err) {
|
|
3783
|
+
let src = sources.find((s) => s.filename.href === err.filename)?.src;
|
|
3784
|
+
if (src && typeof src !== "string") src = JSON.stringify(src, void 0, 2);
|
|
3785
|
+
logger.error({
|
|
3786
|
+
...entry,
|
|
3787
|
+
continueOnError,
|
|
3788
|
+
message: err.message,
|
|
3789
|
+
node: err.node,
|
|
3790
|
+
src
|
|
3791
|
+
});
|
|
3792
|
+
}
|
|
3793
|
+
logger.debug({
|
|
3794
|
+
...entry,
|
|
3795
|
+
message: `JSON loaded`,
|
|
3796
|
+
timing: performance.now() - firstLoad
|
|
3797
|
+
});
|
|
3798
|
+
return {
|
|
3799
|
+
tokens: processTokens({
|
|
3800
|
+
filename: sources[0].filename,
|
|
3801
|
+
document,
|
|
3802
|
+
src: momoa.print(document, { indent: 2 })
|
|
3803
|
+
}, {
|
|
3804
|
+
config,
|
|
3805
|
+
logger,
|
|
3806
|
+
refMap,
|
|
3807
|
+
sources,
|
|
3808
|
+
sourceByFilename
|
|
3809
|
+
}),
|
|
3810
|
+
sources
|
|
3811
|
+
};
|
|
3812
|
+
}
|
|
3813
|
+
function transformer(transform) {
|
|
3814
|
+
return async (src, filename) => {
|
|
3815
|
+
let document = toMomoa(src);
|
|
3816
|
+
let lastPath = "#/";
|
|
3817
|
+
let last$type;
|
|
3818
|
+
if (transform.root) {
|
|
3736
3819
|
const result = transform.root(document, {
|
|
3737
3820
|
filename,
|
|
3738
3821
|
parent: void 0,
|
|
@@ -3740,7 +3823,9 @@ function transformer(transform) {
|
|
|
3740
3823
|
});
|
|
3741
3824
|
if (result) document = result;
|
|
3742
3825
|
}
|
|
3743
|
-
|
|
3826
|
+
const isResolver = isLikelyResolver(document);
|
|
3827
|
+
traverse(document, { enter(node, parent, rawPath) {
|
|
3828
|
+
const path = isResolver ? filterResolverPaths(rawPath) : rawPath;
|
|
3744
3829
|
if (node.type !== "Object" || !path.length) return;
|
|
3745
3830
|
const ctx = {
|
|
3746
3831
|
filename,
|
|
@@ -3775,21 +3860,33 @@ function transformer(transform) {
|
|
|
3775
3860
|
/** Parse */
|
|
3776
3861
|
async function parse(_input, { logger = new Logger(), req = defaultReq, skipLint = false, config = {}, continueOnError = false, yamlToMomoa, transform } = {}) {
|
|
3777
3862
|
const inputs = Array.isArray(_input) ? _input : [_input];
|
|
3863
|
+
let tokens = {};
|
|
3864
|
+
let resolver;
|
|
3865
|
+
let sources = [];
|
|
3778
3866
|
const totalStart = performance.now();
|
|
3779
|
-
const
|
|
3867
|
+
const initStart = performance.now();
|
|
3868
|
+
const resolverResult = await loadResolver(inputs, {
|
|
3869
|
+
config,
|
|
3780
3870
|
logger,
|
|
3781
3871
|
req,
|
|
3782
3872
|
yamlToMomoa
|
|
3783
3873
|
});
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3874
|
+
if (resolverResult.resolver) {
|
|
3875
|
+
tokens = resolverResult.tokens;
|
|
3876
|
+
sources = resolverResult.sources;
|
|
3877
|
+
resolver = resolverResult.resolver;
|
|
3878
|
+
} else {
|
|
3879
|
+
const tokenResult = await loadSources(inputs, {
|
|
3880
|
+
req,
|
|
3881
|
+
logger,
|
|
3882
|
+
config,
|
|
3883
|
+
continueOnError,
|
|
3884
|
+
yamlToMomoa,
|
|
3885
|
+
transform
|
|
3886
|
+
});
|
|
3887
|
+
tokens = tokenResult.tokens;
|
|
3888
|
+
sources = tokenResult.sources;
|
|
3889
|
+
}
|
|
3793
3890
|
logger.debug({
|
|
3794
3891
|
message: "Loaded tokens",
|
|
3795
3892
|
group: "parser",
|
|
@@ -3827,7 +3924,12 @@ async function parse(_input, { logger = new Logger(), req = defaultReq, skipLint
|
|
|
3827
3924
|
return {
|
|
3828
3925
|
tokens,
|
|
3829
3926
|
sources,
|
|
3830
|
-
resolver
|
|
3927
|
+
resolver: resolver || await createSyntheticResolver(tokens, {
|
|
3928
|
+
config,
|
|
3929
|
+
logger,
|
|
3930
|
+
req,
|
|
3931
|
+
sources
|
|
3932
|
+
})
|
|
3831
3933
|
};
|
|
3832
3934
|
}
|
|
3833
3935
|
let fs;
|