@invariant-ui/cli 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +105 -0
- package/README.md +250 -2
- package/dist/agent-kit/apply.js +232 -0
- package/dist/agent-kit/guidance.js +236 -0
- package/dist/agent-kit/index.js +5 -0
- package/dist/agent-kit/integrations.js +121 -0
- package/dist/agent-kit/plugin.js +115 -0
- package/dist/artifact-generator/index.js +75 -0
- package/dist/browser-verify/driver.js +2 -0
- package/dist/browser-verify/index.js +4 -0
- package/dist/browser-verify/playwright.js +82 -0
- package/dist/browser-verify/runner.js +175 -0
- package/dist/browser-verify/spec.js +103 -0
- package/dist/cli/args.js +77 -0
- package/dist/cli/baseline.js +64 -0
- package/dist/cli/cli.js +121 -0
- package/dist/cli/commands-browser.js +104 -0
- package/dist/cli/commands-discover.js +312 -0
- package/dist/cli/commands-enforcement.js +35 -0
- package/dist/cli/commands-governance.js +179 -0
- package/dist/cli/commands-hook.js +269 -0
- package/dist/cli/commands-patterns.js +324 -0
- package/dist/cli/commands-setup.js +485 -0
- package/dist/cli/commands-validate.js +157 -0
- package/dist/cli/commands.js +517 -0
- package/dist/cli/config.js +197 -0
- package/dist/cli/diff.js +66 -0
- package/dist/cli/enforcement-log.js +83 -0
- package/dist/cli/enforcement-report.js +96 -0
- package/dist/cli/errors.js +10 -0
- package/dist/cli/format.js +22 -0
- package/dist/cli/index.js +5 -0
- package/dist/cli/io.js +2 -0
- package/dist/cli/main.js +31 -0
- package/dist/cli/pipeline.js +262 -0
- package/dist/cli/publish.js +77 -0
- package/dist/cli/report.js +127 -0
- package/dist/cli/starter-rules.js +57 -0
- package/dist/cli/store.js +60 -0
- package/dist/cli/version.js +5 -0
- package/dist/cli/watch.js +68 -0
- package/dist/cli/workflow.js +52 -0
- package/dist/compiler-angular/adapter.js +115 -0
- package/dist/compiler-angular/analyze.js +222 -0
- package/dist/compiler-angular/classes.js +446 -0
- package/dist/compiler-angular/declared.js +285 -0
- package/dist/compiler-angular/emit.js +183 -0
- package/dist/compiler-angular/index.js +4 -0
- package/dist/compiler-angular/template.js +142 -0
- package/dist/compiler-core/adapter.js +2 -0
- package/dist/compiler-core/adapters/inventory.js +312 -0
- package/dist/compiler-core/compile.js +148 -0
- package/dist/compiler-core/component-facts.js +123 -0
- package/dist/compiler-core/discovery/docs.js +66 -0
- package/dist/compiler-core/discovery/entries.js +270 -0
- package/dist/compiler-core/discovery/exports.js +207 -0
- package/dist/compiler-core/discovery/graph.js +59 -0
- package/dist/compiler-core/discovery/index.js +103 -0
- package/dist/compiler-core/discovery/packages.js +148 -0
- package/dist/compiler-core/discovery/schema.js +144 -0
- package/dist/compiler-core/discovery/storybook.js +232 -0
- package/dist/compiler-core/discovery/support.js +82 -0
- package/dist/compiler-core/discovery/tokens.js +186 -0
- package/dist/compiler-core/discovery/tooling.js +146 -0
- package/dist/compiler-core/fs.js +89 -0
- package/dist/compiler-core/glob.js +3 -0
- package/dist/compiler-core/index.js +16 -0
- package/dist/compiler-core/ir-builder.js +68 -0
- package/dist/compiler-core/json-schema.js +11 -0
- package/dist/compiler-core/testing/index.js +81 -0
- package/dist/compiler-core/ts/ast.js +166 -0
- package/dist/compiler-core/ts/members.js +163 -0
- package/dist/compiler-core/ts/program.js +81 -0
- package/dist/compiler-core/ts/static-eval.js +145 -0
- package/dist/compiler-core/ts/tsconfig-paths.js +60 -0
- package/dist/compiler-core/walk.js +46 -0
- package/dist/compiler-ir/index.js +4 -0
- package/dist/compiler-ir/ir.js +67 -0
- package/dist/compiler-ir/json-schema.js +6 -0
- package/dist/compiler-ir/validate.js +116 -0
- package/dist/compiler-react/adapter.js +147 -0
- package/dist/compiler-react/analyze.js +199 -0
- package/dist/compiler-react/behavior.js +75 -0
- package/dist/compiler-react/detect.js +558 -0
- package/dist/compiler-react/emit.js +188 -0
- package/dist/compiler-react/index.js +2 -0
- package/dist/compiler-react/props.js +157 -0
- package/dist/compiler-react/styling.js +138 -0
- package/dist/compiler-react/usage.js +116 -0
- package/dist/compiler-react/variants.js +111 -0
- package/dist/compiler-storybook/adapter.js +253 -0
- package/dist/compiler-storybook/csf.js +521 -0
- package/dist/compiler-storybook/emit.js +202 -0
- package/dist/compiler-storybook/index-json.js +41 -0
- package/dist/compiler-storybook/index.js +5 -0
- package/dist/compiler-storybook/mdx.js +120 -0
- package/dist/compiler-tokens/adapter.js +158 -0
- package/dist/compiler-tokens/css.js +59 -0
- package/dist/compiler-tokens/index.js +5 -0
- package/dist/compiler-tokens/json-lines.js +106 -0
- package/dist/compiler-tokens/json-tokens.js +52 -0
- package/dist/compiler-vue/adapter.js +107 -0
- package/dist/compiler-vue/analyze.js +344 -0
- package/dist/compiler-vue/declared.js +343 -0
- package/dist/compiler-vue/emit.js +129 -0
- package/dist/compiler-vue/index.js +5 -0
- package/dist/compiler-vue/script.js +472 -0
- package/dist/compiler-vue/sfc.js +44 -0
- package/dist/compiler-vue/template.js +73 -0
- package/dist/contract/archetype-checks.js +153 -0
- package/dist/contract/components.js +102 -0
- package/dist/contract/conflicts.js +39 -0
- package/dist/contract/contract.js +46 -0
- package/dist/contract/evidence.js +84 -0
- package/dist/contract/fact-path.js +39 -0
- package/dist/contract/facts.js +62 -0
- package/dist/contract/index.js +16 -0
- package/dist/contract/integrity.js +21 -0
- package/dist/contract/json-schema.js +11 -0
- package/dist/contract/knowledge.js +95 -0
- package/dist/contract/pattern-checks.js +254 -0
- package/dist/contract/patterns.js +225 -0
- package/dist/contract/primitives.js +81 -0
- package/dist/contract/sources.js +30 -0
- package/dist/contract/tokens.js +41 -0
- package/dist/contract/validate.js +253 -0
- package/dist/contract-query/archetype.js +188 -0
- package/dist/contract-query/index.js +6 -0
- package/dist/contract-query/patterns.js +298 -0
- package/dist/contract-query/search.js +132 -0
- package/dist/contract-query/system.js +148 -0
- package/dist/contract-query/views.js +288 -0
- package/dist/governance/decisions.js +229 -0
- package/dist/governance/index.js +5 -0
- package/dist/governance/patterns-file.js +156 -0
- package/dist/governance/patterns.js +510 -0
- package/dist/governance/policies.js +148 -0
- package/dist/mcp/index.js +7 -0
- package/dist/mcp/loader.js +70 -0
- package/dist/mcp/protocol.js +27 -0
- package/dist/mcp/resources.js +138 -0
- package/dist/mcp/server.js +177 -0
- package/dist/mcp/stdio.js +28 -0
- package/dist/mcp/tools.js +267 -0
- package/dist/reconciliation/code.js +62 -0
- package/dist/reconciliation/components.js +401 -0
- package/dist/reconciliation/conflicts.js +126 -0
- package/dist/reconciliation/facts.js +41 -0
- package/dist/reconciliation/index.js +7 -0
- package/dist/reconciliation/reconcile.js +134 -0
- package/dist/reconciliation/resolve.js +158 -0
- package/dist/reconciliation/review.js +81 -0
- package/dist/reconciliation/storybook.js +370 -0
- package/dist/reconciliation/tokens.js +179 -0
- package/dist/reconciliation/util.js +55 -0
- package/dist/semantic-engine/additive.js +51 -0
- package/dist/semantic-engine/compounds.js +91 -0
- package/dist/semantic-engine/documents.js +157 -0
- package/dist/semantic-engine/enrich.js +42 -0
- package/dist/semantic-engine/index.js +7 -0
- package/dist/semantic-engine/infer.js +38 -0
- package/dist/semantic-engine/tokens.js +120 -0
- package/dist/shared/canonical.js +65 -0
- package/dist/shared/diagnostic.js +78 -0
- package/dist/shared/glob.js +98 -0
- package/dist/shared/index.js +4 -0
- package/dist/shared/json.js +2 -0
- package/dist/validation/card.js +50 -0
- package/dist/validation/discovery/arrangements.js +162 -0
- package/dist/validation/discovery/discover.js +70 -0
- package/dist/validation/discovery/index.js +8 -0
- package/dist/validation/discovery/model.js +127 -0
- package/dist/validation/discovery/promote.js +24 -0
- package/dist/validation/discovery/reviews.js +63 -0
- package/dist/validation/discovery/shapes.js +47 -0
- package/dist/validation/discovery/similar-files.js +146 -0
- package/dist/validation/discovery/util.js +47 -0
- package/dist/validation/index.js +11 -0
- package/dist/validation/interaction-facts.js +341 -0
- package/dist/validation/interaction-workflows.js +633 -0
- package/dist/validation/literals.js +251 -0
- package/dist/validation/pattern-rules.js +608 -0
- package/dist/validation/policy.js +241 -0
- package/dist/validation/report.js +163 -0
- package/dist/validation/rules.js +269 -0
- package/dist/validation/scan.js +295 -0
- package/dist/validation/text.js +34 -0
- package/dist/validation/validate-code.js +513 -0
- package/dist/validation/validate-usage.js +196 -0
- package/package.json +38 -4
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Literal values in application code that could have been design tokens: colors written as rgb(), hsl() or a
|
|
3
|
+
* CSS name, spacing lengths and typography values. Pure text scanning. Only literal values are read; anything
|
|
4
|
+
* that contains `var(`, `calc(` or a binding is skipped, never guessed.
|
|
5
|
+
*/
|
|
6
|
+
const ROOT_PX = 16;
|
|
7
|
+
const round = (n) => Math.round(n);
|
|
8
|
+
const hex2 = (n) => Math.max(0, Math.min(255, round(n)))
|
|
9
|
+
.toString(16)
|
|
10
|
+
.padStart(2, "0");
|
|
11
|
+
function channel(raw) {
|
|
12
|
+
const m = /^(-?\d*\.?\d+)(%?)$/.exec(raw);
|
|
13
|
+
if (!m)
|
|
14
|
+
return undefined;
|
|
15
|
+
const n = Number(m[1]);
|
|
16
|
+
return m[2] ? (n / 100) * 255 : n;
|
|
17
|
+
}
|
|
18
|
+
function alpha(raw) {
|
|
19
|
+
if (raw === undefined)
|
|
20
|
+
return 1;
|
|
21
|
+
const m = /^(-?\d*\.?\d+)(%?)$/.exec(raw);
|
|
22
|
+
if (!m)
|
|
23
|
+
return undefined;
|
|
24
|
+
const n = Number(m[1]);
|
|
25
|
+
return Math.max(0, Math.min(1, m[2] ? n / 100 : n));
|
|
26
|
+
}
|
|
27
|
+
function hslToRgb(h, s, l) {
|
|
28
|
+
const hue = ((h % 360) + 360) % 360;
|
|
29
|
+
const a = s * Math.min(l, 1 - l);
|
|
30
|
+
const f = (n) => {
|
|
31
|
+
const k = (n + hue / 30) % 12;
|
|
32
|
+
return (l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1))) * 255;
|
|
33
|
+
};
|
|
34
|
+
return [f(0), f(8), f(4)];
|
|
35
|
+
}
|
|
36
|
+
/** `#rgb`, `#rgba`, `#rrggbb` or `#rrggbbaa` to the long lowercase form. */
|
|
37
|
+
export function expandHex(hex) {
|
|
38
|
+
const h = hex.slice(1).toLowerCase();
|
|
39
|
+
return `#${h.length <= 4 ? [...h].map((c) => c + c).join("") : h}`;
|
|
40
|
+
}
|
|
41
|
+
/** Opaque colors end up as `#rrggbb`, translucent ones as `#rrggbbaa`, so equal colors compare equal. */
|
|
42
|
+
function toHex(r, g, b, a) {
|
|
43
|
+
const base = `#${hex2(r)}${hex2(g)}${hex2(b)}`;
|
|
44
|
+
return a >= 1 ? base : `${base}${hex2(a * 255)}`;
|
|
45
|
+
}
|
|
46
|
+
/** Normalizes a literal rgb()/rgba()/hsl()/hsla() call, comma or space syntax. Anything else is undefined. */
|
|
47
|
+
export function normalizeColorFunction(text) {
|
|
48
|
+
const m = /^(rgba?|hsla?)\(\s*([^()]*?)\s*\)$/i.exec(text.trim());
|
|
49
|
+
if (!m)
|
|
50
|
+
return undefined;
|
|
51
|
+
const fn = m[1].toLowerCase();
|
|
52
|
+
const parts = m[2].split(/\s*[,/]\s*|\s+/).filter((p) => p !== "");
|
|
53
|
+
if (parts.length !== 3 && parts.length !== 4)
|
|
54
|
+
return undefined;
|
|
55
|
+
const a = alpha(parts[3]);
|
|
56
|
+
if (a === undefined)
|
|
57
|
+
return undefined;
|
|
58
|
+
if (fn.startsWith("rgb")) {
|
|
59
|
+
const ch = parts.slice(0, 3).map((p) => channel(p));
|
|
60
|
+
if (ch.some((c) => c === undefined))
|
|
61
|
+
return undefined;
|
|
62
|
+
const [r, g, b] = ch;
|
|
63
|
+
return toHex(r, g, b, a);
|
|
64
|
+
}
|
|
65
|
+
const hue = /^(-?\d*\.?\d+)(deg)?$/.exec(parts[0]);
|
|
66
|
+
const sat = /^(\d*\.?\d+)%$/.exec(parts[1]);
|
|
67
|
+
const lig = /^(\d*\.?\d+)%$/.exec(parts[2]);
|
|
68
|
+
if (!hue || !sat || !lig)
|
|
69
|
+
return undefined;
|
|
70
|
+
const [r, g, b] = hslToRgb(Number(hue[1]), Number(sat[1]) / 100, Number(lig[1]) / 100);
|
|
71
|
+
return toHex(r, g, b, a);
|
|
72
|
+
}
|
|
73
|
+
/** The CSS named colors (CSS Color Module Level 4), without `transparent` and `currentcolor`. */
|
|
74
|
+
const NAMED_COLORS = new Set(("aliceblue antiquewhite aqua aquamarine azure beige bisque black blanchedalmond blue blueviolet brown " +
|
|
75
|
+
"burlywood cadetblue chartreuse chocolate coral cornflowerblue cornsilk crimson cyan darkblue darkcyan " +
|
|
76
|
+
"darkgoldenrod darkgray darkgreen darkgrey darkkhaki darkmagenta darkolivegreen darkorange darkorchid " +
|
|
77
|
+
"darkred darksalmon darkseagreen darkslateblue darkslategray darkslategrey darkturquoise darkviolet " +
|
|
78
|
+
"deeppink deepskyblue dimgray dimgrey dodgerblue firebrick floralwhite forestgreen fuchsia gainsboro " +
|
|
79
|
+
"ghostwhite gold goldenrod gray green greenyellow grey honeydew hotpink indianred indigo ivory khaki " +
|
|
80
|
+
"lavender lavenderblush lawngreen lemonchiffon lightblue lightcoral lightcyan lightgoldenrodyellow " +
|
|
81
|
+
"lightgray lightgreen lightgrey lightpink lightsalmon lightseagreen lightskyblue lightslategray " +
|
|
82
|
+
"lightslategrey lightsteelblue lightyellow lime limegreen linen magenta maroon mediumaquamarine " +
|
|
83
|
+
"mediumblue mediumorchid mediumpurple mediumseagreen mediumslateblue mediumspringgreen " +
|
|
84
|
+
"mediumturquoise mediumvioletred midnightblue mintcream mistyrose moccasin navajowhite navy oldlace " +
|
|
85
|
+
"olive olivedrab orange orangered orchid palegoldenrod palegreen paleturquoise palevioletred " +
|
|
86
|
+
"papayawhip peachpuff peru pink plum powderblue purple rebeccapurple red rosybrown royalblue " +
|
|
87
|
+
"saddlebrown salmon sandybrown seagreen seashell sienna silver skyblue slateblue slategray slategrey " +
|
|
88
|
+
"snow springgreen steelblue tan teal thistle tomato turquoise violet wheat white whitesmoke yellow " +
|
|
89
|
+
"yellowgreen").split(" "));
|
|
90
|
+
export const isNamedColor = (name) => NAMED_COLORS.has(name.toLowerCase());
|
|
91
|
+
/** Key used to compare a token value with a literal: hex and functional colors by value, names by name. */
|
|
92
|
+
export function colorKey(value) {
|
|
93
|
+
const v = value.trim();
|
|
94
|
+
if (/^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(v))
|
|
95
|
+
return expandHex(v);
|
|
96
|
+
const fn = normalizeColorFunction(v);
|
|
97
|
+
if (fn)
|
|
98
|
+
return fn;
|
|
99
|
+
if (isNamedColor(v))
|
|
100
|
+
return v.toLowerCase();
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
const COLOR_FN = /\b(?:rgba?|hsla?)\(\s*[^()]*?\s*\)/gi;
|
|
104
|
+
const COLOR_PROP = /(?<![\w-])(?:background(?:-?color)?|(?:border|outline|caret|accent|text-decoration|column-rule)(?:-?color)?|color|fill|stroke|border(?:-?(?:top|right|bottom|left))?(?:-?color)?)\s*[:=]\s*["'{`]*\s*([^;},\n]*)/gi;
|
|
105
|
+
/** rgb()/rgba()/hsl()/hsla() calls with literal numbers, in any text. */
|
|
106
|
+
export function colorFunctionLiterals(line) {
|
|
107
|
+
const out = [];
|
|
108
|
+
for (const m of line.matchAll(COLOR_FN)) {
|
|
109
|
+
const key = normalizeColorFunction(m[0]);
|
|
110
|
+
if (key)
|
|
111
|
+
out.push({ text: m[0], keys: [key], column: (m.index ?? 0) + 1 });
|
|
112
|
+
}
|
|
113
|
+
return out;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Named colors, only where the value of a color-bearing property is written: `color: red`,
|
|
117
|
+
* `border: 1px solid tomato`, `fill="teal"`. A bare word elsewhere is never a color.
|
|
118
|
+
*/
|
|
119
|
+
export function namedColorLiterals(line) {
|
|
120
|
+
const out = [];
|
|
121
|
+
for (const m of line.matchAll(COLOR_PROP)) {
|
|
122
|
+
const value = m[1];
|
|
123
|
+
const start = (m.index ?? 0) + m[0].length - value.length;
|
|
124
|
+
for (const w of value.matchAll(/(?<![\w./#-])[A-Za-z]+(?![\w.(-])/g)) {
|
|
125
|
+
if (isNamedColor(w[0]))
|
|
126
|
+
out.push({ text: w[0], keys: [w[0].toLowerCase()], column: start + (w.index ?? 0) + 1 });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return out;
|
|
130
|
+
}
|
|
131
|
+
/** A length as pixels: `px` as is, `rem` and `em` against a 16px root. Unitless is only px when `unitlessPx`. */
|
|
132
|
+
export function lengthKey(raw, unitlessPx) {
|
|
133
|
+
const m = /^(-?\d*\.?\d+)(px|rem|em)?$/.exec(raw.trim());
|
|
134
|
+
if (!m)
|
|
135
|
+
return undefined;
|
|
136
|
+
const n = Number(m[1]);
|
|
137
|
+
const unit = m[2];
|
|
138
|
+
if (unit === undefined && !unitlessPx)
|
|
139
|
+
return undefined;
|
|
140
|
+
const px = unit === "rem" || unit === "em" ? n * ROOT_PX : n;
|
|
141
|
+
return `${Number(px.toFixed(3))}px`;
|
|
142
|
+
}
|
|
143
|
+
const SPACING_PROP = /(?<![\w-])((?:margin|padding)(?:-?(?:top|right|bottom|left|inline|block)(?:-?(?:start|end))?)?|(?:row-?|column-?|grid-?)?gap)\s*[:=]\s*(["'{`]*)\s*([^;}\n,]*)/gi;
|
|
144
|
+
/** Spacing lengths in margin, padding and gap declarations. Zero, `auto`, `var()` and `calc()` are skipped. */
|
|
145
|
+
export function spacingLiterals(line) {
|
|
146
|
+
const out = [];
|
|
147
|
+
for (const m of line.matchAll(SPACING_PROP)) {
|
|
148
|
+
const quoted = m[2] !== "" && /["'`]/.test(m[2]);
|
|
149
|
+
if (/\(/.test(m[3]))
|
|
150
|
+
continue;
|
|
151
|
+
const value = m[3].replace(/["'`]+\s*$/, "");
|
|
152
|
+
const start = (m.index ?? 0) + m[0].length - m[3].length;
|
|
153
|
+
for (const t of value.matchAll(/\S+/g)) {
|
|
154
|
+
const key = lengthKey(t[0], !quoted);
|
|
155
|
+
if (key === undefined || Number.parseFloat(key) === 0)
|
|
156
|
+
continue;
|
|
157
|
+
out.push({
|
|
158
|
+
property: m[1],
|
|
159
|
+
text: t[0],
|
|
160
|
+
keys: [key],
|
|
161
|
+
column: start + (t.index ?? 0) + 1
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
167
|
+
const TYPE_PROP = /(?<![\w-])(font-?size|font-?weight|line-?height|letter-?spacing|font-?family)\s*[:=]\s*(["'{`]*)\s*/gi;
|
|
168
|
+
function typeKeys(prop, raw, quoted) {
|
|
169
|
+
const p = prop.toLowerCase().replace("-", "");
|
|
170
|
+
const v = raw.trim().replace(/["'`,)]+$/, "");
|
|
171
|
+
if (v === "" || /(?:var|calc|clamp|min|max)\(/i.test(v))
|
|
172
|
+
return [];
|
|
173
|
+
if (p === "fontweight") {
|
|
174
|
+
if (v === "normal")
|
|
175
|
+
return ["400"];
|
|
176
|
+
if (v === "bold")
|
|
177
|
+
return ["700"];
|
|
178
|
+
return /^\d{3}$/.test(v) ? [v] : [];
|
|
179
|
+
}
|
|
180
|
+
if (p === "fontfamily") {
|
|
181
|
+
const first = v
|
|
182
|
+
.split(",")[0]
|
|
183
|
+
?.trim()
|
|
184
|
+
.replace(/^["']|["']$/g, "");
|
|
185
|
+
return first ? [first.toLowerCase()] : [];
|
|
186
|
+
}
|
|
187
|
+
if (p === "lineheight" && /^\d*\.?\d+$/.test(v))
|
|
188
|
+
return [String(Number(v))];
|
|
189
|
+
const key = lengthKey(v, !quoted);
|
|
190
|
+
return key ? [key] : [];
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* The text of a value that starts at `from`. A quoted value ends at its closing quote, so a font-family list
|
|
194
|
+
* keeps its commas; an unquoted one ends at `;`, `}` or, in a style object, `,`.
|
|
195
|
+
*/
|
|
196
|
+
function valueText(line, from, quote, isFamily) {
|
|
197
|
+
const rest = line.slice(from);
|
|
198
|
+
const q = quote.replace(/[{\s]/g, "").slice(-1);
|
|
199
|
+
if (q) {
|
|
200
|
+
const end = rest.indexOf(q);
|
|
201
|
+
return end === -1 ? rest : rest.slice(0, end);
|
|
202
|
+
}
|
|
203
|
+
const end = rest.search(isFamily ? /[;}]/ : /[;},]/);
|
|
204
|
+
return end === -1 ? rest : rest.slice(0, end);
|
|
205
|
+
}
|
|
206
|
+
/** font-size, font-weight, line-height, letter-spacing and the first font-family name. */
|
|
207
|
+
export function typographyLiterals(line) {
|
|
208
|
+
const out = [];
|
|
209
|
+
for (const m of line.matchAll(TYPE_PROP)) {
|
|
210
|
+
const from = (m.index ?? 0) + m[0].length;
|
|
211
|
+
const quote = m[2];
|
|
212
|
+
const value = valueText(line, from, quote, /family/i.test(m[1]));
|
|
213
|
+
const keys = typeKeys(m[1], value, /["'`]/.test(quote));
|
|
214
|
+
if (keys.length === 0)
|
|
215
|
+
continue;
|
|
216
|
+
out.push({ property: m[1], text: value.trim(), keys, column: from + 1 });
|
|
217
|
+
}
|
|
218
|
+
return out;
|
|
219
|
+
}
|
|
220
|
+
/** Every comparable key a token value can match: lengths as px, plain numbers, names, and composite parts. */
|
|
221
|
+
export function tokenValueKeys(value, into = new Set()) {
|
|
222
|
+
if (typeof value === "number") {
|
|
223
|
+
into.add(String(value));
|
|
224
|
+
into.add(`${value}px`);
|
|
225
|
+
}
|
|
226
|
+
else if (typeof value === "string") {
|
|
227
|
+
const v = value.trim();
|
|
228
|
+
const len = lengthKey(v, false);
|
|
229
|
+
if (len)
|
|
230
|
+
into.add(len);
|
|
231
|
+
else if (/^\d*\.?\d+$/.test(v))
|
|
232
|
+
into.add(String(Number(v)));
|
|
233
|
+
else if (v !== "" && !/^(?:var|calc)\(/i.test(v)) {
|
|
234
|
+
into.add(v.toLowerCase());
|
|
235
|
+
const first = v
|
|
236
|
+
.split(",")[0]
|
|
237
|
+
?.trim()
|
|
238
|
+
.replace(/^["']|["']$/g, "");
|
|
239
|
+
if (first)
|
|
240
|
+
into.add(first.toLowerCase());
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
else if (Array.isArray(value))
|
|
244
|
+
for (const x of value)
|
|
245
|
+
tokenValueKeys(x, into);
|
|
246
|
+
else if (value && typeof value === "object")
|
|
247
|
+
for (const x of Object.values(value))
|
|
248
|
+
tokenValueKeys(x, into);
|
|
249
|
+
return into;
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=literals.js.map
|