@shapeshift-labs/frontier-lang-css 0.1.22 → 0.1.23
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/README.md +4 -4
- package/dist/index.d.ts +11 -2
- package/dist/postcss-parser-evidence.js +25 -5
- package/dist/scoped-cascade-proof.d.ts +9 -0
- package/dist/semantic-merge-css-modules.js +1 -0
- package/dist/semantic-merge-scoped-cascade.js +22 -7
- package/dist/semantic-merge.js +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -232,11 +232,11 @@ const merge = safeMergeCssSource({
|
|
|
232
232
|
});
|
|
233
233
|
```
|
|
234
234
|
|
|
235
|
-
`sourceMap.mappings` links emitted rule blocks back to Frontier Lang semantic node ids. `createCssSemanticMergeEvidence` records selectors, specificity, declarations, custom properties, `var()` fallback references, animation/keyframe links, font-face links, URL asset references, cascade keys, statement-form at-rules, block-form runtime at-rules, CSS Modules exports, ICSS edges, scoped cascade graph proof hashes, source spans, stable hashes, and fail-closed proof gaps for cascade/render-sensitive CSS surfaces. `safeMergeCssSource` admits independent declaration edits by cascade key,
|
|
235
|
+
`sourceMap.mappings` links emitted rule blocks back to Frontier Lang semantic node ids. `createCssSemanticMergeEvidence` records selectors, specificity, declarations, custom properties, `var()` fallback references, animation/keyframe links, font-face links, URL asset references, cascade keys, statement-form at-rules, block-form runtime at-rules, CSS Modules exports, ICSS edges, scoped cascade graph proof hashes keyed by scope shape, source spans, stable hashes, and fail-closed proof gaps for cascade/render-sensitive CSS surfaces. `safeMergeCssSource` admits independent declaration edits by cascade key, carries deterministic box-shorthand expansion evidence for supported margin/padding/inset/gap/scroll/border-edge families, carries source-bound dependency graph evidence into the merge result, blocks duplicate ordered occurrences of the same cascade key until ordered cascade evidence exists, blocks dependency-affecting declaration edits unless an exact source-bound dependency graph proof is supplied, blocks selector-target rebases unless the host supplies a source-bound selector target graph hash and the parser proves selector specificity is invariant, blocks changed scoped declarations under `@media` / `@supports` / `@container` / `@layer` / `@scope` unless an exact source-bound scoped cascade proof matches the scope shape key, scoped graph hash, and base/worker/head/output source hashes, blocks parallel edits whose CSS shorthand expansions overlap a longhand or sub-shorthand, preserves unchanged statement-form at-rules such as `@layer reset, components;`, preserves unchanged block-form runtime at-rules such as `@keyframes` and `@font-face`, and for `.module.css` files it classifies exported local classes, `composes`, and ICSS import/export records as explicit merge contracts. Cascade-sensitive source-shape changes still block by default, but a host can attach a `css-source-bound-cascade-runtime-proof` / `css-cascade-runtime-proof` that is bound to the exact source path, reason, side, shape key, and base/worker/head/output source hashes to admit that specific change.
|
|
236
236
|
|
|
237
237
|
## Support Boundary
|
|
238
238
|
|
|
239
|
-
- Ready evidence: style rules, selectors, specificity, declarations, source-bound dependency graph hashes for custom properties, `var()` fallbacks, animations/keyframes, font faces, and URL assets, statement-form at-rules, block-form runtime at-rules, CSS Modules local exports, generated class-name map coverage, JS/TS use-site graph hashes, composition graph hashes, ICSS graph hashes, scoped cascade graph hashes, source-bound cascade runtime proofs, source spans, stable hashes.
|
|
240
|
-
- Safe merge: independent declarations with non-overlapping cascade keys, no duplicate ordered occurrences for any changed cascade key, deterministic box-shorthand expansion evidence for supported shorthand families, non-overlapping shorthand expansion sets, and no changed dependency graph surface; unchanged statement-form at-rules and unchanged block-form runtime at-rules preserved in canonical output;
|
|
241
|
-
- Review-only gaps: duplicate ordered occurrences of the same cascade key, incomplete generated class-name maps, unproved dependency graph changes, unproved CSS Modules use-site graphs, unproved composition or ICSS graphs, ambiguous shorthand value expansion/equivalence such as `font`, layered `background`, and runtime-substituted `var()` / `env()` shorthand values, statement-form at-rule order/condition changes, one-sided or structurally changed scoped cascade under `@media` / `@supports` / `@container` / `@layer`, changed runtime blocks such as `@keyframes`, `@font-face`, `@page`, and `@property`, browser layout and render equivalence.
|
|
239
|
+
- Ready evidence: style rules, selectors, specificity, declarations, source-bound dependency graph hashes for custom properties, `var()` fallbacks, animations/keyframes, font faces, and URL assets, statement-form at-rules, block-form runtime at-rules, CSS Modules local exports, generated class-name map coverage, JS/TS use-site graph hashes, composition graph hashes, ICSS graph hashes, scoped cascade graph hashes by scope shape key, source-bound scoped cascade proofs, source-bound cascade runtime proofs, source spans, stable hashes.
|
|
240
|
+
- Safe merge: independent declarations with non-overlapping cascade keys, no duplicate ordered occurrences for any changed cascade key, deterministic box-shorthand expansion evidence for supported shorthand families, non-overlapping shorthand expansion sets, and no changed dependency graph surface; unchanged statement-form at-rules and unchanged block-form runtime at-rules preserved in canonical output; changed scoped declaration edits only when an exact source-bound scoped cascade proof matches the scope shape key, scoped graph hash, and base/worker/head/output source hashes; dependency-affecting declaration edits only when an exact source-bound dependency graph proof is supplied; selector-target rebases only when a matching selector target graph hash is supplied and before/after selector specificity is identical; source-shape/cascade-sensitive edits only when an exact source-bound cascade runtime proof is supplied; explicit CSS Modules export additions/deletions when generated class-name and JS/TS use-site graph proof is supplied; composition edits when composition graph proof is supplied; ICSS edits when ICSS graph proof is supplied. Output is a canonical CSS render and not a byte/trivia-preserving claim.
|
|
241
|
+
- Review-only gaps: duplicate ordered occurrences of the same cascade key, incomplete generated class-name maps, unproved dependency graph changes, unproved CSS Modules use-site graphs, unproved composition or ICSS graphs, ambiguous shorthand value expansion/equivalence such as `font`, layered `background`, and runtime-substituted `var()` / `env()` shorthand values, statement-form at-rule order/condition changes, one-sided or structurally changed scoped cascade under `@media` / `@supports` / `@container` / `@layer` / `@scope`, changed runtime blocks such as `@keyframes`, `@font-face`, `@page`, and `@property`, browser layout and render equivalence.
|
|
242
242
|
- Claims: dependency graph evidence is an admission/review signal only unless an exact source-bound dependency graph proof admits the changed dependency surface; `autoMergeClaim`, `semanticEquivalenceClaim`, and `browserRenderEquivalenceClaim` remain false. `browserCascadeEquivalenceClaim` is only true on a safe-merge result when a source-bound cascade runtime proof admits the specific cascade-sensitive source-shape change.
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,14 @@ export interface CssProjectionOptions {
|
|
|
13
13
|
readonly cssModuleCompositionGraphHash?: string;
|
|
14
14
|
readonly icssGraphHash?: string;
|
|
15
15
|
readonly scopedCascadeGraphHash?: string;
|
|
16
|
+
readonly scopedCascadeGraphHashesByShapeKey?: Readonly<Record<string, string>>;
|
|
17
|
+
readonly cssScopedCascadeGraphHashesByShapeKey?: Readonly<Record<string, string>>;
|
|
18
|
+
readonly baseScopedCascadeGraphHashesByShapeKey?: Readonly<Record<string, string>>;
|
|
19
|
+
readonly workerScopedCascadeGraphHashesByShapeKey?: Readonly<Record<string, string>>;
|
|
20
|
+
readonly headScopedCascadeGraphHashesByShapeKey?: Readonly<Record<string, string>>;
|
|
21
|
+
readonly baseCssScopedCascadeGraphHashesByShapeKey?: Readonly<Record<string, string>>;
|
|
22
|
+
readonly workerCssScopedCascadeGraphHashesByShapeKey?: Readonly<Record<string, string>>;
|
|
23
|
+
readonly headCssScopedCascadeGraphHashesByShapeKey?: Readonly<Record<string, string>>;
|
|
16
24
|
readonly cssScopedCascadeProof?: CssScopedCascadeProof; readonly cssScopedCascadeProofs?: readonly CssScopedCascadeProof[];
|
|
17
25
|
readonly cssSourceBoundScopedCascadeProof?: CssScopedCascadeProof; readonly cssSourceBoundScopedCascadeProofs?: readonly CssScopedCascadeProof[];
|
|
18
26
|
readonly cssCascadeRuntimeProof?: CssCascadeRuntimeProof; readonly cssCascadeRuntimeProofs?: readonly CssCascadeRuntimeProof[];
|
|
@@ -129,6 +137,7 @@ export interface CssSemanticRecord {
|
|
|
129
137
|
readonly scopeKey?: string;
|
|
130
138
|
readonly statementText?: string;
|
|
131
139
|
readonly blockText?: string;
|
|
140
|
+
readonly scopedCascadeGraphShapeKey?: string;
|
|
132
141
|
readonly scopedCascadeGraphHash?: string;
|
|
133
142
|
readonly selectorTargetGraphHash?: string;
|
|
134
143
|
readonly sourceSpan: CssSourceSpan;
|
|
@@ -256,12 +265,12 @@ export interface CssSafeMergeResult {
|
|
|
256
265
|
export interface CssSafeMergeParserEvidence {
|
|
257
266
|
readonly kind: 'frontier.lang.cssSafeMergeParserEvidence'; readonly version: 1; readonly parserNames: readonly string[];
|
|
258
267
|
readonly sourceCodeLocationInfo: boolean; readonly parserBackedSourceSpans: boolean; readonly parserBackedDeclarationSpans: boolean; readonly parserBackedTriviaHashes: boolean;
|
|
259
|
-
readonly scopedCascadeGraphHashPresent: boolean; readonly parseErrors: number; readonly sides: Readonly<Record<string, CssSafeMergeParserSideEvidence>>;
|
|
268
|
+
readonly scopedCascadeGraphHashPresent: boolean; readonly scopedCascadeGraphShapeHashPresent?: boolean; readonly parseErrors: number; readonly sides: Readonly<Record<string, CssSafeMergeParserSideEvidence>>;
|
|
260
269
|
}
|
|
261
270
|
|
|
262
271
|
export interface CssSafeMergeParserSideEvidence {
|
|
263
272
|
readonly parserName: string; readonly sourceCodeLocationInfo: boolean; readonly parserBackedSourceSpans: boolean; readonly parserBackedDeclarationSpans: boolean; readonly parserBackedTriviaHashes: boolean;
|
|
264
|
-
readonly scopedCascadeGraphHashPresent: boolean; readonly parseErrors: number; readonly recordCount: number; readonly declarationCount: number;
|
|
273
|
+
readonly scopedCascadeGraphHashPresent: boolean; readonly scopedCascadeGraphShapeHashPresent?: boolean; readonly scopedCascadeGraphShapeKeys?: number; readonly parseErrors: number; readonly recordCount: number; readonly declarationCount: number;
|
|
265
274
|
}
|
|
266
275
|
|
|
267
276
|
export interface CssSafeMergeInput {
|
|
@@ -42,9 +42,11 @@ function postcssRuleRecord(node, scopes, sourceHash, options) {
|
|
|
42
42
|
const selectors = String(node.selector ?? '').split(',').map((selector) => selector.trim()).filter(Boolean);
|
|
43
43
|
const declarations = (node.nodes ?? []).filter((child) => child.type === 'decl').map(postcssDeclaration);
|
|
44
44
|
const nestedChildren = (node.nodes ?? []).filter((child) => child.type !== 'decl' && child.type !== 'comment');
|
|
45
|
+
const scopedCascadeGraphShapeKey = scopedCascadeGraphShapeKeyForScopes(scopes);
|
|
46
|
+
const scopedCascadeGraphHash = scopedCascadeGraphHashForShape(scopedCascadeGraphShapeKey, options);
|
|
45
47
|
const proofGaps = [
|
|
46
48
|
...declarations.filter((declaration) => ShorthandProperties.has(declaration.property)).map((declaration) => proofGap('css-shorthand-expansion-unproved', `CSS shorthand ${declaration.property} needs longhand expansion evidence.`)),
|
|
47
|
-
...scopes.length && !
|
|
49
|
+
...scopes.length && !scopedCascadeGraphHash ? [proofGap('css-scoped-cascade-equivalence-unproved', 'Scoped cascade equivalence requires browser/style evidence.')] : [],
|
|
48
50
|
...nestedChildren.length ? [proofGap('css-nesting-semantic-unproved', 'CSS nested rule semantics require nesting expansion evidence.')] : []
|
|
49
51
|
];
|
|
50
52
|
return compactRecord({
|
|
@@ -60,7 +62,8 @@ function postcssRuleRecord(node, scopes, sourceHash, options) {
|
|
|
60
62
|
declarationHash: hashSemanticValue({ kind: 'frontier.lang.css.declaration.v2.postcss', scopes, selectors, property: declaration.property, rawProperty: declaration.rawProperty, value: declaration.value, important: declaration.important })
|
|
61
63
|
})),
|
|
62
64
|
customProperties: declarations.filter((declaration) => declaration.property.startsWith('--')).map((declaration) => declaration.property),
|
|
63
|
-
|
|
65
|
+
scopedCascadeGraphShapeKey,
|
|
66
|
+
scopedCascadeGraphHash,
|
|
64
67
|
selectorTargetGraphHash: options.selectorTargetGraphHash,
|
|
65
68
|
sourceSpan: sourceSpanFromPostcss(node.source, options.sourcePath),
|
|
66
69
|
sourceHash,
|
|
@@ -89,9 +92,12 @@ function postcssAtRuleRecord(node, scopes, sourceHash, options) {
|
|
|
89
92
|
const atRuleName = String(node.name ?? 'unknown').toLowerCase();
|
|
90
93
|
const conditionText = String(node.params ?? '').trim();
|
|
91
94
|
const rawText = rawPostcssText(node);
|
|
95
|
+
const scopeKey = postcssAtRuleScopeKey(node);
|
|
96
|
+
const scopedCascadeGraphShapeKey = ScopeAtRules.has(atRuleName) ? scopedCascadeGraphShapeKeyForScopes([...scopes, scopeKey]) : undefined;
|
|
97
|
+
const scopedCascadeGraphHash = scopedCascadeGraphHashForShape(scopedCascadeGraphShapeKey, options);
|
|
92
98
|
const proofGaps = [];
|
|
93
99
|
if (RuntimeAtRules.has(atRuleName)) proofGaps.push(proofGap(`css-${atRuleName}-runtime-equivalence-unproved`, `CSS @${atRuleName} semantics require browser evidence.`));
|
|
94
|
-
if (ScopeAtRules.has(atRuleName) && !
|
|
100
|
+
if (ScopeAtRules.has(atRuleName) && !scopedCascadeGraphHash) proofGaps.push(proofGap(`css-${atRuleName}-cascade-scope-unproved`, `CSS @${atRuleName} scoped cascade requires condition evaluation evidence.`));
|
|
95
101
|
if (!node.nodes?.length && atRuleName === 'layer') proofGaps.push(proofGap('css-layer-order-statement-unsupported', 'CSS @layer statement order requires cascade order evidence.'));
|
|
96
102
|
else if (!node.nodes?.length) proofGaps.push(proofGap(`css-${atRuleName}-statement-equivalence-unproved`, `CSS @${atRuleName} statement semantics require host evidence.`));
|
|
97
103
|
const kind = node.nodes?.length ? 'at-rule' : 'at-rule-statement';
|
|
@@ -101,10 +107,11 @@ function postcssAtRuleRecord(node, scopes, sourceHash, options) {
|
|
|
101
107
|
conditionText,
|
|
102
108
|
statementText: kind === 'at-rule-statement' ? rawText : undefined,
|
|
103
109
|
blockText: kind === 'at-rule' ? rawText : undefined,
|
|
104
|
-
scopeKey
|
|
110
|
+
scopeKey,
|
|
105
111
|
scopes,
|
|
106
112
|
dependencyTokens: atRuleDependencyTokens(node, atRuleName),
|
|
107
|
-
|
|
113
|
+
scopedCascadeGraphShapeKey,
|
|
114
|
+
scopedCascadeGraphHash,
|
|
108
115
|
sourceSpan: sourceSpanFromPostcss(node.source, options.sourcePath),
|
|
109
116
|
sourceHash,
|
|
110
117
|
rawTextHash: hashSemanticValue({ kind: 'frontier.lang.css.rawAtRuleText.v1', text: rawText }),
|
|
@@ -118,6 +125,19 @@ function postcssAtRuleScopeKey(node) {
|
|
|
118
125
|
return `@${String(node.name ?? 'unknown').toLowerCase()} ${String(node.params ?? '').trim()}`.trim();
|
|
119
126
|
}
|
|
120
127
|
|
|
128
|
+
function scopedCascadeGraphShapeKeyForScopes(scopes = []) {
|
|
129
|
+
return scopes.length ? scopes.join('::') : undefined;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function scopedCascadeGraphHashForShape(shapeKey, options) {
|
|
133
|
+
if (!shapeKey) return undefined;
|
|
134
|
+
return scopedCascadeGraphHashesByShapeKey(options)?.[shapeKey] ?? options.scopedCascadeGraphHash;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function scopedCascadeGraphHashesByShapeKey(options) {
|
|
138
|
+
return options.scopedCascadeGraphHashesByShapeKey ?? options.cssScopedCascadeGraphHashesByShapeKey ?? options.scopedCascadeGraphHashes;
|
|
139
|
+
}
|
|
140
|
+
|
|
121
141
|
function atRuleDependencyTokens(node, atRuleName) {
|
|
122
142
|
if (atRuleName !== 'font-face') return undefined;
|
|
123
143
|
const declarations = (node.nodes ?? []).filter((child) => child.type === 'decl');
|
|
@@ -16,6 +16,10 @@ export interface CssScopedCascadeProof {
|
|
|
16
16
|
readonly scopes?: readonly string[];
|
|
17
17
|
readonly property?: string;
|
|
18
18
|
readonly properties?: readonly string[];
|
|
19
|
+
readonly scopedCascadeGraphShapeKey?: string;
|
|
20
|
+
readonly scopedCascadeGraphShapeKeys?: readonly string[];
|
|
21
|
+
readonly shapeKey?: string;
|
|
22
|
+
readonly shapeKeys?: readonly string[];
|
|
19
23
|
readonly scopedCascadeGraphHash?: string;
|
|
20
24
|
readonly graphHash?: string;
|
|
21
25
|
readonly baseScopedCascadeGraphHash?: string;
|
|
@@ -23,6 +27,9 @@ export interface CssScopedCascadeProof {
|
|
|
23
27
|
readonly headScopedCascadeGraphHash?: string;
|
|
24
28
|
readonly scopedCascadeGraphHashes?: Readonly<Record<string, string>>;
|
|
25
29
|
readonly graphHashes?: Readonly<Record<string, string>>;
|
|
30
|
+
readonly scopedCascadeGraphHashesByShapeKey?: Readonly<Record<string, string>>;
|
|
31
|
+
readonly graphHashesByShapeKey?: Readonly<Record<string, string>>;
|
|
32
|
+
readonly scopedCascadeGraphHashesByRoleAndShape?: Readonly<Record<string, Readonly<Record<string, string>>>>;
|
|
26
33
|
readonly baseSourceText?: string; readonly workerSourceText?: string; readonly headSourceText?: string; readonly outputSourceText?: string; readonly mergedSourceText?: string;
|
|
27
34
|
readonly baseSourceHash?: string; readonly workerSourceHash?: string; readonly headSourceHash?: string; readonly outputSourceHash?: string; readonly mergedSourceHash?: string;
|
|
28
35
|
readonly sourceTexts?: Readonly<Record<string, string>>;
|
|
@@ -42,9 +49,11 @@ export interface CssScopedCascadeProofRecord {
|
|
|
42
49
|
readonly ruleKey?: string;
|
|
43
50
|
readonly property?: string;
|
|
44
51
|
readonly scopes?: readonly string[];
|
|
52
|
+
readonly scopedCascadeGraphShapeKey?: string;
|
|
45
53
|
readonly sourcePath?: string;
|
|
46
54
|
readonly scopedCascadeGraphHash?: string;
|
|
47
55
|
readonly scopedCascadeGraphHashes?: Readonly<Record<string, string>>;
|
|
56
|
+
readonly scopedCascadeGraphShapeKeys?: Readonly<Record<string, string>>;
|
|
48
57
|
readonly baseSourceHash?: string;
|
|
49
58
|
readonly workerSourceHash?: string;
|
|
50
59
|
readonly headSourceHash?: string;
|
|
@@ -12,6 +12,7 @@ function sheetOptions(input, side, sourcePath) {
|
|
|
12
12
|
cssModuleCompositionGraphHash: input[`${prefix}CssModuleCompositionGraphHash`] ?? input.cssModuleCompositionGraphHash,
|
|
13
13
|
icssGraphHash: input[`${prefix}IcssGraphHash`] ?? input.icssGraphHash,
|
|
14
14
|
scopedCascadeGraphHash: input[`${prefix}ScopedCascadeGraphHash`] ?? input.scopedCascadeGraphHash,
|
|
15
|
+
scopedCascadeGraphHashesByShapeKey: input[`${prefix}ScopedCascadeGraphHashesByShapeKey`] ?? input[`${prefix}CssScopedCascadeGraphHashesByShapeKey`] ?? input.scopedCascadeGraphHashesByShapeKey ?? input.cssScopedCascadeGraphHashesByShapeKey,
|
|
15
16
|
selectorTargetGraphHash: input[`${prefix}SelectorTargetGraphHash`] ?? input.selectorTargetGraphHash
|
|
16
17
|
};
|
|
17
18
|
}
|
|
@@ -23,11 +23,13 @@ function scopedCascadeChangesForSide(changes, side, baseIndex) {
|
|
|
23
23
|
ruleKey: entry.ruleKey,
|
|
24
24
|
selectors: entry.selectors,
|
|
25
25
|
scopes: entry.scopes,
|
|
26
|
+
scopedCascadeGraphShapeKey: entry.scopedCascadeGraphShapeKey,
|
|
26
27
|
property: entry.property,
|
|
27
28
|
specificity: entry.specificity,
|
|
28
29
|
scopedCascadeGraphReady: graphRoles.every((item) => typeof item.hash === 'string'),
|
|
29
30
|
scopedCascadeGraphHash: graphRoles.find((item) => typeof item.hash === 'string')?.hash,
|
|
30
31
|
scopedCascadeGraphHashes: Object.fromEntries(graphRoles.map((item) => [item.role, item.hash]).filter(([, value]) => typeof value === 'string')),
|
|
32
|
+
scopedCascadeGraphShapeKeys: Object.fromEntries(graphRoles.map((item) => [item.role, item.shapeKey]).filter(([, value]) => typeof value === 'string')),
|
|
31
33
|
before: scopedCascadeDeclarationDetails(change.before),
|
|
32
34
|
after: scopedCascadeDeclarationDetails(change.after)
|
|
33
35
|
}];
|
|
@@ -93,13 +95,25 @@ function scopedCascadeGraphHashMatches(proof, change) {
|
|
|
93
95
|
if (!hashes.length) return false;
|
|
94
96
|
return hashes.every(([role, expected]) => {
|
|
95
97
|
const sharedHash = firstString(proof.scopedCascadeGraphHash, proof.graphHash);
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
proof.
|
|
99
|
-
proof.
|
|
98
|
+
const shapeKey = change.scopedCascadeGraphShapeKeys?.[role] ?? change.scopedCascadeGraphShapeKey;
|
|
99
|
+
return proof.scopedCascadeGraphHashesByShapeKey?.[shapeKey] === expected ||
|
|
100
|
+
proof.graphHashesByShapeKey?.[shapeKey] === expected ||
|
|
101
|
+
proof.scopedCascadeGraphHashesByRoleAndShape?.[role]?.[shapeKey] === expected ||
|
|
102
|
+
((sharedHash === expected || proof[`${role}ScopedCascadeGraphHash`] === expected || proof.scopedCascadeGraphHashes?.[role] === expected || proof.graphHashes?.[role] === expected) && proofShapeMatches(proof, shapeKey));
|
|
100
103
|
});
|
|
101
104
|
}
|
|
102
105
|
|
|
106
|
+
function proofShapeMatches(proof, shapeKey) {
|
|
107
|
+
if (!shapeKey) return true;
|
|
108
|
+
if (proof.scopedCascadeGraphShapeKey === shapeKey || proof.shapeKey === shapeKey) return true;
|
|
109
|
+
if (proof.scopedCascadeGraphShapeKeys?.includes?.(shapeKey) || proof.shapeKeys?.includes?.(shapeKey)) return true;
|
|
110
|
+
return !hasProofShapeBinding(proof);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function hasProofShapeBinding(proof) {
|
|
114
|
+
return Boolean(proof.scopedCascadeGraphShapeKey || proof.shapeKey || proof.scopedCascadeGraphShapeKeys || proof.shapeKeys || proof.scopedCascadeGraphHashesByShapeKey || proof.graphHashesByShapeKey || proof.scopedCascadeGraphHashesByRoleAndShape);
|
|
115
|
+
}
|
|
116
|
+
|
|
103
117
|
function scopedCascadeProofRecord(proof, change, sourcePath, binding, hash) {
|
|
104
118
|
return {
|
|
105
119
|
id: proof.id,
|
|
@@ -112,6 +126,7 @@ function scopedCascadeProofRecord(proof, change, sourcePath, binding, hash) {
|
|
|
112
126
|
ruleKey: change.ruleKey,
|
|
113
127
|
property: change.property,
|
|
114
128
|
scopes: change.scopes,
|
|
129
|
+
scopedCascadeGraphShapeKey: change.scopedCascadeGraphShapeKey,
|
|
115
130
|
sourcePath,
|
|
116
131
|
scopedCascadeGraphHash: change.scopedCascadeGraphHash,
|
|
117
132
|
scopedCascadeGraphHashes: change.scopedCascadeGraphHashes,
|
|
@@ -124,13 +139,13 @@ function scopedCascadeProofRecord(proof, change, sourcePath, binding, hash) {
|
|
|
124
139
|
|
|
125
140
|
function scopedCascadeGraphRoles(change, side) {
|
|
126
141
|
return [
|
|
127
|
-
change.before?.scopedCascadeGraphHash ? { role: 'base', hash: change.before.scopedCascadeGraphHash } : undefined,
|
|
128
|
-
change.after?.scopedCascadeGraphHash ? { role: side, hash: change.after.scopedCascadeGraphHash } : undefined
|
|
142
|
+
change.before?.scopedCascadeGraphHash ? { role: 'base', hash: change.before.scopedCascadeGraphHash, shapeKey: change.before.scopedCascadeGraphShapeKey } : undefined,
|
|
143
|
+
change.after?.scopedCascadeGraphHash ? { role: side, hash: change.after.scopedCascadeGraphHash, shapeKey: change.after.scopedCascadeGraphShapeKey } : undefined
|
|
129
144
|
].filter(Boolean);
|
|
130
145
|
}
|
|
131
146
|
|
|
132
147
|
function scopedCascadeDeclarationDetails(entry) {
|
|
133
|
-
return entry ? { property: entry.property, value: entry.value, ruleKey: entry.ruleKey, cascadeKey: entry.key, scopes: entry.scopes, scopedCascadeGraphHash: entry.scopedCascadeGraphHash } : undefined;
|
|
148
|
+
return entry ? { property: entry.property, value: entry.value, ruleKey: entry.ruleKey, cascadeKey: entry.key, scopes: entry.scopes, scopedCascadeGraphShapeKey: entry.scopedCascadeGraphShapeKey, scopedCascadeGraphHash: entry.scopedCascadeGraphHash } : undefined;
|
|
134
149
|
}
|
|
135
150
|
|
|
136
151
|
function scopedCascadeReasonCodes(scopes = []) {
|
package/dist/semantic-merge.js
CHANGED
|
@@ -106,6 +106,7 @@ function declarationIndex(sheet, hash) {
|
|
|
106
106
|
declarationOrdinal: declaration.ordinal,
|
|
107
107
|
declarationHash: declaration.declarationHash,
|
|
108
108
|
shorthandExpansion: deterministicShorthandExpansion(declaration.property, declaration.value, hash),
|
|
109
|
+
scopedCascadeGraphShapeKey: record.scopedCascadeGraphShapeKey,
|
|
109
110
|
scopedCascadeGraphHash: record.scopedCascadeGraphHash,
|
|
110
111
|
selectorTargetGraphHash: record.selectorTargetGraphHash,
|
|
111
112
|
proofGaps: proofGapsForDeclaration(record, declaration)
|
|
@@ -163,6 +164,7 @@ function mergeParserEvidence(sheets) {
|
|
|
163
164
|
parserBackedDeclarationSpans: entries.every(([, evidence]) => evidence.parserBackedDeclarationSpans === true),
|
|
164
165
|
parserBackedTriviaHashes: entries.every(([, evidence]) => evidence.parserBackedTriviaHashes === true),
|
|
165
166
|
scopedCascadeGraphHashPresent: entries.every(([, evidence]) => evidence.scopedCascadeGraphHashPresent === true),
|
|
167
|
+
scopedCascadeGraphShapeHashPresent: entries.every(([, evidence]) => evidence.scopedCascadeGraphShapeHashPresent === true),
|
|
166
168
|
parseErrors: entries.reduce((sum, [, evidence]) => sum + evidence.parseErrors, 0),
|
|
167
169
|
sides: Object.fromEntries(entries)
|
|
168
170
|
};
|
|
@@ -178,6 +180,8 @@ function sheetParserEvidence(sheet) {
|
|
|
178
180
|
parserBackedDeclarationSpans: declarations.some((declaration) => declaration.sourceSpan?.startOffset !== undefined),
|
|
179
181
|
parserBackedTriviaHashes: records.some((record) => record.parser === 'postcss' && typeof record.rawTextHash === 'string'),
|
|
180
182
|
scopedCascadeGraphHashPresent: records.every((record) => !(record.scopes?.length) || Boolean(record.scopedCascadeGraphHash)),
|
|
183
|
+
scopedCascadeGraphShapeHashPresent: records.every((record) => !(record.scopes?.length) || Boolean(record.scopedCascadeGraphHash && record.scopedCascadeGraphShapeKey)),
|
|
184
|
+
scopedCascadeGraphShapeKeys: unique(records.filter((record) => record.scopes?.length).map((record) => record.scopedCascadeGraphShapeKey)).length,
|
|
181
185
|
parseErrors: sheet.parser?.parseErrors?.length ?? 0,
|
|
182
186
|
recordCount: records.length,
|
|
183
187
|
declarationCount: declarations.length
|
package/package.json
CHANGED