@shapeshift-labs/frontier-lang-compiler 0.2.94 → 0.2.95
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/declarations/bidirectional-target-change.d.ts +54 -0
- package/dist/declarations/semantic-patch-bundle-index.d.ts +3 -0
- package/dist/declarations/semantic-patch-bundle.d.ts +9 -0
- package/dist/internal/index-impl/bidirectionalTargetChangeRecordInternals.js +9 -3
- package/dist/internal/index-impl/bidirectionalTargetPortability.js +152 -0
- package/dist/internal/index-impl/createBidirectionalTargetChangeRecord.js +24 -1
- package/dist/internal/index-impl/semanticPatchBundleRecords.js +16 -7
- package/package.json +1 -1
|
@@ -13,6 +13,15 @@ import type { SemanticLineageEvent, SemanticLineageResolution } from './semantic
|
|
|
13
13
|
import type { SemanticPatchBundleRecord } from './semantic-patch-bundle.js';
|
|
14
14
|
|
|
15
15
|
export type BidirectionalTargetChangeAnchorStatus = 'matched' | 'unmatched' | 'ambiguous' | 'deleted' | string;
|
|
16
|
+
export type BidirectionalTargetPortabilityStatus = 'portable' | 'needs-port' | 'stale' | 'conflict' | 'blocked' | 'evidence-only' | string;
|
|
17
|
+
export type BidirectionalTargetPortabilityAction =
|
|
18
|
+
| 'port-with-source-map-review'
|
|
19
|
+
| 'human-port'
|
|
20
|
+
| 'refresh-source-map'
|
|
21
|
+
| 'resolve-anchor-conflict'
|
|
22
|
+
| 'block'
|
|
23
|
+
| 'record-evidence'
|
|
24
|
+
| string;
|
|
16
25
|
|
|
17
26
|
export interface BidirectionalTargetChangeSourceAnchorMapping {
|
|
18
27
|
readonly targetAnchorKey?: string;
|
|
@@ -62,6 +71,20 @@ export interface BidirectionalTargetChangeAnchor {
|
|
|
62
71
|
readonly metadata?: Record<string, unknown>;
|
|
63
72
|
}
|
|
64
73
|
|
|
74
|
+
export interface BidirectionalTargetMatchPortability {
|
|
75
|
+
readonly status: BidirectionalTargetPortabilityStatus;
|
|
76
|
+
readonly action: BidirectionalTargetPortabilityAction;
|
|
77
|
+
readonly readiness: SemanticMergeReadiness | string;
|
|
78
|
+
readonly confidence?: number;
|
|
79
|
+
readonly reviewRequired: true;
|
|
80
|
+
readonly autoMergeClaim: false;
|
|
81
|
+
readonly semanticEquivalenceClaim: false;
|
|
82
|
+
readonly reasonCodes: readonly string[];
|
|
83
|
+
readonly sourceMapLinkIds: readonly string[];
|
|
84
|
+
readonly sourceMapMappingIds: readonly string[];
|
|
85
|
+
readonly staleSourceMapLinkIds: readonly string[];
|
|
86
|
+
}
|
|
87
|
+
|
|
65
88
|
export interface BidirectionalTargetChangeSourceAnchorMatch {
|
|
66
89
|
readonly kind: 'frontier.lang.bidirectionalTargetChangeSourceAnchorMatch';
|
|
67
90
|
readonly version: 1;
|
|
@@ -70,6 +93,7 @@ export interface BidirectionalTargetChangeSourceAnchorMatch {
|
|
|
70
93
|
readonly sourceAnchors: readonly BidirectionalTargetChangeAnchor[];
|
|
71
94
|
readonly lineageResolutions: readonly SemanticLineageResolution[];
|
|
72
95
|
readonly sourceMapLinks: readonly BidirectionalTargetChangeSourceMapLink[];
|
|
96
|
+
readonly portability?: BidirectionalTargetMatchPortability;
|
|
73
97
|
readonly status: BidirectionalTargetChangeAnchorStatus;
|
|
74
98
|
readonly confidence?: number;
|
|
75
99
|
readonly reasonCodes: readonly string[];
|
|
@@ -79,6 +103,31 @@ export interface BidirectionalTargetChangeSourceAnchorMatch {
|
|
|
79
103
|
readonly conflictKeys: readonly string[];
|
|
80
104
|
}
|
|
81
105
|
|
|
106
|
+
export interface BidirectionalTargetPortabilityRecord {
|
|
107
|
+
readonly kind: 'frontier.lang.bidirectionalTargetPortability';
|
|
108
|
+
readonly version: 1;
|
|
109
|
+
readonly id?: string;
|
|
110
|
+
readonly status: BidirectionalTargetPortabilityStatus;
|
|
111
|
+
readonly action: BidirectionalTargetPortabilityAction;
|
|
112
|
+
readonly readiness: SemanticMergeReadiness | string;
|
|
113
|
+
readonly confidence?: number;
|
|
114
|
+
readonly reviewRequired: true;
|
|
115
|
+
readonly autoMergeClaim: false;
|
|
116
|
+
readonly semanticEquivalenceClaim: false;
|
|
117
|
+
readonly reasonCodes: readonly string[];
|
|
118
|
+
readonly conflictKeys: readonly string[];
|
|
119
|
+
readonly sourceAnchorMatchIds: readonly string[];
|
|
120
|
+
readonly sourceMapLinkIds: readonly string[];
|
|
121
|
+
readonly sourceMapMappingIds: readonly string[];
|
|
122
|
+
readonly staleSourceMapLinkIds: readonly string[];
|
|
123
|
+
readonly targetChangedRegions: number;
|
|
124
|
+
readonly matchedTargetRegions: number;
|
|
125
|
+
readonly sourceMapBackedRegions: number;
|
|
126
|
+
readonly unmatchedTargetRegions: number;
|
|
127
|
+
readonly ambiguousTargetRegions: number;
|
|
128
|
+
readonly deletedSourceAnchors: number;
|
|
129
|
+
}
|
|
130
|
+
|
|
82
131
|
export interface CreateBidirectionalTargetChangeRecordOptions {
|
|
83
132
|
readonly id?: string;
|
|
84
133
|
readonly source?: NativeSourceImportResult | ImportNativeSourceOptions;
|
|
@@ -130,6 +179,7 @@ export interface BidirectionalTargetChangeRecord {
|
|
|
130
179
|
readonly sourceImport?: NativeSourceImportResult;
|
|
131
180
|
readonly targetChangeSet: NativeSourceChangeSet;
|
|
132
181
|
readonly sourceAnchorMatches: readonly BidirectionalTargetChangeSourceAnchorMatch[];
|
|
182
|
+
readonly targetPortability: BidirectionalTargetPortabilityRecord;
|
|
133
183
|
readonly sourcePatchBundle: SemanticPatchBundleRecord;
|
|
134
184
|
readonly historyRecord: SemanticHistoryRecord;
|
|
135
185
|
readonly evidence: readonly EvidenceRecord[];
|
|
@@ -143,6 +193,10 @@ export interface BidirectionalTargetChangeRecord {
|
|
|
143
193
|
readonly deletedSourceAnchors: number;
|
|
144
194
|
readonly sourceChangedRegions: number;
|
|
145
195
|
readonly sourceMapBackedMatches: number;
|
|
196
|
+
readonly targetPortabilityStatus: BidirectionalTargetPortabilityStatus;
|
|
197
|
+
readonly portableTargetRegions: number;
|
|
198
|
+
readonly staleTargetRegions: number;
|
|
199
|
+
readonly conflictingTargetRegions: number;
|
|
146
200
|
};
|
|
147
201
|
readonly metadata: {
|
|
148
202
|
readonly autoMergeClaim: false;
|
|
@@ -36,6 +36,9 @@ export interface SemanticPatchBundleRecordIndex {
|
|
|
36
36
|
readonly transformTargetLanguages: readonly string[];
|
|
37
37
|
readonly transformSourcePaths: readonly string[];
|
|
38
38
|
readonly transformTargetPaths: readonly string[];
|
|
39
|
+
readonly targetPortabilityStatuses: readonly string[];
|
|
40
|
+
readonly targetPortabilityActions: readonly string[];
|
|
41
|
+
readonly targetPortabilityReasonCodes: readonly string[];
|
|
39
42
|
readonly patchIds: readonly string[];
|
|
40
43
|
readonly mergeCandidateIds: readonly string[];
|
|
41
44
|
readonly readinesses: readonly string[];
|
|
@@ -10,6 +10,7 @@ import type { NativeSourceChangeKind, NativeSourceChangeSet } from './native-dif
|
|
|
10
10
|
import type { SemanticEditProjection, SemanticEditReplay, SemanticEditScript } from './semantic-edit-script.js';
|
|
11
11
|
import type { SemanticPatchBundleRecordIndex } from './semantic-patch-bundle-index.js';
|
|
12
12
|
import type { SemanticTransformIdentityRecord } from './semantic-transform-identity.js';
|
|
13
|
+
import type { BidirectionalTargetPortabilityRecord } from './bidirectional-target-change.js';
|
|
13
14
|
|
|
14
15
|
export type { SemanticPatchBundleRecordIndex } from './semantic-patch-bundle-index.js';
|
|
15
16
|
|
|
@@ -56,6 +57,7 @@ export interface SemanticPatchBundleChangedRegion {
|
|
|
56
57
|
readonly reasonCodes?: readonly string[];
|
|
57
58
|
readonly conflictKeys?: readonly string[];
|
|
58
59
|
};
|
|
60
|
+
readonly metadata?: Record<string, unknown>;
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
export interface SemanticPatchBundleSourceMapLink {
|
|
@@ -185,6 +187,7 @@ export interface CreateSemanticPatchBundleRecordOptions {
|
|
|
185
187
|
readonly semanticEditReplays?: readonly SemanticEditReplay[] | SemanticEditReplay;
|
|
186
188
|
readonly semanticTransformIdentity?: SemanticTransformIdentityRecord | Record<string, unknown>;
|
|
187
189
|
readonly semanticTransformIdentities?: readonly (SemanticTransformIdentityRecord | Record<string, unknown>)[];
|
|
190
|
+
readonly targetPortability?: BidirectionalTargetPortabilityRecord | Record<string, unknown>;
|
|
188
191
|
readonly sourceLanguage?: FrontierSourceLanguage | string;
|
|
189
192
|
readonly targetLanguage?: FrontierSourceLanguage | string;
|
|
190
193
|
readonly conflictKeys?: readonly string[] | string;
|
|
@@ -275,6 +278,12 @@ export interface SemanticPatchBundleRecordQuery {
|
|
|
275
278
|
readonly transformSourcePaths?: readonly string[];
|
|
276
279
|
readonly transformTargetPath?: string | readonly string[];
|
|
277
280
|
readonly transformTargetPaths?: readonly string[];
|
|
281
|
+
readonly targetPortabilityStatus?: string | readonly string[];
|
|
282
|
+
readonly targetPortabilityStatuses?: readonly string[];
|
|
283
|
+
readonly targetPortabilityAction?: string | readonly string[];
|
|
284
|
+
readonly targetPortabilityActions?: readonly string[];
|
|
285
|
+
readonly targetPortabilityReasonCode?: string | readonly string[];
|
|
286
|
+
readonly targetPortabilityReasonCodes?: readonly string[];
|
|
278
287
|
readonly readiness?: SemanticMergeReadiness | string | readonly string[];
|
|
279
288
|
readonly readinesses?: readonly string[];
|
|
280
289
|
readonly admissionStatus?: SemanticPatchBundleAdmissionStatus | readonly string[];
|
|
@@ -55,6 +55,7 @@ export function classifyBidirectionalReadiness(targetChangeSet, source, matches)
|
|
|
55
55
|
|
|
56
56
|
export function sourceRegionsForMatch(match, readiness) {
|
|
57
57
|
const anchors = match.sourceAnchors.length ? match.sourceAnchors : [undefined];
|
|
58
|
+
const portability = match.portability;
|
|
58
59
|
return anchors.map((anchor, index) => compactRecord({
|
|
59
60
|
id: `source_port_region_${idFragment(match.id)}_${index + 1}`,
|
|
60
61
|
key: anchor?.key ?? `unmapped-target#${match.targetRegion.key ?? match.targetRegion.id}`,
|
|
@@ -70,9 +71,9 @@ export function sourceRegionsForMatch(match, readiness) {
|
|
|
70
71
|
sourceSpan: anchor?.sourceSpan,
|
|
71
72
|
sourceMapLinks: match.sourceMapLinks,
|
|
72
73
|
admission: {
|
|
73
|
-
readiness,
|
|
74
|
-
action: 'review-port-from-target-change',
|
|
75
|
-
reasonCodes: match.reasonCodes,
|
|
74
|
+
readiness: portability?.readiness ?? readiness,
|
|
75
|
+
action: portability?.action ?? 'review-port-from-target-change',
|
|
76
|
+
reasonCodes: uniqueStrings([...match.reasonCodes, ...array(portability?.reasonCodes)]),
|
|
76
77
|
conflictKeys: match.conflictKeys
|
|
77
78
|
},
|
|
78
79
|
metadata: {
|
|
@@ -81,6 +82,7 @@ export function sourceRegionsForMatch(match, readiness) {
|
|
|
81
82
|
targetRegion: match.targetRegion,
|
|
82
83
|
sourceMapLinkIds: match.sourceMapLinks.map((link) => link.id),
|
|
83
84
|
lineageResolutionIds: match.lineageResolutions.map((resolution) => resolution.id),
|
|
85
|
+
targetPortability: portability,
|
|
84
86
|
reviewRequired: true,
|
|
85
87
|
autoMergeClaim: false,
|
|
86
88
|
semanticEquivalenceClaim: false
|
|
@@ -104,6 +106,10 @@ export function createBidirectionalEvidence(context) {
|
|
|
104
106
|
sourceAnchorMatchIds: context.sourceAnchorMatches.map((match) => match.id),
|
|
105
107
|
sourceMapBackedMatches: context.sourceAnchorMatches.filter((match) => match.sourceMapLinks.length > 0).length,
|
|
106
108
|
sourceMapLinkIds: context.sourceAnchorMatches.flatMap((match) => match.sourceMapLinks.map((link) => link.id)),
|
|
109
|
+
targetPortabilityStatus: context.targetPortability?.status,
|
|
110
|
+
targetPortabilityAction: context.targetPortability?.action,
|
|
111
|
+
targetPortabilityReasonCodes: context.targetPortability?.reasonCodes,
|
|
112
|
+
targetPortabilitySourceMapLinkIds: context.targetPortability?.sourceMapLinkIds,
|
|
107
113
|
readiness: context.readiness,
|
|
108
114
|
reasons: context.reasons,
|
|
109
115
|
autoMergeClaim: false,
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { uniqueStrings } from '../../native-import-utils.js';
|
|
2
|
+
|
|
3
|
+
export function classifyBidirectionalTargetPortability(context = {}) {
|
|
4
|
+
const matches = array(context.sourceAnchorMatches);
|
|
5
|
+
const targetRegions = Number(context.targetChangeSet?.changedRegions?.length ?? matches.length);
|
|
6
|
+
const links = matches.flatMap((match) => array(match.sourceMapLinks));
|
|
7
|
+
const sourceMapBackedMatches = matches.filter((match) => array(match.sourceMapLinks).length > 0).length;
|
|
8
|
+
const unmatched = matches.filter((match) => match.status === 'unmatched').length;
|
|
9
|
+
const ambiguous = matches.filter((match) => match.status === 'ambiguous').length;
|
|
10
|
+
const deleted = matches.filter((match) => match.status === 'deleted').length;
|
|
11
|
+
const staleLinks = links.filter((link) => sourceMapLinkIsStale(link, context));
|
|
12
|
+
const status = portabilityStatus({ context, targetRegions, matches, sourceMapBackedMatches, unmatched, ambiguous, deleted, staleLinks });
|
|
13
|
+
return compactRecord({
|
|
14
|
+
kind: 'frontier.lang.bidirectionalTargetPortability',
|
|
15
|
+
version: 1,
|
|
16
|
+
id: context.id ? `target_portability_${context.id}` : undefined,
|
|
17
|
+
status,
|
|
18
|
+
action: portabilityAction(status),
|
|
19
|
+
readiness: status === 'blocked' ? 'blocked' : 'needs-review',
|
|
20
|
+
confidence: portabilityConfidence({ status, targetRegions, sourceMapBackedMatches, unmatched, ambiguous, deleted, staleLinks }),
|
|
21
|
+
reviewRequired: true,
|
|
22
|
+
autoMergeClaim: false,
|
|
23
|
+
semanticEquivalenceClaim: false,
|
|
24
|
+
reasonCodes: portabilityReasons({ context, targetRegions, matches, sourceMapBackedMatches, unmatched, ambiguous, deleted, staleLinks, status }),
|
|
25
|
+
conflictKeys: uniqueStrings(matches.flatMap((match) => array(match.conflictKeys))),
|
|
26
|
+
sourceAnchorMatchIds: uniqueStrings(matches.map((match) => match.id)),
|
|
27
|
+
sourceMapLinkIds: uniqueStrings(links.map((link) => link.id)),
|
|
28
|
+
sourceMapMappingIds: uniqueStrings(links.map((link) => link.sourceMapMappingId)),
|
|
29
|
+
staleSourceMapLinkIds: uniqueStrings(staleLinks.map((link) => link.id)),
|
|
30
|
+
targetChangedRegions: targetRegions,
|
|
31
|
+
matchedTargetRegions: matches.filter((match) => match.status === 'matched').length,
|
|
32
|
+
sourceMapBackedRegions: sourceMapBackedMatches,
|
|
33
|
+
unmatchedTargetRegions: unmatched,
|
|
34
|
+
ambiguousTargetRegions: ambiguous,
|
|
35
|
+
deletedSourceAnchors: deleted
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function attachBidirectionalMatchPortability(match = {}, context = {}) {
|
|
40
|
+
return {
|
|
41
|
+
...match,
|
|
42
|
+
portability: classifyBidirectionalMatchPortability(match, context)
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function classifyBidirectionalMatchPortability(match = {}, context = {}) {
|
|
47
|
+
const links = array(match.sourceMapLinks);
|
|
48
|
+
const staleLinks = links.filter((link) => sourceMapLinkIsStale(link, context));
|
|
49
|
+
const status = matchPortabilityStatus(match, links, staleLinks);
|
|
50
|
+
return compactRecord({
|
|
51
|
+
status,
|
|
52
|
+
action: portabilityAction(status),
|
|
53
|
+
readiness: status === 'blocked' ? 'blocked' : 'needs-review',
|
|
54
|
+
confidence: matchPortabilityConfidence(status, links),
|
|
55
|
+
reviewRequired: true,
|
|
56
|
+
autoMergeClaim: false,
|
|
57
|
+
semanticEquivalenceClaim: false,
|
|
58
|
+
reasonCodes: matchPortabilityReasons(match, links, staleLinks, status),
|
|
59
|
+
sourceMapLinkIds: uniqueStrings(links.map((link) => link.id)),
|
|
60
|
+
sourceMapMappingIds: uniqueStrings(links.map((link) => link.sourceMapMappingId)),
|
|
61
|
+
staleSourceMapLinkIds: uniqueStrings(staleLinks.map((link) => link.id))
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function portabilityStatus(input) {
|
|
66
|
+
if (!input.context.source) return 'blocked';
|
|
67
|
+
if (input.targetRegions === 0 || input.matches.length === 0) return 'evidence-only';
|
|
68
|
+
if (input.deleted > 0) return 'blocked';
|
|
69
|
+
if (input.unmatched === input.targetRegions) return 'blocked';
|
|
70
|
+
if (input.staleLinks.length > 0) return 'stale';
|
|
71
|
+
if (input.ambiguous > 0) return 'conflict';
|
|
72
|
+
if (input.unmatched > 0) return 'needs-port';
|
|
73
|
+
if (input.sourceMapBackedMatches === input.targetRegions) return 'portable';
|
|
74
|
+
return 'needs-port';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function portabilityAction(status) {
|
|
78
|
+
if (status === 'portable') return 'port-with-source-map-review';
|
|
79
|
+
if (status === 'needs-port') return 'human-port';
|
|
80
|
+
if (status === 'stale') return 'refresh-source-map';
|
|
81
|
+
if (status === 'conflict') return 'resolve-anchor-conflict';
|
|
82
|
+
if (status === 'blocked') return 'block';
|
|
83
|
+
return 'record-evidence';
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function matchPortabilityStatus(match, links, staleLinks) {
|
|
87
|
+
if (match.status === 'deleted' || match.status === 'unmatched') return 'blocked';
|
|
88
|
+
if (staleLinks.length > 0) return 'stale';
|
|
89
|
+
if (match.status === 'ambiguous') return 'conflict';
|
|
90
|
+
if (match.status === 'matched' && links.length > 0) return 'portable';
|
|
91
|
+
return 'needs-port';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function matchPortabilityConfidence(status, links) {
|
|
95
|
+
if (status === 'portable') return 0.72;
|
|
96
|
+
if (status === 'needs-port') return links.length > 0 ? 0.52 : 0.35;
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function matchPortabilityReasons(match, links, staleLinks, status) {
|
|
101
|
+
return uniqueStrings([
|
|
102
|
+
status === 'portable' ? 'target-region-source-map-portable' : undefined,
|
|
103
|
+
links.length > 0 ? 'target-region-source-map-backed' : undefined,
|
|
104
|
+
links.length === 0 ? 'target-region-not-source-map-backed' : undefined,
|
|
105
|
+
match.status === 'unmatched' ? 'target-anchor-unmatched' : undefined,
|
|
106
|
+
match.status === 'ambiguous' ? 'target-anchor-ambiguous' : undefined,
|
|
107
|
+
match.status === 'deleted' ? 'target-anchor-deleted' : undefined,
|
|
108
|
+
staleLinks.length > 0 ? 'target-source-map-stale' : undefined,
|
|
109
|
+
'target-region-is-portability-evidence-not-proof'
|
|
110
|
+
]);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function portabilityConfidence(input) {
|
|
114
|
+
if (input.status === 'portable') return 0.74;
|
|
115
|
+
if (input.status === 'needs-port') return input.sourceMapBackedMatches > 0 ? 0.52 : 0.35;
|
|
116
|
+
if (input.status === 'evidence-only') return 0.25;
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function portabilityReasons(input) {
|
|
121
|
+
const sourceMapBacked = input.sourceMapBackedMatches > 0;
|
|
122
|
+
return uniqueStrings([
|
|
123
|
+
input.context.source ? undefined : 'source-import-missing',
|
|
124
|
+
input.targetRegions === 0 ? 'target-change-empty' : undefined,
|
|
125
|
+
input.status === 'portable' ? 'target-change-source-map-portable' : undefined,
|
|
126
|
+
sourceMapBacked ? 'target-change-source-map-backed' : undefined,
|
|
127
|
+
input.sourceMapBackedMatches < input.targetRegions ? 'target-change-not-fully-source-map-backed' : undefined,
|
|
128
|
+
input.unmatched > 0 ? 'target-anchor-unmatched' : undefined,
|
|
129
|
+
input.ambiguous > 0 ? 'target-anchor-ambiguous' : undefined,
|
|
130
|
+
input.deleted > 0 ? 'target-anchor-deleted' : undefined,
|
|
131
|
+
input.staleLinks.length > 0 ? 'target-source-map-stale' : undefined,
|
|
132
|
+
'target-change-is-portability-evidence-not-proof',
|
|
133
|
+
...input.matches.flatMap((match) => array(match.reasonCodes))
|
|
134
|
+
]);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function sourceMapLinkIsStale(link, context) {
|
|
138
|
+
const currentSourceHash = context.currentSourceHash;
|
|
139
|
+
const baseTargetHash = context.targetChangeSet?.beforeHash;
|
|
140
|
+
return Boolean(
|
|
141
|
+
(link.sourceHash && currentSourceHash && link.sourceHash !== currentSourceHash)
|
|
142
|
+
|| (link.targetHash && baseTargetHash && link.targetHash !== baseTargetHash)
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function array(value) {
|
|
147
|
+
return value === undefined || value === null ? [] : Array.isArray(value) ? value : [value];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function compactRecord(value) {
|
|
151
|
+
return Object.fromEntries(Object.entries(value ?? {}).filter(([, entry]) => entry !== undefined && (!Array.isArray(entry) || entry.length > 0)));
|
|
152
|
+
}
|
|
@@ -8,6 +8,7 @@ import { createSemanticPatchBundleRecord } from './semanticPatchBundleRecords.js
|
|
|
8
8
|
import { createSemanticHistoryRecord } from './semanticHistoryRecords.js';
|
|
9
9
|
import { diffNativeSourceImports } from './diffNativeSourceImports.js';
|
|
10
10
|
import { normalizeNativeDiffImport } from './normalizeNativeDiffImport.js';
|
|
11
|
+
import { attachBidirectionalMatchPortability, classifyBidirectionalTargetPortability } from './bidirectionalTargetPortability.js';
|
|
11
12
|
import {
|
|
12
13
|
anchorsFromSourceSidecar,
|
|
13
14
|
classifyBidirectionalReadiness,
|
|
@@ -64,12 +65,24 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
64
65
|
mappings,
|
|
65
66
|
sourceMaps,
|
|
66
67
|
lineage
|
|
68
|
+
})).map((match) => attachBidirectionalMatchPortability(match, {
|
|
69
|
+
currentSourceHash: sourceHash(source),
|
|
70
|
+
targetChangeSet
|
|
67
71
|
}));
|
|
72
|
+
const targetPortability = classifyBidirectionalTargetPortability({
|
|
73
|
+
id,
|
|
74
|
+
source,
|
|
75
|
+
currentSourceHash: sourceHash(source),
|
|
76
|
+
targetChangeSet,
|
|
77
|
+
sourceAnchorMatches
|
|
78
|
+
});
|
|
68
79
|
const readiness = classifyBidirectionalReadiness(targetChangeSet, source, sourceAnchorMatches);
|
|
69
80
|
const reasons = uniqueStrings([
|
|
70
81
|
'source-port-review-required',
|
|
71
82
|
'target-change-is-merge-evidence-not-proof',
|
|
83
|
+
`target-portability:${targetPortability.status}`,
|
|
72
84
|
...array(targetChangeSet.reasons),
|
|
85
|
+
...array(targetPortability.reasonCodes),
|
|
73
86
|
...sourceAnchorMatches.flatMap((match) => match.reasonCodes)
|
|
74
87
|
]);
|
|
75
88
|
const evidence = [createBidirectionalEvidence({
|
|
@@ -78,6 +91,7 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
78
91
|
source,
|
|
79
92
|
targetChangeSet,
|
|
80
93
|
sourceAnchorMatches,
|
|
94
|
+
targetPortability,
|
|
81
95
|
readiness,
|
|
82
96
|
reasons
|
|
83
97
|
})];
|
|
@@ -97,6 +111,7 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
97
111
|
targetChangeSetId: targetChangeSet.id,
|
|
98
112
|
targetPatchId: targetChangeSet.patch?.id,
|
|
99
113
|
targetMergeCandidateId: targetChangeSet.mergeCandidate?.id,
|
|
114
|
+
targetPortability,
|
|
100
115
|
sourceMapBackprojection: summarizeSourceMapBackprojection(sourceAnchorMatches)
|
|
101
116
|
}
|
|
102
117
|
}, {
|
|
@@ -106,6 +121,7 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
106
121
|
admission: { status: readiness === 'blocked' ? 'blocked' : 'needs-review', readiness },
|
|
107
122
|
metadata: {
|
|
108
123
|
source: 'createBidirectionalTargetChangeRecord',
|
|
124
|
+
targetPortability,
|
|
109
125
|
autoMergeClaim: false,
|
|
110
126
|
semanticEquivalenceClaim: false
|
|
111
127
|
}
|
|
@@ -138,6 +154,7 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
138
154
|
bidirectionalTargetChangeId: id,
|
|
139
155
|
sourcePatchBundleId: sourcePatchBundle.id,
|
|
140
156
|
targetChangeSetId: targetChangeSet.id,
|
|
157
|
+
targetPortability,
|
|
141
158
|
sourceMapBackprojection: summarizeSourceMapBackprojection(sourceAnchorMatches),
|
|
142
159
|
autoMergeClaim: false,
|
|
143
160
|
semanticEquivalenceClaim: false
|
|
@@ -154,6 +171,7 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
154
171
|
sourceImport: source,
|
|
155
172
|
targetChangeSet,
|
|
156
173
|
sourceAnchorMatches,
|
|
174
|
+
targetPortability,
|
|
157
175
|
sourcePatchBundle,
|
|
158
176
|
historyRecord,
|
|
159
177
|
evidence,
|
|
@@ -166,12 +184,17 @@ export function createBidirectionalTargetChangeRecord(input = {}, options = {})
|
|
|
166
184
|
unmatchedTargetRegions: sourceAnchorMatches.filter((match) => match.status === 'unmatched').length,
|
|
167
185
|
deletedSourceAnchors: sourceAnchorMatches.filter((match) => match.status === 'deleted').length,
|
|
168
186
|
sourceChangedRegions: sourceChangedRegions.length,
|
|
169
|
-
sourceMapBackedMatches: sourceAnchorMatches.filter((match) => match.sourceMapLinks.length > 0).length
|
|
187
|
+
sourceMapBackedMatches: sourceAnchorMatches.filter((match) => match.sourceMapLinks.length > 0).length,
|
|
188
|
+
targetPortabilityStatus: targetPortability.status,
|
|
189
|
+
portableTargetRegions: targetPortability.status === 'portable' ? targetPortability.targetChangedRegions : 0,
|
|
190
|
+
staleTargetRegions: targetPortability.status === 'stale' ? targetPortability.targetChangedRegions : 0,
|
|
191
|
+
conflictingTargetRegions: targetPortability.status === 'conflict' ? targetPortability.ambiguousTargetRegions : 0
|
|
170
192
|
},
|
|
171
193
|
metadata: {
|
|
172
194
|
autoMergeClaim: false,
|
|
173
195
|
semanticEquivalenceClaim: false,
|
|
174
196
|
reviewRequired: true,
|
|
197
|
+
targetPortability,
|
|
175
198
|
...input.metadata
|
|
176
199
|
}
|
|
177
200
|
};
|
|
@@ -16,6 +16,7 @@ export function createSemanticPatchBundleRecord(input={},options={}){
|
|
|
16
16
|
const transformContext={sourceLanguage:options.sourceLanguage??source.sourceLanguage??source.language,targetLanguage:options.targetLanguage??source.targetLanguage};
|
|
17
17
|
const semanticTransformIdentities=normalizeSemanticTransformIdentityRecords(semanticTransformInputs(source,options),transformContext);
|
|
18
18
|
const semanticTransformIndex=semanticTransformRecordIndex(semanticTransformIdentities,source);
|
|
19
|
+
const targetPortability=options.targetPortability??source.targetPortability??source.metadata?.targetPortability??options.metadata?.targetPortability;
|
|
19
20
|
const regionInputs=array(options.changedRegions??source.changedRegions??source.regions);
|
|
20
21
|
const sourceMapLinks=normalizeSourceMapLinks([
|
|
21
22
|
...array(options.sourceMapLinks??source.sourceMapLinks),
|
|
@@ -50,7 +51,7 @@ export function createSemanticPatchBundleRecord(input={},options={}){
|
|
|
50
51
|
??`semantic_patch_bundle_${idFragment(firstString(source.id,patchId,mergeCandidateId,source.sourcePath,source.language,'record'))}`;
|
|
51
52
|
const language=options.language??source.language??mergeCandidate?.language??sources.find((item)=>item.language)?.language;
|
|
52
53
|
const sourcePath=options.sourcePath??source.sourcePath??mergeCandidate?.sourcePath??sources.find((item)=>item.sourcePath)?.sourcePath;
|
|
53
|
-
const index=recordIndex({baseHash,targetHash,sources,changedRegions,sourceMapLinks,evidenceIds,proofIds,historyIds,semanticOperationIds,patchId,mergeCandidateId,admission,semanticEditIndex,semanticTransformIndex});
|
|
54
|
+
const index=recordIndex({baseHash,targetHash,sources,changedRegions,sourceMapLinks,evidenceIds,proofIds,historyIds,semanticOperationIds,patchId,mergeCandidateId,admission,semanticEditIndex,semanticTransformIndex,targetPortability});
|
|
54
55
|
return{
|
|
55
56
|
kind:'frontier.lang.semanticPatchBundleRecord',
|
|
56
57
|
version:1,
|
|
@@ -85,6 +86,7 @@ export function createSemanticPatchBundleRecord(input={},options={}){
|
|
|
85
86
|
semanticMergeConflictSummary:source.metadata?.semanticMergeConflictSummary,
|
|
86
87
|
semanticEditSummary:semanticEditSummary(semanticEditIndex),
|
|
87
88
|
semanticTransformSummary:semanticTransformSummary(semanticTransformIndex),
|
|
89
|
+
targetPortability,
|
|
88
90
|
...options.metadata
|
|
89
91
|
})
|
|
90
92
|
};
|
|
@@ -154,11 +156,12 @@ function normalizeRegions(regions,context){
|
|
|
154
156
|
sourceMapIds:uniqueStrings([...strings(region.sourceMapIds),...links.map((link)=>link.sourceMapId)]),
|
|
155
157
|
sourceMapMappingIds:uniqueStrings([...strings(region.sourceMapMappingIds),...links.map((link)=>link.sourceMapMappingId)]),
|
|
156
158
|
admission:compactRecord({
|
|
157
|
-
readiness:projection?.admission?.readiness,
|
|
158
|
-
action:projection?.admission?.action,
|
|
159
|
-
reasonCodes:uniqueStrings(projection?.admission?.reasons),
|
|
160
|
-
conflictKeys:uniqueStrings(projection?.admission?.conflictKeys)
|
|
161
|
-
})
|
|
159
|
+
readiness:projection?.admission?.readiness??region.admission?.readiness,
|
|
160
|
+
action:projection?.admission?.action??region.admission?.action,
|
|
161
|
+
reasonCodes:uniqueStrings([...strings(region.admission?.reasonCodes),...strings(projection?.admission?.reasons)]),
|
|
162
|
+
conflictKeys:uniqueStrings([...strings(region.admission?.conflictKeys),...strings(projection?.admission?.conflictKeys)])
|
|
163
|
+
}),
|
|
164
|
+
metadata:region.metadata
|
|
162
165
|
});
|
|
163
166
|
});
|
|
164
167
|
}
|
|
@@ -229,6 +232,9 @@ function recordIndex(parts){
|
|
|
229
232
|
transformTargetLanguages:semanticTransformIndex.transformTargetLanguages,
|
|
230
233
|
transformSourcePaths:semanticTransformIndex.transformSourcePaths,
|
|
231
234
|
transformTargetPaths:semanticTransformIndex.transformTargetPaths,
|
|
235
|
+
targetPortabilityStatuses:uniqueStrings([parts.targetPortability?.status]),
|
|
236
|
+
targetPortabilityActions:uniqueStrings([parts.targetPortability?.action]),
|
|
237
|
+
targetPortabilityReasonCodes:uniqueStrings(parts.targetPortability?.reasonCodes),
|
|
232
238
|
patchIds:uniqueStrings([parts.patchId]),
|
|
233
239
|
mergeCandidateIds:uniqueStrings([parts.mergeCandidateId]),
|
|
234
240
|
readinesses:uniqueStrings([parts.admission.readiness,...parts.changedRegions.map((region)=>region.admission?.readiness)]),
|
|
@@ -237,7 +243,7 @@ function recordIndex(parts){
|
|
|
237
243
|
}
|
|
238
244
|
|
|
239
245
|
function matchesRecord(record,query){
|
|
240
|
-
const index=record.index??recordIndex({...record,baseHash:record.baseHash,targetHash:record.targetHash,sources:record.sources??[],changedRegions:record.changedRegions??[],sourceMapLinks:record.sourceMapLinks??[],evidenceIds:record.evidenceIds??[],proofIds:record.proofIds??[],historyIds:record.historyIds??[],semanticOperationIds:record.semanticOperationIds??[],patchId:record.patchId,mergeCandidateId:record.mergeCandidateId,admission:record.admission??{}});
|
|
246
|
+
const index=record.index??recordIndex({...record,baseHash:record.baseHash,targetHash:record.targetHash,sources:record.sources??[],changedRegions:record.changedRegions??[],sourceMapLinks:record.sourceMapLinks??[],evidenceIds:record.evidenceIds??[],proofIds:record.proofIds??[],historyIds:record.historyIds??[],semanticOperationIds:record.semanticOperationIds??[],patchId:record.patchId,mergeCandidateId:record.mergeCandidateId,admission:record.admission??{},targetPortability:record.metadata?.targetPortability});
|
|
241
247
|
return matchAny(queryValues(query.id,query.ids),[record.id])
|
|
242
248
|
&&matchAny(queryValues(query.patchId,query.patchIds),index.patchIds)
|
|
243
249
|
&&matchAny(queryValues(query.mergeCandidateId,query.mergeCandidateIds),index.mergeCandidateIds)
|
|
@@ -278,6 +284,9 @@ function matchesRecord(record,query){
|
|
|
278
284
|
&&matchAny(queryValues(query.transformTargetLanguage,query.transformTargetLanguages),index.transformTargetLanguages)
|
|
279
285
|
&&matchAny(queryValues(query.transformSourcePath,query.transformSourcePaths),index.transformSourcePaths)
|
|
280
286
|
&&matchAny(queryValues(query.transformTargetPath,query.transformTargetPaths),index.transformTargetPaths)
|
|
287
|
+
&&matchAny(queryValues(query.targetPortabilityStatus,query.targetPortabilityStatuses),index.targetPortabilityStatuses)
|
|
288
|
+
&&matchAny(queryValues(query.targetPortabilityAction,query.targetPortabilityActions),index.targetPortabilityActions)
|
|
289
|
+
&&matchAny(queryValues(query.targetPortabilityReasonCode,query.targetPortabilityReasonCodes),index.targetPortabilityReasonCodes)
|
|
281
290
|
&&matchAny(queryValues(query.readiness,query.readinesses),index.readinesses)
|
|
282
291
|
&&matchAny(queryValues(query.admissionStatus,query.admissionStatuses),index.admissionStatuses);
|
|
283
292
|
}
|
package/package.json
CHANGED