@variance-authority/core 0.1.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/CHANGELOG.md +79 -0
- package/LICENSE +21 -0
- package/README.md +169 -0
- package/dist/artifact.d.ts +47 -0
- package/dist/artifact.js +2 -0
- package/dist/artifact.js.map +1 -0
- package/dist/attribute/because.d.ts +43 -0
- package/dist/attribute/because.js +64 -0
- package/dist/attribute/because.js.map +1 -0
- package/dist/attribute/boundary.d.ts +191 -0
- package/dist/attribute/boundary.js +328 -0
- package/dist/attribute/boundary.js.map +1 -0
- package/dist/attribute/call-site.d.ts +96 -0
- package/dist/attribute/call-site.js +183 -0
- package/dist/attribute/call-site.js.map +1 -0
- package/dist/attribute/component-hash.d.ts +188 -0
- package/dist/attribute/component-hash.js +312 -0
- package/dist/attribute/component-hash.js.map +1 -0
- package/dist/attribute/composition-fixture.d.ts +18 -0
- package/dist/attribute/composition-fixture.js +53 -0
- package/dist/attribute/composition-fixture.js.map +1 -0
- package/dist/attribute/composition.d.ts +182 -0
- package/dist/attribute/composition.js +169 -0
- package/dist/attribute/composition.js.map +1 -0
- package/dist/attribute/control.d.ts +43 -0
- package/dist/attribute/control.js +54 -0
- package/dist/attribute/control.js.map +1 -0
- package/dist/attribute/coverage.d.ts +99 -0
- package/dist/attribute/coverage.js +86 -0
- package/dist/attribute/coverage.js.map +1 -0
- package/dist/attribute/divergence.d.ts +102 -0
- package/dist/attribute/divergence.js +152 -0
- package/dist/attribute/divergence.js.map +1 -0
- package/dist/attribute/index.d.ts +43 -0
- package/dist/attribute/index.js +29 -0
- package/dist/attribute/index.js.map +1 -0
- package/dist/attribute/instability.d.ts +89 -0
- package/dist/attribute/instability.js +183 -0
- package/dist/attribute/instability.js.map +1 -0
- package/dist/attribute/instances.d.ts +145 -0
- package/dist/attribute/instances.js +140 -0
- package/dist/attribute/instances.js.map +1 -0
- package/dist/attribute/locate.d.ts +22 -0
- package/dist/attribute/locate.js +100 -0
- package/dist/attribute/locate.js.map +1 -0
- package/dist/attribute/mask.d.ts +156 -0
- package/dist/attribute/mask.js +201 -0
- package/dist/attribute/mask.js.map +1 -0
- package/dist/attribute/movement.d.ts +211 -0
- package/dist/attribute/movement.js +181 -0
- package/dist/attribute/movement.js.map +1 -0
- package/dist/attribute/region.d.ts +188 -0
- package/dist/attribute/region.js +144 -0
- package/dist/attribute/region.js.map +1 -0
- package/dist/attribute/source-map.d.ts +98 -0
- package/dist/attribute/source-map.js +264 -0
- package/dist/attribute/source-map.js.map +1 -0
- package/dist/attribute/source.d.ts +77 -0
- package/dist/attribute/source.js +95 -0
- package/dist/attribute/source.js.map +1 -0
- package/dist/attribute/stack.d.ts +80 -0
- package/dist/attribute/stack.js +108 -0
- package/dist/attribute/stack.js.map +1 -0
- package/dist/compare/band.d.ts +85 -0
- package/dist/compare/band.js +70 -0
- package/dist/compare/band.js.map +1 -0
- package/dist/compare/cascade.d.ts +45 -0
- package/dist/compare/cascade.js +71 -0
- package/dist/compare/cascade.js.map +1 -0
- package/dist/compare/derive.d.ts +78 -0
- package/dist/compare/derive.js +39 -0
- package/dist/compare/derive.js.map +1 -0
- package/dist/compare/diff/attribution.d.ts +23 -0
- package/dist/compare/diff/attribution.js +244 -0
- package/dist/compare/diff/attribution.js.map +1 -0
- package/dist/compare/diff/compare-nodes.d.ts +15 -0
- package/dist/compare/diff/compare-nodes.js +227 -0
- package/dist/compare/diff/compare-nodes.js.map +1 -0
- package/dist/compare/diff/components.d.ts +20 -0
- package/dist/compare/diff/components.js +76 -0
- package/dist/compare/diff/components.js.map +1 -0
- package/dist/compare/diff/delta.d.ts +165 -0
- package/dist/compare/diff/delta.js +12 -0
- package/dist/compare/diff/delta.js.map +1 -0
- package/dist/compare/diff/index.d.ts +69 -0
- package/dist/compare/diff/index.js +101 -0
- package/dist/compare/diff/index.js.map +1 -0
- package/dist/compare/diff/match.d.ts +37 -0
- package/dist/compare/diff/match.js +167 -0
- package/dist/compare/diff/match.js.map +1 -0
- package/dist/compare/explain.d.ts +23 -0
- package/dist/compare/explain.js +190 -0
- package/dist/compare/explain.js.map +1 -0
- package/dist/compare/holding-diff.d.ts +25 -0
- package/dist/compare/holding-diff.js +74 -0
- package/dist/compare/holding-diff.js.map +1 -0
- package/dist/compare/impact.d.ts +56 -0
- package/dist/compare/impact.js +124 -0
- package/dist/compare/impact.js.map +1 -0
- package/dist/compare/index.d.ts +30 -0
- package/dist/compare/index.js +22 -0
- package/dist/compare/index.js.map +1 -0
- package/dist/compare/instance.d.ts +30 -0
- package/dist/compare/instance.js +145 -0
- package/dist/compare/instance.js.map +1 -0
- package/dist/compare/observability.d.ts +49 -0
- package/dist/compare/observability.js +57 -0
- package/dist/compare/observability.js.map +1 -0
- package/dist/compare/parting.d.ts +179 -0
- package/dist/compare/parting.js +244 -0
- package/dist/compare/parting.js.map +1 -0
- package/dist/compare/slice.d.ts +74 -0
- package/dist/compare/slice.js +79 -0
- package/dist/compare/slice.js.map +1 -0
- package/dist/compare/value.d.ts +60 -0
- package/dist/compare/value.js +111 -0
- package/dist/compare/value.js.map +1 -0
- package/dist/format/accessibility.d.ts +27 -0
- package/dist/format/accessibility.js +17 -0
- package/dist/format/accessibility.js.map +1 -0
- package/dist/format/canonical.d.ts +38 -0
- package/dist/format/canonical.js +65 -0
- package/dist/format/canonical.js.map +1 -0
- package/dist/format/capture.d.ts +212 -0
- package/dist/format/capture.js +2 -0
- package/dist/format/capture.js.map +1 -0
- package/dist/format/document.d.ts +279 -0
- package/dist/format/document.js +65 -0
- package/dist/format/document.js.map +1 -0
- package/dist/format/environment.d.ts +120 -0
- package/dist/format/environment.js +53 -0
- package/dist/format/environment.js.map +1 -0
- package/dist/format/hash.d.ts +45 -0
- package/dist/format/hash.js +41 -0
- package/dist/format/hash.js.map +1 -0
- package/dist/format/holding.d.ts +134 -0
- package/dist/format/holding.js +2 -0
- package/dist/format/holding.js.map +1 -0
- package/dist/format/index.d.ts +39 -0
- package/dist/format/index.js +25 -0
- package/dist/format/index.js.map +1 -0
- package/dist/format/intervention.d.ts +87 -0
- package/dist/format/intervention.js +11 -0
- package/dist/format/intervention.js.map +1 -0
- package/dist/format/profile.d.ts +59 -0
- package/dist/format/profile.js +66 -0
- package/dist/format/profile.js.map +1 -0
- package/dist/format/provenance.d.ts +179 -0
- package/dist/format/provenance.js +222 -0
- package/dist/format/provenance.js.map +1 -0
- package/dist/format/sha256.d.ts +34 -0
- package/dist/format/sha256.js +152 -0
- package/dist/format/sha256.js.map +1 -0
- package/dist/format/snapshot.d.ts +263 -0
- package/dist/format/snapshot.js +2 -0
- package/dist/format/snapshot.js.map +1 -0
- package/dist/format/stabilize.d.ts +190 -0
- package/dist/format/stabilize.js +333 -0
- package/dist/format/stabilize.js.map +1 -0
- package/dist/format/tier.d.ts +19 -0
- package/dist/format/tier.js +11 -0
- package/dist/format/tier.js.map +1 -0
- package/dist/format/value.d.ts +115 -0
- package/dist/format/value.js +182 -0
- package/dist/format/value.js.map +1 -0
- package/dist/format/wiring.d.ts +115 -0
- package/dist/format/wiring.js +60 -0
- package/dist/format/wiring.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/judge/docket.d.ts +85 -0
- package/dist/judge/docket.js +162 -0
- package/dist/judge/docket.js.map +1 -0
- package/dist/judge/fingerprint.d.ts +53 -0
- package/dist/judge/fingerprint.js +144 -0
- package/dist/judge/fingerprint.js.map +1 -0
- package/dist/judge/ignore.d.ts +206 -0
- package/dist/judge/ignore.js +237 -0
- package/dist/judge/ignore.js.map +1 -0
- package/dist/judge/index.d.ts +44 -0
- package/dist/judge/index.js +34 -0
- package/dist/judge/index.js.map +1 -0
- package/dist/judge/inspect.d.ts +148 -0
- package/dist/judge/inspect.js +208 -0
- package/dist/judge/inspect.js.map +1 -0
- package/dist/judge/intent.d.ts +146 -0
- package/dist/judge/intent.js +150 -0
- package/dist/judge/intent.js.map +1 -0
- package/dist/judge/locale.d.ts +111 -0
- package/dist/judge/locale.js +247 -0
- package/dist/judge/locale.js.map +1 -0
- package/dist/judge/scope.d.ts +41 -0
- package/dist/judge/scope.js +47 -0
- package/dist/judge/scope.js.map +1 -0
- package/dist/judge/sensitivity.d.ts +202 -0
- package/dist/judge/sensitivity.js +152 -0
- package/dist/judge/sensitivity.js.map +1 -0
- package/dist/judge/trail.d.ts +122 -0
- package/dist/judge/trail.js +96 -0
- package/dist/judge/trail.js.map +1 -0
- package/dist/judge/verdict.d.ts +39 -0
- package/dist/judge/verdict.js +32 -0
- package/dist/judge/verdict.js.map +1 -0
- package/dist/plan/index.d.ts +12 -0
- package/dist/plan/index.js +11 -0
- package/dist/plan/index.js.map +1 -0
- package/dist/plan/tool.d.ts +85 -0
- package/dist/plan/tool.js +87 -0
- package/dist/plan/tool.js.map +1 -0
- package/dist/relate/graph.d.ts +190 -0
- package/dist/relate/graph.js +234 -0
- package/dist/relate/graph.js.map +1 -0
- package/dist/relate/index.d.ts +16 -0
- package/dist/relate/index.js +16 -0
- package/dist/relate/index.js.map +1 -0
- package/dist/relate/merkle.d.ts +110 -0
- package/dist/relate/merkle.js +246 -0
- package/dist/relate/merkle.js.map +1 -0
- package/dist/relate/reach.d.ts +65 -0
- package/dist/relate/reach.js +111 -0
- package/dist/relate/reach.js.map +1 -0
- package/dist/relate/records.d.ts +129 -0
- package/dist/relate/records.js +112 -0
- package/dist/relate/records.js.map +1 -0
- package/dist/rules/index.d.ts +19 -0
- package/dist/rules/index.js +17 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/normalize/alias.d.ts +50 -0
- package/dist/rules/normalize/alias.js +111 -0
- package/dist/rules/normalize/alias.js.map +1 -0
- package/dist/rules/normalize/cascade.d.ts +85 -0
- package/dist/rules/normalize/cascade.js +324 -0
- package/dist/rules/normalize/cascade.js.map +1 -0
- package/dist/rules/normalize/color.d.ts +30 -0
- package/dist/rules/normalize/color.js +185 -0
- package/dist/rules/normalize/color.js.map +1 -0
- package/dist/rules/normalize/fixture.d.ts +83 -0
- package/dist/rules/normalize/fixture.js +74 -0
- package/dist/rules/normalize/fixture.js.map +1 -0
- package/dist/rules/normalize/index.d.ts +39 -0
- package/dist/rules/normalize/index.js +268 -0
- package/dist/rules/normalize/index.js.map +1 -0
- package/dist/rules/normalize/project.d.ts +42 -0
- package/dist/rules/normalize/project.js +83 -0
- package/dist/rules/normalize/project.js.map +1 -0
- package/dist/rules/normalize/shorthand.d.ts +38 -0
- package/dist/rules/normalize/shorthand.js +388 -0
- package/dist/rules/normalize/shorthand.js.map +1 -0
- package/dist/rules/normalize/value.d.ts +23 -0
- package/dist/rules/normalize/value.js +162 -0
- package/dist/rules/normalize/value.js.map +1 -0
- package/dist/rules/normalize/wrapper.d.ts +16 -0
- package/dist/rules/normalize/wrapper.js +137 -0
- package/dist/rules/normalize/wrapper.js.map +1 -0
- package/dist/rules/ruleset.d.ts +93 -0
- package/dist/rules/ruleset.js +175 -0
- package/dist/rules/ruleset.js.map +1 -0
- package/mark.svg +30 -0
- package/package.json +69 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { CanonicalValue } from '../../format/canonical.js';
|
|
2
|
+
import type { IgnoreSite, SemanticNode } from '../../format/snapshot.js';
|
|
3
|
+
/**
|
|
4
|
+
* What a finished tree projects into.
|
|
5
|
+
*
|
|
6
|
+
* Three walks over the same normalized tree, each producing something the
|
|
7
|
+
* snapshot carries: two hash inputs and one list. They sit together because the
|
|
8
|
+
* relationship between them is the interesting part — **what a projection omits
|
|
9
|
+
* is a decision**, and reading them side by side is the only way to check that
|
|
10
|
+
* the decisions still line up.
|
|
11
|
+
*
|
|
12
|
+
* The projections are explicit field lists rather than "the node minus some
|
|
13
|
+
* keys", and that is load-bearing rather than stylistic. A field added to
|
|
14
|
+
* `SemanticNode` must be *chosen* into a hash by someone editing this file; the
|
|
15
|
+
* subtractive form would have swept `ignoredBy` into the structure hash the day
|
|
16
|
+
* it was added, and every subject carrying an ignore would have re-baselined.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Structure alone: shape, roles, names, descriptions, states, admitted
|
|
20
|
+
* attributes, text.
|
|
21
|
+
*
|
|
22
|
+
* Hashed separately from style so the docket can say *which* held. "The DOM is
|
|
23
|
+
* identical, only styling moved" is the sentence that turns a diff into a
|
|
24
|
+
* token-band root instead of a structural review.
|
|
25
|
+
*/
|
|
26
|
+
export declare function structureOf(node: SemanticNode): CanonicalValue;
|
|
27
|
+
export declare function styleOf(node: SemanticNode, includeLayout: boolean): CanonicalValue;
|
|
28
|
+
/**
|
|
29
|
+
* Every excluded subtree in the finished tree, outermost first (spec 0024).
|
|
30
|
+
*
|
|
31
|
+
* Read from the *finished* tree rather than recorded during the walk, because
|
|
32
|
+
* wrapper collapse re-paths whole subtrees: a path taken on the way down names a
|
|
33
|
+
* node that may not be there on the way out, and an ignore that quietly slid one
|
|
34
|
+
* level up absorbs a sibling nobody excluded.
|
|
35
|
+
*
|
|
36
|
+
* Nested marks are kept rather than collapsed. Two rules can reach the same
|
|
37
|
+
* subtree, and the register has to be able to say which of them absorbed what;
|
|
38
|
+
* the cost is a duplicate site absorbing the same deltas under two names, which
|
|
39
|
+
* shows up in the register, where it belongs.
|
|
40
|
+
*/
|
|
41
|
+
export declare function sitesIn(root: SemanticNode): readonly IgnoreSite[];
|
|
42
|
+
//# sourceMappingURL=project.d.ts.map
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a finished tree projects into.
|
|
3
|
+
*
|
|
4
|
+
* Three walks over the same normalized tree, each producing something the
|
|
5
|
+
* snapshot carries: two hash inputs and one list. They sit together because the
|
|
6
|
+
* relationship between them is the interesting part — **what a projection omits
|
|
7
|
+
* is a decision**, and reading them side by side is the only way to check that
|
|
8
|
+
* the decisions still line up.
|
|
9
|
+
*
|
|
10
|
+
* The projections are explicit field lists rather than "the node minus some
|
|
11
|
+
* keys", and that is load-bearing rather than stylistic. A field added to
|
|
12
|
+
* `SemanticNode` must be *chosen* into a hash by someone editing this file; the
|
|
13
|
+
* subtractive form would have swept `ignoredBy` into the structure hash the day
|
|
14
|
+
* it was added, and every subject carrying an ignore would have re-baselined.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Structure alone: shape, roles, names, descriptions, states, admitted
|
|
18
|
+
* attributes, text.
|
|
19
|
+
*
|
|
20
|
+
* Hashed separately from style so the docket can say *which* held. "The DOM is
|
|
21
|
+
* identical, only styling moved" is the sentence that turns a diff into a
|
|
22
|
+
* token-band root instead of a structural review.
|
|
23
|
+
*/
|
|
24
|
+
export function structureOf(node) {
|
|
25
|
+
return {
|
|
26
|
+
tag: node.tag,
|
|
27
|
+
alias: node.alias,
|
|
28
|
+
portalled: node.portalled,
|
|
29
|
+
role: node.role,
|
|
30
|
+
name: node.name,
|
|
31
|
+
description: node.description,
|
|
32
|
+
state: node.state,
|
|
33
|
+
attributes: node.attributes,
|
|
34
|
+
text: node.text,
|
|
35
|
+
children: node.children.map(structureOf),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export function styleOf(node, includeLayout) {
|
|
39
|
+
const entries = [];
|
|
40
|
+
const visit = (current) => {
|
|
41
|
+
entries.push({
|
|
42
|
+
path: current.path,
|
|
43
|
+
style: current.style,
|
|
44
|
+
tokens: current.tokens,
|
|
45
|
+
// Absent, never zeroed, under a profile without layout (ADR-0002).
|
|
46
|
+
rect: includeLayout && current.rect ? { ...current.rect } : undefined,
|
|
47
|
+
});
|
|
48
|
+
for (const child of current.children)
|
|
49
|
+
visit(child);
|
|
50
|
+
};
|
|
51
|
+
visit(node);
|
|
52
|
+
return entries;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Every excluded subtree in the finished tree, outermost first (spec 0024).
|
|
56
|
+
*
|
|
57
|
+
* Read from the *finished* tree rather than recorded during the walk, because
|
|
58
|
+
* wrapper collapse re-paths whole subtrees: a path taken on the way down names a
|
|
59
|
+
* node that may not be there on the way out, and an ignore that quietly slid one
|
|
60
|
+
* level up absorbs a sibling nobody excluded.
|
|
61
|
+
*
|
|
62
|
+
* Nested marks are kept rather than collapsed. Two rules can reach the same
|
|
63
|
+
* subtree, and the register has to be able to say which of them absorbed what;
|
|
64
|
+
* the cost is a duplicate site absorbing the same deltas under two names, which
|
|
65
|
+
* shows up in the register, where it belongs.
|
|
66
|
+
*/
|
|
67
|
+
export function sitesIn(root) {
|
|
68
|
+
const sites = [];
|
|
69
|
+
const visit = (node) => {
|
|
70
|
+
for (const rule of node.ignoredBy ?? []) {
|
|
71
|
+
sites.push({
|
|
72
|
+
path: node.path,
|
|
73
|
+
rule,
|
|
74
|
+
...(node.rect ? { rect: node.rect } : {}),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
for (const child of node.children)
|
|
78
|
+
visit(child);
|
|
79
|
+
};
|
|
80
|
+
visit(root);
|
|
81
|
+
return sites;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../../src/rules/normalize/project.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,IAAkB;IAC5C,OAAO;QACL,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,KAAK,EAAE,IAAI,CAAC,KAAmC;QAC/C,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC;KACzC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAAkB,EAAE,aAAsB;IAChE,MAAM,OAAO,GAAqB,EAAE,CAAC;IAErC,MAAM,KAAK,GAAG,CAAC,OAAqB,EAAQ,EAAE;QAC5C,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,mEAAmE;YACnE,IAAI,EAAE,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS;SACtE,CAAC,CAAC;QACH,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,QAAQ;YAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACrD,CAAC,CAAC;IAEF,KAAK,CAAC,IAAI,CAAC,CAAC;IACZ,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,OAAO,CAAC,IAAkB;IACxC,MAAM,KAAK,GAAiB,EAAE,CAAC;IAE/B,MAAM,KAAK,GAAG,CAAC,IAAkB,EAAQ,EAAE;QACzC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC;YACxC,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,IAAI;gBACJ,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC1C,CAAC,CAAC;QACL,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ;YAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC;IAEF,KAAK,CAAC,IAAI,CAAC,CAAC;IACZ,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import type { CanonicalValue } from '../../format/canonical.js';\nimport type { IgnoreSite, SemanticNode } from '../../format/snapshot.js';\n\n/**\n * What a finished tree projects into.\n *\n * Three walks over the same normalized tree, each producing something the\n * snapshot carries: two hash inputs and one list. They sit together because the\n * relationship between them is the interesting part — **what a projection omits\n * is a decision**, and reading them side by side is the only way to check that\n * the decisions still line up.\n *\n * The projections are explicit field lists rather than \"the node minus some\n * keys\", and that is load-bearing rather than stylistic. A field added to\n * `SemanticNode` must be *chosen* into a hash by someone editing this file; the\n * subtractive form would have swept `ignoredBy` into the structure hash the day\n * it was added, and every subject carrying an ignore would have re-baselined.\n */\n\n/**\n * Structure alone: shape, roles, names, descriptions, states, admitted\n * attributes, text.\n *\n * Hashed separately from style so the docket can say *which* held. \"The DOM is\n * identical, only styling moved\" is the sentence that turns a diff into a\n * token-band root instead of a structural review.\n */\nexport function structureOf(node: SemanticNode): CanonicalValue {\n return {\n tag: node.tag,\n alias: node.alias,\n portalled: node.portalled,\n role: node.role,\n name: node.name,\n description: node.description,\n state: node.state as CanonicalValue | undefined,\n attributes: node.attributes,\n text: node.text,\n children: node.children.map(structureOf),\n };\n}\n\nexport function styleOf(node: SemanticNode, includeLayout: boolean): CanonicalValue {\n const entries: CanonicalValue[] = [];\n\n const visit = (current: SemanticNode): void => {\n entries.push({\n path: current.path,\n style: current.style,\n tokens: current.tokens,\n // Absent, never zeroed, under a profile without layout (ADR-0002).\n rect: includeLayout && current.rect ? { ...current.rect } : undefined,\n });\n for (const child of current.children) visit(child);\n };\n\n visit(node);\n return entries;\n}\n\n/**\n * Every excluded subtree in the finished tree, outermost first (spec 0024).\n *\n * Read from the *finished* tree rather than recorded during the walk, because\n * wrapper collapse re-paths whole subtrees: a path taken on the way down names a\n * node that may not be there on the way out, and an ignore that quietly slid one\n * level up absorbs a sibling nobody excluded.\n *\n * Nested marks are kept rather than collapsed. Two rules can reach the same\n * subtree, and the register has to be able to say which of them absorbed what;\n * the cost is a duplicate site absorbing the same deltas under two names, which\n * shows up in the register, where it belongs.\n */\nexport function sitesIn(root: SemanticNode): readonly IgnoreSite[] {\n const sites: IgnoreSite[] = [];\n\n const visit = (node: SemanticNode): void => {\n for (const rule of node.ignoredBy ?? []) {\n sites.push({\n path: node.path,\n rule,\n ...(node.rect ? { rect: node.rect } : {}),\n });\n }\n for (const child of node.children) visit(child);\n };\n\n visit(root);\n return sites;\n}\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shorthand expansion.
|
|
3
|
+
*
|
|
4
|
+
* The allowlist holds longhands only, so `margin: 4px` and
|
|
5
|
+
* `margin-top: 4px; margin-right: 4px; …` must reduce to the same snapshot.
|
|
6
|
+
* Without that, splitting a shorthand during a refactor — a change no user can
|
|
7
|
+
* perceive — would invalidate every baseline it touches.
|
|
8
|
+
*
|
|
9
|
+
* The safety rule throughout: **an expansion we are not sure of is not
|
|
10
|
+
* performed.** {@link expandDeclaration} returns `confident: false` and hands
|
|
11
|
+
* back the shorthand unchanged, which the projection step then admits under its
|
|
12
|
+
* own name. A partially-expanded shorthand would drop the components it failed
|
|
13
|
+
* to classify, and a dropped declaration is a value missing from the hash — a
|
|
14
|
+
* false `unchanged`. Keeping an un-normalized value costs at most a review
|
|
15
|
+
* nobody needed; dropping one costs a missed regression.
|
|
16
|
+
*/
|
|
17
|
+
export interface Expansion {
|
|
18
|
+
readonly declarations: readonly {
|
|
19
|
+
readonly property: string;
|
|
20
|
+
readonly value: string;
|
|
21
|
+
}[];
|
|
22
|
+
/**
|
|
23
|
+
* `false` when the shorthand could not be decomposed with certainty. The
|
|
24
|
+
* single returned declaration is then the original shorthand.
|
|
25
|
+
*/
|
|
26
|
+
readonly confident: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** Shorthands admitted under their own name when expansion is not confident. */
|
|
29
|
+
export declare const SHORTHAND_PROPERTIES: readonly string[];
|
|
30
|
+
export declare function expandDeclaration(property: string, value: string): Expansion;
|
|
31
|
+
/**
|
|
32
|
+
* Split on whitespace, but never inside a function call.
|
|
33
|
+
*
|
|
34
|
+
* `margin: calc(1px + 2px) 0` is two values, not four. Splitting naively would
|
|
35
|
+
* silently corrupt every `calc()`, `var()`, and gradient in the corpus.
|
|
36
|
+
*/
|
|
37
|
+
export declare function topLevelParts(value: string): string[];
|
|
38
|
+
//# sourceMappingURL=shorthand.d.ts.map
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import { parseColor } from './color.js';
|
|
2
|
+
/** Shorthands admitted under their own name when expansion is not confident. */
|
|
3
|
+
export const SHORTHAND_PROPERTIES = [
|
|
4
|
+
'margin', 'padding', 'inset', 'gap', 'overflow',
|
|
5
|
+
'border', 'border-width', 'border-style', 'border-color', 'border-radius',
|
|
6
|
+
'border-top', 'border-right', 'border-bottom', 'border-left',
|
|
7
|
+
'outline', 'flex', 'flex-flow', 'place-items', 'place-content', 'place-self',
|
|
8
|
+
'grid-row', 'grid-column', 'grid-area', 'text-decoration', 'background', 'font',
|
|
9
|
+
];
|
|
10
|
+
const SIDES = ['top', 'right', 'bottom', 'left'];
|
|
11
|
+
const CORNERS = [
|
|
12
|
+
'border-top-left-radius', 'border-top-right-radius',
|
|
13
|
+
'border-bottom-right-radius', 'border-bottom-left-radius',
|
|
14
|
+
];
|
|
15
|
+
const LINE_STYLES = new Set([
|
|
16
|
+
'none', 'hidden', 'dotted', 'dashed', 'solid', 'double',
|
|
17
|
+
'groove', 'ridge', 'inset', 'outset',
|
|
18
|
+
]);
|
|
19
|
+
const LINE_WIDTHS = new Set(['thin', 'medium', 'thick']);
|
|
20
|
+
export function expandDeclaration(property, value) {
|
|
21
|
+
const expand = EXPANDERS[property];
|
|
22
|
+
if (!expand)
|
|
23
|
+
return { declarations: [{ property, value }], confident: true };
|
|
24
|
+
const expanded = expand(value.trim());
|
|
25
|
+
return expanded ?? { declarations: [{ property, value }], confident: false };
|
|
26
|
+
}
|
|
27
|
+
const EXPANDERS = {
|
|
28
|
+
margin: (v) => box(v, (side) => `margin-${side}`),
|
|
29
|
+
padding: (v) => box(v, (side) => `padding-${side}`),
|
|
30
|
+
inset: (v) => box(v, (side) => side),
|
|
31
|
+
'border-width': (v) => box(v, (side) => `border-${side}-width`),
|
|
32
|
+
'border-style': (v) => box(v, (side) => `border-${side}-style`),
|
|
33
|
+
'border-color': (v) => box(v, (side) => `border-${side}-color`),
|
|
34
|
+
'scroll-margin': (v) => box(v, (side) => `scroll-margin-${side}`),
|
|
35
|
+
'scroll-padding': (v) => box(v, (side) => `scroll-padding-${side}`),
|
|
36
|
+
gap: (v) => pair(v, 'row-gap', 'column-gap'),
|
|
37
|
+
overflow: (v) => pair(v, 'overflow-x', 'overflow-y'),
|
|
38
|
+
'place-items': (v) => pair(v, 'align-items', 'justify-items'),
|
|
39
|
+
'place-content': (v) => pair(v, 'align-content', 'justify-content'),
|
|
40
|
+
'place-self': (v) => pair(v, 'align-self', 'justify-self'),
|
|
41
|
+
'grid-row': (v) => slash(v, 'grid-row-start', 'grid-row-end'),
|
|
42
|
+
'grid-column': (v) => slash(v, 'grid-column-start', 'grid-column-end'),
|
|
43
|
+
'border-radius': expandBorderRadius,
|
|
44
|
+
border: (v) => expandBorderSides(v, SIDES),
|
|
45
|
+
'border-top': (v) => expandBorderSides(v, ['top']),
|
|
46
|
+
'border-right': (v) => expandBorderSides(v, ['right']),
|
|
47
|
+
'border-bottom': (v) => expandBorderSides(v, ['bottom']),
|
|
48
|
+
'border-left': (v) => expandBorderSides(v, ['left']),
|
|
49
|
+
outline: expandOutline,
|
|
50
|
+
flex: expandFlex,
|
|
51
|
+
'flex-flow': expandFlexFlow,
|
|
52
|
+
'text-decoration': expandTextDecoration,
|
|
53
|
+
// `background` and `font` are the two shorthands whose grammars are genuinely
|
|
54
|
+
// ambiguous to decompose (a bare `<length>` in `background` may be a position
|
|
55
|
+
// or a size; `font` interleaves four optional keyword slots before a required
|
|
56
|
+
// size). Both are declared unexpandable rather than guessed at — see the
|
|
57
|
+
// safety rule above. Under a profile with computed style the engine has
|
|
58
|
+
// already resolved them into longhands, so this only affects the declared-only
|
|
59
|
+
// tier, where an un-normalized value is a correct description of what is known.
|
|
60
|
+
background: () => null,
|
|
61
|
+
font: () => null,
|
|
62
|
+
};
|
|
63
|
+
/** 1–4 values in top/right/bottom/left order, per the CSS box grammar. */
|
|
64
|
+
function box(value, name) {
|
|
65
|
+
const parts = topLevelParts(value);
|
|
66
|
+
if (parts.length === 0 || parts.length > 4)
|
|
67
|
+
return null;
|
|
68
|
+
if (parts.some(isGlobalKeywordAmbiguity))
|
|
69
|
+
return null;
|
|
70
|
+
const [a, b = a, c = a, d = b] = parts;
|
|
71
|
+
const resolved = [a, b, c, d];
|
|
72
|
+
return {
|
|
73
|
+
declarations: SIDES.map((side, index) => ({
|
|
74
|
+
property: name(side),
|
|
75
|
+
value: resolved[index],
|
|
76
|
+
})),
|
|
77
|
+
confident: true,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function pair(value, first, second) {
|
|
81
|
+
const parts = topLevelParts(value);
|
|
82
|
+
if (parts.length === 0 || parts.length > 2)
|
|
83
|
+
return null;
|
|
84
|
+
const a = parts[0];
|
|
85
|
+
const b = parts[1] ?? a;
|
|
86
|
+
return {
|
|
87
|
+
declarations: [
|
|
88
|
+
{ property: first, value: a },
|
|
89
|
+
{ property: second, value: b },
|
|
90
|
+
],
|
|
91
|
+
confident: true,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function slash(value, start, end) {
|
|
95
|
+
const parts = value.split('/').map((part) => part.trim());
|
|
96
|
+
if (parts.length > 2)
|
|
97
|
+
return null;
|
|
98
|
+
const a = parts[0];
|
|
99
|
+
// Omitted end defaults to `auto`, not to a copy of start, except for a
|
|
100
|
+
// custom-ident line name — where it does copy. Ambiguous, so decline.
|
|
101
|
+
if (parts.length === 1) {
|
|
102
|
+
if (/^-?[a-z_]/i.test(a) && !/^(auto|span)\b/i.test(a))
|
|
103
|
+
return null;
|
|
104
|
+
return {
|
|
105
|
+
declarations: [
|
|
106
|
+
{ property: start, value: a },
|
|
107
|
+
{ property: end, value: 'auto' },
|
|
108
|
+
],
|
|
109
|
+
confident: true,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
declarations: [
|
|
114
|
+
{ property: start, value: a },
|
|
115
|
+
{ property: end, value: parts[1] },
|
|
116
|
+
],
|
|
117
|
+
confident: true,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/** `border-radius: a b / c d` — the `/` separates horizontal from vertical radii. */
|
|
121
|
+
function expandBorderRadius(value) {
|
|
122
|
+
const [horizontal, vertical] = value.split('/').map((part) => part.trim());
|
|
123
|
+
const h = cornerValues(horizontal ?? '');
|
|
124
|
+
if (!h)
|
|
125
|
+
return null;
|
|
126
|
+
if (vertical === undefined) {
|
|
127
|
+
return {
|
|
128
|
+
declarations: CORNERS.map((property, index) => ({ property, value: h[index] })),
|
|
129
|
+
confident: true,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
const v = cornerValues(vertical);
|
|
133
|
+
if (!v)
|
|
134
|
+
return null;
|
|
135
|
+
return {
|
|
136
|
+
declarations: CORNERS.map((property, index) => ({
|
|
137
|
+
property,
|
|
138
|
+
value: `${h[index]} ${v[index]}`,
|
|
139
|
+
})),
|
|
140
|
+
confident: true,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/** Corner order is TL, TR, BR, BL — different from the box order. */
|
|
144
|
+
function cornerValues(value) {
|
|
145
|
+
const parts = topLevelParts(value);
|
|
146
|
+
if (parts.length === 0 || parts.length > 4)
|
|
147
|
+
return null;
|
|
148
|
+
const [a, b = a, c = a, d = b] = parts;
|
|
149
|
+
return [a, b, c, d];
|
|
150
|
+
}
|
|
151
|
+
function expandBorderSides(value, sides) {
|
|
152
|
+
const parsed = classifyLineComponents(value);
|
|
153
|
+
if (!parsed)
|
|
154
|
+
return null;
|
|
155
|
+
const declarations = sides.flatMap((side) => [
|
|
156
|
+
{ property: `border-${side}-width`, value: parsed.width },
|
|
157
|
+
{ property: `border-${side}-style`, value: parsed.style },
|
|
158
|
+
{ property: `border-${side}-color`, value: parsed.color },
|
|
159
|
+
]);
|
|
160
|
+
return { declarations, confident: true };
|
|
161
|
+
}
|
|
162
|
+
function expandOutline(value) {
|
|
163
|
+
const parsed = classifyLineComponents(value);
|
|
164
|
+
if (!parsed)
|
|
165
|
+
return null;
|
|
166
|
+
return {
|
|
167
|
+
declarations: [
|
|
168
|
+
{ property: 'outline-width', value: parsed.width },
|
|
169
|
+
{ property: 'outline-style', value: parsed.style },
|
|
170
|
+
{ property: 'outline-color', value: parsed.color },
|
|
171
|
+
],
|
|
172
|
+
confident: true,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Split `<width> || <style> || <color>`, which may appear in any order.
|
|
177
|
+
*
|
|
178
|
+
* Omitted components take their initial values rather than being left out —
|
|
179
|
+
* `border: solid` really does reset width and colour, and recording only the
|
|
180
|
+
* style would let a genuine colour change slip through as unobserved.
|
|
181
|
+
*/
|
|
182
|
+
function classifyLineComponents(value) {
|
|
183
|
+
const parts = topLevelParts(value);
|
|
184
|
+
if (parts.length === 0 || parts.length > 3)
|
|
185
|
+
return null;
|
|
186
|
+
let width;
|
|
187
|
+
let style;
|
|
188
|
+
let color;
|
|
189
|
+
for (const part of parts) {
|
|
190
|
+
const lower = part.toLowerCase();
|
|
191
|
+
if (LINE_STYLES.has(lower)) {
|
|
192
|
+
if (style !== undefined)
|
|
193
|
+
return null;
|
|
194
|
+
style = lower;
|
|
195
|
+
}
|
|
196
|
+
else if (LINE_WIDTHS.has(lower) || isLength(part)) {
|
|
197
|
+
if (width !== undefined)
|
|
198
|
+
return null;
|
|
199
|
+
width = part;
|
|
200
|
+
}
|
|
201
|
+
else if (lower === 'currentcolor' || parseColor(part) !== null || part.startsWith('var(')) {
|
|
202
|
+
if (color !== undefined)
|
|
203
|
+
return null;
|
|
204
|
+
color = part;
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
width: width ?? 'medium',
|
|
212
|
+
style: style ?? 'none',
|
|
213
|
+
color: color ?? 'currentcolor',
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
/** `flex: <grow> <shrink>? <basis>?`, plus the `none`/`auto`/`initial` keywords. */
|
|
217
|
+
function expandFlex(value) {
|
|
218
|
+
const lower = value.toLowerCase().trim();
|
|
219
|
+
const keyword = {
|
|
220
|
+
none: ['0', '0', 'auto'],
|
|
221
|
+
auto: ['1', '1', 'auto'],
|
|
222
|
+
initial: ['0', '1', 'auto'],
|
|
223
|
+
};
|
|
224
|
+
const preset = keyword[lower];
|
|
225
|
+
const [grow, shrink, basis] = preset ?? classifyFlexParts(topLevelParts(value)) ?? [];
|
|
226
|
+
if (grow === undefined || shrink === undefined || basis === undefined)
|
|
227
|
+
return null;
|
|
228
|
+
return {
|
|
229
|
+
declarations: [
|
|
230
|
+
{ property: 'flex-grow', value: grow },
|
|
231
|
+
{ property: 'flex-shrink', value: shrink },
|
|
232
|
+
{ property: 'flex-basis', value: basis },
|
|
233
|
+
],
|
|
234
|
+
confident: true,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* A single number is `flex-grow`; a single length is `flex-basis`. The
|
|
239
|
+
* one-value form is the only place the two are distinguishable at all, which is
|
|
240
|
+
* why the split happens here rather than positionally.
|
|
241
|
+
*/
|
|
242
|
+
function classifyFlexParts(parts) {
|
|
243
|
+
if (parts.length === 1) {
|
|
244
|
+
const only = parts[0];
|
|
245
|
+
if (isBareNumber(only))
|
|
246
|
+
return [only, '1', '0%'];
|
|
247
|
+
if (isLength(only) || only === 'auto' || only === 'content')
|
|
248
|
+
return ['1', '1', only];
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
if (parts.length === 2) {
|
|
252
|
+
const [first, second] = parts;
|
|
253
|
+
if (!isBareNumber(first))
|
|
254
|
+
return null;
|
|
255
|
+
if (isBareNumber(second))
|
|
256
|
+
return [first, second, '0%'];
|
|
257
|
+
return [first, '1', second];
|
|
258
|
+
}
|
|
259
|
+
if (parts.length === 3) {
|
|
260
|
+
const [grow, shrink, basis] = parts;
|
|
261
|
+
if (!isBareNumber(grow) || !isBareNumber(shrink))
|
|
262
|
+
return null;
|
|
263
|
+
return [grow, shrink, basis];
|
|
264
|
+
}
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
function expandFlexFlow(value) {
|
|
268
|
+
const parts = topLevelParts(value);
|
|
269
|
+
if (parts.length === 0 || parts.length > 2)
|
|
270
|
+
return null;
|
|
271
|
+
const wraps = new Set(['nowrap', 'wrap', 'wrap-reverse']);
|
|
272
|
+
const directions = new Set(['row', 'row-reverse', 'column', 'column-reverse']);
|
|
273
|
+
let direction;
|
|
274
|
+
let wrap;
|
|
275
|
+
for (const part of parts) {
|
|
276
|
+
const lower = part.toLowerCase();
|
|
277
|
+
if (directions.has(lower)) {
|
|
278
|
+
if (direction !== undefined)
|
|
279
|
+
return null;
|
|
280
|
+
direction = lower;
|
|
281
|
+
}
|
|
282
|
+
else if (wraps.has(lower)) {
|
|
283
|
+
if (wrap !== undefined)
|
|
284
|
+
return null;
|
|
285
|
+
wrap = lower;
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return {
|
|
292
|
+
declarations: [
|
|
293
|
+
{ property: 'flex-direction', value: direction ?? 'row' },
|
|
294
|
+
{ property: 'flex-wrap', value: wrap ?? 'nowrap' },
|
|
295
|
+
],
|
|
296
|
+
confident: true,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
function expandTextDecoration(value) {
|
|
300
|
+
const parts = topLevelParts(value);
|
|
301
|
+
if (parts.length === 0 || parts.length > 4)
|
|
302
|
+
return null;
|
|
303
|
+
const lines = new Set(['none', 'underline', 'overline', 'line-through', 'blink']);
|
|
304
|
+
const styles = new Set(['solid', 'double', 'dotted', 'dashed', 'wavy']);
|
|
305
|
+
const lineParts = [];
|
|
306
|
+
let style;
|
|
307
|
+
let color;
|
|
308
|
+
let thickness;
|
|
309
|
+
for (const part of parts) {
|
|
310
|
+
const lower = part.toLowerCase();
|
|
311
|
+
if (lines.has(lower))
|
|
312
|
+
lineParts.push(lower);
|
|
313
|
+
else if (styles.has(lower)) {
|
|
314
|
+
if (style !== undefined)
|
|
315
|
+
return null;
|
|
316
|
+
style = lower;
|
|
317
|
+
}
|
|
318
|
+
else if (lower === 'auto' || lower === 'from-font' || isLength(part)) {
|
|
319
|
+
if (thickness !== undefined)
|
|
320
|
+
return null;
|
|
321
|
+
thickness = part;
|
|
322
|
+
}
|
|
323
|
+
else if (lower === 'currentcolor' || parseColor(part) !== null || part.startsWith('var(')) {
|
|
324
|
+
if (color !== undefined)
|
|
325
|
+
return null;
|
|
326
|
+
color = part;
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return {
|
|
333
|
+
declarations: [
|
|
334
|
+
{ property: 'text-decoration-line', value: lineParts.length > 0 ? lineParts.join(' ') : 'none' },
|
|
335
|
+
{ property: 'text-decoration-style', value: style ?? 'solid' },
|
|
336
|
+
{ property: 'text-decoration-color', value: color ?? 'currentcolor' },
|
|
337
|
+
{ property: 'text-decoration-thickness', value: thickness ?? 'auto' },
|
|
338
|
+
],
|
|
339
|
+
confident: true,
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Split on whitespace, but never inside a function call.
|
|
344
|
+
*
|
|
345
|
+
* `margin: calc(1px + 2px) 0` is two values, not four. Splitting naively would
|
|
346
|
+
* silently corrupt every `calc()`, `var()`, and gradient in the corpus.
|
|
347
|
+
*/
|
|
348
|
+
export function topLevelParts(value) {
|
|
349
|
+
const parts = [];
|
|
350
|
+
let depth = 0;
|
|
351
|
+
let current = '';
|
|
352
|
+
for (const char of value.trim()) {
|
|
353
|
+
if (char === '(')
|
|
354
|
+
depth += 1;
|
|
355
|
+
else if (char === ')')
|
|
356
|
+
depth -= 1;
|
|
357
|
+
if (depth === 0 && /\s/.test(char)) {
|
|
358
|
+
if (current.length > 0)
|
|
359
|
+
parts.push(current);
|
|
360
|
+
current = '';
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
current += char;
|
|
364
|
+
}
|
|
365
|
+
if (current.length > 0)
|
|
366
|
+
parts.push(current);
|
|
367
|
+
return parts;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* `inherit`, `initial`, `unset`, `revert`, and any `var()` reference are
|
|
371
|
+
* indivisible: they apply to the whole shorthand and cannot be distributed to
|
|
372
|
+
* longhands without resolving them first.
|
|
373
|
+
*/
|
|
374
|
+
function isGlobalKeywordAmbiguity(part) {
|
|
375
|
+
const lower = part.toLowerCase();
|
|
376
|
+
return (lower === 'inherit' ||
|
|
377
|
+
lower === 'initial' ||
|
|
378
|
+
lower === 'unset' ||
|
|
379
|
+
lower === 'revert' ||
|
|
380
|
+
lower === 'revert-layer');
|
|
381
|
+
}
|
|
382
|
+
function isLength(part) {
|
|
383
|
+
return /^[+-]?(\d+\.?\d*|\.\d+)([a-z]+|%)?$/i.test(part) || part.toLowerCase().startsWith('calc(');
|
|
384
|
+
}
|
|
385
|
+
function isBareNumber(part) {
|
|
386
|
+
return /^[+-]?(\d+\.?\d*|\.\d+)$/.test(part);
|
|
387
|
+
}
|
|
388
|
+
//# sourceMappingURL=shorthand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shorthand.js","sourceRoot":"","sources":["../../../src/rules/normalize/shorthand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA4BxC,gFAAgF;AAChF,MAAM,CAAC,MAAM,oBAAoB,GAAsB;IACrD,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU;IAC/C,QAAQ,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe;IACzE,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa;IAC5D,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,eAAe,EAAE,YAAY;IAC5E,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM;CAChF,CAAC;AAEF,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAU,CAAC;AAE1D,MAAM,OAAO,GAAG;IACd,wBAAwB,EAAE,yBAAyB;IACnD,4BAA4B,EAAE,2BAA2B;CACjD,CAAC;AAEX,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC;IAC1B,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ;IACvD,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ;CACrC,CAAC,CAAC;AAEH,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;AAEzD,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,KAAa;IAC/D,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,YAAY,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAE7E,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACtC,OAAO,QAAQ,IAAI,EAAE,YAAY,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AAC/E,CAAC;AAID,MAAM,SAAS,GAAuC;IACpD,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,IAAI,EAAE,CAAC;IACjD,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,IAAI,EAAE,CAAC;IACnD,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC;IACpC,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,IAAI,QAAQ,CAAC;IAC/D,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,IAAI,QAAQ,CAAC;IAC/D,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,IAAI,QAAQ,CAAC;IAC/D,eAAe,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,iBAAiB,IAAI,EAAE,CAAC;IACjE,gBAAgB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,kBAAkB,IAAI,EAAE,CAAC;IAEnE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,SAAS,EAAE,YAAY,CAAC;IAC5C,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,YAAY,EAAE,YAAY,CAAC;IACpD,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,aAAa,EAAE,eAAe,CAAC;IAC7D,eAAe,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,eAAe,EAAE,iBAAiB,CAAC;IACnE,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,YAAY,EAAE,cAAc,CAAC;IAE1D,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,EAAE,cAAc,CAAC;IAC7D,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,mBAAmB,EAAE,iBAAiB,CAAC;IAEtE,eAAe,EAAE,kBAAkB;IACnC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,EAAE,KAAK,CAAC;IAC1C,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;IAClD,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;IACtD,eAAe,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;IACxD,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;IACpD,OAAO,EAAE,aAAa;IACtB,IAAI,EAAE,UAAU;IAChB,WAAW,EAAE,cAAc;IAC3B,iBAAiB,EAAE,oBAAoB;IAEvC,8EAA8E;IAC9E,8EAA8E;IAC9E,8EAA8E;IAC9E,yEAAyE;IACzE,wEAAwE;IACxE,+EAA+E;IAC/E,gFAAgF;IAChF,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI;IACtB,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI;CACjB,CAAC;AAEF,0EAA0E;AAC1E,SAAS,GAAG,CAAC,KAAa,EAAE,IAA8B;IACxD,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACxD,IAAI,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC;QAAE,OAAO,IAAI,CAAC;IAEtD,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,KAA4C,CAAC;IAC9E,MAAM,QAAQ,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAU,CAAC;IAEvC,OAAO;QACL,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YACxC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC;YACpB,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAE;SACxB,CAAC,CAAC;QACH,SAAS,EAAE,IAAI;KAChB,CAAC;AACJ,CAAC;AAED,SAAS,IAAI,CAAC,KAAa,EAAE,KAAa,EAAE,MAAc;IACxD,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAExD,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;IACpB,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACxB,OAAO;QACL,YAAY,EAAE;YACZ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE;YAC7B,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE;SAC/B;QACD,SAAS,EAAE,IAAI;KAChB,CAAC;AACJ,CAAC;AAED,SAAS,KAAK,CAAC,KAAa,EAAE,KAAa,EAAE,GAAW;IACtD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1D,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAElC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;IACpB,uEAAuE;IACvE,sEAAsE;IACtE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QACpE,OAAO;YACL,YAAY,EAAE;gBACZ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE;gBAC7B,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE;aACjC;YACD,SAAS,EAAE,IAAI;SAChB,CAAC;IACJ,CAAC;IAED,OAAO;QACL,YAAY,EAAE;YACZ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE;YAC7B,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAE,EAAE;SACpC;QACD,SAAS,EAAE,IAAI;KAChB,CAAC;AACJ,CAAC;AAED,qFAAqF;AACrF,SAAS,kBAAkB,CAAC,KAAa;IACvC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAE3E,MAAM,CAAC,GAAG,YAAY,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;IACzC,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpB,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO;YACL,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAE,EAAE,CAAC,CAAC;YAChF,SAAS,EAAE,IAAI;SAChB,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACjC,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpB,OAAO;QACL,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YAC9C,QAAQ;YACR,KAAK,EAAE,GAAG,CAAC,CAAC,KAAK,CAAE,IAAI,CAAC,CAAC,KAAK,CAAE,EAAE;SACnC,CAAC,CAAC;QACH,SAAS,EAAE,IAAI;KAChB,CAAC;AACJ,CAAC;AAED,qEAAqE;AACrE,SAAS,YAAY,CAAC,KAAa;IACjC,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAExD,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,KAA4C,CAAC;IAC9E,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACtB,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAa,EAAE,KAAwB;IAChE,MAAM,MAAM,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAC;IAC7C,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC3C,EAAE,QAAQ,EAAE,UAAU,IAAI,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE;QACzD,EAAE,QAAQ,EAAE,UAAU,IAAI,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE;QACzD,EAAE,QAAQ,EAAE,UAAU,IAAI,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE;KAC1D,CAAC,CAAC;IAEH,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AAC3C,CAAC;AAED,SAAS,aAAa,CAAC,KAAa;IAClC,MAAM,MAAM,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAC;IAC7C,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,OAAO;QACL,YAAY,EAAE;YACZ,EAAE,QAAQ,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE;YAClD,EAAE,QAAQ,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE;YAClD,EAAE,QAAQ,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE;SACnD;QACD,SAAS,EAAE,IAAI;KAChB,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,sBAAsB,CAC7B,KAAa;IAEb,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAExD,IAAI,KAAyB,CAAC;IAC9B,IAAI,KAAyB,CAAC;IAC9B,IAAI,KAAyB,CAAC;IAE9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAEjC,IAAI,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3B,IAAI,KAAK,KAAK,SAAS;gBAAE,OAAO,IAAI,CAAC;YACrC,KAAK,GAAG,KAAK,CAAC;QAChB,CAAC;aAAM,IAAI,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACpD,IAAI,KAAK,KAAK,SAAS;gBAAE,OAAO,IAAI,CAAC;YACrC,KAAK,GAAG,IAAI,CAAC;QACf,CAAC;aAAM,IAAI,KAAK,KAAK,cAAc,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5F,IAAI,KAAK,KAAK,SAAS;gBAAE,OAAO,IAAI,CAAC;YACrC,KAAK,GAAG,IAAI,CAAC;QACf,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO;QACL,KAAK,EAAE,KAAK,IAAI,QAAQ;QACxB,KAAK,EAAE,KAAK,IAAI,MAAM;QACtB,KAAK,EAAE,KAAK,IAAI,cAAc;KAC/B,CAAC;AACJ,CAAC;AAED,oFAAoF;AACpF,SAAS,UAAU,CAAC,KAAa;IAC/B,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IACzC,MAAM,OAAO,GAAgE;QAC3E,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC;QACxB,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC;QACxB,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC;KAC5B,CAAC;IAEF,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC9B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,iBAAiB,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IACtF,IAAI,IAAI,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAEnF,OAAO;QACL,YAAY,EAAE;YACZ,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE;YACtC,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE;YAC1C,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE;SACzC;QACD,SAAS,EAAE,IAAI;KAChB,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,iBAAiB,CACxB,KAAwB;IAExB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;QACvB,IAAI,YAAY,CAAC,IAAI,CAAC;YAAE,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QACjD,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QACrF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,KAAyB,CAAC;QAClD,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACtC,IAAI,YAAY,CAAC,MAAM,CAAC;YAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;QACvD,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAC9B,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG,KAAiC,CAAC;QAChE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;YAAE,OAAO,IAAI,CAAC;QAC9D,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAExD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC;IAC1D,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAE/E,IAAI,SAA6B,CAAC;IAClC,IAAI,IAAwB,CAAC;IAE7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACjC,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,IAAI,SAAS,KAAK,SAAS;gBAAE,OAAO,IAAI,CAAC;YACzC,SAAS,GAAG,KAAK,CAAC;QACpB,CAAC;aAAM,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,IAAI,IAAI,KAAK,SAAS;gBAAE,OAAO,IAAI,CAAC;YACpC,IAAI,GAAG,KAAK,CAAC;QACf,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO;QACL,YAAY,EAAE;YACZ,EAAE,QAAQ,EAAE,gBAAgB,EAAE,KAAK,EAAE,SAAS,IAAI,KAAK,EAAE;YACzD,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,IAAI,QAAQ,EAAE;SACnD;QACD,SAAS,EAAE,IAAI;KAChB,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAa;IACzC,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAExD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC;IAClF,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;IAExE,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,IAAI,KAAyB,CAAC;IAC9B,IAAI,KAAyB,CAAC;IAC9B,IAAI,SAA6B,CAAC;IAElC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACjC,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;aACvC,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3B,IAAI,KAAK,KAAK,SAAS;gBAAE,OAAO,IAAI,CAAC;YACrC,KAAK,GAAG,KAAK,CAAC;QAChB,CAAC;aAAM,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,WAAW,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACvE,IAAI,SAAS,KAAK,SAAS;gBAAE,OAAO,IAAI,CAAC;YACzC,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC;aAAM,IAAI,KAAK,KAAK,cAAc,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5F,IAAI,KAAK,KAAK,SAAS;gBAAE,OAAO,IAAI,CAAC;YACrC,KAAK,GAAG,IAAI,CAAC;QACf,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO;QACL,YAAY,EAAE;YACZ,EAAE,QAAQ,EAAE,sBAAsB,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE;YAChG,EAAE,QAAQ,EAAE,uBAAuB,EAAE,KAAK,EAAE,KAAK,IAAI,OAAO,EAAE;YAC9D,EAAE,QAAQ,EAAE,uBAAuB,EAAE,KAAK,EAAE,KAAK,IAAI,cAAc,EAAE;YACrE,EAAE,QAAQ,EAAE,2BAA2B,EAAE,KAAK,EAAE,SAAS,IAAI,MAAM,EAAE;SACtE;QACD,SAAS,EAAE,IAAI;KAChB,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,OAAO,GAAG,EAAE,CAAC;IAEjB,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QAChC,IAAI,IAAI,KAAK,GAAG;YAAE,KAAK,IAAI,CAAC,CAAC;aACxB,IAAI,IAAI,KAAK,GAAG;YAAE,KAAK,IAAI,CAAC,CAAC;QAElC,IAAI,KAAK,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC5C,OAAO,GAAG,EAAE,CAAC;YACb,SAAS;QACX,CAAC;QACD,OAAO,IAAI,IAAI,CAAC;IAClB,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5C,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,SAAS,wBAAwB,CAAC,IAAY;IAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,OAAO,CACL,KAAK,KAAK,SAAS;QACnB,KAAK,KAAK,SAAS;QACnB,KAAK,KAAK,OAAO;QACjB,KAAK,KAAK,QAAQ;QAClB,KAAK,KAAK,cAAc,CACzB,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,sCAAsC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;AACrG,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAChC,OAAO,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC/C,CAAC","sourcesContent":["import { parseColor } from './color.js';\n\n/**\n * Shorthand expansion.\n *\n * The allowlist holds longhands only, so `margin: 4px` and\n * `margin-top: 4px; margin-right: 4px; …` must reduce to the same snapshot.\n * Without that, splitting a shorthand during a refactor — a change no user can\n * perceive — would invalidate every baseline it touches.\n *\n * The safety rule throughout: **an expansion we are not sure of is not\n * performed.** {@link expandDeclaration} returns `confident: false` and hands\n * back the shorthand unchanged, which the projection step then admits under its\n * own name. A partially-expanded shorthand would drop the components it failed\n * to classify, and a dropped declaration is a value missing from the hash — a\n * false `unchanged`. Keeping an un-normalized value costs at most a review\n * nobody needed; dropping one costs a missed regression.\n */\n\nexport interface Expansion {\n readonly declarations: readonly { readonly property: string; readonly value: string }[];\n /**\n * `false` when the shorthand could not be decomposed with certainty. The\n * single returned declaration is then the original shorthand.\n */\n readonly confident: boolean;\n}\n\n/** Shorthands admitted under their own name when expansion is not confident. */\nexport const SHORTHAND_PROPERTIES: readonly string[] = [\n 'margin', 'padding', 'inset', 'gap', 'overflow',\n 'border', 'border-width', 'border-style', 'border-color', 'border-radius',\n 'border-top', 'border-right', 'border-bottom', 'border-left',\n 'outline', 'flex', 'flex-flow', 'place-items', 'place-content', 'place-self',\n 'grid-row', 'grid-column', 'grid-area', 'text-decoration', 'background', 'font',\n];\n\nconst SIDES = ['top', 'right', 'bottom', 'left'] as const;\n\nconst CORNERS = [\n 'border-top-left-radius', 'border-top-right-radius',\n 'border-bottom-right-radius', 'border-bottom-left-radius',\n] as const;\n\nconst LINE_STYLES = new Set([\n 'none', 'hidden', 'dotted', 'dashed', 'solid', 'double',\n 'groove', 'ridge', 'inset', 'outset',\n]);\n\nconst LINE_WIDTHS = new Set(['thin', 'medium', 'thick']);\n\nexport function expandDeclaration(property: string, value: string): Expansion {\n const expand = EXPANDERS[property];\n if (!expand) return { declarations: [{ property, value }], confident: true };\n\n const expanded = expand(value.trim());\n return expanded ?? { declarations: [{ property, value }], confident: false };\n}\n\ntype Expander = (value: string) => Expansion | null;\n\nconst EXPANDERS: Readonly<Record<string, Expander>> = {\n margin: (v) => box(v, (side) => `margin-${side}`),\n padding: (v) => box(v, (side) => `padding-${side}`),\n inset: (v) => box(v, (side) => side),\n 'border-width': (v) => box(v, (side) => `border-${side}-width`),\n 'border-style': (v) => box(v, (side) => `border-${side}-style`),\n 'border-color': (v) => box(v, (side) => `border-${side}-color`),\n 'scroll-margin': (v) => box(v, (side) => `scroll-margin-${side}`),\n 'scroll-padding': (v) => box(v, (side) => `scroll-padding-${side}`),\n\n gap: (v) => pair(v, 'row-gap', 'column-gap'),\n overflow: (v) => pair(v, 'overflow-x', 'overflow-y'),\n 'place-items': (v) => pair(v, 'align-items', 'justify-items'),\n 'place-content': (v) => pair(v, 'align-content', 'justify-content'),\n 'place-self': (v) => pair(v, 'align-self', 'justify-self'),\n\n 'grid-row': (v) => slash(v, 'grid-row-start', 'grid-row-end'),\n 'grid-column': (v) => slash(v, 'grid-column-start', 'grid-column-end'),\n\n 'border-radius': expandBorderRadius,\n border: (v) => expandBorderSides(v, SIDES),\n 'border-top': (v) => expandBorderSides(v, ['top']),\n 'border-right': (v) => expandBorderSides(v, ['right']),\n 'border-bottom': (v) => expandBorderSides(v, ['bottom']),\n 'border-left': (v) => expandBorderSides(v, ['left']),\n outline: expandOutline,\n flex: expandFlex,\n 'flex-flow': expandFlexFlow,\n 'text-decoration': expandTextDecoration,\n\n // `background` and `font` are the two shorthands whose grammars are genuinely\n // ambiguous to decompose (a bare `<length>` in `background` may be a position\n // or a size; `font` interleaves four optional keyword slots before a required\n // size). Both are declared unexpandable rather than guessed at — see the\n // safety rule above. Under a profile with computed style the engine has\n // already resolved them into longhands, so this only affects the declared-only\n // tier, where an un-normalized value is a correct description of what is known.\n background: () => null,\n font: () => null,\n};\n\n/** 1–4 values in top/right/bottom/left order, per the CSS box grammar. */\nfunction box(value: string, name: (side: string) => string): Expansion | null {\n const parts = topLevelParts(value);\n if (parts.length === 0 || parts.length > 4) return null;\n if (parts.some(isGlobalKeywordAmbiguity)) return null;\n\n const [a, b = a, c = a, d = b] = parts as [string, string?, string?, string?];\n const resolved = [a, b, c, d] as const;\n\n return {\n declarations: SIDES.map((side, index) => ({\n property: name(side),\n value: resolved[index]!,\n })),\n confident: true,\n };\n}\n\nfunction pair(value: string, first: string, second: string): Expansion | null {\n const parts = topLevelParts(value);\n if (parts.length === 0 || parts.length > 2) return null;\n\n const a = parts[0]!;\n const b = parts[1] ?? a;\n return {\n declarations: [\n { property: first, value: a },\n { property: second, value: b },\n ],\n confident: true,\n };\n}\n\nfunction slash(value: string, start: string, end: string): Expansion | null {\n const parts = value.split('/').map((part) => part.trim());\n if (parts.length > 2) return null;\n\n const a = parts[0]!;\n // Omitted end defaults to `auto`, not to a copy of start, except for a\n // custom-ident line name — where it does copy. Ambiguous, so decline.\n if (parts.length === 1) {\n if (/^-?[a-z_]/i.test(a) && !/^(auto|span)\\b/i.test(a)) return null;\n return {\n declarations: [\n { property: start, value: a },\n { property: end, value: 'auto' },\n ],\n confident: true,\n };\n }\n\n return {\n declarations: [\n { property: start, value: a },\n { property: end, value: parts[1]! },\n ],\n confident: true,\n };\n}\n\n/** `border-radius: a b / c d` — the `/` separates horizontal from vertical radii. */\nfunction expandBorderRadius(value: string): Expansion | null {\n const [horizontal, vertical] = value.split('/').map((part) => part.trim());\n\n const h = cornerValues(horizontal ?? '');\n if (!h) return null;\n\n if (vertical === undefined) {\n return {\n declarations: CORNERS.map((property, index) => ({ property, value: h[index]! })),\n confident: true,\n };\n }\n\n const v = cornerValues(vertical);\n if (!v) return null;\n\n return {\n declarations: CORNERS.map((property, index) => ({\n property,\n value: `${h[index]!} ${v[index]!}`,\n })),\n confident: true,\n };\n}\n\n/** Corner order is TL, TR, BR, BL — different from the box order. */\nfunction cornerValues(value: string): readonly [string, string, string, string] | null {\n const parts = topLevelParts(value);\n if (parts.length === 0 || parts.length > 4) return null;\n\n const [a, b = a, c = a, d = b] = parts as [string, string?, string?, string?];\n return [a, b, c, d];\n}\n\nfunction expandBorderSides(value: string, sides: readonly string[]): Expansion | null {\n const parsed = classifyLineComponents(value);\n if (!parsed) return null;\n\n const declarations = sides.flatMap((side) => [\n { property: `border-${side}-width`, value: parsed.width },\n { property: `border-${side}-style`, value: parsed.style },\n { property: `border-${side}-color`, value: parsed.color },\n ]);\n\n return { declarations, confident: true };\n}\n\nfunction expandOutline(value: string): Expansion | null {\n const parsed = classifyLineComponents(value);\n if (!parsed) return null;\n\n return {\n declarations: [\n { property: 'outline-width', value: parsed.width },\n { property: 'outline-style', value: parsed.style },\n { property: 'outline-color', value: parsed.color },\n ],\n confident: true,\n };\n}\n\n/**\n * Split `<width> || <style> || <color>`, which may appear in any order.\n *\n * Omitted components take their initial values rather than being left out —\n * `border: solid` really does reset width and colour, and recording only the\n * style would let a genuine colour change slip through as unobserved.\n */\nfunction classifyLineComponents(\n value: string,\n): { width: string; style: string; color: string } | null {\n const parts = topLevelParts(value);\n if (parts.length === 0 || parts.length > 3) return null;\n\n let width: string | undefined;\n let style: string | undefined;\n let color: string | undefined;\n\n for (const part of parts) {\n const lower = part.toLowerCase();\n\n if (LINE_STYLES.has(lower)) {\n if (style !== undefined) return null;\n style = lower;\n } else if (LINE_WIDTHS.has(lower) || isLength(part)) {\n if (width !== undefined) return null;\n width = part;\n } else if (lower === 'currentcolor' || parseColor(part) !== null || part.startsWith('var(')) {\n if (color !== undefined) return null;\n color = part;\n } else {\n return null;\n }\n }\n\n return {\n width: width ?? 'medium',\n style: style ?? 'none',\n color: color ?? 'currentcolor',\n };\n}\n\n/** `flex: <grow> <shrink>? <basis>?`, plus the `none`/`auto`/`initial` keywords. */\nfunction expandFlex(value: string): Expansion | null {\n const lower = value.toLowerCase().trim();\n const keyword: Readonly<Record<string, readonly [string, string, string]>> = {\n none: ['0', '0', 'auto'],\n auto: ['1', '1', 'auto'],\n initial: ['0', '1', 'auto'],\n };\n\n const preset = keyword[lower];\n const [grow, shrink, basis] = preset ?? classifyFlexParts(topLevelParts(value)) ?? [];\n if (grow === undefined || shrink === undefined || basis === undefined) return null;\n\n return {\n declarations: [\n { property: 'flex-grow', value: grow },\n { property: 'flex-shrink', value: shrink },\n { property: 'flex-basis', value: basis },\n ],\n confident: true,\n };\n}\n\n/**\n * A single number is `flex-grow`; a single length is `flex-basis`. The\n * one-value form is the only place the two are distinguishable at all, which is\n * why the split happens here rather than positionally.\n */\nfunction classifyFlexParts(\n parts: readonly string[],\n): readonly [string, string, string] | null {\n if (parts.length === 1) {\n const only = parts[0]!;\n if (isBareNumber(only)) return [only, '1', '0%'];\n if (isLength(only) || only === 'auto' || only === 'content') return ['1', '1', only];\n return null;\n }\n\n if (parts.length === 2) {\n const [first, second] = parts as [string, string];\n if (!isBareNumber(first)) return null;\n if (isBareNumber(second)) return [first, second, '0%'];\n return [first, '1', second];\n }\n\n if (parts.length === 3) {\n const [grow, shrink, basis] = parts as [string, string, string];\n if (!isBareNumber(grow) || !isBareNumber(shrink)) return null;\n return [grow, shrink, basis];\n }\n\n return null;\n}\n\nfunction expandFlexFlow(value: string): Expansion | null {\n const parts = topLevelParts(value);\n if (parts.length === 0 || parts.length > 2) return null;\n\n const wraps = new Set(['nowrap', 'wrap', 'wrap-reverse']);\n const directions = new Set(['row', 'row-reverse', 'column', 'column-reverse']);\n\n let direction: string | undefined;\n let wrap: string | undefined;\n\n for (const part of parts) {\n const lower = part.toLowerCase();\n if (directions.has(lower)) {\n if (direction !== undefined) return null;\n direction = lower;\n } else if (wraps.has(lower)) {\n if (wrap !== undefined) return null;\n wrap = lower;\n } else {\n return null;\n }\n }\n\n return {\n declarations: [\n { property: 'flex-direction', value: direction ?? 'row' },\n { property: 'flex-wrap', value: wrap ?? 'nowrap' },\n ],\n confident: true,\n };\n}\n\nfunction expandTextDecoration(value: string): Expansion | null {\n const parts = topLevelParts(value);\n if (parts.length === 0 || parts.length > 4) return null;\n\n const lines = new Set(['none', 'underline', 'overline', 'line-through', 'blink']);\n const styles = new Set(['solid', 'double', 'dotted', 'dashed', 'wavy']);\n\n const lineParts: string[] = [];\n let style: string | undefined;\n let color: string | undefined;\n let thickness: string | undefined;\n\n for (const part of parts) {\n const lower = part.toLowerCase();\n if (lines.has(lower)) lineParts.push(lower);\n else if (styles.has(lower)) {\n if (style !== undefined) return null;\n style = lower;\n } else if (lower === 'auto' || lower === 'from-font' || isLength(part)) {\n if (thickness !== undefined) return null;\n thickness = part;\n } else if (lower === 'currentcolor' || parseColor(part) !== null || part.startsWith('var(')) {\n if (color !== undefined) return null;\n color = part;\n } else {\n return null;\n }\n }\n\n return {\n declarations: [\n { property: 'text-decoration-line', value: lineParts.length > 0 ? lineParts.join(' ') : 'none' },\n { property: 'text-decoration-style', value: style ?? 'solid' },\n { property: 'text-decoration-color', value: color ?? 'currentcolor' },\n { property: 'text-decoration-thickness', value: thickness ?? 'auto' },\n ],\n confident: true,\n };\n}\n\n/**\n * Split on whitespace, but never inside a function call.\n *\n * `margin: calc(1px + 2px) 0` is two values, not four. Splitting naively would\n * silently corrupt every `calc()`, `var()`, and gradient in the corpus.\n */\nexport function topLevelParts(value: string): string[] {\n const parts: string[] = [];\n let depth = 0;\n let current = '';\n\n for (const char of value.trim()) {\n if (char === '(') depth += 1;\n else if (char === ')') depth -= 1;\n\n if (depth === 0 && /\\s/.test(char)) {\n if (current.length > 0) parts.push(current);\n current = '';\n continue;\n }\n current += char;\n }\n\n if (current.length > 0) parts.push(current);\n return parts;\n}\n\n/**\n * `inherit`, `initial`, `unset`, `revert`, and any `var()` reference are\n * indivisible: they apply to the whole shorthand and cannot be distributed to\n * longhands without resolving them first.\n */\nfunction isGlobalKeywordAmbiguity(part: string): boolean {\n const lower = part.toLowerCase();\n return (\n lower === 'inherit' ||\n lower === 'initial' ||\n lower === 'unset' ||\n lower === 'revert' ||\n lower === 'revert-layer'\n );\n}\n\nfunction isLength(part: string): boolean {\n return /^[+-]?(\\d+\\.?\\d*|\\.\\d+)([a-z]+|%)?$/i.test(part) || part.toLowerCase().startsWith('calc(');\n}\n\nfunction isBareNumber(part: string): boolean {\n return /^[+-]?(\\d+\\.?\\d*|\\.\\d+)$/.test(part);\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Units left symbolic because they cannot be resolved without a layout engine.
|
|
3
|
+
*
|
|
4
|
+
* This is the `declared-only` boundary made concrete (ADR-0002): under a profile
|
|
5
|
+
* without computed style, `padding: 1rem` stays `1rem`. That is honest — it is
|
|
6
|
+
* genuinely all that tier knows — and it is why JSDOM decides the token band
|
|
7
|
+
* `declared-only` rather than `full`. Resolving these by assuming a root font
|
|
8
|
+
* size would fabricate precision the tier does not have.
|
|
9
|
+
*/
|
|
10
|
+
export declare const RELATIVE_UNITS: readonly string[];
|
|
11
|
+
export declare function canonicalizeValue(property: string, value: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Rewrite a value token by token.
|
|
14
|
+
*
|
|
15
|
+
* Quoted strings and `url()` payloads are passed through untouched: a font
|
|
16
|
+
* family name and a resource path are opaque data, and normalizing their case
|
|
17
|
+
* would change what they refer to.
|
|
18
|
+
*/
|
|
19
|
+
export declare function canonicalizeTokens(value: string): string;
|
|
20
|
+
/** Canonicalize one `<number><unit>` token. */
|
|
21
|
+
export declare function canonicalizeDimension(token: string): string;
|
|
22
|
+
export declare function isRelativeUnit(unit: string): boolean;
|
|
23
|
+
//# sourceMappingURL=value.d.ts.map
|