@terrazzo/parser 2.0.0-beta.3 → 2.0.0-beta.5
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/CHANGELOG.md +8 -0
- package/dist/index.d.ts +8 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +278 -149
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { BORDER_REQUIRED_PROPERTIES, COLOR_SPACE, CachedWildcardMatcher, 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, tokenToColor } from "@terrazzo/token-tools";
|
|
2
2
|
import * as momoa from "@humanwhocodes/momoa";
|
|
3
3
|
import pc from "picocolors";
|
|
4
4
|
import { merge } from "merge-anything";
|
|
5
|
-
import { BORDER_REQUIRED_PROPERTIES, COLOR_SPACE, 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, tokenToColor } from "@terrazzo/token-tools";
|
|
6
5
|
import { contrastWCAG21, inGamut } from "colorjs.io/fn";
|
|
7
6
|
import { camelCase, kebabCase, pascalCase, snakeCase } from "scule";
|
|
8
7
|
import { bundle, encodeFragment, findNode, getObjMember, getObjMembers, isPure$ref, maybeRawJSON, mergeObjects, parseRef, replaceNode, traverse } from "@terrazzo/json-schema-tools";
|
|
@@ -96,9 +95,20 @@ const LOG_ORDER = [
|
|
|
96
95
|
"info",
|
|
97
96
|
"debug"
|
|
98
97
|
];
|
|
98
|
+
const GROUP_COLOR = {
|
|
99
|
+
config: pc.cyan,
|
|
100
|
+
import: pc.green,
|
|
101
|
+
lint: pc.yellowBright,
|
|
102
|
+
parser: pc.magenta,
|
|
103
|
+
plugin: pc.greenBright,
|
|
104
|
+
resolver: pc.magentaBright,
|
|
105
|
+
server: pc.gray
|
|
106
|
+
};
|
|
99
107
|
const MESSAGE_COLOR = {
|
|
100
108
|
error: pc.red,
|
|
101
|
-
warn: pc.yellow
|
|
109
|
+
warn: pc.yellow,
|
|
110
|
+
info: (msg) => msg,
|
|
111
|
+
debug: pc.gray
|
|
102
112
|
};
|
|
103
113
|
const timeFormatter = new Intl.DateTimeFormat("en-us", {
|
|
104
114
|
hour: "numeric",
|
|
@@ -113,9 +123,10 @@ const timeFormatter = new Intl.DateTimeFormat("en-us", {
|
|
|
113
123
|
* @return {string}
|
|
114
124
|
*/
|
|
115
125
|
function formatMessage(entry, severity) {
|
|
126
|
+
const groupColor = GROUP_COLOR[entry.group];
|
|
127
|
+
const messageColor = MESSAGE_COLOR[severity];
|
|
116
128
|
let message = entry.message;
|
|
117
|
-
message =
|
|
118
|
-
if (severity in MESSAGE_COLOR) message = MESSAGE_COLOR[severity](message);
|
|
129
|
+
message = `${groupColor(`${entry.group}${entry.label ? `:${entry.label}` : ""}:`)} ${messageColor(message)}`;
|
|
119
130
|
if (typeof entry.timing === "number") message = `${message} ${formatTiming(entry.timing)}`;
|
|
120
131
|
if (entry.node) {
|
|
121
132
|
const start = entry.node?.loc?.start ?? {
|
|
@@ -128,6 +139,7 @@ function formatMessage(entry, severity) {
|
|
|
128
139
|
}
|
|
129
140
|
return message;
|
|
130
141
|
}
|
|
142
|
+
const debugMatch = new CachedWildcardMatcher();
|
|
131
143
|
var Logger = class {
|
|
132
144
|
level = "info";
|
|
133
145
|
debugScope = "*";
|
|
@@ -179,7 +191,7 @@ var Logger = class {
|
|
|
179
191
|
this.debugCount++;
|
|
180
192
|
let message = formatMessage(entry, "debug");
|
|
181
193
|
const debugPrefix = entry.label ? `${entry.group}:${entry.label}` : entry.group;
|
|
182
|
-
if (this.debugScope !== "*" && !
|
|
194
|
+
if (this.debugScope !== "*" && !debugMatch.match(this.debugScope)(debugPrefix)) return;
|
|
183
195
|
message.replace(/\[config[^\]]+\]/, (match) => pc.green(match)).replace(/\[parser[^\]]+\]/, (match) => pc.magenta(match)).replace(/\[lint[^\]]+\]/, (match) => pc.yellow(match)).replace(/\[plugin[^\]]+\]/, (match) => pc.cyan(match));
|
|
184
196
|
message = `${pc.dim(timeFormatter.format(performance.now()))} ${message}`;
|
|
185
197
|
if (typeof entry.timing === "number") message = `${message} ${formatTiming(entry.timing)}`;
|
|
@@ -231,6 +243,7 @@ function validateTransformParams({ params, logger, pluginName }) {
|
|
|
231
243
|
});
|
|
232
244
|
}
|
|
233
245
|
const FALLBACK_PERMUTATION_ID = JSON.stringify({ tzMode: "*" });
|
|
246
|
+
const cachedMatcher$1 = new CachedWildcardMatcher();
|
|
234
247
|
/** Run build stage */
|
|
235
248
|
async function build(tokens, { resolver, sources, logger = new Logger(), config }) {
|
|
236
249
|
const formats = {};
|
|
@@ -245,84 +258,95 @@ async function build(tokens, { resolver, sources, logger = new Logger(), config
|
|
|
245
258
|
});
|
|
246
259
|
return [];
|
|
247
260
|
}
|
|
248
|
-
const
|
|
249
|
-
const
|
|
250
|
-
const
|
|
261
|
+
const isLegacyModes = params.input && Object.keys(params.input).length === 1 && "tzMode" in params.input;
|
|
262
|
+
const permutationID = params.input && !isLegacyModes ? resolver.getPermutationID(params.input) : FALLBACK_PERMUTATION_ID;
|
|
263
|
+
const mode = params.mode || isLegacyModes && params.input.tzMode || void 0;
|
|
264
|
+
const singleTokenID = typeof params.id === "string" && tokens[params.id]?.id || Array.isArray(params.id) && params.id.length === 1 && tokens[params.id[0]]?.id || void 0;
|
|
265
|
+
const $type = typeof params.$type === "string" && [params.$type] || Array.isArray(params.$type) && params.$type || void 0;
|
|
266
|
+
const idMatcher = params.id && !singleTokenID && !isFullWildcard(params.id) ? cachedMatcher$1.tokenIDMatch(params.id) : null;
|
|
267
|
+
const modeMatcher = mode && mode !== "." && !isFullWildcard(mode) ? cachedMatcher$1.match(mode) : null;
|
|
251
268
|
return (formats[params.format]?.[permutationID] ?? []).filter((token) => {
|
|
252
|
-
if (
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
}
|
|
256
|
-
if (tokenMatcher && !tokenMatcher(token.token.id)) return false;
|
|
257
|
-
if (params.input && token.permutationID !== resolver.getPermutationID(params.input)) return false;
|
|
258
|
-
if (modeMatcher && !modeMatcher(token.mode)) return false;
|
|
269
|
+
if (singleTokenID && token.id !== singleTokenID || idMatcher && !idMatcher(token.id)) return false;
|
|
270
|
+
if (params.$type && !$type?.some((value) => token.token.$type === value)) return false;
|
|
271
|
+
if (mode === "." && token.mode !== "." || modeMatcher && !modeMatcher(token.mode)) return false;
|
|
259
272
|
return true;
|
|
260
273
|
});
|
|
261
274
|
};
|
|
262
275
|
}
|
|
263
276
|
let transformsLocked = false;
|
|
264
277
|
const startTransform = performance.now();
|
|
265
|
-
for (const plugin of config.plugins) if (typeof plugin.transform === "function")
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
278
|
+
for (const plugin of config.plugins) if (typeof plugin.transform === "function") {
|
|
279
|
+
const pt = performance.now();
|
|
280
|
+
await plugin.transform({
|
|
281
|
+
context: { logger },
|
|
282
|
+
tokens,
|
|
283
|
+
sources,
|
|
284
|
+
getTransforms: getTransforms(plugin.name),
|
|
285
|
+
setTransform(id, params) {
|
|
286
|
+
if (transformsLocked) {
|
|
287
|
+
logger.warn({
|
|
288
|
+
message: "Attempted to call setTransform() after transform step has completed.",
|
|
289
|
+
group: "plugin",
|
|
290
|
+
label: plugin.name
|
|
291
|
+
});
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
const token = tokens[id];
|
|
295
|
+
if (!token) logger.error({
|
|
274
296
|
group: "plugin",
|
|
275
|
-
label: plugin.name
|
|
297
|
+
label: plugin.name,
|
|
298
|
+
message: `No token "${id}"`
|
|
276
299
|
});
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
if (!formats[params.format]) formats[params.format] = {};
|
|
291
|
-
if (!formats[params.format][permutationID]) formats[params.format][permutationID] = [];
|
|
292
|
-
let foundTokenI = -1;
|
|
293
|
-
if (params.mode) foundTokenI = formats[params.format][permutationID].findIndex((t) => id === t.id && (!params.localID || params.localID === t.localID) && params.mode === t.mode);
|
|
294
|
-
else if (params.input) {
|
|
300
|
+
const isLegacyModes = params.input && Object.keys(params.input).length === 1 && "tzMode" in params.input;
|
|
301
|
+
const permutationID = params.input && !isLegacyModes ? resolver.getPermutationID(params.input) : FALLBACK_PERMUTATION_ID;
|
|
302
|
+
const mode = params.mode || isLegacyModes && params.input.tzMode || void 0;
|
|
303
|
+
const cleanValue = typeof params.value === "string" ? params.value : { ...params.value };
|
|
304
|
+
validateTransformParams({
|
|
305
|
+
logger,
|
|
306
|
+
params: {
|
|
307
|
+
...params,
|
|
308
|
+
value: cleanValue
|
|
309
|
+
},
|
|
310
|
+
pluginName: plugin.name
|
|
311
|
+
});
|
|
312
|
+
if (!formats[params.format]) formats[params.format] = {};
|
|
295
313
|
if (!formats[params.format][permutationID]) formats[params.format][permutationID] = [];
|
|
296
|
-
foundTokenI = formats[params.format][permutationID].findIndex((t) => id === t.id && (!params.localID || params.localID === t.localID) &&
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
314
|
+
const foundTokenI = formats[params.format][permutationID].findIndex((t) => id === t.id && (!params.localID || params.localID === t.localID) && (!mode || t.mode === mode));
|
|
315
|
+
if (foundTokenI === -1) formats[params.format][permutationID].push({
|
|
316
|
+
...params,
|
|
317
|
+
id,
|
|
318
|
+
value: cleanValue,
|
|
319
|
+
type: typeof cleanValue === "string" ? SINGLE_VALUE : MULTI_VALUE,
|
|
320
|
+
mode: mode || ".",
|
|
321
|
+
token: makeReadOnlyToken(token),
|
|
322
|
+
permutationID,
|
|
323
|
+
input: JSON.parse(permutationID)
|
|
324
|
+
});
|
|
325
|
+
else {
|
|
326
|
+
formats[params.format][permutationID][foundTokenI].value = cleanValue;
|
|
327
|
+
formats[params.format][permutationID][foundTokenI].type = typeof cleanValue === "string" ? SINGLE_VALUE : MULTI_VALUE;
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
resolver
|
|
331
|
+
});
|
|
332
|
+
logger.debug({
|
|
333
|
+
group: "plugin",
|
|
334
|
+
label: plugin.name,
|
|
335
|
+
message: "transform()",
|
|
336
|
+
timing: performance.now() - pt
|
|
337
|
+
});
|
|
338
|
+
}
|
|
315
339
|
transformsLocked = true;
|
|
316
340
|
logger.debug({
|
|
317
341
|
group: "parser",
|
|
318
342
|
label: "transform",
|
|
319
|
-
message: "transform()
|
|
343
|
+
message: "All plugins finished transform()",
|
|
320
344
|
timing: performance.now() - startTransform
|
|
321
345
|
});
|
|
322
346
|
const startBuild = performance.now();
|
|
323
347
|
await Promise.all(config.plugins.map(async (plugin) => {
|
|
324
348
|
if (typeof plugin.build === "function") {
|
|
325
|
-
const
|
|
349
|
+
const pb = performance.now();
|
|
326
350
|
await plugin.build({
|
|
327
351
|
context: { logger },
|
|
328
352
|
tokens,
|
|
@@ -340,18 +364,25 @@ async function build(tokens, { resolver, sources, logger = new Logger(), config
|
|
|
340
364
|
filename,
|
|
341
365
|
contents,
|
|
342
366
|
plugin: plugin.name,
|
|
343
|
-
time: performance.now() -
|
|
367
|
+
time: performance.now() - pb
|
|
344
368
|
});
|
|
345
369
|
}
|
|
346
370
|
});
|
|
371
|
+
logger.debug({
|
|
372
|
+
group: "plugin",
|
|
373
|
+
label: plugin.name,
|
|
374
|
+
message: "build()",
|
|
375
|
+
timing: performance.now() - pb
|
|
376
|
+
});
|
|
347
377
|
}
|
|
348
378
|
}));
|
|
349
379
|
logger.debug({
|
|
350
380
|
group: "parser",
|
|
351
381
|
label: "build",
|
|
352
|
-
message: "build()
|
|
382
|
+
message: "All plugins finished build()",
|
|
353
383
|
timing: performance.now() - startBuild
|
|
354
384
|
});
|
|
385
|
+
cachedMatcher$1.reset();
|
|
355
386
|
const startBuildEnd = performance.now();
|
|
356
387
|
await Promise.all(config.plugins.map(async (plugin) => plugin.buildEnd?.({
|
|
357
388
|
context: { logger },
|
|
@@ -368,6 +399,65 @@ async function build(tokens, { resolver, sources, logger = new Logger(), config
|
|
|
368
399
|
});
|
|
369
400
|
return result;
|
|
370
401
|
}
|
|
402
|
+
function isFullWildcard(value) {
|
|
403
|
+
return typeof value === "string" && (value === "*" || value === "**") || Array.isArray(value) && value.some((v) => v === "*" || v === "**");
|
|
404
|
+
}
|
|
405
|
+
/** Generate getters for transformed tokens. Reduces memory usage while improving accuracy. Provides some safety for read-only values. */
|
|
406
|
+
function makeReadOnlyToken(token) {
|
|
407
|
+
return {
|
|
408
|
+
get id() {
|
|
409
|
+
return token.id;
|
|
410
|
+
},
|
|
411
|
+
get $value() {
|
|
412
|
+
return token.$value;
|
|
413
|
+
},
|
|
414
|
+
get $type() {
|
|
415
|
+
return token.$type;
|
|
416
|
+
},
|
|
417
|
+
get $description() {
|
|
418
|
+
return token.$description;
|
|
419
|
+
},
|
|
420
|
+
get $deprecated() {
|
|
421
|
+
return token.$deprecated;
|
|
422
|
+
},
|
|
423
|
+
get $extends() {
|
|
424
|
+
return token.$extends;
|
|
425
|
+
},
|
|
426
|
+
get $extensions() {
|
|
427
|
+
return token.$extensions;
|
|
428
|
+
},
|
|
429
|
+
get mode() {
|
|
430
|
+
return token.mode;
|
|
431
|
+
},
|
|
432
|
+
get originalValue() {
|
|
433
|
+
return token.originalValue;
|
|
434
|
+
},
|
|
435
|
+
get aliasChain() {
|
|
436
|
+
return token.aliasChain;
|
|
437
|
+
},
|
|
438
|
+
get aliasOf() {
|
|
439
|
+
return token.aliasOf;
|
|
440
|
+
},
|
|
441
|
+
get partialAliasOf() {
|
|
442
|
+
return token.partialAliasOf;
|
|
443
|
+
},
|
|
444
|
+
get aliasedBy() {
|
|
445
|
+
return token.aliasedBy;
|
|
446
|
+
},
|
|
447
|
+
get group() {
|
|
448
|
+
return token.group;
|
|
449
|
+
},
|
|
450
|
+
get source() {
|
|
451
|
+
return token.source;
|
|
452
|
+
},
|
|
453
|
+
get jsonID() {
|
|
454
|
+
return token.jsonID;
|
|
455
|
+
},
|
|
456
|
+
get dependencies() {
|
|
457
|
+
return token.dependencies;
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
}
|
|
371
461
|
|
|
372
462
|
//#endregion
|
|
373
463
|
//#region src/lint/plugin-core/lib/docs.ts
|
|
@@ -423,6 +513,22 @@ const rule$26 = {
|
|
|
423
513
|
}
|
|
424
514
|
};
|
|
425
515
|
|
|
516
|
+
//#endregion
|
|
517
|
+
//#region src/lint/plugin-core/lib/matchers.ts
|
|
518
|
+
/**
|
|
519
|
+
* Share one cached matcher factory for all lint plugins.
|
|
520
|
+
*
|
|
521
|
+
* Creating matchers is CPU-intensive, however, if we made one matcher for very
|
|
522
|
+
* getTransform plugin query, we could end up with tens of thousands of
|
|
523
|
+
* matchers, all taking up space in memory, but without providing any caching
|
|
524
|
+
* benefits if a matcher is used only once. So a reasonable balance is we
|
|
525
|
+
* maintain one cache per task category, and we garbage-collect everything after
|
|
526
|
+
* it’s done. Lint tasks are likely to have frequently-occurring patterns. So
|
|
527
|
+
* we’d expect for most use cases a shared lint cache has benefits, but only
|
|
528
|
+
* so long as this doesn’t spread to other plugins and other task categories.
|
|
529
|
+
*/
|
|
530
|
+
const cachedLintMatcher = new CachedWildcardMatcher();
|
|
531
|
+
|
|
426
532
|
//#endregion
|
|
427
533
|
//#region src/lint/plugin-core/rules/a11y-min-font-size.ts
|
|
428
534
|
const A11Y_MIN_FONT_SIZE = "a11y/min-font-size";
|
|
@@ -438,7 +544,7 @@ const rule$25 = {
|
|
|
438
544
|
defaultOptions: {},
|
|
439
545
|
create({ tokens, options, report }) {
|
|
440
546
|
if (!options.minSizePx && !options.minSizeRem) throw new Error("Must specify at least one of minSizePx or minSizeRem");
|
|
441
|
-
const shouldIgnore = options.ignore ?
|
|
547
|
+
const shouldIgnore = options.ignore ? cachedLintMatcher.tokenIDMatch(options.ignore) : null;
|
|
442
548
|
for (const t of Object.values(tokens)) {
|
|
443
549
|
if (shouldIgnore?.(t.id)) continue;
|
|
444
550
|
if (t.aliasOf) continue;
|
|
@@ -479,7 +585,7 @@ const rule$24 = {
|
|
|
479
585
|
defaultOptions: { colorSpace: "srgb" },
|
|
480
586
|
create({ tokens, options, report }) {
|
|
481
587
|
if (!options.colorSpace) return;
|
|
482
|
-
const shouldIgnore = options.ignore ?
|
|
588
|
+
const shouldIgnore = options.ignore ? cachedLintMatcher.tokenIDMatch(options.ignore) : null;
|
|
483
589
|
for (const t of Object.values(tokens)) {
|
|
484
590
|
if (shouldIgnore?.(t.id)) continue;
|
|
485
591
|
if (t.aliasOf) continue;
|
|
@@ -590,7 +696,7 @@ const rule$22 = {
|
|
|
590
696
|
},
|
|
591
697
|
defaultOptions: {},
|
|
592
698
|
create({ tokens, options, report }) {
|
|
593
|
-
const shouldIgnore = options.ignore ?
|
|
699
|
+
const shouldIgnore = options.ignore ? cachedLintMatcher.tokenIDMatch(options.ignore) : null;
|
|
594
700
|
for (const t of Object.values(tokens)) {
|
|
595
701
|
if (shouldIgnore?.(t.id)) continue;
|
|
596
702
|
if (!t.$description) report({
|
|
@@ -617,7 +723,7 @@ const rule$21 = {
|
|
|
617
723
|
defaultOptions: {},
|
|
618
724
|
create({ report, tokens, options }) {
|
|
619
725
|
const values = {};
|
|
620
|
-
const shouldIgnore = options.ignore ?
|
|
726
|
+
const shouldIgnore = options.ignore ? cachedLintMatcher.tokenIDMatch(options.ignore) : null;
|
|
621
727
|
for (const t of Object.values(tokens)) {
|
|
622
728
|
if (shouldIgnore?.(t.id)) continue;
|
|
623
729
|
if (!values[t.$type]) values[t.$type] = /* @__PURE__ */ new Set();
|
|
@@ -670,7 +776,7 @@ const rule$20 = {
|
|
|
670
776
|
create({ tokens, options, report }) {
|
|
671
777
|
if (!options?.gamut) return;
|
|
672
778
|
if (options.gamut !== "srgb" && options.gamut !== "p3" && options.gamut !== "rec2020") throw new Error(`Unknown gamut "${options.gamut}". Options are "srgb", "p3", or "rec2020"`);
|
|
673
|
-
const shouldIgnore = options.ignore ?
|
|
779
|
+
const shouldIgnore = options.ignore ? cachedLintMatcher.tokenIDMatch(options.ignore) : null;
|
|
674
780
|
for (const t of Object.values(tokens)) {
|
|
675
781
|
if (shouldIgnore?.(t.id)) continue;
|
|
676
782
|
if (t.aliasOf) continue;
|
|
@@ -749,7 +855,7 @@ const rule$19 = {
|
|
|
749
855
|
const { match, requiredTokens, requiredGroups } = options.matches[matchI];
|
|
750
856
|
if (!match.length) throw new Error(`Match ${matchI}: must declare \`match: […]\``);
|
|
751
857
|
if (!requiredTokens?.length && !requiredGroups?.length) throw new Error(`Match ${matchI}: must declare either \`requiredTokens: […]\` or \`requiredGroups: […]\``);
|
|
752
|
-
const matcher =
|
|
858
|
+
const matcher = cachedLintMatcher.tokenIDMatch(match);
|
|
753
859
|
const matchGroups = [];
|
|
754
860
|
const matchTokens = [];
|
|
755
861
|
let tokensMatched = false;
|
|
@@ -804,7 +910,7 @@ const rule$18 = {
|
|
|
804
910
|
const { match, modes } = options.matches[matchI];
|
|
805
911
|
if (!match.length) throw new Error(`Match ${matchI}: must declare \`match: […]\``);
|
|
806
912
|
if (!modes?.length) throw new Error(`Match ${matchI}: must declare \`modes: […]\``);
|
|
807
|
-
const matcher =
|
|
913
|
+
const matcher = cachedLintMatcher.tokenIDMatch(match);
|
|
808
914
|
let tokensMatched = false;
|
|
809
915
|
for (const t of Object.values(tokens)) {
|
|
810
916
|
if (!matcher(t.id)) continue;
|
|
@@ -865,7 +971,7 @@ const rule$16 = {
|
|
|
865
971
|
create({ tokens, options, report }) {
|
|
866
972
|
if (!options) return;
|
|
867
973
|
if (!options.properties.length) throw new Error(`"properties" can’t be empty`);
|
|
868
|
-
const shouldIgnore = options.ignore ?
|
|
974
|
+
const shouldIgnore = options.ignore ? cachedLintMatcher.tokenIDMatch(options.ignore) : null;
|
|
869
975
|
for (const t of Object.values(tokens)) {
|
|
870
976
|
if (shouldIgnore?.(t.id)) continue;
|
|
871
977
|
if (t.$type !== "typography") continue;
|
|
@@ -1376,7 +1482,7 @@ const rule$6 = {
|
|
|
1376
1482
|
"lineHeight"
|
|
1377
1483
|
] },
|
|
1378
1484
|
create({ tokens, options, report }) {
|
|
1379
|
-
const isIgnored = options.ignore ?
|
|
1485
|
+
const isIgnored = options.ignore ? cachedLintMatcher.tokenIDMatch(options.ignore) : () => false;
|
|
1380
1486
|
for (const t of Object.values(tokens)) {
|
|
1381
1487
|
if (t.aliasOf || !t.originalValue || t.$type !== "typography" || isIgnored(t.id)) continue;
|
|
1382
1488
|
validateTypography(t.originalValue.$value, {
|
|
@@ -2100,13 +2206,11 @@ function normalizeTokens({ rawConfig, config, logger, cwd }) {
|
|
|
2100
2206
|
for (const file of rawConfig.tokens) if (typeof file === "string" || file instanceof URL) config.tokens.push(file);
|
|
2101
2207
|
else logger.error({
|
|
2102
2208
|
group: "config",
|
|
2103
|
-
|
|
2104
|
-
message: `Expected array of strings, encountered ${JSON.stringify(file)}`
|
|
2209
|
+
message: `tokens: Expected array of strings, encountered ${JSON.stringify(file)}`
|
|
2105
2210
|
});
|
|
2106
2211
|
} else logger.error({
|
|
2107
2212
|
group: "config",
|
|
2108
|
-
|
|
2109
|
-
message: `Expected string or array of strings, received ${typeof rawConfig.tokens}`
|
|
2213
|
+
message: `tokens: Expected string or array of strings, received ${typeof rawConfig.tokens}`
|
|
2110
2214
|
});
|
|
2111
2215
|
for (let i = 0; i < config.tokens.length; i++) {
|
|
2112
2216
|
const filepath = config.tokens[i];
|
|
@@ -2128,8 +2232,7 @@ function normalizeOutDir({ config, cwd, logger }) {
|
|
|
2128
2232
|
if (config.outDir instanceof URL) {} else if (typeof config.outDir === "undefined") config.outDir = new URL("./tokens/", cwd);
|
|
2129
2233
|
else if (typeof config.outDir !== "string") logger.error({
|
|
2130
2234
|
group: "config",
|
|
2131
|
-
|
|
2132
|
-
message: `Expected string, received ${JSON.stringify(config.outDir)}`
|
|
2235
|
+
message: `outDir: Expected string, received ${JSON.stringify(config.outDir)}`
|
|
2133
2236
|
});
|
|
2134
2237
|
else {
|
|
2135
2238
|
config.outDir = new URL(config.outDir, cwd);
|
|
@@ -2141,16 +2244,14 @@ function normalizePlugins({ config, logger }) {
|
|
|
2141
2244
|
if (typeof config.plugins === "undefined") config.plugins = [];
|
|
2142
2245
|
if (!Array.isArray(config.plugins)) logger.error({
|
|
2143
2246
|
group: "config",
|
|
2144
|
-
|
|
2145
|
-
message: `Expected array of plugins, received ${JSON.stringify(config.plugins)}`
|
|
2247
|
+
message: `plugins: Expected array of plugins, received ${JSON.stringify(config.plugins)}`
|
|
2146
2248
|
});
|
|
2147
2249
|
config.plugins.push(coreLintPlugin());
|
|
2148
2250
|
for (let n = 0; n < config.plugins.length; n++) {
|
|
2149
2251
|
const plugin = config.plugins[n];
|
|
2150
2252
|
if (typeof plugin !== "object") logger.error({
|
|
2151
2253
|
group: "config",
|
|
2152
|
-
|
|
2153
|
-
message: `Expected output plugin, received ${JSON.stringify(plugin)}`
|
|
2254
|
+
message: `plugin#${n}: Expected output plugin, received ${JSON.stringify(plugin)}`
|
|
2154
2255
|
});
|
|
2155
2256
|
else if (!plugin.name) logger.error({
|
|
2156
2257
|
group: "config",
|
|
@@ -2175,8 +2276,7 @@ function normalizeLint({ config, logger }) {
|
|
|
2175
2276
|
if (config.lint.build.enabled !== void 0) {
|
|
2176
2277
|
if (typeof config.lint.build.enabled !== "boolean") logger.error({
|
|
2177
2278
|
group: "config",
|
|
2178
|
-
|
|
2179
|
-
message: `Expected boolean, received ${JSON.stringify(config.lint.build)}`
|
|
2279
|
+
message: `lint.build.enabled: Expected boolean, received ${JSON.stringify(config.lint.build)}`
|
|
2180
2280
|
});
|
|
2181
2281
|
} else config.lint.build.enabled = true;
|
|
2182
2282
|
if (config.lint.rules === void 0) config.lint.rules = { ...RECOMMENDED_CONFIG };
|
|
@@ -2184,8 +2284,7 @@ function normalizeLint({ config, logger }) {
|
|
|
2184
2284
|
if (config.lint.rules === null || typeof config.lint.rules !== "object" || Array.isArray(config.lint.rules)) {
|
|
2185
2285
|
logger.error({
|
|
2186
2286
|
group: "config",
|
|
2187
|
-
|
|
2188
|
-
message: `Expected object, received ${JSON.stringify(config.lint.rules)}`
|
|
2287
|
+
message: `lint.rules: Expected object, received ${JSON.stringify(config.lint.rules)}`
|
|
2189
2288
|
});
|
|
2190
2289
|
return;
|
|
2191
2290
|
}
|
|
@@ -2196,16 +2295,14 @@ function normalizeLint({ config, logger }) {
|
|
|
2196
2295
|
if (!pluginRules || Array.isArray(pluginRules) || typeof pluginRules !== "object") {
|
|
2197
2296
|
logger.error({
|
|
2198
2297
|
group: "config",
|
|
2199
|
-
|
|
2200
|
-
message: `Expected object for lint() received ${JSON.stringify(pluginRules)}`
|
|
2298
|
+
message: `${plugin.name}: Expected object for lint() received ${JSON.stringify(pluginRules)}`
|
|
2201
2299
|
});
|
|
2202
2300
|
continue;
|
|
2203
2301
|
}
|
|
2204
2302
|
for (const rule of Object.keys(pluginRules)) {
|
|
2205
2303
|
if (allRules.get(rule) && allRules.get(rule) !== plugin.name) logger.error({
|
|
2206
2304
|
group: "config",
|
|
2207
|
-
|
|
2208
|
-
message: `Duplicate rule ${rule} already registered by plugin ${allRules.get(rule)}`
|
|
2305
|
+
message: `${plugin.name}: Duplicate rule ${rule} already registered by plugin ${allRules.get(rule)}`
|
|
2209
2306
|
});
|
|
2210
2307
|
allRules.set(rule, plugin.name);
|
|
2211
2308
|
}
|
|
@@ -2213,8 +2310,7 @@ function normalizeLint({ config, logger }) {
|
|
|
2213
2310
|
for (const id of Object.keys(config.lint.rules)) {
|
|
2214
2311
|
if (!allRules.has(id)) logger.error({
|
|
2215
2312
|
group: "config",
|
|
2216
|
-
|
|
2217
|
-
message: "Unknown rule. Is the plugin installed?"
|
|
2313
|
+
message: `lint.rules.${id}: Unknown rule. Is the plugin installed?`
|
|
2218
2314
|
});
|
|
2219
2315
|
const value = config.lint.rules[id];
|
|
2220
2316
|
let severity = "off";
|
|
@@ -2225,15 +2321,13 @@ function normalizeLint({ config, logger }) {
|
|
|
2225
2321
|
options = value[1];
|
|
2226
2322
|
} else if (value !== void 0) logger.error({
|
|
2227
2323
|
group: "config",
|
|
2228
|
-
|
|
2229
|
-
message: `Invalid eyntax. Expected \`string | number | Array\`, received ${JSON.stringify(value)}}`
|
|
2324
|
+
message: `lint.rules.${id}: Invalid syntax. Expected \`string | number | Array\`, received ${JSON.stringify(value)}}`
|
|
2230
2325
|
});
|
|
2231
2326
|
config.lint.rules[id] = [severity, options];
|
|
2232
2327
|
if (typeof severity === "number") {
|
|
2233
2328
|
if (severity !== 0 && severity !== 1 && severity !== 2) logger.error({
|
|
2234
2329
|
group: "config",
|
|
2235
|
-
|
|
2236
|
-
message: `Invalid number ${severity}. Specify 0 (off), 1 (warn), or 2 (error).`
|
|
2330
|
+
message: `lint.rules.${id}: Invalid number ${severity}. Specify 0 (off), 1 (warn), or 2 (error).`
|
|
2237
2331
|
});
|
|
2238
2332
|
config.lint.rules[id][0] = [
|
|
2239
2333
|
"off",
|
|
@@ -2243,13 +2337,11 @@ function normalizeLint({ config, logger }) {
|
|
|
2243
2337
|
} else if (typeof severity === "string") {
|
|
2244
2338
|
if (severity !== "off" && severity !== "warn" && severity !== "error") logger.error({
|
|
2245
2339
|
group: "config",
|
|
2246
|
-
|
|
2247
|
-
message: `Invalid string ${JSON.stringify(severity)}. Specify "off", "warn", or "error".`
|
|
2340
|
+
message: `lint.rules.${id}: Invalid string ${JSON.stringify(severity)}. Specify "off", "warn", or "error".`
|
|
2248
2341
|
});
|
|
2249
2342
|
} else if (value !== null) logger.error({
|
|
2250
2343
|
group: "config",
|
|
2251
|
-
|
|
2252
|
-
message: `Expected string or number, received ${JSON.stringify(value)}`
|
|
2344
|
+
message: `lint.rules.${id}: Expected string or number, received ${JSON.stringify(value)}`
|
|
2253
2345
|
});
|
|
2254
2346
|
}
|
|
2255
2347
|
}
|
|
@@ -2264,13 +2356,11 @@ function normalizeIgnore({ config, logger }) {
|
|
|
2264
2356
|
config.ignore.deprecated ??= false;
|
|
2265
2357
|
if (!Array.isArray(config.ignore.tokens) || config.ignore.tokens.some((x) => typeof x !== "string")) logger.error({
|
|
2266
2358
|
group: "config",
|
|
2267
|
-
|
|
2268
|
-
message: `Expected array of strings, received ${JSON.stringify(config.ignore.tokens)}`
|
|
2359
|
+
message: `ignore.tokens: Expected array of strings, received ${JSON.stringify(config.ignore.tokens)}`
|
|
2269
2360
|
});
|
|
2270
2361
|
if (typeof config.ignore.deprecated !== "boolean") logger.error({
|
|
2271
2362
|
group: "config",
|
|
2272
|
-
|
|
2273
|
-
message: `Expected boolean, received ${JSON.stringify(config.ignore.deprecated)}`
|
|
2363
|
+
message: `ignore.deprecated: Expected boolean, received ${JSON.stringify(config.ignore.deprecated)}`
|
|
2274
2364
|
});
|
|
2275
2365
|
}
|
|
2276
2366
|
/** Merge configs */
|
|
@@ -2345,6 +2435,7 @@ async function lintRunner({ tokens, filename, config = {}, sources, logger }) {
|
|
|
2345
2435
|
message: "Finished",
|
|
2346
2436
|
timing: performance.now() - s
|
|
2347
2437
|
});
|
|
2438
|
+
cachedLintMatcher.reset();
|
|
2348
2439
|
}
|
|
2349
2440
|
const errCount = errors.length ? `${errors.length} ${pluralize(errors.length, "error", "errors")}` : "";
|
|
2350
2441
|
const warnCount = warnings.length ? `${warnings.length} ${pluralize(warnings.length, "warning", "warnings")}` : "";
|
|
@@ -2376,6 +2467,13 @@ function toMomoa(srcRaw) {
|
|
|
2376
2467
|
});
|
|
2377
2468
|
}
|
|
2378
2469
|
|
|
2470
|
+
//#endregion
|
|
2471
|
+
//#region src/lib/array.ts
|
|
2472
|
+
/** JS compiler-optimizable comparator */
|
|
2473
|
+
function alphaComparator(a, b) {
|
|
2474
|
+
return a.localeCompare(b, "en-us", { numeric: true });
|
|
2475
|
+
}
|
|
2476
|
+
|
|
2379
2477
|
//#endregion
|
|
2380
2478
|
//#region src/lib/resolver-utils.ts
|
|
2381
2479
|
/**
|
|
@@ -2397,8 +2495,32 @@ function filterResolverPaths(path) {
|
|
|
2397
2495
|
}
|
|
2398
2496
|
/** Make a deterministic string from an object */
|
|
2399
2497
|
function getPermutationID(input) {
|
|
2400
|
-
const keys = Object.keys(input).sort(
|
|
2401
|
-
|
|
2498
|
+
const keys = Object.keys(input).sort(alphaComparator);
|
|
2499
|
+
const sortedInput = {};
|
|
2500
|
+
for (const k of keys) sortedInput[k] = input[k];
|
|
2501
|
+
return JSON.stringify(sortedInput);
|
|
2502
|
+
}
|
|
2503
|
+
/**
|
|
2504
|
+
* Destructively merge B into A, with B overwriting A
|
|
2505
|
+
*
|
|
2506
|
+
* This is needed for resolvers because we need a really performant way to merge
|
|
2507
|
+
* token sets. merge-anything is a package we use for merging more complex
|
|
2508
|
+
* configurations like terrazzo.config.ts files, but that’s too slow for tokens.
|
|
2509
|
+
*/
|
|
2510
|
+
function destructiveMerge(a, b) {
|
|
2511
|
+
if (!a || !b || typeof b !== "object") return;
|
|
2512
|
+
for (const k in b) {
|
|
2513
|
+
if (!Object.hasOwn(b, k)) continue;
|
|
2514
|
+
const b2 = b[k];
|
|
2515
|
+
if (b2 != null && typeof b2 === "object") if (Array.isArray(b2)) {
|
|
2516
|
+
a[k] = [];
|
|
2517
|
+
destructiveMerge(a[k], [...b2]);
|
|
2518
|
+
} else {
|
|
2519
|
+
if (!(k in a)) a[k] = {};
|
|
2520
|
+
destructiveMerge(a[k], { ...b2 });
|
|
2521
|
+
}
|
|
2522
|
+
else a[k] = b2;
|
|
2523
|
+
}
|
|
2402
2524
|
}
|
|
2403
2525
|
|
|
2404
2526
|
//#endregion
|
|
@@ -2459,15 +2581,12 @@ function normalize(token, { logger, src }) {
|
|
|
2459
2581
|
switch (token.$type) {
|
|
2460
2582
|
case "color":
|
|
2461
2583
|
for (const mode of Object.keys(token.mode)) token.mode[mode].$value = normalizeColor(token.mode[mode].$value, token.mode[mode].source.node);
|
|
2462
|
-
token.$value = token.mode["."].$value;
|
|
2463
2584
|
break;
|
|
2464
2585
|
case "fontFamily":
|
|
2465
2586
|
for (const mode of Object.keys(token.mode)) token.mode[mode].$value = normalizeFontFamily(token.mode[mode].$value);
|
|
2466
|
-
token.$value = token.mode["."].$value;
|
|
2467
2587
|
break;
|
|
2468
2588
|
case "fontWeight":
|
|
2469
2589
|
for (const mode of Object.keys(token.mode)) token.mode[mode].$value = normalizeFontWeight(token.mode[mode].$value);
|
|
2470
|
-
token.$value = token.mode["."].$value;
|
|
2471
2590
|
break;
|
|
2472
2591
|
case "border":
|
|
2473
2592
|
for (const mode of Object.keys(token.mode)) {
|
|
@@ -2475,7 +2594,6 @@ function normalize(token, { logger, src }) {
|
|
|
2475
2594
|
if (!border || typeof border !== "object") continue;
|
|
2476
2595
|
if (border.color) border.color = normalizeColor(border.color, getObjMember(token.mode[mode].source.node, "color"));
|
|
2477
2596
|
}
|
|
2478
|
-
token.$value = token.mode["."].$value;
|
|
2479
2597
|
break;
|
|
2480
2598
|
case "shadow":
|
|
2481
2599
|
for (const mode of Object.keys(token.mode)) {
|
|
@@ -2489,7 +2607,6 @@ function normalize(token, { logger, src }) {
|
|
|
2489
2607
|
if (!("inset" in shadow)) shadow.inset = false;
|
|
2490
2608
|
}
|
|
2491
2609
|
}
|
|
2492
|
-
token.$value = token.mode["."].$value;
|
|
2493
2610
|
break;
|
|
2494
2611
|
case "gradient":
|
|
2495
2612
|
for (const mode of Object.keys(token.mode)) {
|
|
@@ -2502,7 +2619,6 @@ function normalize(token, { logger, src }) {
|
|
|
2502
2619
|
if (stop.color) stop.color = normalizeColor(stop.color, getObjMember(stopNode, "color"));
|
|
2503
2620
|
}
|
|
2504
2621
|
}
|
|
2505
|
-
token.$value = token.mode["."].$value;
|
|
2506
2622
|
break;
|
|
2507
2623
|
case "typography":
|
|
2508
2624
|
for (const mode of Object.keys(token.mode)) {
|
|
@@ -2517,7 +2633,6 @@ function normalize(token, { logger, src }) {
|
|
|
2517
2633
|
break;
|
|
2518
2634
|
}
|
|
2519
2635
|
}
|
|
2520
|
-
token.$value = token.mode["."].$value;
|
|
2521
2636
|
break;
|
|
2522
2637
|
}
|
|
2523
2638
|
}
|
|
@@ -2536,6 +2651,7 @@ function aliasToTokenRef(alias, mode) {
|
|
|
2536
2651
|
if (id === alias) return;
|
|
2537
2652
|
return { $ref: `#/${id.replace(/~/g, "~0").replace(/\//g, "~1").replace(/\./g, "/")}${mode && mode !== "." ? `/$extensions/mode/${mode}` : ""}/$value` };
|
|
2538
2653
|
}
|
|
2654
|
+
const cachedMatcher = new CachedWildcardMatcher();
|
|
2539
2655
|
/** Generate a TokenNormalized from a Momoa node */
|
|
2540
2656
|
function tokenFromNode(node, { groups, path, source, ignore }) {
|
|
2541
2657
|
if (!(node.type === "Object" && !!getObjMember(node, "$value") && !path.includes("$extensions"))) return;
|
|
@@ -2553,33 +2669,45 @@ function tokenFromNode(node, { groups, path, source, ignore }) {
|
|
|
2553
2669
|
$type: originalToken.$type || group.$type,
|
|
2554
2670
|
$description: originalToken.$description || void 0,
|
|
2555
2671
|
$deprecated: originalToken.$deprecated ?? group.$deprecated ?? void 0,
|
|
2556
|
-
$value
|
|
2672
|
+
get $value() {
|
|
2673
|
+
return this.mode["."].$value;
|
|
2674
|
+
},
|
|
2557
2675
|
$extensions: originalToken.$extensions || void 0,
|
|
2558
2676
|
$extends: originalToken.$extends || void 0,
|
|
2559
|
-
aliasChain
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2677
|
+
get aliasChain() {
|
|
2678
|
+
return this.mode["."].aliasChain;
|
|
2679
|
+
},
|
|
2680
|
+
get aliasedBy() {
|
|
2681
|
+
return this.mode["."].aliasedBy;
|
|
2682
|
+
},
|
|
2683
|
+
get aliasOf() {
|
|
2684
|
+
return this.mode["."].aliasOf;
|
|
2685
|
+
},
|
|
2686
|
+
get partialAliasOf() {
|
|
2687
|
+
return this.mode["."].partialAliasOf;
|
|
2688
|
+
},
|
|
2689
|
+
get dependencies() {
|
|
2690
|
+
return this.mode["."].dependencies;
|
|
2691
|
+
},
|
|
2564
2692
|
group,
|
|
2565
2693
|
originalValue: void 0,
|
|
2566
2694
|
source: nodeSource,
|
|
2567
2695
|
jsonID,
|
|
2568
2696
|
mode: { ".": {
|
|
2569
2697
|
$value: originalToken.$value,
|
|
2570
|
-
aliasOf: void 0,
|
|
2571
2698
|
aliasChain: void 0,
|
|
2572
|
-
partialAliasOf: void 0,
|
|
2573
2699
|
aliasedBy: void 0,
|
|
2574
|
-
|
|
2700
|
+
aliasOf: void 0,
|
|
2701
|
+
partialAliasOf: void 0,
|
|
2575
2702
|
dependencies: void 0,
|
|
2703
|
+
originalValue: void 0,
|
|
2576
2704
|
source: {
|
|
2577
2705
|
...nodeSource,
|
|
2578
2706
|
node: getObjMember(nodeSource.node, "$value") ?? nodeSource.node
|
|
2579
2707
|
}
|
|
2580
2708
|
} }
|
|
2581
2709
|
};
|
|
2582
|
-
if (ignore?.deprecated && token.$deprecated || ignore?.tokens &&
|
|
2710
|
+
if (ignore?.deprecated && token.$deprecated || ignore?.tokens && cachedMatcher.tokenIDMatch(ignore.tokens)(token.id)) return;
|
|
2583
2711
|
const $extensions = getObjMember(node, "$extensions");
|
|
2584
2712
|
if ($extensions) {
|
|
2585
2713
|
const modeNode = getObjMember($extensions, "mode");
|
|
@@ -2688,7 +2816,7 @@ function graphAliases(refMap, { tokens, logger, sources }) {
|
|
|
2688
2816
|
if (!modeValue) continue;
|
|
2689
2817
|
if (!modeValue.dependencies) modeValue.dependencies = [];
|
|
2690
2818
|
modeValue.dependencies.push(...refChain.filter((r) => !modeValue.dependencies.includes(r)));
|
|
2691
|
-
modeValue.dependencies.sort(
|
|
2819
|
+
modeValue.dependencies.sort(alphaComparator);
|
|
2692
2820
|
if (jsonID.endsWith("/$value") || tokens[jsonID]) {
|
|
2693
2821
|
modeValue.aliasOf = refToTokenID(refChain.at(-1));
|
|
2694
2822
|
modeValue.aliasChain = [...refChain.map(refToTokenID)];
|
|
@@ -2732,26 +2860,16 @@ function graphAliases(refMap, { tokens, logger, sources }) {
|
|
|
2732
2860
|
const aliasedByRefs = [jsonID, ...refChain].reverse();
|
|
2733
2861
|
for (let i = 0; i < aliasedByRefs.length; i++) {
|
|
2734
2862
|
const baseRef = getTokenRef(aliasedByRefs[i]);
|
|
2735
|
-
const baseToken = tokens[baseRef]?.mode[mode] || tokens[baseRef];
|
|
2863
|
+
const baseToken = tokens[baseRef]?.mode[mode] || tokens[baseRef]?.mode["."];
|
|
2736
2864
|
if (!baseToken) continue;
|
|
2737
2865
|
const upstream = aliasedByRefs.slice(i + 1);
|
|
2738
2866
|
if (!upstream.length) break;
|
|
2739
2867
|
if (!baseToken.aliasedBy) baseToken.aliasedBy = [];
|
|
2740
2868
|
for (let j = 0; j < upstream.length; j++) {
|
|
2741
2869
|
const downstream = refToTokenID(upstream[j]);
|
|
2742
|
-
if (!baseToken.aliasedBy.includes(downstream))
|
|
2743
|
-
baseToken.aliasedBy.push(downstream);
|
|
2744
|
-
if (mode === ".") tokens[baseRef].aliasedBy = baseToken.aliasedBy;
|
|
2745
|
-
}
|
|
2870
|
+
if (!baseToken.aliasedBy.includes(downstream)) baseToken.aliasedBy.push(downstream);
|
|
2746
2871
|
}
|
|
2747
|
-
baseToken.aliasedBy.sort(
|
|
2748
|
-
}
|
|
2749
|
-
if (mode === ".") {
|
|
2750
|
-
tokens[rootRef].aliasChain = modeValue.aliasChain;
|
|
2751
|
-
tokens[rootRef].aliasedBy = modeValue.aliasedBy;
|
|
2752
|
-
tokens[rootRef].aliasOf = modeValue.aliasOf;
|
|
2753
|
-
tokens[rootRef].dependencies = modeValue.dependencies;
|
|
2754
|
-
tokens[rootRef].partialAliasOf = modeValue.partialAliasOf;
|
|
2872
|
+
baseToken.aliasedBy.sort(alphaComparator);
|
|
2755
2873
|
}
|
|
2756
2874
|
}
|
|
2757
2875
|
}
|
|
@@ -2888,7 +3006,6 @@ function resolveAliases(tokens, { logger, refMap, sources }) {
|
|
|
2888
3006
|
});
|
|
2889
3007
|
if (!token.$type) token.$type = $type;
|
|
2890
3008
|
if ($value) token.mode[mode].$value = $value;
|
|
2891
|
-
if (mode === ".") token.$value = token.mode[mode].$value;
|
|
2892
3009
|
}
|
|
2893
3010
|
}
|
|
2894
3011
|
}
|
|
@@ -3049,6 +3166,7 @@ function processTokens(rootSource, { config, logger, sourceByFilename, isResolve
|
|
|
3049
3166
|
});
|
|
3050
3167
|
if (tokenRawValues && tokens[tokenRawValues?.jsonID]) {
|
|
3051
3168
|
tokens[tokenRawValues.jsonID].originalValue = tokenRawValues.originalValue;
|
|
3169
|
+
tokens[tokenRawValues.jsonID].mode["."].originalValue = tokenRawValues.originalValue;
|
|
3052
3170
|
tokens[tokenRawValues.jsonID].source = tokenRawValues.source;
|
|
3053
3171
|
for (const mode of Object.keys(tokenRawValues.mode)) {
|
|
3054
3172
|
tokens[tokenRawValues.jsonID].mode[mode].originalValue = tokenRawValues.mode[mode].originalValue;
|
|
@@ -3093,12 +3211,12 @@ function processTokens(rootSource, { config, logger, sourceByFilename, isResolve
|
|
|
3093
3211
|
if (config.alphabetize === false) return tokens;
|
|
3094
3212
|
const sortStart = performance.now();
|
|
3095
3213
|
const tokensSorted = {};
|
|
3096
|
-
tokenIDs.sort(
|
|
3214
|
+
tokenIDs.sort(alphaComparator);
|
|
3097
3215
|
for (const path of tokenIDs) {
|
|
3098
3216
|
const id = refToTokenID(path);
|
|
3099
3217
|
tokensSorted[id] = tokens[path];
|
|
3100
3218
|
}
|
|
3101
|
-
for (const group of Object.values(groups)) group.tokens.sort(
|
|
3219
|
+
for (const group of Object.values(groups)) group.tokens.sort(alphaComparator);
|
|
3102
3220
|
logger.debug({
|
|
3103
3221
|
...entry,
|
|
3104
3222
|
message: "Sorted tokens",
|
|
@@ -3682,7 +3800,7 @@ function createResolver(resolverSource, { config, logger, sources }) {
|
|
|
3682
3800
|
}
|
|
3683
3801
|
return {
|
|
3684
3802
|
apply(inputRaw) {
|
|
3685
|
-
|
|
3803
|
+
const tokensRaw = {};
|
|
3686
3804
|
const input = {
|
|
3687
3805
|
...inputDefaults,
|
|
3688
3806
|
...inputRaw
|
|
@@ -3691,7 +3809,7 @@ function createResolver(resolverSource, { config, logger, sources }) {
|
|
|
3691
3809
|
if (resolverCache[permutationID]) return resolverCache[permutationID];
|
|
3692
3810
|
for (const item of resolverSource.resolutionOrder) switch (item.type) {
|
|
3693
3811
|
case "set":
|
|
3694
|
-
for (const s of item.sources)
|
|
3812
|
+
for (const s of item.sources) destructiveMerge(tokensRaw, s);
|
|
3695
3813
|
break;
|
|
3696
3814
|
case "modifier": {
|
|
3697
3815
|
const context = input[item.name];
|
|
@@ -3700,7 +3818,7 @@ function createResolver(resolverSource, { config, logger, sources }) {
|
|
|
3700
3818
|
group: "resolver",
|
|
3701
3819
|
message: `Modifier ${item.name} has no context ${JSON.stringify(context)}.`
|
|
3702
3820
|
});
|
|
3703
|
-
for (const s of sources ?? [])
|
|
3821
|
+
for (const s of sources ?? []) destructiveMerge(tokensRaw, s);
|
|
3704
3822
|
break;
|
|
3705
3823
|
}
|
|
3706
3824
|
}
|
|
@@ -3738,6 +3856,7 @@ function createResolver(resolverSource, { config, logger, sources }) {
|
|
|
3738
3856
|
return false;
|
|
3739
3857
|
}
|
|
3740
3858
|
for (const [name, contexts] of Object.entries(validContexts)) if (name in input) {
|
|
3859
|
+
if (name === "tzMode") continue;
|
|
3741
3860
|
if (!contexts.includes(input[name])) {
|
|
3742
3861
|
if (throwError) logger.error({
|
|
3743
3862
|
group: "resolver",
|
|
@@ -3787,7 +3906,6 @@ function calculatePermutations(options) {
|
|
|
3787
3906
|
async function createSyntheticResolver(tokens, { config, logger, req, sources }) {
|
|
3788
3907
|
const contexts = {};
|
|
3789
3908
|
for (const token of Object.values(tokens)) for (const [mode, value] of Object.entries(token.mode)) {
|
|
3790
|
-
if (mode === ".") continue;
|
|
3791
3909
|
if (!(mode in contexts)) contexts[mode] = [{}];
|
|
3792
3910
|
addToken(contexts[mode][0], {
|
|
3793
3911
|
...token,
|
|
@@ -3801,7 +3919,8 @@ async function createSyntheticResolver(tokens, { config, logger, req, sources })
|
|
|
3801
3919
|
sets: { allTokens: { sources: [simpleFlatten(tokens, { logger })] } },
|
|
3802
3920
|
modifiers: { tzMode: {
|
|
3803
3921
|
description: "Automatically built from $extensions.mode",
|
|
3804
|
-
contexts
|
|
3922
|
+
contexts,
|
|
3923
|
+
default: "."
|
|
3805
3924
|
} }
|
|
3806
3925
|
}, void 0, 2);
|
|
3807
3926
|
return createResolver(await normalizeResolver(momoa.parse(src), {
|
|
@@ -3958,6 +4077,16 @@ async function parse(_input, { logger = new Logger(), req = defaultReq, skipLint
|
|
|
3958
4077
|
let tokens = {};
|
|
3959
4078
|
let resolver;
|
|
3960
4079
|
let sources = [];
|
|
4080
|
+
if (inputs.length === 0) logger.error({
|
|
4081
|
+
group: "parser",
|
|
4082
|
+
label: "init",
|
|
4083
|
+
message: "Nothing to parse."
|
|
4084
|
+
});
|
|
4085
|
+
for (let i = 0; i < inputs.length; i++) if (!inputs[i] || typeof inputs[i] !== "object" || !inputs[i]?.src || inputs[i]?.filename && !(inputs[i].filename instanceof URL)) logger.error({
|
|
4086
|
+
group: "parser",
|
|
4087
|
+
label: "init",
|
|
4088
|
+
message: `Input ${i}: expected { src: any; filename: URL }`
|
|
4089
|
+
});
|
|
3961
4090
|
const totalStart = performance.now();
|
|
3962
4091
|
const initStart = performance.now();
|
|
3963
4092
|
const resolverResult = await loadResolver(inputs, {
|