@velarscript/web 0.22.1 → 0.23.1

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.
@@ -26,6 +26,13 @@ export declare class VelarWebAnalyzer extends Analyzer {
26
26
  private readonly honoredJsxKeys;
27
27
  private readonly reportedJsxKeys;
28
28
  private lookBuilderNames;
29
+ /**
30
+ * D103: the module's `velar/look` import, so the migration off
31
+ * `color("var(--x)")` can write the `token` import it needs in the same
32
+ * rewrite. A migration that only changed the call would leave the module
33
+ * naming a builder it never imported, which is not a mechanical fix.
34
+ */
35
+ private lookImport;
29
36
  private lookDeclarations;
30
37
  private lookLiteralDepth;
31
38
  /**
@@ -270,6 +277,31 @@ export declare class VelarWebAnalyzer extends Analyzer {
270
277
  * module compiles; dynamic arguments keep the runtime guard.
271
278
  */
272
279
  private checkLookBuilderCall;
280
+ /**
281
+ * D103 rules 1 and 5 — what a checked token reference has to be at the site
282
+ * that writes it.
283
+ *
284
+ * The compiler cannot see a design system's values: no token stylesheet is an
285
+ * input to this compile, and the whole point of the contract is that the
286
+ * theme swaps values under the same names. So the reference itself is the
287
+ * only thing there is to check, and it is checked completely — a literal
288
+ * name, spelled as a CSS custom property identifier, and nothing else in the
289
+ * call. A computed name would leave a Look value with no checked part at all,
290
+ * which is the surface D50 rule 92 says is worse than none.
291
+ */
292
+ private checkLookTokenCall;
293
+ /**
294
+ * D103 rule 4 — the migration off the one passthrough that used to work.
295
+ *
296
+ * The rewrite carries the `token` import when the module does not already
297
+ * have one, because a fix that leaves a module naming an unimported builder
298
+ * is not mechanical. A `var(--x, fallback)` reference has no rewrite: rule 5
299
+ * closed the contract against per-site fallbacks, so the message says that
300
+ * rather than offering a migration that would silently drop the fallback.
301
+ */
302
+ private reportLookColorVarReference;
303
+ /** The one edit that gives this module a `token` import, in the shape D103's migration needs. */
304
+ private lookTokenImportEdit;
273
305
  private checkAnimateBuilderCall;
274
306
  private checkAnimationKeyword;
275
307
  private analyzeKeyframes;
@@ -288,6 +320,35 @@ export declare class VelarWebAnalyzer extends Analyzer {
288
320
  * property no longer co-reports a `stringType` fallback assignment error.
289
321
  */
290
322
  private analyzeLookValue;
323
+ /** Whether this value is written as a call to the module's `token` builder, alias included. */
324
+ private isLookTokenCall;
325
+ /** How this module spells a call to the token builder, honouring an aliased import. */
326
+ private lookTokenCallText;
327
+ /**
328
+ * The edits that replace one written Look value with the checked token call,
329
+ * in the spelling of the site that wrote it.
330
+ *
331
+ * A `look:property="text"` directive is analyzed through a synthetic literal
332
+ * standing for the whole attribute, so the rewrite replaces the attribute:
333
+ * splicing a call between an attribute's quotes is not JSX, and a fix that
334
+ * produces a parse error is not a mechanical fix. The `look:property={...}`
335
+ * spelling carries a real expression whose span is the value alone, and is
336
+ * rewritten in place like a block entry.
337
+ */
338
+ private lookTokenRewrite;
339
+ /**
340
+ * D103 rule 4, free-text half — an advisory rather than a refusal.
341
+ *
342
+ * `fontFamily`, `backdropFilter` and the other free-text kinds accept
343
+ * arbitrary CSS text by construction, and a `var()` inside a larger value is
344
+ * a legitimate spelling with no single token to rewrite it to: the tail of a
345
+ * font stack, one layer of a filter list. Refusing there would refuse real
346
+ * CSS. What is advised is the narrow case where the *whole* value is one
347
+ * reference, because there `token("--name")` is the checked spelling of the
348
+ * same thing and the rewrite is unambiguous — which is the bar the `A`
349
+ * roster is written to.
350
+ */
351
+ private adviseLookTokenSpelling;
291
352
  /**
292
353
  * `subject` names the position in the message. It is the property itself
293
354
  * everywhere except the `transition(...)` builder, whose first argument takes
@@ -1 +1 @@
1
- {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"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"}
package/dist/analyzer.js CHANGED
@@ -1,10 +1,11 @@
1
- import { semanticTypeIdentity } from "@velarscript/compiler";
1
+ import { mechanicalEdits, mechanicalFix, semanticTypeIdentity } from "@velarscript/compiler";
2
2
  import { Analyzer, anyType, boolType, describeType, expressionContainsDirectAwait, invalidType, isInvalidType, isAssignable, isReadonlyView, nullType, nonOptional, numberType, optionalOf, spanIdentity, stringType, unknownType, } from "@velarscript/compiler/extension";
3
3
  import { BROWSER_TEST_MODULE, BROWSER_TEST_SOURCE_SUFFIX, browserTestImportGuidance } from "./browser-test.js";
4
4
  import { cssTokens } from "./css-tokens.js";
5
- import { LOOK_ABSENT_MEDIA_SUBJECTS, LOOK_ARITHMETIC_HINT, LOOK_ANIMATION_DIRECTIONS, LOOK_ANIMATION_EASINGS, LOOK_ANIMATION_FILLS, LOOK_BORDER_STYLE_NAMES, LOOK_BUILDER_NUMERIC_RANGES, LOOK_BUILDER_SIGNATURES, LOOK_BUILDERS, LOOK_EXCLUDED_PROPERTIES, LOOK_HOOKS, LOOK_CSS_WIDE_KEYWORDS, LOOK_LARGE_KEYWORD_SETS, LOOK_LENGTH_BUILDERS, LOOK_MEDIA_LENGTH_UNITS, LOOK_MEDIA_SUBJECTS, LOOK_NUMERIC_TYPE_NAMES, LOOK_NON_ANIMATABLE_PROPERTIES, LOOK_PARTIAL_KEYWORD_PROPERTIES, LOOK_PROPERTIES, LOOK_PROPERTY_KEYWORDS, LOOK_PROPERTY_VALUE_KINDS, LOOK_TARGETS, LOOK_UNIT_TYPES, LOOK_UNITLESS_PROPERTIES, lookOwnKeywords, nearestLookName, } from "./look.js";
5
+ import { LOOK_ABSENT_MEDIA_SUBJECTS, LOOK_ARITHMETIC_HINT, LOOK_ANIMATION_DIRECTIONS, LOOK_ANIMATION_EASINGS, LOOK_ANIMATION_FILLS, LOOK_BORDER_STYLE_NAMES, LOOK_BUILDER_NUMERIC_RANGES, LOOK_BUILDER_SIGNATURES, LOOK_BUILDERS, LOOK_EXCLUDED_PROPERTIES, LOOK_HOOKS, LOOK_CSS_WIDE_KEYWORDS, LOOK_LARGE_KEYWORD_SETS, LOOK_LENGTH_BUILDERS, LOOK_MEDIA_LENGTH_UNITS, LOOK_MEDIA_SUBJECTS, LOOK_NUMERIC_TYPE_NAMES, LOOK_NON_ANIMATABLE_PROPERTIES, LOOK_PARTIAL_KEYWORD_PROPERTIES, LOOK_PROPERTIES, LOOK_PROPERTY_KEYWORDS, LOOK_PROPERTY_VALUE_KINDS, LOOK_TARGETS, LOOK_TOKEN_NAME_RULE, LOOK_TOKEN_NO_FALLBACK_GUIDANCE, LOOK_UNIT_TYPES, LOOK_UNITLESS_PROPERTIES, isLookTokenName, isLookVarReference, lookOwnKeywords, lookTokenReference, lookVarReferenceName, nearestLookName, } from "./look.js";
6
6
  import { collectLookStaticValues, evaluateLookStaticExpression, isLookStaticValue, lookStaticCss } from "./look-static.js";
7
7
  import { keyframeCssValue } from "./keyframes.js";
8
+ import { byCodeUnit } from "./stable-order.js";
8
9
  import { dynamicChildLeaves, JSX_SCALAR_TEXT_HINT } from "./emitter.js";
9
10
  import { isWebCustomElementName, WEB_ARIA_ATTRIBUTES, WEB_ARIA_ENUMERATED_VALUES, WEB_ARIA_ROLES, WEB_ARIA_ROLE_SYNONYMS, WEB_MISSPELLED_ATTRIBUTES, WEB_NATIVE_ELEMENTS, } from "./elements.js";
10
11
  import { isWebExpression, isWebJsx, isWebKeyframes, isWebLook, isWebStatement, isWebUnit, } from "./ast.js";
@@ -55,7 +56,7 @@ const textualWebPrimitiveNames = new Set(["Length", "Percentage", "LengthPercent
55
56
  // D72 rule 186: derived from the published table, not restated beside it.
56
57
  const webEventTypeNames = WEB_EVENT_TYPE_NAMES;
57
58
  const webEventDeadFields = new Set(["target", "currentTarget", "value", "checked"]);
58
- const diagnostic = (code, message, sourceSpan) => ({ code, message, span: sourceSpan });
59
+ const diagnostic = (code, message, sourceSpan, fix) => fix ? { code, message, span: sourceSpan, fix } : { code, message, span: sourceSpan };
59
60
  const bindTargetGuidance = (directive) => `${directive} requires a writable reactive location: a state name, or a field or index path on one such as ${directive}={form.name} or ${directive}={items[0]}`;
60
61
  const LOOK_CONDITION_TERM_LIMIT = 32;
61
62
  const lookLength = { kind: "named", name: "Length" };
@@ -784,6 +785,27 @@ function lookContributions(look, looks, visited = new Set()) {
784
785
  walk(look.entries, "");
785
786
  return { properties, composed };
786
787
  }
788
+ function collectLookImportSite(program) {
789
+ let lastImportEnd = null;
790
+ for (const statement of program.body) {
791
+ if (statement.kind !== "ImportDeclaration")
792
+ continue;
793
+ lastImportEnd = statement.span.end;
794
+ if (statement.source !== "velar/look" || statement.javascript || statement.specifiers.some((specifier) => specifier.namespace))
795
+ continue;
796
+ return {
797
+ declaration: {
798
+ span: statement.span,
799
+ specifiers: statement.specifiers.map((specifier) => ({ imported: specifier.imported, local: specifier.local })),
800
+ },
801
+ insertAt: statement.span.end,
802
+ leadingBlankLine: false,
803
+ };
804
+ }
805
+ return lastImportEnd === null
806
+ ? { declaration: null, insertAt: program.body[0]?.span.start ?? 0, leadingBlankLine: true }
807
+ : { declaration: null, insertAt: lastImportEnd, leadingBlankLine: false };
808
+ }
787
809
  /** Local names bound to a velar/look builder, including aliased imports. */
788
810
  function collectLookBuilderNames(program) {
789
811
  const names = new Map();
@@ -1407,6 +1429,13 @@ export class VelarWebAnalyzer extends Analyzer {
1407
1429
  honoredJsxKeys = new Set();
1408
1430
  reportedJsxKeys = new Set();
1409
1431
  lookBuilderNames = new Map();
1432
+ /**
1433
+ * D103: the module's `velar/look` import, so the migration off
1434
+ * `color("var(--x)")` can write the `token` import it needs in the same
1435
+ * rewrite. A migration that only changed the call would leave the module
1436
+ * naming a builder it never imported, which is not a mechanical fix.
1437
+ */
1438
+ lookImport = null;
1410
1439
  lookDeclarations = new Map();
1411
1440
  lookLiteralDepth = 0;
1412
1441
  /**
@@ -1441,6 +1470,7 @@ export class VelarWebAnalyzer extends Analyzer {
1441
1470
  analyze(program) {
1442
1471
  this.lookStaticValues = collectLookStaticValues(program, this.importedLookStaticValues);
1443
1472
  this.lookBuilderNames = collectLookBuilderNames(program);
1473
+ this.lookImport = collectLookImportSite(program);
1444
1474
  this.lookDeclarations = collectLookDeclarations(program);
1445
1475
  for (const name of collectDerivedReactiveNames(program))
1446
1476
  this.derivedReactiveNames.add(name);
@@ -2731,6 +2761,10 @@ export class VelarWebAnalyzer extends Analyzer {
2731
2761
  this.checkAnimateBuilderCall(expression);
2732
2762
  return;
2733
2763
  }
2764
+ if (builder === "token") {
2765
+ this.checkLookTokenCall(expression);
2766
+ return;
2767
+ }
2734
2768
  const ranges = LOOK_BUILDER_NUMERIC_RANGES.get(builder);
2735
2769
  // A named argument fills the same slot its positional spelling does, so the
2736
2770
  // position comes from the builder's own signature — the one table the
@@ -2772,11 +2806,104 @@ export class VelarWebAnalyzer extends Analyzer {
2772
2806
  if (builder === "transition" && position === 0) {
2773
2807
  this.validateLookStringVocabulary("transitionProperty", argument, "The transition builder's property argument");
2774
2808
  }
2809
+ // D103 rule 4: one spelling. `color(string)` used to be the only checked
2810
+ // Look value that let a design token through, and it let it through as
2811
+ // text nobody read — so the same reference was legal on `color` and
2812
+ // refused on `width`, and the accepting half checked nothing.
2813
+ if (builder === "color" && position === 0)
2814
+ this.reportLookColorVarReference(expression, argument);
2775
2815
  }
2776
2816
  if (builder === "tracks" && expression.arguments.length > 1024) {
2777
2817
  this.diagnostics.push(diagnostic("VEL5042", "tracks cannot contain more than 1024 values", expression.span));
2778
2818
  }
2779
2819
  }
2820
+ /**
2821
+ * D103 rules 1 and 5 — what a checked token reference has to be at the site
2822
+ * that writes it.
2823
+ *
2824
+ * The compiler cannot see a design system's values: no token stylesheet is an
2825
+ * input to this compile, and the whole point of the contract is that the
2826
+ * theme swaps values under the same names. So the reference itself is the
2827
+ * only thing there is to check, and it is checked completely — a literal
2828
+ * name, spelled as a CSS custom property identifier, and nothing else in the
2829
+ * call. A computed name would leave a Look value with no checked part at all,
2830
+ * which is the surface D50 rule 92 says is worse than none.
2831
+ */
2832
+ checkLookTokenCall(expression) {
2833
+ const names = expression.argumentNames;
2834
+ // `token(name="--x")` writes the same one argument the positional spelling
2835
+ // does, so the name position is read from the signature the way every other
2836
+ // builder's is rather than assumed to be index 0.
2837
+ const position = names?.findIndex((entry) => entry === "name") ?? -1;
2838
+ const nameIndex = position >= 0 ? position : names?.[0] === undefined || names[0] === null ? 0 : -1;
2839
+ for (const [index, argument] of expression.arguments.entries()) {
2840
+ if (index === nameIndex)
2841
+ continue;
2842
+ this.diagnostics.push(diagnostic("VEL5042", LOOK_TOKEN_NO_FALLBACK_GUIDANCE, argument.span));
2843
+ }
2844
+ const written = nameIndex >= 0 ? expression.arguments[nameIndex] : undefined;
2845
+ if (!written)
2846
+ return;
2847
+ if (written.kind !== "LiteralExpression" || typeof written.value !== "string") {
2848
+ this.diagnostics.push(diagnostic("VEL5042", `A design token reference names its custom property in the call: ${LOOK_TOKEN_NAME_RULE}. The compiler cannot see a design system's values, so the name is the whole of what it can check — a computed name, an interpolation, or a binding would leave the reference unchecked`, written.span));
2849
+ return;
2850
+ }
2851
+ if (isLookTokenName(written.value)) {
2852
+ // D103 rule 2: the reference is compile-time text, so it is folded here
2853
+ // rather than left as a call the browser makes on every module load. The
2854
+ // fold is stamped only on a call this check has just proved, which is
2855
+ // what keeps the emitter structurally unable to write a name nothing
2856
+ // validated. An aliased builder (`const t = token`) is not resolved here
2857
+ // and keeps the runtime implementation, exactly as every other builder
2858
+ // passed around as a value does.
2859
+ if (expression.arguments.length === 1) {
2860
+ this.extensionLiterals.set(spanIdentity(expression.span), lookTokenReference(written.value));
2861
+ }
2862
+ return;
2863
+ }
2864
+ // A name written without the `--` that makes it a custom property is the
2865
+ // one near miss with a single spelling behind it, so it is migrated rather
2866
+ // than only refused.
2867
+ const prefixed = `--${written.value}`;
2868
+ this.diagnostics.push(diagnostic("VEL5042", `Design token name '${written.value}' is not a CSS custom property identifier; ${LOOK_TOKEN_NAME_RULE}`, written.span, isLookTokenName(prefixed)
2869
+ ? mechanicalFix(written.span, JSON.stringify(prefixed), `Use "${prefixed}"`)
2870
+ : undefined));
2871
+ }
2872
+ /**
2873
+ * D103 rule 4 — the migration off the one passthrough that used to work.
2874
+ *
2875
+ * The rewrite carries the `token` import when the module does not already
2876
+ * have one, because a fix that leaves a module naming an unimported builder
2877
+ * is not mechanical. A `var(--x, fallback)` reference has no rewrite: rule 5
2878
+ * closed the contract against per-site fallbacks, so the message says that
2879
+ * rather than offering a migration that would silently drop the fallback.
2880
+ */
2881
+ reportLookColorVarReference(expression, argument) {
2882
+ if (argument.kind !== "LiteralExpression" || typeof argument.value !== "string")
2883
+ return;
2884
+ if (!isLookVarReference(argument.value))
2885
+ return;
2886
+ const referenced = lookVarReferenceName(argument.value);
2887
+ if (referenced === null) {
2888
+ this.diagnostics.push(diagnostic("VEL5042", `A design token reference is written token("--name"), and it carries no fallback: ${LOOK_TOKEN_NO_FALLBACK_GUIDANCE}`, argument.span));
2889
+ return;
2890
+ }
2891
+ const { call, imported } = this.lookTokenCallText(referenced);
2892
+ const rewrite = { span: expression.span, text: call };
2893
+ this.diagnostics.push(diagnostic("VEL5042", `Write a design token reference as ${call}; color("var(...)") passed the reference through as text nothing checked, and token() is the one checked spelling — legal in every Look property, not only the colour ones`, expression.span, mechanicalEdits(imported ? [rewrite] : [this.lookTokenImportEdit(), rewrite], `Use ${call}`)));
2894
+ }
2895
+ /** The one edit that gives this module a `token` import, in the shape D103's migration needs. */
2896
+ lookTokenImportEdit() {
2897
+ const site = this.lookImport ?? { declaration: null, insertAt: 0, leadingBlankLine: true };
2898
+ const specifiers = [...(site.declaration?.specifiers ?? []), { imported: "token", local: "token" }];
2899
+ const line = `import {${[...specifiers]
2900
+ .sort((left, right) => byCodeUnit(left.imported, right.imported))
2901
+ .map((specifier) => specifier.imported === specifier.local ? specifier.imported : `${specifier.imported} as ${specifier.local}`)
2902
+ .join(", ")}} from "velar/look"`;
2903
+ if (site.declaration)
2904
+ return { span: site.declaration.span, text: line };
2905
+ return { span: { start: site.insertAt, end: site.insertAt }, text: site.leadingBlankLine ? `${line}\n\n` : `\n${line}` };
2906
+ }
2780
2907
  checkAnimateBuilderCall(expression) {
2781
2908
  const argument = (name, position) => {
2782
2909
  const named = expression.argumentNames?.findIndex((candidate) => candidate === name) ?? -1;
@@ -2900,6 +3027,20 @@ export class VelarWebAnalyzer extends Analyzer {
2900
3027
  this.inferExpression(value);
2901
3028
  return false;
2902
3029
  }
3030
+ // D103 rule 1 meets D49. `animation` is the one Look property whose value
3031
+ // names another rule rather than describing one: the `@keyframes` name in
3032
+ // an animation shorthand. Look owns those names — they are generated from
3033
+ // the `keyframes:` value that defines the motion — so a shorthand arriving
3034
+ // from outside this compile is a reference the compiler can check on
3035
+ // neither side, which is the surface D50 rule 92 calls worse than none. The
3036
+ // type refuses it either way; this replaces a bare union dump with the two
3037
+ // spellings that do work.
3038
+ if (name === "animation" && this.isLookTokenCall(value)) {
3039
+ this.diagnostics.push(diagnostic("VEL5038", "Look animation is the one property a design token cannot carry: an animation value names a '@keyframes' rule, and Look generates those names from the 'keyframes:' value that defines the motion, so a shorthand from a design system names a rule this compile never emitted. Declare a checked 'keyframes:' value and pass animate(frames, duration, ...); token() is legal in every other Look property, and a module-level 'import css unsafe \"./styles.css\" before look' carries a design system's own animation when that boundary is intentional", entrySpan));
3040
+ if (!inline)
3041
+ this.inferExpression(value);
3042
+ return false;
3043
+ }
2903
3044
  if (!LOOK_PROPERTIES.has(name)) {
2904
3045
  const nearest = nearestLookName(name, LOOK_PROPERTIES);
2905
3046
  const exclusion = LOOK_EXCLUDED_PROPERTIES.get(name);
@@ -2917,10 +3058,67 @@ export class VelarWebAnalyzer extends Analyzer {
2917
3058
  this.diagnostics.push(diagnostic("VEL5038", shorthandGuidance, value.span));
2918
3059
  return false;
2919
3060
  }
2920
- if (!this.validateLookStringVocabulary(name, value))
3061
+ const site = { property: name, entrySpan, directive };
3062
+ this.adviseLookTokenSpelling(name, value, site);
3063
+ if (!this.validateLookStringVocabulary(name, value, undefined, site))
2921
3064
  return false;
2922
3065
  return true;
2923
3066
  }
3067
+ /** Whether this value is written as a call to the module's `token` builder, alias included. */
3068
+ isLookTokenCall(value) {
3069
+ return value.kind === "CallExpression" && value.callee.kind === "IdentifierExpression"
3070
+ && this.lookBuilderNames.get(value.callee.name) === "token";
3071
+ }
3072
+ /** How this module spells a call to the token builder, honouring an aliased import. */
3073
+ lookTokenCallText(referenced) {
3074
+ const local = [...this.lookBuilderNames].find(([, builder]) => builder === "token")?.[0] ?? null;
3075
+ return { call: `${local ?? "token"}(${JSON.stringify(referenced)})`, imported: local !== null };
3076
+ }
3077
+ /**
3078
+ * The edits that replace one written Look value with the checked token call,
3079
+ * in the spelling of the site that wrote it.
3080
+ *
3081
+ * A `look:property="text"` directive is analyzed through a synthetic literal
3082
+ * standing for the whole attribute, so the rewrite replaces the attribute:
3083
+ * splicing a call between an attribute's quotes is not JSX, and a fix that
3084
+ * produces a parse error is not a mechanical fix. The `look:property={...}`
3085
+ * spelling carries a real expression whose span is the value alone, and is
3086
+ * rewritten in place like a block entry.
3087
+ */
3088
+ lookTokenRewrite(value, referenced, site) {
3089
+ const { call, imported } = this.lookTokenCallText(referenced);
3090
+ const wholeAttribute = site.directive !== null
3091
+ && value.span.start === site.entrySpan.start && value.span.end === site.entrySpan.end;
3092
+ const edit = {
3093
+ span: value.span,
3094
+ text: wholeAttribute ? `${site.directive}:${site.property}={${call}}` : call,
3095
+ };
3096
+ return imported ? [edit] : [this.lookTokenImportEdit(), edit];
3097
+ }
3098
+ /**
3099
+ * D103 rule 4, free-text half — an advisory rather than a refusal.
3100
+ *
3101
+ * `fontFamily`, `backdropFilter` and the other free-text kinds accept
3102
+ * arbitrary CSS text by construction, and a `var()` inside a larger value is
3103
+ * a legitimate spelling with no single token to rewrite it to: the tail of a
3104
+ * font stack, one layer of a filter list. Refusing there would refuse real
3105
+ * CSS. What is advised is the narrow case where the *whole* value is one
3106
+ * reference, because there `token("--name")` is the checked spelling of the
3107
+ * same thing and the rewrite is unambiguous — which is the bar the `A`
3108
+ * roster is written to.
3109
+ */
3110
+ adviseLookTokenSpelling(name, value, site) {
3111
+ const kind = LOOK_PROPERTY_VALUE_KINDS.get(name);
3112
+ if (kind !== "text" && kind !== "filter" && kind !== "transform")
3113
+ return;
3114
+ if (value.kind !== "LiteralExpression" || typeof value.value !== "string")
3115
+ return;
3116
+ const referenced = lookVarReferenceName(value.value);
3117
+ if (referenced === null)
3118
+ return;
3119
+ const { call } = this.lookTokenCallText(referenced);
3120
+ this.advise("A12", `Look property '${name}' accepts free text, so this design token reference compiles — as text nothing checks. ${call} is the checked spelling of the same reference, and it is legal in every Look property. A var() inside a larger value, such as a font stack's fallback, has no single token to stand for it and is not advised`, value.span, mechanicalEdits(this.lookTokenRewrite(value, referenced, site), `Use ${call}`));
3121
+ }
2924
3122
  /**
2925
3123
  * `subject` names the position in the message. It is the property itself
2926
3124
  * everywhere except the `transition(...)` builder, whose first argument takes
@@ -2928,7 +3126,7 @@ export class VelarWebAnalyzer extends Analyzer {
2928
3126
  * refusal that named the longhand there would name a spelling the author
2929
3127
  * never wrote.
2930
3128
  */
2931
- validateLookStringVocabulary(name, value, subject = `Look property '${name}'`) {
3129
+ validateLookStringVocabulary(name, value, subject = `Look property '${name}'`, site) {
2932
3130
  const kind = LOOK_PROPERTY_VALUE_KINDS.get(name);
2933
3131
  if (!kind || kind === "text" || kind === "filter" || kind === "transform" || kind === "animation")
2934
3132
  return true;
@@ -2937,6 +3135,19 @@ export class VelarWebAnalyzer extends Analyzer {
2937
3135
  return true;
2938
3136
  for (const text of values) {
2939
3137
  const normalized = text.trim();
3138
+ // D103 rule 4: this is the refusal the shell wave met — every metric,
3139
+ // shadow and transition property turned a design token reference away and
3140
+ // named `import css unsafe` as the only way out, which is how a product's
3141
+ // whole visual layer ended up outside Look. The reference is still
3142
+ // refused as free text, because free text is what it was; what changed is
3143
+ // that the refusal now names the checked spelling of the same reference
3144
+ // and rewrites to it.
3145
+ const referenced = site && lookVarReferenceName(normalized);
3146
+ if (referenced) {
3147
+ const { call } = this.lookTokenCallText(referenced);
3148
+ this.diagnostics.push(diagnostic("VEL5038", `${subject} does not accept the text '${normalized}'; write the design token reference as ${call}, which is checked and legal in every Look property`, value.span, mechanicalEdits(this.lookTokenRewrite(value, referenced, site), `Use ${call}`)));
3149
+ return false;
3150
+ }
2940
3151
  if (kind === "metric" && /^[+-]?(?:\d+(?:\.\d+)?|\.\d+)(?:px|rem|em|vw|vh|vmin|vmax|%|fr|ms|s|deg|turn)$/u.test(normalized)) {
2941
3152
  this.diagnostics.push(diagnostic("VEL5038", `Use the unit literal ${normalized}; quoted unit values are not part of Look`, value.span));
2942
3153
  return false;