@shapeshift-labs/frontier-lang-css 0.1.14 → 0.1.15
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 +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/semantic-merge-selector-targets.js +14 -7
- package/dist/semantic-merge.js +1 -1
- 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, including existing scoped `@media` / `@supports` / `@container` / `@layer` declarations when a scoped cascade graph proof hash is supplied, carries source-bound dependency graph evidence into the merge result, blocks dependency-affecting declaration edits unless an exact source-bound dependency graph proof is supplied, 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.
|
|
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, including existing scoped `@media` / `@supports` / `@container` / `@layer` declarations when a scoped cascade graph proof hash is supplied, carries source-bound dependency graph evidence into the merge result, 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 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
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, 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; existing scoped declaration edits when scoped cascade graph proof is supplied; dependency-affecting declaration edits only when an exact source-bound dependency graph proof is supplied; 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.
|
|
240
|
+
- Safe merge: independent declarations with non-overlapping cascade keys, 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; existing scoped declaration edits when scoped cascade graph proof is supplied; 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
241
|
- Review-only gaps: incomplete generated class-name maps, unproved dependency graph changes, unproved CSS Modules use-site graphs, unproved composition or ICSS graphs, shorthand value expansion/equivalence beyond known affected-property overlap checks, 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.
|
|
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
|
@@ -273,15 +273,15 @@ export interface CssSafeMergeSelectorTargetSideEvidence {
|
|
|
273
273
|
export interface CssSafeMergeSelectorMove {
|
|
274
274
|
readonly side: string; readonly property: string; readonly beforeRuleKey: string; readonly afterRuleKey: string;
|
|
275
275
|
readonly beforeSelectors?: readonly string[]; readonly afterSelectors?: readonly string[]; readonly beforeScopes?: readonly string[]; readonly afterScopes?: readonly string[];
|
|
276
|
-
readonly declarationHash: string; readonly beforeSelectorTargetGraphHash?: string; readonly afterSelectorTargetGraphHash?: string; readonly selectorTargetGraphHashPresent: boolean;
|
|
276
|
+
readonly beforeSpecificity?: readonly (readonly number[])[]; readonly afterSpecificity?: readonly (readonly number[])[]; readonly specificityInvariant: boolean; readonly declarationHash: string; readonly beforeSelectorTargetGraphHash?: string; readonly afterSelectorTargetGraphHash?: string; readonly selectorTargetGraphHashPresent: boolean;
|
|
277
277
|
}
|
|
278
278
|
|
|
279
279
|
export interface CssSafeMergeSelectorTargetRebaseProof {
|
|
280
|
-
readonly kind: 'css-selector-target-rebase'; readonly side: string; readonly fromRuleKey: string; readonly toRuleKey: string; readonly property: string; readonly cascadeKey: string;
|
|
280
|
+
readonly kind: 'css-selector-target-rebase'; readonly side: string; readonly fromRuleKey: string; readonly toRuleKey: string; readonly property: string; readonly cascadeKey: string; readonly selectorTargetGraphHash?: string; readonly specificityInvariant: true; readonly beforeSpecificity?: readonly (readonly number[])[]; readonly afterSpecificity?: readonly (readonly number[])[];
|
|
281
281
|
}
|
|
282
282
|
|
|
283
283
|
export interface CssSelectorTargetEquivalence {
|
|
284
|
-
readonly fromRuleKey?: string; readonly toRuleKey?: string; readonly fromSelectors?: readonly string[]; readonly toSelectors?: readonly string[]; readonly graphHash?: string;
|
|
284
|
+
readonly sourcePath?: string; readonly fromRuleKey?: string; readonly toRuleKey?: string; readonly fromSelectors?: readonly string[]; readonly toSelectors?: readonly string[]; readonly fromSpecificity?: readonly (readonly number[])[]; readonly toSpecificity?: readonly (readonly number[])[]; readonly graphHash?: string;
|
|
285
285
|
}
|
|
286
286
|
|
|
287
287
|
export interface CssSafeMergeInput {
|
|
@@ -45,6 +45,9 @@ function selectorTargetMoves(changes, side) {
|
|
|
45
45
|
afterSelectors: addition.after.selectors,
|
|
46
46
|
beforeScopes: deletion.before.scopes,
|
|
47
47
|
afterScopes: addition.after.scopes,
|
|
48
|
+
beforeSpecificity: deletion.before.specificity,
|
|
49
|
+
afterSpecificity: addition.after.specificity,
|
|
50
|
+
specificityInvariant: specificityListKey(deletion.before.specificity) === specificityListKey(addition.after.specificity),
|
|
48
51
|
declarationHash: addition.after.declarationHash,
|
|
49
52
|
beforeSelectorTargetGraphHash: deletion.before.selectorTargetGraphHash,
|
|
50
53
|
afterSelectorTargetGraphHash: addition.after.selectorTargetGraphHash,
|
|
@@ -73,7 +76,7 @@ function selectorTargetMoveSidePlan(id, sourcePath, moves, oppositeMoves, opposi
|
|
|
73
76
|
for (let index = 0; index < oppositeChanges.length; index += 1) {
|
|
74
77
|
const change = oppositeChanges[index];
|
|
75
78
|
if (!selectorMoveTouchesChange(move, change)) continue;
|
|
76
|
-
if (canRebaseChange(move, change, options)) {
|
|
79
|
+
if (canRebaseChange(move, change, options, sourcePath)) {
|
|
77
80
|
const rebased = rebaseChangeToSelectorMove(change, move);
|
|
78
81
|
oppositeChanges[index] = rebased.change;
|
|
79
82
|
rebaseProofs.push(rebased.proof);
|
|
@@ -83,16 +86,19 @@ function selectorTargetMoveSidePlan(id, sourcePath, moves, oppositeMoves, opposi
|
|
|
83
86
|
return { conflicts, rebaseProofs };
|
|
84
87
|
}
|
|
85
88
|
|
|
86
|
-
function canRebaseChange(move, change, options) {
|
|
87
|
-
return change.kind === 'add' && change.after && hasSelectorTargetEquivalence(move, options);
|
|
89
|
+
function canRebaseChange(move, change, options, sourcePath) {
|
|
90
|
+
return change.kind === 'add' && change.after && hasSelectorTargetEquivalence(move, options, sourcePath);
|
|
88
91
|
}
|
|
89
92
|
|
|
90
|
-
function hasSelectorTargetEquivalence(move, options) {
|
|
93
|
+
function hasSelectorTargetEquivalence(move, options, sourcePath) {
|
|
94
|
+
if (!move.specificityInvariant) return false;
|
|
91
95
|
return (options.selectorTargetEquivalences ?? []).some((entry) => {
|
|
96
|
+
const sourceMatches = !entry.sourcePath || entry.sourcePath === sourcePath;
|
|
92
97
|
const ruleKeysMatch = entry.fromRuleKey === move.beforeRuleKey && entry.toRuleKey === move.afterRuleKey;
|
|
93
98
|
const selectorsMatch = selectorListKey(entry.fromSelectors) === selectorListKey(move.beforeSelectors) && selectorListKey(entry.toSelectors) === selectorListKey(move.afterSelectors);
|
|
94
|
-
const graphMatches =
|
|
95
|
-
|
|
99
|
+
const graphMatches = Boolean(entry.graphHash && entry.graphHash === move.beforeSelectorTargetGraphHash && entry.graphHash === move.afterSelectorTargetGraphHash);
|
|
100
|
+
const specificityMatches = (!entry.fromSpecificity || specificityListKey(entry.fromSpecificity) === specificityListKey(move.beforeSpecificity)) && (!entry.toSpecificity || specificityListKey(entry.toSpecificity) === specificityListKey(move.afterSpecificity));
|
|
101
|
+
return sourceMatches && graphMatches && specificityMatches && (ruleKeysMatch || selectorsMatch);
|
|
96
102
|
});
|
|
97
103
|
}
|
|
98
104
|
|
|
@@ -100,7 +106,7 @@ function rebaseChangeToSelectorMove(change, move) {
|
|
|
100
106
|
const after = { ...change.after, ruleKey: move.afterRuleKey, selectors: move.afterSelectors, scopes: move.afterScopes ?? [], key: cascadeKey(move.afterScopes, move.afterSelectors, change.after.property), rebasedFromRuleKey: move.beforeRuleKey };
|
|
101
107
|
return {
|
|
102
108
|
change: { ...change, key: after.key, after },
|
|
103
|
-
proof: { kind: 'css-selector-target-rebase', side: change.side, fromRuleKey: move.beforeRuleKey, toRuleKey: move.afterRuleKey, property: change.after.property, cascadeKey: after.key }
|
|
109
|
+
proof: { kind: 'css-selector-target-rebase', side: change.side, fromRuleKey: move.beforeRuleKey, toRuleKey: move.afterRuleKey, property: change.after.property, cascadeKey: after.key, selectorTargetGraphHash: move.afterSelectorTargetGraphHash, specificityInvariant: true, beforeSpecificity: move.beforeSpecificity, afterSpecificity: move.afterSpecificity }
|
|
104
110
|
};
|
|
105
111
|
}
|
|
106
112
|
|
|
@@ -134,6 +140,7 @@ function sameSelectorMove(left, right) {
|
|
|
134
140
|
|
|
135
141
|
function cascadeKey(scopes = [], selectors = [], property) { return [...scopes, selectors.join(','), property].join('::'); }
|
|
136
142
|
function selectorListKey(value = []) { return Array.isArray(value) ? value.join(',') : undefined; }
|
|
143
|
+
function specificityListKey(value = []) { return Array.isArray(value) ? value.map((item) => Array.isArray(item) ? item.join(',') : '').join('|') : undefined; }
|
|
137
144
|
function changeDetails(change) { return { kind: change.kind, property: (change.after ?? change.before)?.property, value: change.after?.value, important: change.after?.important }; }
|
|
138
145
|
|
|
139
146
|
export { mergeSelectorTargetEvidence, planSelectorTargetRebase };
|
package/dist/semantic-merge.js
CHANGED
|
@@ -101,7 +101,7 @@ function declarationIndex(sheet) {
|
|
|
101
101
|
key: declaration.cascadeKey,
|
|
102
102
|
ruleKey,
|
|
103
103
|
selectors: record.selectors,
|
|
104
|
-
scopes: record.scopes ?? [],
|
|
104
|
+
scopes: record.scopes ?? [], specificity: record.specificity,
|
|
105
105
|
property: declaration.property,
|
|
106
106
|
value: declaration.value,
|
|
107
107
|
important: declaration.important,
|
package/package.json
CHANGED