@master/css-binding 0.0.0-site.1793659883.g69c9aebcf628

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.
Files changed (66) hide show
  1. package/artifacts/mastercss.node +0 -0
  2. package/artifacts/mcss +0 -0
  3. package/dist/binding-options.d.ts +14 -0
  4. package/dist/binding-options.js +15 -0
  5. package/dist/binding.d.ts +12 -0
  6. package/dist/binding.js +23 -0
  7. package/dist/browser.d.ts +3 -0
  8. package/dist/browser.js +3 -0
  9. package/dist/compiler-binding-adapter.js +55 -0
  10. package/dist/compiler-binding-browser.d.ts +6 -0
  11. package/dist/compiler-binding-browser.js +24 -0
  12. package/dist/compiler-binding-contract.d.ts +45 -0
  13. package/dist/compiler-binding-node.d.ts +5 -0
  14. package/dist/compiler-binding-node.js +20 -0
  15. package/dist/compiler-binding-wasm.js +58 -0
  16. package/dist/compiler-binding.d.ts +6 -0
  17. package/dist/compiler-binding.js +42 -0
  18. package/dist/compiler.js +52 -0
  19. package/dist/engine-binding-adapter.js +61 -0
  20. package/dist/engine-binding-browser.d.ts +8 -0
  21. package/dist/engine-binding-browser.js +35 -0
  22. package/dist/engine-binding-js.js +81 -0
  23. package/dist/engine-binding-node.d.ts +9 -0
  24. package/dist/engine-binding-node.js +38 -0
  25. package/dist/engine-binding-wasm.js +64 -0
  26. package/dist/engine-binding.d.ts +40 -0
  27. package/dist/engine-binding.js +57 -0
  28. package/dist/engine-contract.d.ts +14 -0
  29. package/dist/engine-js/src/animation.js +154 -0
  30. package/dist/engine-js/src/apply.js +207 -0
  31. package/dist/engine-js/src/class-syntax.js +333 -0
  32. package/dist/engine-js/src/condition.js +440 -0
  33. package/dist/engine-js/src/css-syntax.js +247 -0
  34. package/dist/engine-js/src/generate.js +288 -0
  35. package/dist/engine-js/src/mixin.js +328 -0
  36. package/dist/engine-js/src/native-properties.js +5 -0
  37. package/dist/engine-js/src/order.js +97 -0
  38. package/dist/engine-js/src/program-model.js +19 -0
  39. package/dist/engine-js/src/program.js +434 -0
  40. package/dist/engine-js/src/selector.js +195 -0
  41. package/dist/engine-js/src/session.js +540 -0
  42. package/dist/engine-js/src/state.js +62 -0
  43. package/dist/engine-js/src/text.js +51 -0
  44. package/dist/engine-js/src/utility.js +236 -0
  45. package/dist/engine-js/src/value.js +254 -0
  46. package/dist/engine.js +86 -0
  47. package/dist/errors.js +10 -0
  48. package/dist/index.d.ts +4 -0
  49. package/dist/index.js +3 -0
  50. package/dist/native-loader.js +134 -0
  51. package/dist/normalize-error.js +63 -0
  52. package/dist/protocol.d.ts +1119 -0
  53. package/dist/protocol.js +14 -0
  54. package/dist/tooling-binding-adapter.js +23 -0
  55. package/dist/tooling-binding-browser.d.ts +5 -0
  56. package/dist/tooling-binding-browser.js +15 -0
  57. package/dist/tooling-binding-contract.d.ts +92 -0
  58. package/dist/tooling-binding-native.js +46 -0
  59. package/dist/tooling-binding-node.d.ts +4 -0
  60. package/dist/tooling-binding-node.js +11 -0
  61. package/dist/tooling-binding-wasm.js +127 -0
  62. package/dist/tooling-binding.d.ts +5 -0
  63. package/dist/tooling-binding.js +21 -0
  64. package/dist/tooling.js +144 -0
  65. package/dist/version.js +3 -0
  66. package/package.json +78 -0
@@ -0,0 +1,288 @@
1
+ import { trim } from "./text.js";
2
+ import { collectCssVariableReferences, normalizeCssMathFunctions, substituteInlineTokens } from "./value.js";
3
+ import { cssEscape } from "./program.js";
4
+ import { analyzeAnimations, stylesheetDeclarations } from "./animation.js";
5
+ import { decodeNativeValue, parseNativeDeclaration, splitTopLevel, validClassStructure } from "./class-syntax.js";
6
+ import { atomicShape } from "./order.js";
7
+ import { conditionPriority } from "./condition.js";
8
+ import { replaceNestingSelector, selectorPriority } from "./selector.js";
9
+ import { expandUtility } from "./mixin.js";
10
+ import { resolveStateBranches } from "./state.js";
11
+ import { matchingUtilities } from "./utility.js";
12
+ import { applicationRules } from "./apply.js";
13
+ // ../engine-js/src/generate.ts
14
+ function formatDeclaration(property, value, important) {
15
+ return important && !value.endsWith("!important") ? `${property}:${value}!important` : `${property}:${value}`;
16
+ }
17
+ /**
18
+ * Compatibility declarations are an engine output policy, not preset recipes: every
19
+ * utility declaration, whether a native head, a token, a static or a function utility
20
+ * emits it, gets the same companions.
21
+ */
22
+ const WEBKIT_PROPERTIES = /* @__PURE__ */ new Set([
23
+ "text-decoration",
24
+ "backdrop-filter",
25
+ "box-decoration-break",
26
+ "mask-image",
27
+ "user-drag",
28
+ "user-select"
29
+ ]);
30
+ function formatOutputDeclaration(property, value, important) {
31
+ const standard = formatDeclaration(property, value, important);
32
+ return WEBKIT_PROPERTIES.has(property) ? `${formatDeclaration(`-webkit-${property}`, value, important)};${standard}` : standard;
33
+ }
34
+ function emitDeclarations(utility, matched, important, program) {
35
+ const { emit } = utility;
36
+ if (emit.type === "property") return matched.value === void 0 ? [] : [[
37
+ formatOutputDeclaration(emit.property, matched.value, important),
38
+ void 0,
39
+ []
40
+ ]];
41
+ return expansion(utility, matched, program).map(({ selector, conditions, declarations }) => [
42
+ declarations.map(([property, value]) => formatOutputDeclaration(property, value, important)).join(";"),
43
+ selector === "&" ? void 0 : selector,
44
+ conditions
45
+ ]);
46
+ }
47
+ /** The recipe expansion of a match, computed once and shared by its state branches. */
48
+ function expansion(utility, matched, program) {
49
+ const { emit } = utility;
50
+ if (emit.type !== "recipe") return [];
51
+ if (matched.expansion === void 0) matched.expansion = expandUtility(program, program.utilityDefinitions[emit.definition], matched.arguments) ?? null;
52
+ return matched.expansion ?? [];
53
+ }
54
+ /**
55
+ * The shape of a named utility match, read from its expanded structure before
56
+ * compatibility declarations: duplicates still count, so `margin:0;margin:0` is a recipe.
57
+ */
58
+ function utilityShape(utility, matched, program) {
59
+ if (utility.emit.type === "property") return matched.value === void 0 ? { category: 0 } : atomicShape(utility.emit.property, matched.value);
60
+ const [rule, other] = expansion(utility, matched, program);
61
+ return rule && !other && rule.selector === "&" && !rule.conditions.length && rule.declarations.length === 1 ? atomicShape(...rule.declarations[0]) : { category: 0 };
62
+ }
63
+ /** Declaration semantics for ordering; static and enum identities keep their manifest order. */
64
+ function sortKey(utility, matched, program) {
65
+ if (utility.utilityType === -2 && matched.matcherType !== "token") return "";
66
+ return emitDeclarations(utility, matched, false, program).map(([declarations]) => declarations).join(";");
67
+ }
68
+ /** The declaration of a `(property:value)` head as a property utility, its match and whether its value ends with `!important`. */
69
+ function nativeDeclaration(className) {
70
+ const head = parseNativeDeclaration(className);
71
+ if (!head) return;
72
+ const property = className.slice(...head.property);
73
+ const value = normalizeCssMathFunctions(decodeNativeValue(className.slice(...head.value)));
74
+ const id = `native:${property}`;
75
+ return [
76
+ {
77
+ id,
78
+ name: id,
79
+ utilityType: 0,
80
+ variableAliasRefs: [],
81
+ nativeFallback: true,
82
+ emit: {
83
+ type: "property",
84
+ property
85
+ },
86
+ matchers: []
87
+ },
88
+ {
89
+ value,
90
+ arguments: [],
91
+ stateToken: className.slice(head.suffixStart),
92
+ variableNames: [],
93
+ matcherType: "key"
94
+ },
95
+ head.important
96
+ ];
97
+ }
98
+ /** The class selector in a branch's template, then in a nested rule's. */
99
+ function createSelectorText(className, branch, ruleSelector) {
100
+ const body = `.${cssEscape(className)}`;
101
+ const template = branch.selectorTemplate;
102
+ const selector = template === void 0 ? body : replaceNestingSelector(template, body) ?? template;
103
+ return ruleSelector === void 0 ? selector : replaceNestingSelector(ruleSelector, selector) ?? ruleSelector;
104
+ }
105
+ function wrapRawConditions(text, conditions) {
106
+ for (let index = conditions.length - 1; index >= 0; index--) {
107
+ const condition = trim(conditions[index]);
108
+ if (condition) text = `${condition}{${text}}`;
109
+ }
110
+ return text;
111
+ }
112
+ const reportedFeatures = (features) => features.some(({ lower, upper }) => Object.is(lower?.value, -0) || Object.is(upper?.value, -0)) ? features.map((feature) => ({
113
+ ...feature,
114
+ lower: feature.lower && {
115
+ ...feature.lower,
116
+ value: feature.lower.value + 0
117
+ },
118
+ upper: feature.upper && {
119
+ ...feature.upper,
120
+ value: feature.upper.value + 0
121
+ }
122
+ })) : features;
123
+ /** A rule priority as the Rust JSON reports it, omitting empty fields. */
124
+ function rulePriority(features, selector, conditions, valuePriority, sortKey, shape) {
125
+ const priority = {
126
+ features: reportedFeatures(features),
127
+ selector
128
+ };
129
+ if (conditions.length) priority.conditions = conditions;
130
+ if (valuePriority) priority.valuePriority = valuePriority;
131
+ if (sortKey) priority.sortKey = sortKey;
132
+ priority.category = shape.category;
133
+ for (const key of [
134
+ "family",
135
+ "coverage",
136
+ "property"
137
+ ]) if (shape[key]) priority[key] = shape[key];
138
+ return priority;
139
+ }
140
+ function declarationAnimationReferences(declarations, program) {
141
+ if (!declarations.includes("\\") && !/animation/i.test(declarations)) return {
142
+ names: [],
143
+ retainAll: false
144
+ };
145
+ return analyzeAnimations(stylesheetDeclarations(`a{${declarations}}`), program);
146
+ }
147
+ /** Keyframe references of a rule; absent when there are none. */
148
+ function addAnimationReferences(ir, declarations, program) {
149
+ const { names, retainAll } = declarationAnimationReferences(declarations, program);
150
+ if (names.length) ir.keyframeNames = names;
151
+ if (retainAll) ir.retainAllKeyframes = true;
152
+ }
153
+ /**
154
+ * Matches a class and visits each state branch that emits declarations. A
155
+ * `(property:value)` head is a native declaration and never a utility.
156
+ */
157
+ function generatedBranches(className, program, visit) {
158
+ const classImportant = className.endsWith("!");
159
+ const source = classImportant ? className.slice(0, -1) : className;
160
+ const candidates = matchingUtilities(source, program).map(([index, matched]) => [
161
+ program.utilities[index],
162
+ matched,
163
+ classImportant,
164
+ void 0
165
+ ]);
166
+ const native = nativeDeclaration(source);
167
+ if (native) candidates.push([
168
+ native[0],
169
+ native[1],
170
+ classImportant || native[2],
171
+ { category: 2 }
172
+ ]);
173
+ const seen = /* @__PURE__ */ new Set();
174
+ for (const [utility, matched, important, nativeShape] of candidates) {
175
+ const shape = nativeShape ?? utilityShape(utility, matched, program);
176
+ let branchSortKey = shape.content;
177
+ for (const [index, branch] of resolveStateBranches(matched.stateToken, important, program).entries()) {
178
+ const rules = emitDeclarations(utility, matched, branch.important, program);
179
+ if (!rules.length) continue;
180
+ const key = index === 0 && !branch.key ? className : `${className}\0${branch.key}`;
181
+ const layer = branch.layer ?? "utilities";
182
+ if (seen.has(`${layer} ${key}`)) continue;
183
+ seen.add(`${layer} ${key}`);
184
+ const wrappers = branch.conditionWrappers;
185
+ const [features, conditions] = conditionPriority(wrappers);
186
+ branchSortKey ??= sortKey(utility, matched, program);
187
+ visit({
188
+ utility,
189
+ matched,
190
+ branch,
191
+ key,
192
+ layer,
193
+ emitted: rules,
194
+ sortTier: wrappers.length ? 3 : branch.selectorTemplate === void 0 ? 0 : 1,
195
+ features,
196
+ priority: rulePriority(features, selectorPriority(branch.selectorTemplate), conditions, matched.matcherType === "token" ? -1 : 0, branchSortKey, shape)
197
+ });
198
+ }
199
+ }
200
+ }
201
+ function generateClassRules(className, program) {
202
+ const application = applicationRules(className, program);
203
+ if (application) return application;
204
+ if (!validClassStructure(className)) return [];
205
+ const rules = [];
206
+ generatedBranches(className, program, ({ utility, matched, branch, key, layer, emitted, sortTier, features, priority }) => {
207
+ const selectorText = createSelectorText(className, branch);
208
+ const texts = [];
209
+ const declarationTexts = [];
210
+ for (const [raw, selector, conditions] of emitted) {
211
+ const declarations = substituteInlineTokens(raw, program);
212
+ const text = wrapRawConditions(`${selector === void 0 ? selectorText : createSelectorText(className, branch, selector)}{${declarations}}`, conditions);
213
+ texts.push(branch.conditionWrappers.reduceRight((rule, [, wrapper]) => `${wrapper}{${rule}}`, text));
214
+ declarationTexts.push(declarations);
215
+ }
216
+ const declarations = declarationTexts.join(";");
217
+ const variableNames = matched.variableNames.filter((name) => program.variables.get(name)?.inlineValue === void 0);
218
+ for (const name of collectCssVariableReferences(declarations)) if (program.variables.has(name) && !variableNames.includes(name)) variableNames.push(name);
219
+ const ir = {
220
+ className,
221
+ key,
222
+ layer,
223
+ type: utility.utilityType,
224
+ sortTier,
225
+ priority,
226
+ text: texts.join(""),
227
+ selectorText
228
+ };
229
+ if (texts.length > 1) ir.nodes = texts.map((text) => ({ text }));
230
+ if (variableNames.length) ir.variableNames = variableNames;
231
+ addAnimationReferences(ir, declarations, program);
232
+ rules.push({
233
+ ir,
234
+ features
235
+ });
236
+ });
237
+ return rules;
238
+ }
239
+ /** Serialized declarations split at top-level `;` and their first top-level `:`. */
240
+ function parseSerializedDeclarations(source) {
241
+ const declarations = [];
242
+ for (const declaration of splitTopLevel(source, ";")) {
243
+ let quote = 0;
244
+ let escaped = false;
245
+ let depth = 0;
246
+ let separator = -1;
247
+ for (let index = 0; index < declaration.length; index++) {
248
+ const unit = declaration.charCodeAt(index);
249
+ if (escaped) escaped = false;
250
+ else if (unit === 92) escaped = true;
251
+ else if (quote) {
252
+ if (unit === quote) quote = 0;
253
+ } else if (unit === 34 || unit === 39) quote = unit;
254
+ else if (unit === 40 || unit === 91 || unit === 123) depth++;
255
+ else if (unit === 41 || unit === 93 || unit === 125) {
256
+ if (depth) depth--;
257
+ } else if (unit === 58 && !depth) {
258
+ separator = index;
259
+ break;
260
+ }
261
+ }
262
+ if (separator < 0) continue;
263
+ const property = trim(declaration.slice(0, separator));
264
+ if (property) declarations.push([property, trim(declaration.slice(separator + 1))]);
265
+ }
266
+ return declarations;
267
+ }
268
+ /** The rules of a class without `@apply` suffixes, before inline theme substitution. */
269
+ function compositionRules(className, program) {
270
+ if (!validClassStructure(className)) return [];
271
+ const rules = [];
272
+ generatedBranches(className, program, ({ utility, branch, layer, emitted, priority }) => {
273
+ const template = branch.selectorTemplate;
274
+ const base = template === void 0 ? "&" : replaceNestingSelector(template, "&") ?? template;
275
+ const branchConditions = branch.conditionWrappers.filter(([kind]) => kind !== "layer" || branch.layer === void 0).map(([, wrapper]) => wrapper);
276
+ for (const [declarations, selector, conditions] of emitted) rules.push({
277
+ layer,
278
+ explicitLayer: branch.layer,
279
+ type: utility.utilityType,
280
+ valuePriority: priority.valuePriority ?? 0,
281
+ selector: selector === void 0 ? base : replaceNestingSelector(selector, base) ?? selector,
282
+ declarations: parseSerializedDeclarations(declarations),
283
+ conditions: [...branchConditions, ...conditions]
284
+ });
285
+ });
286
+ return rules;
287
+ }
288
+ export { addAnimationReferences, compositionRules, declarationAnimationReferences, formatDeclaration, generateClassRules, nativeDeclaration, rulePriority, wrapRawConditions };
@@ -0,0 +1,328 @@
1
+ import { asciiLowercase, isWhitespace, trim } from "./text.js";
2
+ import { tokenize } from "./css-syntax.js";
3
+ import { decimalIsFinite, parseDecimal } from "./value.js";
4
+ import { cssEscape } from "./program.js";
5
+ import { splitTopLevel } from "./class-syntax.js";
6
+ import { replaceNestingSelector } from "./selector.js";
7
+ import { NATIVE_CSS_PROPERTY_SET } from "./native-properties.js";
8
+ // ../engine-js/src/mixin.ts
9
+ /** Unwinds an expansion that fails; never leaves this module. */
10
+ const EXPANSION_ERROR = /* @__PURE__ */ new Error("Invalid mixin expansion");
11
+ const fail = () => {
12
+ throw EXPANSION_ERROR;
13
+ };
14
+ const MAX_DEPTH = 64;
15
+ const MAX_STEPS = 1e5;
16
+ const EMPTY = /* @__PURE__ */ new Map();
17
+ const WIDE_KEYWORDS = /* @__PURE__ */ new Set([
18
+ "initial",
19
+ "inherit",
20
+ "unset",
21
+ "revert",
22
+ "revert-layer",
23
+ "default"
24
+ ]);
25
+ const isWide = (name) => WIDE_KEYWORDS.has(asciiLowercase(name));
26
+ const DYNAMIC_FUNCTIONS = /* @__PURE__ */ new Set([
27
+ "attr",
28
+ "env",
29
+ "random",
30
+ "random-item"
31
+ ]);
32
+ /** Rust `str::parse::<i64>`: an optional sign and digits within range. */
33
+ function isInteger(text) {
34
+ if (!/^[+-]?\d+$/.test(text)) return false;
35
+ const value = BigInt(text);
36
+ return value >= -9223372036854775808n && value <= 9223372036854775807n;
37
+ }
38
+ function validArgument(parameter, value, allowVar) {
39
+ const tokens = tokenize(value);
40
+ if (!tokens.length) return false;
41
+ for (const token of tokens) if (token.kind === 3) {
42
+ const name = asciiLowercase(token.value);
43
+ if (name === "var" && !allowVar || DYNAMIC_FUNCTIONS.has(name) || token.value.startsWith("--")) return false;
44
+ }
45
+ for (const token of tokens) {
46
+ if (token.kind === 8 && ";{}!".includes(token.value)) return false;
47
+ if ((token.kind === 3 || token.kind === 8 && (token.value === "(" || token.value === "[")) && token.close < 0) return false;
48
+ }
49
+ const [only] = tokens;
50
+ const single = tokens.length === 1;
51
+ if (single && only.kind === 0 && isWide(only.value)) return false;
52
+ switch (parameter.syntax) {
53
+ case void 0: return true;
54
+ case "integer": return single && only.kind === 4 && isInteger(only.value);
55
+ case "number": {
56
+ const decimal = single && only.kind === 4 ? parseDecimal(only.value) : void 0;
57
+ return !!decimal && decimalIsFinite(decimal);
58
+ }
59
+ case "string": return single && only.kind === 1 && (value.endsWith("\"") || value.endsWith("'"));
60
+ case "custom-ident": return single && only.kind === 0 && !isWide(only.value);
61
+ }
62
+ }
63
+ function ident(value) {
64
+ let result = "";
65
+ for (const token of tokenize(value)) if (token.kind === 1 || token.kind === 0 || token.kind === 4 && isInteger(token.value)) result += token.value;
66
+ else return;
67
+ return result ? cssEscape(result) : void 0;
68
+ }
69
+ /** The parameter a `var()` argument names, when the environment binds it. */
70
+ function parameterValue(inner, environment) {
71
+ const tokens = tokenize(trim(splitTopLevel(inner, ",")[0]));
72
+ return tokens.length === 1 && tokens[0].kind === 0 ? environment.get(tokens[0].value) : void 0;
73
+ }
74
+ /** A mixin value with bound parameters substituted; undefined when an `ident()` is invalid. */
75
+ function evaluateValue(value, environment) {
76
+ let output = "";
77
+ for (const part of value) {
78
+ if (part.type === "text") {
79
+ output += part.value;
80
+ continue;
81
+ }
82
+ const inner = evaluateValue(part.value, environment);
83
+ if (inner === void 0) return;
84
+ const name = asciiLowercase(part.name);
85
+ const argument = name === "var" ? parameterValue(inner, environment) : void 0;
86
+ if (argument !== void 0) output += argument;
87
+ else if (name === "ident") {
88
+ const result = ident(inner);
89
+ if (result === void 0) return;
90
+ output += result;
91
+ } else output += `${part.name}(${inner})`;
92
+ }
93
+ return output;
94
+ }
95
+ function referencesParameters(value, environment) {
96
+ if (!environment.size) return false;
97
+ return value.some((part) => {
98
+ if (part.type === "text") return false;
99
+ if (asciiLowercase(part.name) === "var") {
100
+ const inner = evaluateValue(part.value, EMPTY);
101
+ if (inner !== void 0 && parameterValue(inner, environment) !== void 0) return true;
102
+ }
103
+ return referencesParameters(part.value, environment);
104
+ });
105
+ }
106
+ const restricted = (environment, names) => {
107
+ if (!names.size) return EMPTY;
108
+ const result = /* @__PURE__ */ new Map();
109
+ for (const [name, value] of environment) if (names.has(name)) result.set(name, value);
110
+ return result;
111
+ };
112
+ const PSEUDO_ELEMENTS = /* @__PURE__ */ new Set([
113
+ "before",
114
+ "after",
115
+ "first-letter",
116
+ "first-line"
117
+ ]);
118
+ /**
119
+ * A nested selector stays on the invoking element only when it is one compound rooted
120
+ * at `&`, without a pseudo-element. Functional pseudo-classes may hold selector
121
+ * arguments without changing the subject.
122
+ */
123
+ function sameSubject(selector) {
124
+ return splitTopLevel(selector, ",").every((part) => {
125
+ const branch = trim(part);
126
+ const tokens = tokenize(branch);
127
+ let ampersands = 0;
128
+ let subject = false;
129
+ let previousEnd = 0;
130
+ for (let index = 0; index < tokens.length; index++) {
131
+ const token = tokens[index];
132
+ for (let unit = previousEnd; unit < token.start; unit++) if (isWhitespace(branch.charCodeAt(unit))) {
133
+ subject = false;
134
+ break;
135
+ }
136
+ if (token.kind === 8) {
137
+ if (token.value === "&") {
138
+ ampersands++;
139
+ subject = true;
140
+ } else if (">+~|".includes(token.value)) subject = false;
141
+ else if (token.value === ":") {
142
+ const next = tokens[index + 1];
143
+ if (next && (next.kind === 8 && next.value === ":" || next.kind === 0 && PSEUDO_ELEMENTS.has(next.value))) return false;
144
+ }
145
+ }
146
+ if (token.kind === 3 || token.kind === 8 && token.value === "[") {
147
+ if (token.close < 0) return false;
148
+ index = token.close;
149
+ }
150
+ previousEnd = tokens[index].end;
151
+ }
152
+ return ampersands === 1 && subject;
153
+ });
154
+ }
155
+ /** Whether a number token is a positive integer, decided on its digits; one beyond `f64` is not. */
156
+ function isPositiveInteger(number) {
157
+ const decimal = parseDecimal(number);
158
+ return !decimal || !decimal.negative && !!decimal.digits && decimal.point >= decimal.digits.length && decimalIsFinite(decimal);
159
+ }
160
+ /** Substituted values keep the positive integers the grammar requires. */
161
+ function validDeclaration(name, value) {
162
+ const tokens = tokenize(value);
163
+ const property = asciiLowercase(name);
164
+ for (const [index, token] of tokens.entries()) {
165
+ const positive = token.kind === 3 && asciiLowercase(token.value) === "repeat" || (property === "grid-column" || property === "grid-row") && token.kind === 0 && asciiLowercase(token.value) === "span";
166
+ const next = tokens[index + 1];
167
+ if (positive && next?.kind === 4 && !isPositiveInteger(next.value)) return false;
168
+ }
169
+ return property !== "-webkit-line-clamp" || tokens[0]?.kind !== 4 || isPositiveInteger(tokens[0].value);
170
+ }
171
+ const directValueMixins = /* @__PURE__ */ new WeakMap();
172
+ /** Only this identity-shaped body, `property: var(--parameter)`, accepts delayed CSS values as arguments. */
173
+ function isDirectValueMixin(definition) {
174
+ let direct = directValueMixins.get(definition);
175
+ if (direct === void 0) directValueMixins.set(definition, direct = directValue(definition));
176
+ return direct;
177
+ }
178
+ function directValue({ parameters, body }) {
179
+ const [parameter] = parameters;
180
+ const [declaration] = body;
181
+ if (parameters.length !== 1 || parameter.syntax !== void 0 || parameter.default !== void 0) return false;
182
+ if (body.length !== 1 || declaration.type !== "declaration") return false;
183
+ if (declaration.property.startsWith("--") || !NATIVE_CSS_PROPERTY_SET.has(declaration.property)) return false;
184
+ const parts = declaration.value.filter((part) => part.type !== "text" || trim(part.value));
185
+ const [call] = parts;
186
+ if (parts.length !== 1 || call.type !== "function" || asciiLowercase(call.name) !== "var") return false;
187
+ let argument = "";
188
+ for (const part of call.value) {
189
+ if (part.type !== "text") return false;
190
+ argument += part.value;
191
+ }
192
+ const tokens = tokenize(argument);
193
+ return tokens.length === 1 && tokens[0].kind === 0 && tokens[0].value === parameter.name;
194
+ }
195
+ const sameConditions = (left, right) => left.length === right.length && left.every((condition, index) => condition === right[index]);
196
+ var Expansion = class {
197
+ lookup;
198
+ symbolicRoot;
199
+ stack = [];
200
+ output = [];
201
+ steps = 0;
202
+ depth = 0;
203
+ constructor(lookup, symbolicRoot) {
204
+ this.lookup = lookup;
205
+ this.symbolicRoot = symbolicRoot;
206
+ }
207
+ call(name, args, outer, selector, conditions, forbidden, contents) {
208
+ if (this.depth >= MAX_DEPTH || this.stack.includes(name)) fail();
209
+ const definition = this.lookup(name) ?? fail();
210
+ this.stack.push(name);
211
+ this.depth++;
212
+ if (args.length > definition.parameters.length) fail();
213
+ const environment = new Map(outer);
214
+ const allowVar = isDirectValueMixin(definition) || this.symbolicRoot === name;
215
+ const unbound = new Set(forbidden);
216
+ for (const [index, parameter] of definition.parameters.entries()) {
217
+ const value = index < args.length ? args[index] : parameter.default ?? fail();
218
+ if (!validArgument(parameter, value, allowVar)) fail();
219
+ environment.set(parameter.name, value);
220
+ unbound.delete(parameter.name);
221
+ }
222
+ this.nodes(definition.body, environment, selector, conditions, true, unbound, contents);
223
+ this.stack.pop();
224
+ this.depth--;
225
+ }
226
+ /** Whether a value uses a parameter it may not: any across elements, or a forbidden one. */
227
+ crossesElements(value, environment, safeSubject, forbidden) {
228
+ return !safeSubject && referencesParameters(value, environment) || referencesParameters(value, restricted(environment, forbidden));
229
+ }
230
+ nodes(nodes, environment, selector, conditions, safeSubject, forbidden, contents) {
231
+ for (const node of nodes) {
232
+ if (++this.steps > MAX_STEPS) fail();
233
+ switch (node.type) {
234
+ case "declaration": {
235
+ if (environment.has(node.property) || this.crossesElements(node.value, environment, safeSubject, forbidden)) fail();
236
+ const substituted = referencesParameters(node.value, environment);
237
+ const value = evaluateValue(node.value, environment) ?? fail();
238
+ if (substituted && !validDeclaration(node.property, value)) fail();
239
+ const previous = this.output[this.output.length - 1];
240
+ if (previous && previous.selector === selector && sameConditions(previous.conditions, conditions)) previous.declarations.push([node.property, value]);
241
+ else this.output.push({
242
+ selector,
243
+ conditions: [...conditions],
244
+ declarations: [[node.property, value]]
245
+ });
246
+ break;
247
+ }
248
+ case "rule": {
249
+ const next = replaceNestingSelector(node.selector, selector) ?? `${selector} ${node.selector}`;
250
+ this.nodes(node.body, environment, next, conditions, safeSubject && sameSubject(node.selector), forbidden, contents);
251
+ break;
252
+ }
253
+ case "condition":
254
+ this.nodes(node.body, environment, selector, [...conditions, node.condition], safeSubject, forbidden, contents);
255
+ break;
256
+ case "contents":
257
+ if (contents) {
258
+ const stack = this.stack;
259
+ this.stack = [...contents.stack];
260
+ this.nodes(contents.nodes, contents.environment, selector, conditions, safeSubject && contents.safeSubject, contents.forbidden, contents.outer);
261
+ this.stack = stack;
262
+ } else this.nodes(node.fallback, environment, selector, conditions, safeSubject, forbidden);
263
+ break;
264
+ case "apply": {
265
+ if (node.arguments.some((argument) => this.crossesElements(argument, environment, safeSubject, forbidden))) fail();
266
+ const args = node.arguments.map((argument) => evaluateValue(argument, environment) ?? fail());
267
+ const next = safeSubject ? forbidden : /* @__PURE__ */ new Set([...forbidden, ...environment.keys()]);
268
+ const passed = node.contents && {
269
+ nodes: node.contents,
270
+ environment,
271
+ outer: contents,
272
+ stack: [...this.stack],
273
+ safeSubject,
274
+ forbidden: next
275
+ };
276
+ this.call(node.name, args, environment, selector, conditions, next, passed);
277
+ break;
278
+ }
279
+ }
280
+ }
281
+ }
282
+ };
283
+ const registries = /* @__PURE__ */ new WeakMap();
284
+ /** Mixins by name; a later definition replaces an earlier one. */
285
+ function registry(mixins) {
286
+ let result = registries.get(mixins);
287
+ if (!result) registries.set(mixins, result = new Map(mixins.map((definition) => [definition.name, definition])));
288
+ return result;
289
+ }
290
+ function run(expansion, execute) {
291
+ try {
292
+ execute();
293
+ } catch (error) {
294
+ if (error === EXPANSION_ERROR) return;
295
+ throw error;
296
+ }
297
+ return expansion.output;
298
+ }
299
+ /** A mixin call, with the caller's `@contents` when given. */
300
+ function expandMixin(program, name, args, contents) {
301
+ const mixins = registry(program.mixins);
302
+ const expansion = new Expansion((mixin) => mixins.get(mixin));
303
+ const context = contents && {
304
+ nodes: contents,
305
+ environment: EMPTY,
306
+ stack: [],
307
+ safeSubject: true,
308
+ forbidden: /* @__PURE__ */ new Set()
309
+ };
310
+ return run(expansion, () => expansion.call(name, args, EMPTY, "&", [], /* @__PURE__ */ new Set(), context));
311
+ }
312
+ /** An already compiled caller body, without a named definition. */
313
+ function expandBody(program, body) {
314
+ const mixins = registry(program.mixins);
315
+ const expansion = new Expansion((mixin) => mixins.get(mixin));
316
+ return run(expansion, () => expansion.nodes(body, EMPTY, "&", [], true, /* @__PURE__ */ new Set()));
317
+ }
318
+ /**
319
+ * A utility recipe, registered in its own namespace over the mixins. Only token
320
+ * recipes with an untyped value bind symbolic arguments such as `var()`.
321
+ */
322
+ function expandUtility(program, definition, args) {
323
+ const { recipe } = definition;
324
+ const mixins = registry(program.mixins);
325
+ const expansion = new Expansion((name) => name === recipe.name ? recipe : mixins.get(name), definition.kind === "token" && recipe.parameters[0]?.syntax === void 0 ? recipe.name : void 0);
326
+ return run(expansion, () => expansion.call(recipe.name, args, EMPTY, "&", [], /* @__PURE__ */ new Set()));
327
+ }
328
+ export { expandBody, expandMixin, expandUtility };
@@ -0,0 +1,5 @@
1
+ // ../engine-js/src/native-properties.ts
2
+ /** The native CSS property registry in byte order, including the `--*` entry. */
3
+ const NATIVE_CSS_PROPERTIES = "--* -moz-appearance -moz-binding -moz-border-bottom-colors -moz-border-left-colors -moz-border-right-colors -moz-border-top-colors -moz-context-properties -moz-float-edge -moz-force-broken-image-icon -moz-orient -moz-outline-radius -moz-outline-radius-bottomleft -moz-outline-radius-bottomright -moz-outline-radius-topleft -moz-outline-radius-topright -moz-stack-sizing -moz-text-blink -moz-user-focus -moz-user-input -moz-user-modify -moz-window-dragging -moz-window-shadow -ms-accelerator -ms-block-progression -ms-content-zoom-chaining -ms-content-zoom-limit -ms-content-zoom-limit-max -ms-content-zoom-limit-min -ms-content-zoom-snap -ms-content-zoom-snap-points -ms-content-zoom-snap-type -ms-content-zooming -ms-filter -ms-flow-from -ms-flow-into -ms-grid-columns -ms-grid-rows -ms-high-contrast-adjust -ms-hyphenate-limit-chars -ms-hyphenate-limit-lines -ms-hyphenate-limit-zone -ms-ime-align -ms-overflow-style -ms-scroll-chaining -ms-scroll-limit -ms-scroll-limit-x-max -ms-scroll-limit-x-min -ms-scroll-limit-y-max -ms-scroll-limit-y-min -ms-scroll-rails -ms-scroll-snap-points-x -ms-scroll-snap-points-y -ms-scroll-snap-type -ms-scroll-snap-x -ms-scroll-snap-y -ms-scroll-translation -ms-scrollbar-3dlight-color -ms-scrollbar-arrow-color -ms-scrollbar-base-color -ms-scrollbar-darkshadow-color -ms-scrollbar-face-color -ms-scrollbar-highlight-color -ms-scrollbar-shadow-color -ms-scrollbar-track-color -ms-text-autospace -ms-touch-select -ms-user-select -ms-wrap-flow -ms-wrap-margin -ms-wrap-through -webkit-appearance -webkit-border-after -webkit-border-after-color -webkit-border-after-style -webkit-border-after-width -webkit-border-before -webkit-border-before-color -webkit-border-before-style -webkit-border-before-width -webkit-border-end -webkit-border-end-color -webkit-border-end-style -webkit-border-end-width -webkit-border-start -webkit-border-start-color -webkit-border-start-style -webkit-border-start-width -webkit-box-reflect -webkit-line-clamp -webkit-mask -webkit-mask-attachment -webkit-mask-clip -webkit-mask-composite -webkit-mask-image -webkit-mask-origin -webkit-mask-position -webkit-mask-position-x -webkit-mask-position-y -webkit-mask-repeat -webkit-mask-repeat-x -webkit-mask-repeat-y -webkit-mask-size -webkit-overflow-scrolling -webkit-tap-highlight-color -webkit-text-fill-color -webkit-text-stroke -webkit-text-stroke-color -webkit-text-stroke-width -webkit-touch-callout -webkit-user-modify -webkit-user-select accent-color align-content align-items align-self align-tracks alignment-baseline all anchor-name anchor-scope animation animation-composition animation-delay animation-direction animation-duration animation-fill-mode animation-iteration-count animation-name animation-play-state animation-range animation-range-end animation-range-start animation-timeline animation-timing-function animation-trigger appearance aspect-ratio backdrop-filter backface-visibility background background-attachment background-blend-mode background-clip background-color background-image background-origin background-position background-position-x background-position-y background-repeat background-size baseline-shift baseline-source block-size border border-block border-block-color border-block-end border-block-end-color border-block-end-style border-block-end-width border-block-start border-block-start-color border-block-start-style border-block-start-width border-block-style border-block-width border-bottom border-bottom-color border-bottom-left-radius border-bottom-right-radius border-bottom-style border-bottom-width border-collapse border-color border-end-end-radius border-end-start-radius border-image border-image-outset border-image-repeat border-image-slice border-image-source border-image-width border-inline border-inline-color border-inline-end border-inline-end-color border-inline-end-style border-inline-end-width border-inline-start border-inline-start-color border-inline-start-style border-inline-start-width border-inline-style border-inline-width border-left border-left-color border-left-style border-left-width border-radius border-right border-right-color border-right-style border-right-width border-shape border-spacing border-start-end-radius border-start-start-radius border-style border-top border-top-color border-top-left-radius border-top-right-radius border-top-style border-top-width border-width bottom box-align box-decoration-break box-direction box-flex box-flex-group box-lines box-ordinal-group box-orient box-pack box-shadow box-sizing break-after break-before break-inside caption-side caret caret-animation caret-color caret-shape clear clip clip-path clip-rule color color-interpolation-filters color-scheme column-count column-fill column-gap column-height column-rule column-rule-color column-rule-style column-rule-width column-span column-width column-wrap columns contain contain-intrinsic-block-size contain-intrinsic-height contain-intrinsic-inline-size contain-intrinsic-size contain-intrinsic-width container container-name container-type content content-visibility corner-block-end-shape corner-block-start-shape corner-bottom-left-shape corner-bottom-right-shape corner-bottom-shape corner-end-end-shape corner-end-start-shape corner-inline-end-shape corner-inline-start-shape corner-left-shape corner-right-shape corner-shape corner-start-end-shape corner-start-start-shape corner-top-left-shape corner-top-right-shape corner-top-shape counter-increment counter-reset counter-set cursor cx cy d direction display dominant-baseline dynamic-range-limit empty-cells field-sizing fill fill-opacity fill-rule filter flex flex-basis flex-direction flex-flow flex-grow flex-line-count flex-shrink flex-wrap float flood-color flood-opacity font font-family font-feature-settings font-kerning font-language-override font-optical-sizing font-palette font-size font-size-adjust font-smooth font-stretch font-style font-synthesis font-synthesis-position font-synthesis-small-caps font-synthesis-style font-synthesis-weight font-variant font-variant-alternates font-variant-caps font-variant-east-asian font-variant-emoji font-variant-ligatures font-variant-numeric font-variant-position font-variation-settings font-weight font-width forced-color-adjust frame-sizing gap grid grid-area grid-auto-columns grid-auto-flow grid-auto-rows grid-column grid-column-end grid-column-gap grid-column-start grid-gap grid-row grid-row-end grid-row-gap grid-row-start grid-template grid-template-areas grid-template-columns grid-template-rows hanging-punctuation height hyphenate-character hyphenate-limit-chars hyphens image-orientation image-rendering image-resolution ime-mode initial-letter initial-letter-align inline-size inset inset-block inset-block-end inset-block-start inset-inline inset-inline-end inset-inline-start interactivity interest-delay interest-delay-end interest-delay-start interpolate-size isolation justify-content justify-items justify-self justify-tracks left letter-spacing lighting-color line-break line-clamp line-height line-height-step link-parameters list-style list-style-image list-style-position list-style-type margin margin-block margin-block-end margin-block-start margin-bottom margin-inline margin-inline-end margin-inline-start margin-left margin-right margin-top margin-trim marker marker-end marker-mid marker-start mask mask-border mask-border-mode mask-border-outset mask-border-repeat mask-border-slice mask-border-source mask-border-width mask-clip mask-composite mask-image mask-mode mask-origin mask-position mask-repeat mask-size mask-type masonry-auto-flow math-depth math-shift math-style max-block-size max-height max-inline-size max-lines max-width min-block-size min-height min-inline-size min-width mix-blend-mode object-fit object-position object-view-box offset offset-anchor offset-distance offset-path offset-position offset-rotate opacity order orphans outline outline-color outline-offset outline-style outline-width overflow overflow-anchor overflow-block overflow-clip-box overflow-clip-margin overflow-inline overflow-wrap overflow-x overflow-y overlay overscroll-behavior overscroll-behavior-block overscroll-behavior-inline overscroll-behavior-x overscroll-behavior-y padding padding-block padding-block-end padding-block-start padding-bottom padding-inline padding-inline-end padding-inline-start padding-left padding-right padding-top page page-break-after page-break-before page-break-inside paint-order path-length perspective perspective-origin place-content place-items place-self pointer-events position position-anchor position-area position-try position-try-fallbacks position-try-order position-visibility print-color-adjust quotes r reading-flow reading-order resize right rotate row-gap ruby-align ruby-merge ruby-overhang ruby-position rx ry scale scroll-axis-lock scroll-behavior scroll-initial-target scroll-margin scroll-margin-block scroll-margin-block-end scroll-margin-block-start scroll-margin-bottom scroll-margin-inline scroll-margin-inline-end scroll-margin-inline-start scroll-margin-left scroll-margin-right scroll-margin-top scroll-marker-group scroll-padding scroll-padding-block scroll-padding-block-end scroll-padding-block-start scroll-padding-bottom scroll-padding-inline scroll-padding-inline-end scroll-padding-inline-start scroll-padding-left scroll-padding-right scroll-padding-top scroll-snap-align scroll-snap-coordinate scroll-snap-destination scroll-snap-points-x scroll-snap-points-y scroll-snap-stop scroll-snap-type scroll-snap-type-x scroll-snap-type-y scroll-target-group scroll-timeline scroll-timeline-axis scroll-timeline-name scrollbar-color scrollbar-gutter scrollbar-width shape-image-threshold shape-margin shape-outside shape-rendering speak-as stop-color stop-opacity stroke stroke-color stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width tab-size table-layout text-align text-align-last text-anchor text-autospace text-box text-box-edge text-box-trim text-combine-upright text-decoration text-decoration-color text-decoration-inset text-decoration-line text-decoration-skip text-decoration-skip-ink text-decoration-style text-decoration-thickness text-emphasis text-emphasis-color text-emphasis-position text-emphasis-style text-fit text-indent text-justify text-orientation text-overflow text-rendering text-shadow text-size-adjust text-spacing-trim text-transform text-underline-offset text-underline-position text-wrap text-wrap-mode text-wrap-style timeline-scope timeline-trigger timeline-trigger-activation-range timeline-trigger-activation-range-end timeline-trigger-activation-range-start timeline-trigger-active-range timeline-trigger-active-range-end timeline-trigger-active-range-start timeline-trigger-name timeline-trigger-source top touch-action transform transform-box transform-origin transform-style transition transition-behavior transition-delay transition-duration transition-property transition-timing-function translate trigger-scope unicode-bidi user-select vector-effect vertical-align view-timeline view-timeline-axis view-timeline-inset view-timeline-name view-transition-class view-transition-name view-transition-scope visibility white-space white-space-collapse widows width will-change window-drag word-break word-spacing word-wrap writing-mode x y z-index zoom".split(" ");
4
+ const NATIVE_CSS_PROPERTY_SET = new Set(NATIVE_CSS_PROPERTIES);
5
+ export { NATIVE_CSS_PROPERTIES, NATIVE_CSS_PROPERTY_SET };