@shapeshift-labs/frontier-lang-css 0.1.8 → 0.1.9
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/dist/index.d.ts +15 -11
- package/dist/semantic-merge-selector-targets.js +50 -10
- package/dist/semantic-merge.js +6 -7
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -235,9 +235,7 @@ export interface CssSemanticMergeEvidence {
|
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
export interface CssSafeMergeConflict {
|
|
238
|
-
readonly code: string;
|
|
239
|
-
readonly gateId: 'css-semantic-merge' | string;
|
|
240
|
-
readonly sourcePath?: string;
|
|
238
|
+
readonly code: string; readonly gateId: 'css-semantic-merge' | string; readonly sourcePath?: string;
|
|
241
239
|
readonly details: Readonly<Record<string, unknown>> & { readonly reasonCode: string; readonly conflictKey: string };
|
|
242
240
|
}
|
|
243
241
|
|
|
@@ -262,22 +260,20 @@ export interface CssSafeMergeResult {
|
|
|
262
260
|
export interface CssSafeMergeParserEvidence {
|
|
263
261
|
readonly kind: 'frontier.lang.cssSafeMergeParserEvidence'; readonly version: 1; readonly parserNames: readonly string[];
|
|
264
262
|
readonly sourceCodeLocationInfo: boolean; readonly parserBackedSourceSpans: boolean; readonly parserBackedDeclarationSpans: boolean; readonly parserBackedTriviaHashes: boolean;
|
|
265
|
-
readonly scopedCascadeGraphHashPresent: boolean; readonly parseErrors: number;
|
|
266
|
-
readonly sides: Readonly<Record<string, CssSafeMergeParserSideEvidence>>;
|
|
263
|
+
readonly scopedCascadeGraphHashPresent: boolean; readonly parseErrors: number; readonly sides: Readonly<Record<string, CssSafeMergeParserSideEvidence>>;
|
|
267
264
|
}
|
|
268
265
|
|
|
269
266
|
export interface CssSafeMergeParserSideEvidence {
|
|
270
|
-
readonly parserName: string;
|
|
271
|
-
readonly sourceCodeLocationInfo: boolean; readonly parserBackedSourceSpans: boolean; readonly parserBackedDeclarationSpans: boolean; readonly parserBackedTriviaHashes: boolean;
|
|
267
|
+
readonly parserName: string; readonly sourceCodeLocationInfo: boolean; readonly parserBackedSourceSpans: boolean; readonly parserBackedDeclarationSpans: boolean; readonly parserBackedTriviaHashes: boolean;
|
|
272
268
|
readonly scopedCascadeGraphHashPresent: boolean; readonly parseErrors: number; readonly recordCount: number; readonly declarationCount: number;
|
|
273
269
|
}
|
|
274
270
|
|
|
275
271
|
export interface CssSafeMergeSelectorTargetEvidence {
|
|
276
|
-
readonly kind: 'frontier.lang.cssSafeMergeSelectorTargetEvidence'; readonly version: 1;
|
|
277
|
-
readonly selectorTargetGraphHashPresent: boolean; readonly parserBackedRuleSpans: boolean;
|
|
272
|
+
readonly kind: 'frontier.lang.cssSafeMergeSelectorTargetEvidence'; readonly version: 1; readonly selectorTargetGraphHashPresent: boolean; readonly parserBackedRuleSpans: boolean;
|
|
278
273
|
readonly selectorMoveCount: number; readonly workerSelectorMoves: number; readonly headSelectorMoves: number;
|
|
279
274
|
readonly sides: Readonly<Record<string, CssSafeMergeSelectorTargetSideEvidence>>;
|
|
280
275
|
readonly moves: Readonly<Record<'worker' | 'head', readonly CssSafeMergeSelectorMove[]>>;
|
|
276
|
+
readonly rebasedChangeCount?: number; readonly rebaseProofs?: readonly CssSafeMergeSelectorTargetRebaseProof[];
|
|
281
277
|
}
|
|
282
278
|
|
|
283
279
|
export interface CssSafeMergeSelectorTargetSideEvidence {
|
|
@@ -288,7 +284,15 @@ export interface CssSafeMergeSelectorTargetSideEvidence {
|
|
|
288
284
|
export interface CssSafeMergeSelectorMove {
|
|
289
285
|
readonly side: string; readonly property: string; readonly beforeRuleKey: string; readonly afterRuleKey: string;
|
|
290
286
|
readonly beforeSelectors?: readonly string[]; readonly afterSelectors?: readonly string[]; readonly beforeScopes?: readonly string[]; readonly afterScopes?: readonly string[];
|
|
291
|
-
readonly declarationHash: string; readonly selectorTargetGraphHashPresent: boolean;
|
|
287
|
+
readonly declarationHash: string; readonly beforeSelectorTargetGraphHash?: string; readonly afterSelectorTargetGraphHash?: string; readonly selectorTargetGraphHashPresent: boolean;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export interface CssSafeMergeSelectorTargetRebaseProof {
|
|
291
|
+
readonly kind: 'css-selector-target-rebase'; readonly side: string; readonly fromRuleKey: string; readonly toRuleKey: string; readonly property: string; readonly cascadeKey: string;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export interface CssSelectorTargetEquivalence {
|
|
295
|
+
readonly fromRuleKey?: string; readonly toRuleKey?: string; readonly fromSelectors?: readonly string[]; readonly toSelectors?: readonly string[]; readonly graphHash?: string;
|
|
292
296
|
}
|
|
293
297
|
|
|
294
298
|
export interface CssSafeMergeInput {
|
|
@@ -296,7 +300,7 @@ export interface CssSafeMergeInput {
|
|
|
296
300
|
readonly cssModule?: boolean; readonly cssModules?: boolean;
|
|
297
301
|
readonly generatedClassNameMap?: Readonly<Record<string, string>>;
|
|
298
302
|
readonly generatedClassNameMapHash?: string; readonly jsTsUseSiteGraphHash?: string; readonly cssModuleCompositionGraphHash?: string; readonly icssGraphHash?: string; readonly scopedCascadeGraphHash?: string;
|
|
299
|
-
readonly selectorTargetGraphHash?: string;
|
|
303
|
+
readonly selectorTargetGraphHash?: string; readonly selectorTargetEquivalences?: readonly CssSelectorTargetEquivalence[];
|
|
300
304
|
readonly baseGeneratedClassNameMap?: Readonly<Record<string, string>>; readonly workerGeneratedClassNameMap?: Readonly<Record<string, string>>; readonly headGeneratedClassNameMap?: Readonly<Record<string, string>>;
|
|
301
305
|
readonly baseGeneratedClassNameMapHash?: string; readonly workerGeneratedClassNameMapHash?: string; readonly headGeneratedClassNameMapHash?: string;
|
|
302
306
|
readonly baseJsTsUseSiteGraphHash?: string; readonly workerJsTsUseSiteGraphHash?: string; readonly headJsTsUseSiteGraphHash?: string;
|
|
@@ -46,26 +46,64 @@ function selectorTargetMoves(changes, side) {
|
|
|
46
46
|
beforeScopes: deletion.before.scopes,
|
|
47
47
|
afterScopes: addition.after.scopes,
|
|
48
48
|
declarationHash: addition.after.declarationHash,
|
|
49
|
+
beforeSelectorTargetGraphHash: deletion.before.selectorTargetGraphHash,
|
|
50
|
+
afterSelectorTargetGraphHash: addition.after.selectorTargetGraphHash,
|
|
49
51
|
selectorTargetGraphHashPresent: Boolean(deletion.before.selectorTargetGraphHash && addition.after.selectorTargetGraphHash)
|
|
50
52
|
});
|
|
51
53
|
}
|
|
52
54
|
return moves;
|
|
53
55
|
}
|
|
54
56
|
|
|
55
|
-
function
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
function planSelectorTargetRebase(id, sourcePath, selectorTargetEvidence, changed, options = {}) {
|
|
58
|
+
const planned = { worker: [...changed.worker], head: [...changed.head] };
|
|
59
|
+
const worker = selectorTargetMoveSidePlan(id, sourcePath, selectorTargetEvidence.moves.worker, selectorTargetEvidence.moves.head, planned.head, options);
|
|
60
|
+
const head = selectorTargetMoveSidePlan(id, sourcePath, selectorTargetEvidence.moves.head, selectorTargetEvidence.moves.worker, planned.worker, options);
|
|
61
|
+
return {
|
|
62
|
+
changed: planned,
|
|
63
|
+
conflicts: [...worker.conflicts, ...head.conflicts],
|
|
64
|
+
evidence: { ...selectorTargetEvidence, rebasedChangeCount: worker.rebaseProofs.length + head.rebaseProofs.length, rebaseProofs: [...worker.rebaseProofs, ...head.rebaseProofs] }
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function selectorTargetMoveSidePlan(id, sourcePath, moves, oppositeMoves, oppositeChanges, options) {
|
|
69
|
+
const conflicts = [];
|
|
70
|
+
const rebaseProofs = [];
|
|
71
|
+
for (const move of moves) {
|
|
72
|
+
if (oppositeMoves.some((oppositeMove) => sameSelectorMove(move, oppositeMove))) continue;
|
|
73
|
+
for (let index = 0; index < oppositeChanges.length; index += 1) {
|
|
74
|
+
const change = oppositeChanges[index];
|
|
75
|
+
if (!selectorMoveTouchesChange(move, change)) continue;
|
|
76
|
+
if (canRebaseChange(move, change, options)) {
|
|
77
|
+
const rebased = rebaseChangeToSelectorMove(change, move);
|
|
78
|
+
oppositeChanges[index] = rebased.change;
|
|
79
|
+
rebaseProofs.push(rebased.proof);
|
|
80
|
+
} else conflicts.push(conflict(id, sourcePath, change.key, move, change));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return { conflicts, rebaseProofs };
|
|
60
84
|
}
|
|
61
85
|
|
|
62
|
-
function
|
|
63
|
-
return
|
|
64
|
-
|
|
65
|
-
|
|
86
|
+
function canRebaseChange(move, change, options) {
|
|
87
|
+
return change.kind === 'add' && change.after && hasSelectorTargetEquivalence(move, options);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function hasSelectorTargetEquivalence(move, options) {
|
|
91
|
+
return (options.selectorTargetEquivalences ?? []).some((entry) => {
|
|
92
|
+
const ruleKeysMatch = entry.fromRuleKey === move.beforeRuleKey && entry.toRuleKey === move.afterRuleKey;
|
|
93
|
+
const selectorsMatch = selectorListKey(entry.fromSelectors) === selectorListKey(move.beforeSelectors) && selectorListKey(entry.toSelectors) === selectorListKey(move.afterSelectors);
|
|
94
|
+
const graphMatches = !entry.graphHash || entry.graphHash === move.beforeSelectorTargetGraphHash || entry.graphHash === move.afterSelectorTargetGraphHash;
|
|
95
|
+
return graphMatches && (ruleKeysMatch || selectorsMatch);
|
|
66
96
|
});
|
|
67
97
|
}
|
|
68
98
|
|
|
99
|
+
function rebaseChangeToSelectorMove(change, move) {
|
|
100
|
+
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
|
+
return {
|
|
102
|
+
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 }
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
69
107
|
function conflict(id, sourcePath, cascadeKey, selectorMove, change) {
|
|
70
108
|
return {
|
|
71
109
|
code: 'css-selector-target-conflict',
|
|
@@ -94,6 +132,8 @@ function sameSelectorMove(left, right) {
|
|
|
94
132
|
return left.property === right.property && left.beforeRuleKey === right.beforeRuleKey && left.afterRuleKey === right.afterRuleKey && left.declarationHash === right.declarationHash;
|
|
95
133
|
}
|
|
96
134
|
|
|
135
|
+
function cascadeKey(scopes = [], selectors = [], property) { return [...scopes, selectors.join(','), property].join('::'); }
|
|
136
|
+
function selectorListKey(value = []) { return Array.isArray(value) ? value.join(',') : undefined; }
|
|
97
137
|
function changeDetails(change) { return { kind: change.kind, property: (change.after ?? change.before)?.property, value: change.after?.value, important: change.after?.important }; }
|
|
98
138
|
|
|
99
|
-
export { mergeSelectorTargetEvidence,
|
|
139
|
+
export { mergeSelectorTargetEvidence, planSelectorTargetRebase };
|
package/dist/semantic-merge.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cssModuleContractChanges, cssModuleContractConflicts, sheetOptions, unsupportedSourceShapeConflicts } from './semantic-merge-css-modules.js';
|
|
2
|
-
import { mergeSelectorTargetEvidence,
|
|
2
|
+
import { mergeSelectorTargetEvidence, planSelectorTargetRebase } from './semantic-merge-selector-targets.js';
|
|
3
3
|
|
|
4
4
|
function safeMergeCssSource(input = {}, context = {}) {
|
|
5
5
|
const parseSheet = context.parseCssSemanticSheet;
|
|
@@ -31,11 +31,10 @@ function safeMergeCssSource(input = {}, context = {}) {
|
|
|
31
31
|
const moduleConflicts = cssModuleContractConflicts(id, sourcePath, moduleChanges);
|
|
32
32
|
const sourceShapeConflicts = unsupportedSourceShapeConflicts(id, sourcePath, sheets, changed, hash);
|
|
33
33
|
const parserEvidence = mergeParserEvidence(sheets);
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const mergedIndex = applyDeclarationChanges(applyDeclarationChanges(indexes.base, changed.head), changed.worker);
|
|
34
|
+
const selectorTargetPlan = planSelectorTargetRebase(id, sourcePath, mergeSelectorTargetEvidence(sheets, changed), changed, input);
|
|
35
|
+
const conflicts = [...parserConflicts, ...proofConflicts, ...overlapConflicts, ...moduleConflicts, ...sourceShapeConflicts, ...selectorTargetPlan.conflicts];
|
|
36
|
+
if (conflicts.length) return blocked(id, sourcePath, 'css-semantic-merge-conflict', conflicts, { parserEvidence, selectorTargetEvidence: selectorTargetPlan.evidence });
|
|
37
|
+
const mergedIndex = applyDeclarationChanges(applyDeclarationChanges(indexes.base, selectorTargetPlan.changed.head), selectorTargetPlan.changed.worker);
|
|
39
38
|
return merged(id, sourcePath, renderDeclarationIndex(mergedIndex), 'semantic-declaration-merge', hash, {
|
|
40
39
|
baseSheetHash: sheets.base.sheetHash,
|
|
41
40
|
workerSheetHash: sheets.worker.sheetHash,
|
|
@@ -45,7 +44,7 @@ function safeMergeCssSource(input = {}, context = {}) {
|
|
|
45
44
|
workerChangedCssModuleContracts: moduleChanges.worker.length,
|
|
46
45
|
headChangedCssModuleContracts: moduleChanges.head.length,
|
|
47
46
|
parserEvidence,
|
|
48
|
-
selectorTargetEvidence
|
|
47
|
+
selectorTargetEvidence: selectorTargetPlan.evidence
|
|
49
48
|
});
|
|
50
49
|
}
|
|
51
50
|
|
package/package.json
CHANGED