@shapeshift-labs/frontier-lang-css 0.1.21 → 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 +20 -3
- package/dist/postcss-parser-evidence.js +25 -5
- package/dist/scoped-cascade-proof.d.ts +61 -0
- package/dist/semantic-merge-css-modules.js +1 -0
- package/dist/semantic-merge-scoped-cascade.js +182 -0
- package/dist/semantic-merge.js +14 -11
- 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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FrontierLangDocument } from '@shapeshift-labs/frontier-lang-kernel'; import type { CssCascadeRuntimeProof, CssCascadeRuntimeProofRecord } from './cascade-runtime-proof.js'; import type { CssDependencyGraphEvidence, CssDependencyGraphProof, CssDependencyGraphProofRecord } from './dependency-graph.js'; import type { CssModuleContractProof, CssModuleContractProofRecord } from './css-module-contract-proof.js'; import type { CssSafeMergeShorthandExpansionEvidence, CssShorthandExpansionEvidence } from './shorthand-expansion.js'; import type { CssSafeMergeSelectorTargetEvidence, CssSelectorTargetEquivalence, CssSelectorTargetProof } from './selector-target-proof.js'; export type { CssCascadeRuntimeProof, CssCascadeRuntimeProofRecord } from './cascade-runtime-proof.js'; export type { CssDependencyGraphChange, CssDependencyGraphEvidence, CssDependencyGraphProof, CssDependencyGraphProofRecord } from './dependency-graph.js'; export type { CssModuleContractProof, CssModuleContractProofRecord } from './css-module-contract-proof.js'; export type { CssSafeMergeChangedShorthandExpansion, CssSafeMergeShorthandExpansionEvidence, CssSafeMergeShorthandExpansionSideEvidence, CssShorthandExpansionEvidence, CssShorthandLonghandExpansion } from './shorthand-expansion.js'; export type { CssSafeMergeSelectorMove, CssSafeMergeSelectorTargetEvidence, CssSafeMergeSelectorTargetRebaseProof, CssSafeMergeSelectorTargetSideEvidence, CssSelectorTargetEquivalence, CssSelectorTargetProof } from './selector-target-proof.js';
|
|
1
|
+
import type { FrontierLangDocument } from '@shapeshift-labs/frontier-lang-kernel'; import type { CssCascadeRuntimeProof, CssCascadeRuntimeProofRecord } from './cascade-runtime-proof.js'; import type { CssDependencyGraphEvidence, CssDependencyGraphProof, CssDependencyGraphProofRecord } from './dependency-graph.js'; import type { CssModuleContractProof, CssModuleContractProofRecord } from './css-module-contract-proof.js'; import type { CssScopedCascadeProof, CssScopedCascadeProofRecord } from './scoped-cascade-proof.js'; import type { CssSafeMergeShorthandExpansionEvidence, CssShorthandExpansionEvidence } from './shorthand-expansion.js'; import type { CssSafeMergeSelectorTargetEvidence, CssSelectorTargetEquivalence, CssSelectorTargetProof } from './selector-target-proof.js'; export type { CssCascadeRuntimeProof, CssCascadeRuntimeProofRecord } from './cascade-runtime-proof.js'; export type { CssDependencyGraphChange, CssDependencyGraphEvidence, CssDependencyGraphProof, CssDependencyGraphProofRecord } from './dependency-graph.js'; export type { CssModuleContractProof, CssModuleContractProofRecord } from './css-module-contract-proof.js'; export type { CssScopedCascadeProof, CssScopedCascadeProofRecord } from './scoped-cascade-proof.js'; export type { CssSafeMergeChangedShorthandExpansion, CssSafeMergeShorthandExpansionEvidence, CssSafeMergeShorthandExpansionSideEvidence, CssShorthandExpansionEvidence, CssShorthandLonghandExpansion } from './shorthand-expansion.js'; export type { CssSafeMergeSelectorMove, CssSafeMergeSelectorTargetEvidence, CssSafeMergeSelectorTargetRebaseProof, CssSafeMergeSelectorTargetSideEvidence, CssSelectorTargetEquivalence, CssSelectorTargetProof } from './selector-target-proof.js';
|
|
2
2
|
|
|
3
3
|
export interface CssProjectionOptions {
|
|
4
4
|
readonly banner?: string;
|
|
@@ -13,6 +13,16 @@ 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>>;
|
|
24
|
+
readonly cssScopedCascadeProof?: CssScopedCascadeProof; readonly cssScopedCascadeProofs?: readonly CssScopedCascadeProof[];
|
|
25
|
+
readonly cssSourceBoundScopedCascadeProof?: CssScopedCascadeProof; readonly cssSourceBoundScopedCascadeProofs?: readonly CssScopedCascadeProof[];
|
|
16
26
|
readonly cssCascadeRuntimeProof?: CssCascadeRuntimeProof; readonly cssCascadeRuntimeProofs?: readonly CssCascadeRuntimeProof[];
|
|
17
27
|
readonly cssSourceBoundCascadeProof?: CssCascadeRuntimeProof; readonly cssSourceBoundCascadeProofs?: readonly CssCascadeRuntimeProof[];
|
|
18
28
|
readonly selectorTargetGraphHash?: string;
|
|
@@ -127,6 +137,7 @@ export interface CssSemanticRecord {
|
|
|
127
137
|
readonly scopeKey?: string;
|
|
128
138
|
readonly statementText?: string;
|
|
129
139
|
readonly blockText?: string;
|
|
140
|
+
readonly scopedCascadeGraphShapeKey?: string;
|
|
130
141
|
readonly scopedCascadeGraphHash?: string;
|
|
131
142
|
readonly selectorTargetGraphHash?: string;
|
|
132
143
|
readonly sourceSpan: CssSourceSpan;
|
|
@@ -228,6 +239,7 @@ export interface CssSafeMergeAdmission {
|
|
|
228
239
|
readonly reviewRequired: boolean; readonly reasonCodes: readonly string[];
|
|
229
240
|
readonly browserCascadeEquivalenceClaim?: true;
|
|
230
241
|
readonly cssCascadeRuntimeProofs?: readonly CssCascadeRuntimeProofRecord[];
|
|
242
|
+
readonly cssScopedCascadeProofs?: readonly CssScopedCascadeProofRecord[];
|
|
231
243
|
readonly cssDependencyGraphProofs?: readonly CssDependencyGraphProofRecord[];
|
|
232
244
|
readonly cssModuleContractProofs?: readonly CssModuleContractProofRecord[];
|
|
233
245
|
}
|
|
@@ -245,6 +257,7 @@ export interface CssSafeMergeResult {
|
|
|
245
257
|
readonly workerChangedCssModuleContracts?: number; readonly headChangedCssModuleContracts?: number;
|
|
246
258
|
readonly parserEvidence?: CssSafeMergeParserEvidence; readonly shorthandExpansionEvidence?: CssSafeMergeShorthandExpansionEvidence; readonly selectorTargetEvidence?: CssSafeMergeSelectorTargetEvidence; readonly dependencyGraphEvidence?: CssDependencyGraphEvidence;
|
|
247
259
|
readonly cssModuleContractProofs?: readonly CssModuleContractProofRecord[];
|
|
260
|
+
readonly scopedCascadeProofs?: readonly CssScopedCascadeProofRecord[];
|
|
248
261
|
readonly cascadeRuntimeProofs?: readonly CssCascadeRuntimeProofRecord[];
|
|
249
262
|
readonly dependencyGraphProofs?: readonly CssDependencyGraphProofRecord[];
|
|
250
263
|
}
|
|
@@ -252,18 +265,22 @@ export interface CssSafeMergeResult {
|
|
|
252
265
|
export interface CssSafeMergeParserEvidence {
|
|
253
266
|
readonly kind: 'frontier.lang.cssSafeMergeParserEvidence'; readonly version: 1; readonly parserNames: readonly string[];
|
|
254
267
|
readonly sourceCodeLocationInfo: boolean; readonly parserBackedSourceSpans: boolean; readonly parserBackedDeclarationSpans: boolean; readonly parserBackedTriviaHashes: boolean;
|
|
255
|
-
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>>;
|
|
256
269
|
}
|
|
257
270
|
|
|
258
271
|
export interface CssSafeMergeParserSideEvidence {
|
|
259
272
|
readonly parserName: string; readonly sourceCodeLocationInfo: boolean; readonly parserBackedSourceSpans: boolean; readonly parserBackedDeclarationSpans: boolean; readonly parserBackedTriviaHashes: boolean;
|
|
260
|
-
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;
|
|
261
274
|
}
|
|
262
275
|
|
|
263
276
|
export interface CssSafeMergeInput {
|
|
264
277
|
readonly id?: string; readonly sourcePath?: string; readonly baseSourceText?: string; readonly workerSourceText?: string; readonly headSourceText?: string;
|
|
265
278
|
readonly cssModule?: boolean; readonly cssModules?: boolean; readonly generatedClassNameMap?: Readonly<Record<string, string>>;
|
|
266
279
|
readonly generatedClassNameMapHash?: string; readonly jsTsUseSiteGraphHash?: string; readonly cssModuleCompositionGraphHash?: string; readonly icssGraphHash?: string; readonly scopedCascadeGraphHash?: string;
|
|
280
|
+
readonly cssScopedCascadeProof?: CssScopedCascadeProof; readonly cssScopedCascadeProofs?: readonly CssScopedCascadeProof[]; readonly cssScopedCascadeProofsByPath?: Readonly<Record<string, CssScopedCascadeProof | readonly CssScopedCascadeProof[]>>;
|
|
281
|
+
readonly cssSourceBoundScopedCascadeProof?: CssScopedCascadeProof; readonly cssSourceBoundScopedCascadeProofs?: readonly CssScopedCascadeProof[]; readonly cssSourceBoundScopedCascadeProofsByPath?: Readonly<Record<string, CssScopedCascadeProof | readonly CssScopedCascadeProof[]>>;
|
|
282
|
+
readonly scopedCascadeProof?: CssScopedCascadeProof; readonly scopedCascadeProofs?: readonly CssScopedCascadeProof[]; readonly scopedCascadeProofsByPath?: Readonly<Record<string, CssScopedCascadeProof | readonly CssScopedCascadeProof[]>>;
|
|
283
|
+
readonly sourceBoundScopedCascadeProof?: CssScopedCascadeProof; readonly sourceBoundScopedCascadeProofs?: readonly CssScopedCascadeProof[]; readonly sourceBoundScopedCascadeProofsByPath?: Readonly<Record<string, CssScopedCascadeProof | readonly CssScopedCascadeProof[]>>;
|
|
267
284
|
readonly cssCascadeRuntimeProof?: CssCascadeRuntimeProof; readonly cssCascadeRuntimeProofs?: readonly CssCascadeRuntimeProof[]; readonly cssCascadeRuntimeProofsByPath?: Readonly<Record<string, CssCascadeRuntimeProof | readonly CssCascadeRuntimeProof[]>>;
|
|
268
285
|
readonly cssSourceBoundCascadeProof?: CssCascadeRuntimeProof; readonly cssSourceBoundCascadeProofs?: readonly CssCascadeRuntimeProof[];
|
|
269
286
|
readonly cssSourceBoundCascadeProofsByPath?: Readonly<Record<string, CssCascadeRuntimeProof | readonly CssCascadeRuntimeProof[]>>;
|
|
@@ -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');
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export interface CssScopedCascadeProof {
|
|
2
|
+
readonly id?: string;
|
|
3
|
+
readonly kind: 'css-scoped-cascade-proof' | 'css-source-bound-scoped-cascade-proof' | 'css-scoped-cascade-runtime-proof' | 'css-source-bound-scoped-cascade-runtime-proof' | string;
|
|
4
|
+
readonly status: 'passed' | string;
|
|
5
|
+
readonly proofLevel?: string;
|
|
6
|
+
readonly sourcePath?: string;
|
|
7
|
+
readonly reasonCode?: string;
|
|
8
|
+
readonly reasonCodes?: readonly string[];
|
|
9
|
+
readonly side?: 'worker' | 'head' | string;
|
|
10
|
+
readonly sides?: readonly string[];
|
|
11
|
+
readonly cascadeKey?: string;
|
|
12
|
+
readonly cascadeKeys?: readonly string[];
|
|
13
|
+
readonly ruleKey?: string;
|
|
14
|
+
readonly ruleKeys?: readonly string[];
|
|
15
|
+
readonly selectors?: readonly string[];
|
|
16
|
+
readonly scopes?: readonly string[];
|
|
17
|
+
readonly property?: string;
|
|
18
|
+
readonly properties?: readonly string[];
|
|
19
|
+
readonly scopedCascadeGraphShapeKey?: string;
|
|
20
|
+
readonly scopedCascadeGraphShapeKeys?: readonly string[];
|
|
21
|
+
readonly shapeKey?: string;
|
|
22
|
+
readonly shapeKeys?: readonly string[];
|
|
23
|
+
readonly scopedCascadeGraphHash?: string;
|
|
24
|
+
readonly graphHash?: string;
|
|
25
|
+
readonly baseScopedCascadeGraphHash?: string;
|
|
26
|
+
readonly workerScopedCascadeGraphHash?: string;
|
|
27
|
+
readonly headScopedCascadeGraphHash?: string;
|
|
28
|
+
readonly scopedCascadeGraphHashes?: Readonly<Record<string, string>>;
|
|
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>>>>;
|
|
33
|
+
readonly baseSourceText?: string; readonly workerSourceText?: string; readonly headSourceText?: string; readonly outputSourceText?: string; readonly mergedSourceText?: string;
|
|
34
|
+
readonly baseSourceHash?: string; readonly workerSourceHash?: string; readonly headSourceHash?: string; readonly outputSourceHash?: string; readonly mergedSourceHash?: string;
|
|
35
|
+
readonly sourceTexts?: Readonly<Record<string, string>>;
|
|
36
|
+
readonly sources?: Readonly<Record<string, string>>;
|
|
37
|
+
readonly sourceHashes?: Readonly<Record<string, string>>;
|
|
38
|
+
readonly hashes?: Readonly<Record<string, string>>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface CssScopedCascadeProofRecord {
|
|
42
|
+
readonly id?: string;
|
|
43
|
+
readonly kind: string;
|
|
44
|
+
readonly status: 'passed';
|
|
45
|
+
readonly proofLevel: string;
|
|
46
|
+
readonly reasonCode: string;
|
|
47
|
+
readonly side: string;
|
|
48
|
+
readonly cascadeKey: string;
|
|
49
|
+
readonly ruleKey?: string;
|
|
50
|
+
readonly property?: string;
|
|
51
|
+
readonly scopes?: readonly string[];
|
|
52
|
+
readonly scopedCascadeGraphShapeKey?: string;
|
|
53
|
+
readonly sourcePath?: string;
|
|
54
|
+
readonly scopedCascadeGraphHash?: string;
|
|
55
|
+
readonly scopedCascadeGraphHashes?: Readonly<Record<string, string>>;
|
|
56
|
+
readonly scopedCascadeGraphShapeKeys?: Readonly<Record<string, string>>;
|
|
57
|
+
readonly baseSourceHash?: string;
|
|
58
|
+
readonly workerSourceHash?: string;
|
|
59
|
+
readonly headSourceHash?: string;
|
|
60
|
+
readonly outputSourceHash?: string;
|
|
61
|
+
}
|
|
@@ -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
|
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
function scopedCascadeChanges(changed, indexes) {
|
|
2
|
+
return [
|
|
3
|
+
...scopedCascadeChangesForSide(changed.worker, 'worker', indexes.base),
|
|
4
|
+
...scopedCascadeChangesForSide(changed.head, 'head', indexes.base)
|
|
5
|
+
];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function scopedCascadeChangesForSide(changes, side, baseIndex) {
|
|
9
|
+
const baseScopeKeys = new Set([...baseIndex.declarations.values()]
|
|
10
|
+
.filter((entry) => entry.scopes?.length)
|
|
11
|
+
.map((entry) => scopeListKey(entry.scopes)));
|
|
12
|
+
return changes.flatMap((change) => {
|
|
13
|
+
const entries = [change.before, change.after].filter((entry) => entry?.scopes?.length);
|
|
14
|
+
if (!entries.length || !entries.some((entry) => baseScopeKeys.has(scopeListKey(entry.scopes)))) return [];
|
|
15
|
+
const entry = change.after ?? change.before;
|
|
16
|
+
const graphRoles = scopedCascadeGraphRoles(change, side);
|
|
17
|
+
return [{
|
|
18
|
+
side,
|
|
19
|
+
changeKind: change.kind,
|
|
20
|
+
reasonCode: 'css-scoped-cascade-equivalence-unproved',
|
|
21
|
+
reasonCodes: unique(['css-scoped-cascade-equivalence-unproved', ...entries.flatMap((item) => scopedCascadeReasonCodes(item.scopes))]),
|
|
22
|
+
cascadeKey: change.key,
|
|
23
|
+
ruleKey: entry.ruleKey,
|
|
24
|
+
selectors: entry.selectors,
|
|
25
|
+
scopes: entry.scopes,
|
|
26
|
+
scopedCascadeGraphShapeKey: entry.scopedCascadeGraphShapeKey,
|
|
27
|
+
property: entry.property,
|
|
28
|
+
specificity: entry.specificity,
|
|
29
|
+
scopedCascadeGraphReady: graphRoles.every((item) => typeof item.hash === 'string'),
|
|
30
|
+
scopedCascadeGraphHash: graphRoles.find((item) => typeof item.hash === 'string')?.hash,
|
|
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')),
|
|
33
|
+
before: scopedCascadeDeclarationDetails(change.before),
|
|
34
|
+
after: scopedCascadeDeclarationDetails(change.after)
|
|
35
|
+
}];
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function admitScopedCascadeProofs({ id, sourcePath, input, changes, binding, hash }) {
|
|
40
|
+
const proofs = scopedCascadeProofCandidates(input, sourcePath);
|
|
41
|
+
const admitted = [];
|
|
42
|
+
const conflicts = [];
|
|
43
|
+
for (const change of changes) {
|
|
44
|
+
const proof = proofs.find((candidate) => isScopedCascadeProofForChange(candidate, change, sourcePath, binding, hash));
|
|
45
|
+
if (proof) admitted.push(scopedCascadeProofRecord(proof, change, sourcePath, binding, hash));
|
|
46
|
+
else conflicts.push(conflict(id, sourcePath, 'css-scoped-cascade-proof-blocked', change.reasonCode, change));
|
|
47
|
+
}
|
|
48
|
+
return { proofs: admitted, conflicts };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function scopedCascadeProofCandidates(input = {}, sourcePath) {
|
|
52
|
+
return [
|
|
53
|
+
input.cssScopedCascadeProof,
|
|
54
|
+
input.cssScopedCascadeProofs,
|
|
55
|
+
input.cssScopedCascadeProofsByPath?.[sourcePath],
|
|
56
|
+
input.cssSourceBoundScopedCascadeProof,
|
|
57
|
+
input.cssSourceBoundScopedCascadeProofs,
|
|
58
|
+
input.cssSourceBoundScopedCascadeProofsByPath?.[sourcePath],
|
|
59
|
+
input.scopedCascadeProof,
|
|
60
|
+
input.scopedCascadeProofs,
|
|
61
|
+
input.scopedCascadeProofsByPath?.[sourcePath],
|
|
62
|
+
input.sourceBoundScopedCascadeProof,
|
|
63
|
+
input.sourceBoundScopedCascadeProofs,
|
|
64
|
+
input.sourceBoundScopedCascadeProofsByPath?.[sourcePath]
|
|
65
|
+
].flatMap(asArray).filter(Boolean);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function isScopedCascadeProofForChange(proof, change, sourcePath, binding, hash) {
|
|
69
|
+
return Boolean(proof && typeof proof === 'object') &&
|
|
70
|
+
ScopedCascadeProofKinds.has(proof.kind) &&
|
|
71
|
+
proof.status === 'passed' &&
|
|
72
|
+
proof.sourcePath === sourcePath &&
|
|
73
|
+
change.scopedCascadeGraphReady === true &&
|
|
74
|
+
proofCoversAny(proof.reasonCode, proof.reasonCodes, change.reasonCodes) &&
|
|
75
|
+
proofCoversValue(proof.side, proof.sides, change.side) &&
|
|
76
|
+
proofCoversValue(proof.cascadeKey, proof.cascadeKeys, change.cascadeKey) &&
|
|
77
|
+
proofCoversValue(proof.property, proof.properties, change.property) &&
|
|
78
|
+
scopedCascadeRuleMatches(proof, change) &&
|
|
79
|
+
scopedCascadeGraphHashMatches(proof, change) &&
|
|
80
|
+
proofSourceMatches(proof, 'base', binding.base, hash) &&
|
|
81
|
+
proofSourceMatches(proof, 'worker', binding.worker, hash) &&
|
|
82
|
+
proofSourceMatches(proof, 'head', binding.head, hash) &&
|
|
83
|
+
proofSourceMatches(proof, 'output', binding.output, hash);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function scopedCascadeRuleMatches(proof, change) {
|
|
87
|
+
const ruleKeyMatches = proof.ruleKey === change.ruleKey || proof.ruleKeys?.includes(change.ruleKey);
|
|
88
|
+
const selectorsMatch = selectorListKey(proof.selectors) === selectorListKey(change.selectors);
|
|
89
|
+
const scopesMatch = scopeListKey(proof.scopes) === scopeListKey(change.scopes);
|
|
90
|
+
return ruleKeyMatches || (selectorsMatch && scopesMatch);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function scopedCascadeGraphHashMatches(proof, change) {
|
|
94
|
+
const hashes = Object.entries(change.scopedCascadeGraphHashes ?? {});
|
|
95
|
+
if (!hashes.length) return false;
|
|
96
|
+
return hashes.every(([role, expected]) => {
|
|
97
|
+
const sharedHash = firstString(proof.scopedCascadeGraphHash, proof.graphHash);
|
|
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));
|
|
103
|
+
});
|
|
104
|
+
}
|
|
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
|
+
|
|
117
|
+
function scopedCascadeProofRecord(proof, change, sourcePath, binding, hash) {
|
|
118
|
+
return {
|
|
119
|
+
id: proof.id,
|
|
120
|
+
kind: proof.kind,
|
|
121
|
+
status: 'passed',
|
|
122
|
+
proofLevel: proof.proofLevel ?? 'css-scoped-cascade-source-bound',
|
|
123
|
+
reasonCode: change.reasonCode,
|
|
124
|
+
side: change.side,
|
|
125
|
+
cascadeKey: change.cascadeKey,
|
|
126
|
+
ruleKey: change.ruleKey,
|
|
127
|
+
property: change.property,
|
|
128
|
+
scopes: change.scopes,
|
|
129
|
+
scopedCascadeGraphShapeKey: change.scopedCascadeGraphShapeKey,
|
|
130
|
+
sourcePath,
|
|
131
|
+
scopedCascadeGraphHash: change.scopedCascadeGraphHash,
|
|
132
|
+
scopedCascadeGraphHashes: change.scopedCascadeGraphHashes,
|
|
133
|
+
baseSourceHash: hash?.(binding.base),
|
|
134
|
+
workerSourceHash: hash?.(binding.worker),
|
|
135
|
+
headSourceHash: hash?.(binding.head),
|
|
136
|
+
outputSourceHash: hash?.(binding.output)
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function scopedCascadeGraphRoles(change, side) {
|
|
141
|
+
return [
|
|
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
|
|
144
|
+
].filter(Boolean);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function scopedCascadeDeclarationDetails(entry) {
|
|
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;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function scopedCascadeReasonCodes(scopes = []) {
|
|
152
|
+
return scopes.map((scope) => /^@([-\w]+)/.exec(scope)?.[1]).filter(Boolean).map((name) => `css-${name}-cascade-scope-unproved`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function proofSourceMatches(proof, role, sourceText, hash) {
|
|
156
|
+
if (typeof sourceText !== 'string') return false;
|
|
157
|
+
const sourceHash = hash?.(sourceText);
|
|
158
|
+
const textFields = role === 'output' ? ['outputSourceText', 'mergedSourceText'] : [`${role}SourceText`];
|
|
159
|
+
const hashFields = role === 'output' ? ['outputSourceHash', 'mergedSourceHash'] : [`${role}SourceHash`];
|
|
160
|
+
const aliases = role === 'output' ? ['output', 'merged'] : [role];
|
|
161
|
+
return textFields.some((field) => proof[field] === sourceText) ||
|
|
162
|
+
aliases.some((alias) => proof.sourceTexts?.[alias] === sourceText || proof.sources?.[alias] === sourceText) ||
|
|
163
|
+
hashFields.some((field) => sourceHash !== undefined && proof[field] === sourceHash) ||
|
|
164
|
+
aliases.some((alias) => sourceHash !== undefined && (proof.sourceHashes?.[alias] === sourceHash || proof.hashes?.[alias] === sourceHash));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function conflict(id, sourcePath, code, reasonCode, details = {}) {
|
|
168
|
+
return { code, gateId: 'css-semantic-merge', sourcePath, details: { reasonCode, conflictKey: `css#${id}#${reasonCode}#${details.cascadeKey ?? sourcePath ?? 'source'}`, ...details } };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function proofCoversAny(value, values, expectedValues = []) { return expectedValues.some((expected) => proofCoversValue(value, values, expected)); }
|
|
172
|
+
function proofCoversValue(value, values, expected) { return value === expected || (Array.isArray(values) && values.includes(expected)); }
|
|
173
|
+
function asArray(value) { return Array.isArray(value) ? value : value === undefined ? [] : [value]; }
|
|
174
|
+
function selectorListKey(value = []) { return Array.isArray(value) ? value.join(',') : undefined; }
|
|
175
|
+
function scopeListKey(value = []) { return Array.isArray(value) ? value.join('::') : undefined; }
|
|
176
|
+
function firstString(...values) { return values.find((value) => typeof value === 'string' && value.length > 0); }
|
|
177
|
+
function unique(values) { return [...new Set(values.filter(Boolean))]; }
|
|
178
|
+
|
|
179
|
+
const ScopedCascadeProofKinds = new Set(['css-scoped-cascade-proof', 'css-source-bound-scoped-cascade-proof', 'css-scoped-cascade-runtime-proof', 'css-source-bound-scoped-cascade-runtime-proof']);
|
|
180
|
+
const ScopedCascadeProofGapCodes = new Set(['css-scoped-cascade-equivalence-unproved', 'css-media-cascade-scope-unproved', 'css-supports-cascade-scope-unproved', 'css-container-cascade-scope-unproved', 'css-layer-cascade-scope-unproved', 'css-scope-cascade-scope-unproved']);
|
|
181
|
+
|
|
182
|
+
export { ScopedCascadeProofGapCodes, admitScopedCascadeProofs, scopedCascadeChanges };
|
package/dist/semantic-merge.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { cssModuleContractChanges, sheetOptions, unsupportedSourceShapeChanges } from './semantic-merge-css-modules.js';
|
|
2
2
|
import { admitCssModuleContractProofs } from './semantic-merge-css-module-proofs.js';
|
|
3
3
|
import { admitCascadeRuntimeProofs } from './semantic-merge-cascade-runtime.js';
|
|
4
|
+
import { ScopedCascadeProofGapCodes, admitScopedCascadeProofs, scopedCascadeChanges } from './semantic-merge-scoped-cascade.js';
|
|
4
5
|
import { admitCssDependencyGraphProofs, mergeCssDependencyGraphEvidence } from './dependency-graph.js';
|
|
5
6
|
import { mergeSelectorTargetEvidence, planSelectorTargetRebase } from './semantic-merge-selector-targets.js';
|
|
6
7
|
import { applyAtRuleBlockChanges, atRuleBlockEntry, atRuleBlockOverlapConflicts, atRuleOccurrenceKey, changedAtRuleBlocks, renderAtRuleBlock, renderAtRuleStatement } from './semantic-merge-at-rules.js';
|
|
@@ -47,20 +48,15 @@ function safeMergeCssSource(input = {}, context = {}) {
|
|
|
47
48
|
const dependencyGraphEvidence = mergeCssDependencyGraphEvidence(sheets, changed);
|
|
48
49
|
const selectorTargetPlan = planSelectorTargetRebase(id, sourcePath, mergeSelectorTargetEvidence(sheets, changed), changed, { ...input, sourceBinding: { base, worker, head }, hashSemanticValue: hash });
|
|
49
50
|
const shapeChanges = unsupportedSourceShapeChanges(sheets, changed, hash);
|
|
51
|
+
const scopedChanges = scopedCascadeChanges(selectorTargetPlan.changed, indexes);
|
|
50
52
|
const mergedIndex = applyAtRuleBlockChanges(applyAtRuleBlockChanges(applyDeclarationChanges(applyDeclarationChanges(indexes.base, selectorTargetPlan.changed.head), selectorTargetPlan.changed.worker), blockChanges.head), blockChanges.worker);
|
|
51
53
|
const mergedSourceText = renderDeclarationIndex(mergedIndex);
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
sourcePath,
|
|
55
|
-
input,
|
|
56
|
-
sourceShapeChanges: shapeChanges,
|
|
57
|
-
binding: { base, worker, head, output: mergedSourceText },
|
|
58
|
-
hash
|
|
59
|
-
});
|
|
54
|
+
const scopedCascadeAdmission = admitScopedCascadeProofs({ id, sourcePath, input, changes: scopedChanges, binding: { base, worker, head, output: mergedSourceText }, hash });
|
|
55
|
+
const cascadeRuntimeAdmission = admitCascadeRuntimeProofs({ id, sourcePath, input, sourceShapeChanges: shapeChanges, binding: { base, worker, head, output: mergedSourceText }, hash });
|
|
60
56
|
const dependencyGraphAdmission = admitCssDependencyGraphProofs({ id, sourcePath, input, dependencyGraphEvidence, binding: { base, worker, head, output: mergedSourceText }, hash });
|
|
61
57
|
const cssModuleAdmission = admitCssModuleContractProofs({ id, sourcePath, input, moduleChanges, binding: { base, worker, head, output: mergedSourceText }, hash });
|
|
62
|
-
const conflicts = [...parserConflicts, ...duplicateCascadeKeyConflicts, ...proofConflicts, ...overlapConflicts, ...cssModuleAdmission.conflicts, ...cascadeRuntimeAdmission.conflicts, ...dependencyGraphAdmission.conflicts, ...selectorTargetPlan.conflicts];
|
|
63
|
-
if (conflicts.length) return blocked(id, sourcePath, 'css-semantic-merge-conflict', conflicts, { parserEvidence, shorthandExpansionEvidence, dependencyGraphEvidence, selectorTargetEvidence: selectorTargetPlan.evidence, cssModuleContractProofs: cssModuleAdmission.proofs, cascadeRuntimeProofs: cascadeRuntimeAdmission.proofs, dependencyGraphProofs: dependencyGraphAdmission.proofs, ...blockedMergeCandidate(input, mergedSourceText, hash) });
|
|
58
|
+
const conflicts = [...parserConflicts, ...duplicateCascadeKeyConflicts, ...proofConflicts, ...overlapConflicts, ...cssModuleAdmission.conflicts, ...scopedCascadeAdmission.conflicts, ...cascadeRuntimeAdmission.conflicts, ...dependencyGraphAdmission.conflicts, ...selectorTargetPlan.conflicts];
|
|
59
|
+
if (conflicts.length) return blocked(id, sourcePath, 'css-semantic-merge-conflict', conflicts, { parserEvidence, shorthandExpansionEvidence, dependencyGraphEvidence, selectorTargetEvidence: selectorTargetPlan.evidence, cssModuleContractProofs: cssModuleAdmission.proofs, scopedCascadeProofs: scopedCascadeAdmission.proofs, cascadeRuntimeProofs: cascadeRuntimeAdmission.proofs, dependencyGraphProofs: dependencyGraphAdmission.proofs, ...blockedMergeCandidate(input, mergedSourceText, hash) });
|
|
64
60
|
return merged(id, sourcePath, mergedSourceText, 'semantic-declaration-merge', hash, {
|
|
65
61
|
baseSheetHash: sheets.base.sheetHash,
|
|
66
62
|
workerSheetHash: sheets.worker.sheetHash,
|
|
@@ -74,6 +70,7 @@ function safeMergeCssSource(input = {}, context = {}) {
|
|
|
74
70
|
dependencyGraphEvidence,
|
|
75
71
|
selectorTargetEvidence: selectorTargetPlan.evidence,
|
|
76
72
|
cssModuleContractProofs: cssModuleAdmission.proofs,
|
|
73
|
+
scopedCascadeProofs: scopedCascadeAdmission.proofs,
|
|
77
74
|
cascadeRuntimeProofs: cascadeRuntimeAdmission.proofs,
|
|
78
75
|
dependencyGraphProofs: dependencyGraphAdmission.proofs,
|
|
79
76
|
browserCascadeEquivalenceClaim: cascadeRuntimeAdmission.proofs.length > 0
|
|
@@ -109,6 +106,8 @@ function declarationIndex(sheet, hash) {
|
|
|
109
106
|
declarationOrdinal: declaration.ordinal,
|
|
110
107
|
declarationHash: declaration.declarationHash,
|
|
111
108
|
shorthandExpansion: deterministicShorthandExpansion(declaration.property, declaration.value, hash),
|
|
109
|
+
scopedCascadeGraphShapeKey: record.scopedCascadeGraphShapeKey,
|
|
110
|
+
scopedCascadeGraphHash: record.scopedCascadeGraphHash,
|
|
112
111
|
selectorTargetGraphHash: record.selectorTargetGraphHash,
|
|
113
112
|
proofGaps: proofGapsForDeclaration(record, declaration)
|
|
114
113
|
};
|
|
@@ -165,6 +164,7 @@ function mergeParserEvidence(sheets) {
|
|
|
165
164
|
parserBackedDeclarationSpans: entries.every(([, evidence]) => evidence.parserBackedDeclarationSpans === true),
|
|
166
165
|
parserBackedTriviaHashes: entries.every(([, evidence]) => evidence.parserBackedTriviaHashes === true),
|
|
167
166
|
scopedCascadeGraphHashPresent: entries.every(([, evidence]) => evidence.scopedCascadeGraphHashPresent === true),
|
|
167
|
+
scopedCascadeGraphShapeHashPresent: entries.every(([, evidence]) => evidence.scopedCascadeGraphShapeHashPresent === true),
|
|
168
168
|
parseErrors: entries.reduce((sum, [, evidence]) => sum + evidence.parseErrors, 0),
|
|
169
169
|
sides: Object.fromEntries(entries)
|
|
170
170
|
};
|
|
@@ -180,6 +180,8 @@ function sheetParserEvidence(sheet) {
|
|
|
180
180
|
parserBackedDeclarationSpans: declarations.some((declaration) => declaration.sourceSpan?.startOffset !== undefined),
|
|
181
181
|
parserBackedTriviaHashes: records.some((record) => record.parser === 'postcss' && typeof record.rawTextHash === 'string'),
|
|
182
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,
|
|
183
185
|
parseErrors: sheet.parser?.parseErrors?.length ?? 0,
|
|
184
186
|
recordCount: records.length,
|
|
185
187
|
declarationCount: declarations.length
|
|
@@ -209,6 +211,7 @@ function shorthandOverlapConflicts(id, sourcePath, workerChanges, headChanges) {
|
|
|
209
211
|
}
|
|
210
212
|
|
|
211
213
|
function canAdmitProofGap(gap, entry, changed, indexes) {
|
|
214
|
+
if (ScopedCascadeProofGapCodes.has(gap.code)) return true;
|
|
212
215
|
if (gap.code !== 'css-shorthand-expansion-unproved' || !entry) return false;
|
|
213
216
|
const group = shorthandGroupForProperty(entry.property);
|
|
214
217
|
if (!group || entry.shorthandExpansion?.status !== 'expanded' || hasRelatedExistingDeclaration(entry, indexes)) return false;
|
|
@@ -296,7 +299,7 @@ function result(id, sourcePath, status, body) {
|
|
|
296
299
|
reviewRequired: status !== 'merged',
|
|
297
300
|
reasonCodes: unique((body.conflicts ?? []).map((item) => item.details.reasonCode)),
|
|
298
301
|
browserCascadeEquivalenceClaim: browserCascadeEquivalenceClaim || undefined,
|
|
299
|
-
cssCascadeRuntimeProofs: body.cascadeRuntimeProofs?.length ? body.cascadeRuntimeProofs : undefined, cssDependencyGraphProofs: body.dependencyGraphProofs?.length ? body.dependencyGraphProofs : undefined, cssModuleContractProofs: body.cssModuleContractProofs?.length ? body.cssModuleContractProofs : undefined
|
|
302
|
+
cssCascadeRuntimeProofs: body.cascadeRuntimeProofs?.length ? body.cascadeRuntimeProofs : undefined, cssScopedCascadeProofs: body.scopedCascadeProofs?.length ? body.scopedCascadeProofs : undefined, cssDependencyGraphProofs: body.dependencyGraphProofs?.length ? body.dependencyGraphProofs : undefined, cssModuleContractProofs: body.cssModuleContractProofs?.length ? body.cssModuleContractProofs : undefined
|
|
300
303
|
}
|
|
301
304
|
};
|
|
302
305
|
}
|
package/package.json
CHANGED