@shapeshift-labs/frontier-lang-compiler 0.2.104 → 0.2.105
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 -1
- package/dist/declarations/js-ts-safe-member-merge.d.ts +29 -1
- package/dist/declarations/js-ts-safe-merge.d.ts +11 -0
- package/dist/js-ts-safe-member-merge.js +69 -6
- package/dist/js-ts-safe-merge-composed.js +170 -0
- package/dist/js-ts-semantic-merge-member-source.js +22 -4
- package/dist/js-ts-semantic-merge-parse.js +1 -0
- package/dist/js-ts-semantic-merge.js +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -168,7 +168,8 @@ The JS/TS semantic merge smoke corpus lives at
|
|
|
168
168
|
`test/smoke/js-ts-semantic-merge-oracles.mjs`. The fixtures are deliberately
|
|
169
169
|
small and dependency-free. They cover accepted projection/replay cases, exact
|
|
170
170
|
source preservation, generated/source-map boundaries, safe import/declaration
|
|
171
|
-
merges, safe unordered member merges,
|
|
171
|
+
merges, safe unordered member merges, composed top-level/member safe merges,
|
|
172
|
+
and rejected unsafe cases such as stale
|
|
172
173
|
ledger spans, import specifier reordering, computed keys, duplicate exported
|
|
173
174
|
names, duplicate object members, decorators, overload anchors, and same-anchor
|
|
174
175
|
edit conflicts. Fixture failures include the fixture id and the actual
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type JsTsSafeMemberMergeRegionKind = 'interface' | 'type' | 'object';
|
|
1
|
+
export type JsTsSafeMemberMergeRegionKind = 'interface' | 'type' | 'class' | 'object';
|
|
2
2
|
export type JsTsSafeMemberMergeOrder = 'non-semantic' | string;
|
|
3
3
|
export type JsTsSafeMemberMergeStatus = 'merged' | 'rejected';
|
|
4
4
|
|
|
@@ -26,6 +26,30 @@ export interface JsTsSafeMemberMergeInput {
|
|
|
26
26
|
readonly policy?: JsTsSafeMemberMergePolicy | readonly JsTsSafeMemberMergePolicyRegion[];
|
|
27
27
|
readonly mergePolicy?: JsTsSafeMemberMergePolicy | readonly JsTsSafeMemberMergePolicyRegion[];
|
|
28
28
|
readonly unorderedRegions?: readonly JsTsSafeMemberMergePolicyRegion[];
|
|
29
|
+
readonly allowNonPolicySourceChanges?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface JsTsSafeMemberMergeConflict {
|
|
33
|
+
readonly code: string;
|
|
34
|
+
readonly gateId: string;
|
|
35
|
+
readonly message: string;
|
|
36
|
+
readonly side?: 'base' | 'worker' | 'head' | string;
|
|
37
|
+
readonly sourcePath?: string;
|
|
38
|
+
readonly details?: Record<string, unknown>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface JsTsSafeMemberMergeGate {
|
|
42
|
+
readonly id: string;
|
|
43
|
+
readonly status: 'passed' | 'blocked' | 'skipped' | string;
|
|
44
|
+
readonly reasonCodes: readonly string[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface JsTsSafeMemberMergeAdmission {
|
|
48
|
+
readonly status: 'auto-merge-candidate' | 'blocked' | string;
|
|
49
|
+
readonly action: 'apply' | 'human-review' | string;
|
|
50
|
+
readonly reviewRequired: boolean;
|
|
51
|
+
readonly autoApplyCandidate: boolean;
|
|
52
|
+
readonly reasonCodes: readonly string[];
|
|
29
53
|
}
|
|
30
54
|
|
|
31
55
|
export interface JsTsSafeMemberMergedRegion {
|
|
@@ -42,12 +66,16 @@ export interface JsTsSafeMemberMergeResult {
|
|
|
42
66
|
readonly status: JsTsSafeMemberMergeStatus;
|
|
43
67
|
readonly sourceText?: string;
|
|
44
68
|
readonly reasonCodes: readonly string[];
|
|
69
|
+
readonly conflicts: readonly JsTsSafeMemberMergeConflict[];
|
|
70
|
+
readonly gates: readonly JsTsSafeMemberMergeGate[];
|
|
71
|
+
readonly admission: JsTsSafeMemberMergeAdmission;
|
|
45
72
|
readonly mergedRegions: readonly JsTsSafeMemberMergedRegion[];
|
|
46
73
|
readonly summary: {
|
|
47
74
|
readonly regions: number;
|
|
48
75
|
readonly workerAdditions: number;
|
|
49
76
|
readonly headAdditions: number;
|
|
50
77
|
readonly appliedAdditions: number;
|
|
78
|
+
readonly conflicts: number;
|
|
51
79
|
};
|
|
52
80
|
readonly metadata: {
|
|
53
81
|
readonly explicitPolicy: boolean;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { FrontierSourceLanguage } from '@shapeshift-labs/frontier-lang-kernel';
|
|
2
|
+
import type {
|
|
3
|
+
JsTsSafeMemberMergePolicy,
|
|
4
|
+
JsTsSafeMemberMergePolicyRegion
|
|
5
|
+
} from './js-ts-safe-member-merge.js';
|
|
2
6
|
|
|
3
7
|
export type JsTsSafeMergeStatus = 'merged' | 'blocked';
|
|
4
8
|
export type JsTsSafeMergeGateStatus = 'passed' | 'blocked' | 'skipped';
|
|
@@ -65,6 +69,9 @@ export interface JsTsSafeMergeInput {
|
|
|
65
69
|
readonly baseSourceLedger?: unknown;
|
|
66
70
|
readonly workerSourceLedger?: unknown;
|
|
67
71
|
readonly headSourceLedger?: unknown;
|
|
72
|
+
readonly policy?: JsTsSafeMemberMergePolicy | readonly JsTsSafeMemberMergePolicyRegion[];
|
|
73
|
+
readonly mergePolicy?: JsTsSafeMemberMergePolicy | readonly JsTsSafeMemberMergePolicyRegion[];
|
|
74
|
+
readonly unorderedRegions?: readonly JsTsSafeMemberMergePolicyRegion[];
|
|
68
75
|
}
|
|
69
76
|
|
|
70
77
|
export interface JsTsSafeMergeConflict {
|
|
@@ -98,6 +105,9 @@ export interface JsTsSafeMergeSummary {
|
|
|
98
105
|
readonly changedExistingDeclarations: number;
|
|
99
106
|
readonly conflicts: number;
|
|
100
107
|
readonly gatesPassed: number;
|
|
108
|
+
readonly memberRegions?: number;
|
|
109
|
+
readonly memberAdditions?: number;
|
|
110
|
+
readonly composedPhases?: number;
|
|
101
111
|
}
|
|
102
112
|
|
|
103
113
|
export interface JsTsSafeMergeResult {
|
|
@@ -118,3 +128,4 @@ export interface JsTsSafeMergeResult {
|
|
|
118
128
|
}
|
|
119
129
|
|
|
120
130
|
export declare function safeMergeJsTsImportsAndDeclarations(input: JsTsSafeMergeInput): JsTsSafeMergeResult;
|
|
131
|
+
export declare function safeMergeJsTsSource(input: JsTsSafeMergeInput): JsTsSafeMergeResult;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
applyMemberAdditions,
|
|
3
|
+
applyPreparedMemberAdditions,
|
|
3
4
|
canonicalizeSourceBodies,
|
|
4
5
|
findContainer,
|
|
5
6
|
normalizeKind,
|
|
@@ -17,6 +18,54 @@ function safeMergeJsTsMembers(input = {}) {
|
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
function mergeJsTsSafeMemberAdditions(input = {}) {
|
|
21
|
+
const analysis = analyzeJsTsSafeMemberAdditions(input);
|
|
22
|
+
const uniqueReasons = uniqueStrings(analysis.reasonCodes);
|
|
23
|
+
if (uniqueReasons.length) {
|
|
24
|
+
return mergeResult('rejected', undefined, uniqueReasons, analysis.preparedRegions, input, analysis.explicitPolicy);
|
|
25
|
+
}
|
|
26
|
+
const sourceText = applyMemberAdditions(analysis.headSourceText, analysis.preparedRegions);
|
|
27
|
+
return mergeResult('merged', sourceText, [], analysis.preparedRegions, input, analysis.explicitPolicy);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function analyzeJsTsSafeMemberAdditions(input = {}) {
|
|
31
|
+
const analysis = prepareJsTsSafeMemberAdditions(input);
|
|
32
|
+
const reasonCodes = [...analysis.reasonCodes];
|
|
33
|
+
if (!input.allowNonPolicySourceChanges) {
|
|
34
|
+
reasonCodes.push(...nonPolicySourceChangeReasons(analysis));
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
...analysis,
|
|
38
|
+
reasonCodes: uniqueStrings(reasonCodes),
|
|
39
|
+
ok: reasonCodes.length === 0
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function neutralizeJsTsSafeMemberMergeSources(input = {}) {
|
|
44
|
+
const analysis = analyzeJsTsSafeMemberAdditions({
|
|
45
|
+
...input,
|
|
46
|
+
allowNonPolicySourceChanges: true
|
|
47
|
+
});
|
|
48
|
+
if (analysis.reasonCodes.length) {
|
|
49
|
+
return {
|
|
50
|
+
ok: false,
|
|
51
|
+
analysis,
|
|
52
|
+
result: mergeResult('rejected', undefined, analysis.reasonCodes, analysis.preparedRegions, input, analysis.explicitPolicy)
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
ok: true,
|
|
57
|
+
analysis,
|
|
58
|
+
baseSourceText: analysis.baseSourceText,
|
|
59
|
+
workerSourceText: canonicalizeSourceBodies(analysis.workerSourceText, analysis.preparedRegions, 'worker'),
|
|
60
|
+
headSourceText: canonicalizeSourceBodies(analysis.headSourceText, analysis.preparedRegions, 'head')
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function applyJsTsPreparedMemberAdditions(sourceText, preparedRegions, sides) {
|
|
65
|
+
return applyPreparedMemberAdditions(sourceText, preparedRegions, sides);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function prepareJsTsSafeMemberAdditions(input = {}) {
|
|
20
69
|
const baseSourceText = input.baseSourceText;
|
|
21
70
|
const workerSourceText = input.workerSourceText;
|
|
22
71
|
const headSourceText = input.headSourceText;
|
|
@@ -36,6 +85,20 @@ function mergeJsTsSafeMemberAdditions(input = {}) {
|
|
|
36
85
|
reasonCodes.push(...prepared.reasonCodes);
|
|
37
86
|
if (prepared.ok) preparedRegions.push(prepared.value);
|
|
38
87
|
}
|
|
88
|
+
const explicitPolicy = policyRegions.length > 0;
|
|
89
|
+
return {
|
|
90
|
+
baseSourceText,
|
|
91
|
+
workerSourceText,
|
|
92
|
+
headSourceText,
|
|
93
|
+
reasonCodes: uniqueStrings(reasonCodes),
|
|
94
|
+
preparedRegions,
|
|
95
|
+
explicitPolicy
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function nonPolicySourceChangeReasons(analysis) {
|
|
100
|
+
const reasonCodes = [];
|
|
101
|
+
const { baseSourceText, workerSourceText, headSourceText, preparedRegions } = analysis;
|
|
39
102
|
if (typeof baseSourceText === 'string' && typeof workerSourceText === 'string' && preparedRegions.length) {
|
|
40
103
|
const canonicalWorker = canonicalizeSourceBodies(workerSourceText, preparedRegions, 'worker');
|
|
41
104
|
if (canonicalWorker !== baseSourceText) reasonCodes.push('non-policy-source-change:worker');
|
|
@@ -44,11 +107,7 @@ function mergeJsTsSafeMemberAdditions(input = {}) {
|
|
|
44
107
|
const canonicalHead = canonicalizeSourceBodies(headSourceText, preparedRegions, 'head');
|
|
45
108
|
if (canonicalHead !== baseSourceText) reasonCodes.push('non-policy-source-change:head');
|
|
46
109
|
}
|
|
47
|
-
|
|
48
|
-
const explicitPolicy = policyRegions.length > 0;
|
|
49
|
-
if (uniqueReasons.length) return mergeResult('rejected', undefined, uniqueReasons, preparedRegions, input, explicitPolicy);
|
|
50
|
-
const sourceText = applyMemberAdditions(headSourceText, preparedRegions);
|
|
51
|
-
return mergeResult('merged', sourceText, [], preparedRegions, input, explicitPolicy);
|
|
110
|
+
return reasonCodes;
|
|
52
111
|
}
|
|
53
112
|
|
|
54
113
|
function normalizePolicyRegions(policy) {
|
|
@@ -125,7 +184,8 @@ function prepareRegion(input) {
|
|
|
125
184
|
headMembers: headMembers.members,
|
|
126
185
|
workerAddedKeys,
|
|
127
186
|
headAddedKeys,
|
|
128
|
-
workerAddedMembers: workerMembers.members.filter((member) => workerAddedKeys.includes(member.key))
|
|
187
|
+
workerAddedMembers: workerMembers.members.filter((member) => workerAddedKeys.includes(member.key)),
|
|
188
|
+
headAddedMembers: headMembers.members.filter((member) => headAddedKeys.includes(member.key))
|
|
129
189
|
}
|
|
130
190
|
};
|
|
131
191
|
}
|
|
@@ -197,6 +257,9 @@ function regionReason(region, reason) {
|
|
|
197
257
|
}
|
|
198
258
|
|
|
199
259
|
export {
|
|
260
|
+
analyzeJsTsSafeMemberAdditions,
|
|
261
|
+
applyJsTsPreparedMemberAdditions,
|
|
200
262
|
mergeJsTsSafeMemberAdditions,
|
|
263
|
+
neutralizeJsTsSafeMemberMergeSources,
|
|
201
264
|
safeMergeJsTsMembers
|
|
202
265
|
};
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import {
|
|
2
|
+
JsTsSafeMergeConflictCodes,
|
|
3
|
+
JsTsSafeMergeGateIds,
|
|
4
|
+
JsTsSafeMergeStatuses,
|
|
5
|
+
jsTsSafeMergeGateOrder
|
|
6
|
+
} from './js-ts-safe-merge-constants.js';
|
|
7
|
+
import { safeMergeJsTsImportsAndDeclarations } from './js-ts-safe-merge.js';
|
|
8
|
+
import {
|
|
9
|
+
applyJsTsPreparedMemberAdditions,
|
|
10
|
+
neutralizeJsTsSafeMemberMergeSources
|
|
11
|
+
} from './js-ts-safe-member-merge.js';
|
|
12
|
+
|
|
13
|
+
function safeMergeJsTsSource(input = {}) {
|
|
14
|
+
if (!hasMemberMergePolicy(input)) return safeMergeJsTsImportsAndDeclarations(input);
|
|
15
|
+
|
|
16
|
+
const memberNeutralization = neutralizeJsTsSafeMemberMergeSources(input);
|
|
17
|
+
if (!memberNeutralization.ok) {
|
|
18
|
+
return composedBlockedResult(input, 'member-analysis', memberNeutralization.result, memberNeutralization.analysis);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const topLevelResult = safeMergeJsTsImportsAndDeclarations({
|
|
22
|
+
...input,
|
|
23
|
+
baseSourceText: memberNeutralization.baseSourceText,
|
|
24
|
+
workerSourceText: memberNeutralization.workerSourceText,
|
|
25
|
+
headSourceText: memberNeutralization.headSourceText
|
|
26
|
+
});
|
|
27
|
+
if (topLevelResult.status !== JsTsSafeMergeStatuses.merged) {
|
|
28
|
+
return composedBlockedResult(input, 'top-level', topLevelResult, memberNeutralization.analysis);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const memberApplication = applyJsTsPreparedMemberAdditions(
|
|
32
|
+
topLevelResult.mergedSourceText,
|
|
33
|
+
memberNeutralization.analysis.preparedRegions,
|
|
34
|
+
['head', 'worker']
|
|
35
|
+
);
|
|
36
|
+
if (memberApplication.reasonCodes.length) {
|
|
37
|
+
return composedMemberApplicationBlockedResult(input, topLevelResult, memberNeutralization.analysis, memberApplication.reasonCodes);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const memberAdditions = memberNeutralization.analysis.preparedRegions.reduce((total, region) => (
|
|
41
|
+
total + region.workerAddedKeys.length + region.headAddedKeys.length
|
|
42
|
+
), 0);
|
|
43
|
+
return {
|
|
44
|
+
...topLevelResult,
|
|
45
|
+
id: String(input.id ?? topLevelResult.id),
|
|
46
|
+
mergedSourceText: memberApplication.sourceText,
|
|
47
|
+
outputSourceText: memberApplication.sourceText,
|
|
48
|
+
summary: {
|
|
49
|
+
...topLevelResult.summary,
|
|
50
|
+
memberRegions: memberNeutralization.analysis.preparedRegions.length,
|
|
51
|
+
memberAdditions,
|
|
52
|
+
composedPhases: 2
|
|
53
|
+
},
|
|
54
|
+
metadata: {
|
|
55
|
+
...topLevelResult.metadata,
|
|
56
|
+
composed: {
|
|
57
|
+
phases: ['top-level', 'member'],
|
|
58
|
+
memberRegions: memberNeutralization.analysis.preparedRegions.map((region) => ({
|
|
59
|
+
kind: region.kind,
|
|
60
|
+
name: region.name,
|
|
61
|
+
regionKind: region.policy.regionKind,
|
|
62
|
+
workerAddedKeys: region.workerAddedKeys,
|
|
63
|
+
headAddedKeys: region.headAddedKeys
|
|
64
|
+
}))
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function hasMemberMergePolicy(input) {
|
|
71
|
+
const policy = input.policy ?? input.mergePolicy ?? input;
|
|
72
|
+
const regions = Array.isArray(policy)
|
|
73
|
+
? policy
|
|
74
|
+
: policy?.unorderedRegions
|
|
75
|
+
?? policy?.unorderedMemberRegions
|
|
76
|
+
?? policy?.safeList
|
|
77
|
+
?? policy?.safeMembers
|
|
78
|
+
?? [];
|
|
79
|
+
return Array.isArray(regions) && regions.length > 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function composedBlockedResult(input, phase, result, memberAnalysis) {
|
|
83
|
+
return {
|
|
84
|
+
kind: 'frontier.lang.jsTsSafeMerge',
|
|
85
|
+
version: 1,
|
|
86
|
+
schema: 'frontier.lang.jsTsSafeMerge.v1',
|
|
87
|
+
id: String(input.id ?? result.id ?? 'js_ts_safe_merge'),
|
|
88
|
+
status: JsTsSafeMergeStatuses.blocked,
|
|
89
|
+
sourcePath: input.sourcePath,
|
|
90
|
+
language: input.language ?? 'typescript',
|
|
91
|
+
conflicts: result.conflicts ?? [],
|
|
92
|
+
gates: result.gates ?? [],
|
|
93
|
+
admission: {
|
|
94
|
+
status: 'blocked',
|
|
95
|
+
action: 'human-review',
|
|
96
|
+
reviewRequired: true,
|
|
97
|
+
autoApplyCandidate: false,
|
|
98
|
+
autoMergeClaim: false,
|
|
99
|
+
semanticEquivalenceClaim: false,
|
|
100
|
+
reasonCodes: result.admission?.reasonCodes ?? result.reasonCodes ?? []
|
|
101
|
+
},
|
|
102
|
+
summary: {
|
|
103
|
+
importSpecifierAdditions: 0,
|
|
104
|
+
topLevelDeclarationAdditions: 0,
|
|
105
|
+
changedExistingDeclarations: result.summary?.changedExistingDeclarations ?? 0,
|
|
106
|
+
conflicts: result.conflicts?.length ?? result.summary?.conflicts ?? 0,
|
|
107
|
+
gatesPassed: result.gates?.filter((gate) => gate.status === 'passed').length ?? 0,
|
|
108
|
+
memberRegions: memberAnalysis?.preparedRegions?.length ?? 0,
|
|
109
|
+
memberAdditions: 0,
|
|
110
|
+
composedPhases: phase === 'top-level' ? 2 : 1
|
|
111
|
+
},
|
|
112
|
+
metadata: {
|
|
113
|
+
composed: {
|
|
114
|
+
phase,
|
|
115
|
+
sourceKind: result.kind
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function composedMemberApplicationBlockedResult(input, topLevelResult, memberAnalysis, reasonCodes) {
|
|
122
|
+
const conflicts = reasonCodes.map((reason) => ({
|
|
123
|
+
code: JsTsSafeMergeConflictCodes.parserLedgerLoss,
|
|
124
|
+
gateId: JsTsSafeMergeGateIds.parseLedger,
|
|
125
|
+
message: 'Composed member application could not find a stable target container.',
|
|
126
|
+
side: 'merged',
|
|
127
|
+
sourcePath: input.sourcePath,
|
|
128
|
+
details: { reason }
|
|
129
|
+
}));
|
|
130
|
+
return {
|
|
131
|
+
...topLevelResult,
|
|
132
|
+
status: JsTsSafeMergeStatuses.blocked,
|
|
133
|
+
mergedSourceText: undefined,
|
|
134
|
+
outputSourceText: undefined,
|
|
135
|
+
conflicts,
|
|
136
|
+
gates: jsTsSafeMergeGateOrder.map((id, index) => ({
|
|
137
|
+
id,
|
|
138
|
+
status: index === 0 ? 'blocked' : 'skipped',
|
|
139
|
+
reasonCodes: index === 0 ? [JsTsSafeMergeConflictCodes.parserLedgerLoss] : []
|
|
140
|
+
})),
|
|
141
|
+
admission: {
|
|
142
|
+
status: 'blocked',
|
|
143
|
+
action: 'human-review',
|
|
144
|
+
reviewRequired: true,
|
|
145
|
+
autoApplyCandidate: false,
|
|
146
|
+
autoMergeClaim: false,
|
|
147
|
+
semanticEquivalenceClaim: false,
|
|
148
|
+
reasonCodes: [JsTsSafeMergeConflictCodes.parserLedgerLoss]
|
|
149
|
+
},
|
|
150
|
+
summary: {
|
|
151
|
+
...topLevelResult.summary,
|
|
152
|
+
conflicts: conflicts.length,
|
|
153
|
+
gatesPassed: 0,
|
|
154
|
+
memberRegions: memberAnalysis.preparedRegions.length,
|
|
155
|
+
memberAdditions: 0,
|
|
156
|
+
composedPhases: 2
|
|
157
|
+
},
|
|
158
|
+
metadata: {
|
|
159
|
+
...topLevelResult.metadata,
|
|
160
|
+
composed: {
|
|
161
|
+
phase: 'member-application',
|
|
162
|
+
reasonCodes
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export {
|
|
169
|
+
safeMergeJsTsSource
|
|
170
|
+
};
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { findContainer } from './js-ts-semantic-merge-member-containers.js';
|
|
2
|
+
import { uniqueStrings } from './js-ts-semantic-merge-member-utils.js';
|
|
3
|
+
|
|
1
4
|
function canonicalizeSourceBodies(sourceText, preparedRegions, side) {
|
|
2
5
|
let output = sourceText;
|
|
3
6
|
const replacements = preparedRegions
|
|
@@ -10,15 +13,29 @@ function canonicalizeSourceBodies(sourceText, preparedRegions, side) {
|
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
function applyMemberAdditions(headSourceText, preparedRegions) {
|
|
13
|
-
|
|
16
|
+
return applyPreparedMemberAdditions(headSourceText, preparedRegions, ['worker']).sourceText;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function applyPreparedMemberAdditions(sourceText, preparedRegions, sides = ['worker']) {
|
|
20
|
+
let output = sourceText;
|
|
21
|
+
const reasonCodes = [];
|
|
14
22
|
const replacements = preparedRegions
|
|
15
|
-
.
|
|
16
|
-
|
|
23
|
+
.map((region) => {
|
|
24
|
+
const match = findContainer(sourceText, region.policy);
|
|
25
|
+
if (match.reasonCodes.length) {
|
|
26
|
+
reasonCodes.push(...match.reasonCodes.map((reason) => `target-${reason}:${region.kind}:${region.name}`));
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
const members = sides.flatMap((side) => region[`${side}AddedMembers`] ?? []);
|
|
30
|
+
if (!members.length) return undefined;
|
|
31
|
+
return { range: match.value, replacement: appendMembersToBody(match.value.body, members) };
|
|
32
|
+
})
|
|
33
|
+
.filter(Boolean)
|
|
17
34
|
.sort((left, right) => right.range.bodyStart - left.range.bodyStart);
|
|
18
35
|
for (const { range, replacement } of replacements) {
|
|
19
36
|
output = `${output.slice(0, range.bodyStart)}${replacement}${output.slice(range.bodyEnd)}`;
|
|
20
37
|
}
|
|
21
|
-
return output;
|
|
38
|
+
return { sourceText: output, reasonCodes: uniqueStrings(reasonCodes) };
|
|
22
39
|
}
|
|
23
40
|
|
|
24
41
|
function appendMembersToBody(body, members) {
|
|
@@ -60,5 +77,6 @@ function leadingWhitespace(line) {
|
|
|
60
77
|
|
|
61
78
|
export {
|
|
62
79
|
applyMemberAdditions,
|
|
80
|
+
applyPreparedMemberAdditions,
|
|
63
81
|
canonicalizeSourceBodies
|
|
64
82
|
};
|
package/package.json
CHANGED