@shapeshift-labs/frontier-lang-compiler 0.2.87 → 0.2.89

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.
@@ -0,0 +1,124 @@
1
+ import type { SemanticPatchBundleRecord } from './semantic-patch-bundle.js';
2
+
3
+ export type SemanticPatchBundleOverlapKind =
4
+ | 'operation-content'
5
+ | 'edit-content'
6
+ | 'semantic-edit-key'
7
+ | 'semantic-identity'
8
+ | 'source-identity'
9
+ | 'transform-content'
10
+ | 'semantic-transform'
11
+ | 'projection-identity'
12
+ | 'region'
13
+ | 'conflict-key'
14
+ | 'source-path'
15
+ | string;
16
+
17
+ export type SemanticPatchBundleOverlapStatus =
18
+ | 'duplicate'
19
+ | 'semantic-overlap'
20
+ | 'source-overlap'
21
+ | 'independent'
22
+ | string;
23
+
24
+ export interface SemanticPatchBundleOverlapShared {
25
+ readonly operationContentHashes: readonly string[];
26
+ readonly editContentHashes: readonly string[];
27
+ readonly semanticEditKeys: readonly string[];
28
+ readonly semanticIdentityHashes: readonly string[];
29
+ readonly sourceIdentityHashes: readonly string[];
30
+ readonly semanticTransformContentHashes: readonly string[];
31
+ readonly semanticTransformIdentityHashes: readonly string[];
32
+ readonly projectionIdentityHashes: readonly string[];
33
+ readonly regionKeys: readonly string[];
34
+ readonly conflictKeys: readonly string[];
35
+ readonly sourcePaths: readonly string[];
36
+ readonly baseHashes: readonly string[];
37
+ readonly targetHashes: readonly string[];
38
+ }
39
+
40
+ export interface SemanticPatchBundleOverlapAdmission {
41
+ readonly status: SemanticPatchBundleOverlapStatus;
42
+ readonly reviewRequired: boolean;
43
+ readonly autoMergeClaim: false;
44
+ readonly reasonCodes: readonly string[];
45
+ readonly sharedKeyCount: number;
46
+ }
47
+
48
+ export interface SemanticPatchBundleOverlapRecord {
49
+ readonly kind: 'frontier.lang.semanticPatchBundleOverlapRecord';
50
+ readonly version: 1;
51
+ readonly schema: 'frontier.lang.semanticPatchBundleOverlapRecord.v1';
52
+ readonly id: string;
53
+ readonly leftBundleId: string;
54
+ readonly rightBundleId: string;
55
+ readonly overlapKinds: readonly SemanticPatchBundleOverlapKind[];
56
+ readonly shared: SemanticPatchBundleOverlapShared;
57
+ readonly admission: SemanticPatchBundleOverlapAdmission;
58
+ readonly score: number;
59
+ readonly summary: {
60
+ readonly sharedKeys: number;
61
+ readonly duplicateSignals: number;
62
+ readonly semanticSignals: number;
63
+ readonly sourceSignals: number;
64
+ readonly baseHashMismatch: boolean;
65
+ readonly targetHashMismatch: boolean;
66
+ };
67
+ readonly metadata?: Record<string, unknown>;
68
+ }
69
+
70
+ export interface CompareSemanticPatchBundleRecordsOptions {
71
+ readonly id?: string;
72
+ readonly includeSourcePaths?: boolean;
73
+ readonly reviewIndependent?: boolean;
74
+ readonly metadata?: Record<string, unknown>;
75
+ }
76
+
77
+ export interface SemanticPatchBundleOverlapQuery {
78
+ readonly includeIndependent?: boolean;
79
+ readonly includeSourcePaths?: boolean;
80
+ readonly reviewIndependent?: boolean;
81
+ readonly metadata?: Record<string, unknown>;
82
+ readonly id?: string | readonly string[];
83
+ readonly ids?: readonly string[];
84
+ readonly bundleId?: string | readonly string[];
85
+ readonly bundleIds?: readonly string[];
86
+ readonly status?: SemanticPatchBundleOverlapStatus | readonly string[];
87
+ readonly statuses?: readonly string[];
88
+ readonly admissionStatus?: SemanticPatchBundleOverlapStatus | readonly string[];
89
+ readonly admissionStatuses?: readonly string[];
90
+ readonly overlapKind?: SemanticPatchBundleOverlapKind | readonly string[];
91
+ readonly overlapKinds?: readonly string[];
92
+ readonly reasonCode?: string | readonly string[];
93
+ readonly reasonCodes?: readonly string[];
94
+ readonly sourcePath?: string | readonly string[];
95
+ readonly sourcePaths?: readonly string[];
96
+ readonly conflictKey?: string | readonly string[];
97
+ readonly conflictKeys?: readonly string[];
98
+ readonly semanticEditKey?: string | readonly string[];
99
+ readonly semanticEditKeys?: readonly string[];
100
+ readonly semanticTransformIdentityHash?: string | readonly string[];
101
+ readonly semanticTransformIdentityHashes?: readonly string[];
102
+ readonly semanticTransformContentHash?: string | readonly string[];
103
+ readonly semanticTransformContentHashes?: readonly string[];
104
+ readonly projectionIdentityHash?: string | readonly string[];
105
+ readonly projectionIdentityHashes?: readonly string[];
106
+ readonly operationContentHash?: string | readonly string[];
107
+ readonly operationContentHashes?: readonly string[];
108
+ readonly editContentHash?: string | readonly string[];
109
+ readonly editContentHashes?: readonly string[];
110
+ readonly reviewRequired?: boolean;
111
+ readonly minScore?: number;
112
+ }
113
+
114
+ export declare const SemanticPatchBundleOverlapKinds: readonly SemanticPatchBundleOverlapKind[];
115
+ export declare const SemanticPatchBundleOverlapStatuses: readonly SemanticPatchBundleOverlapStatus[];
116
+ export declare function compareSemanticPatchBundleRecords(
117
+ left?: SemanticPatchBundleRecord | Record<string, unknown>,
118
+ right?: SemanticPatchBundleRecord | Record<string, unknown>,
119
+ options?: CompareSemanticPatchBundleRecordsOptions
120
+ ): SemanticPatchBundleOverlapRecord;
121
+ export declare function querySemanticPatchBundleOverlaps(
122
+ records: SemanticPatchBundleRecord | readonly SemanticPatchBundleRecord[],
123
+ query?: SemanticPatchBundleOverlapQuery
124
+ ): readonly SemanticPatchBundleOverlapRecord[];
@@ -8,6 +8,7 @@ import type {
8
8
  } from '@shapeshift-labs/frontier-lang-kernel';
9
9
  import type { NativeSourceChangeKind, NativeSourceChangeSet } from './native-diff.js';
10
10
  import type { SemanticEditProjection, SemanticEditScript } from './semantic-edit-script.js';
11
+ import type { SemanticTransformIdentityRecord } from './semantic-transform-identity.js';
11
12
 
12
13
  export type SemanticPatchBundleAdmissionStatus = 'proposed' | 'queued' | 'admitted' | 'needs-review' | 'blocked' | 'rejected' | string;
13
14
 
@@ -110,6 +111,15 @@ export interface SemanticPatchBundleRecordIndex {
110
111
  readonly sourceIdentityHashes: readonly string[];
111
112
  readonly operationContentHashes: readonly string[];
112
113
  readonly editContentHashes: readonly string[];
114
+ readonly semanticTransformIds: readonly string[];
115
+ readonly semanticTransformKeys: readonly string[];
116
+ readonly semanticTransformIdentityHashes: readonly string[];
117
+ readonly semanticTransformContentHashes: readonly string[];
118
+ readonly projectionIdentityHashes: readonly string[];
119
+ readonly transformSourceLanguages: readonly string[];
120
+ readonly transformTargetLanguages: readonly string[];
121
+ readonly transformSourcePaths: readonly string[];
122
+ readonly transformTargetPaths: readonly string[];
113
123
  readonly patchIds: readonly string[];
114
124
  readonly mergeCandidateIds: readonly string[];
115
125
  readonly readinesses: readonly string[];
@@ -137,6 +147,7 @@ export interface SemanticPatchBundleRecord {
137
147
  readonly semanticOperationIds: readonly string[];
138
148
  readonly semanticEditScriptIds: readonly string[];
139
149
  readonly semanticEditProjectionIds: readonly string[];
150
+ readonly semanticTransformIdentityIds: readonly string[];
140
151
  readonly admission: SemanticPatchBundleAdmission;
141
152
  readonly index: SemanticPatchBundleRecordIndex;
142
153
  readonly summary: {
@@ -149,6 +160,7 @@ export interface SemanticPatchBundleRecord {
149
160
  readonly semanticEditScripts: number;
150
161
  readonly semanticEditProjections: number;
151
162
  readonly semanticEditProjectionEdits: number;
163
+ readonly semanticTransformIdentities: number;
152
164
  readonly reviewRequired: boolean;
153
165
  readonly autoMergeClaim: false;
154
166
  };
@@ -181,6 +193,10 @@ export interface CreateSemanticPatchBundleRecordOptions {
181
193
  readonly semanticEditScripts?: readonly SemanticEditScript[] | SemanticEditScript;
182
194
  readonly semanticEditProjection?: SemanticEditProjection;
183
195
  readonly semanticEditProjections?: readonly SemanticEditProjection[] | SemanticEditProjection;
196
+ readonly semanticTransformIdentity?: SemanticTransformIdentityRecord | Record<string, unknown>;
197
+ readonly semanticTransformIdentities?: readonly (SemanticTransformIdentityRecord | Record<string, unknown>)[];
198
+ readonly sourceLanguage?: FrontierSourceLanguage | string;
199
+ readonly targetLanguage?: FrontierSourceLanguage | string;
184
200
  readonly conflictKeys?: readonly string[] | string;
185
201
  readonly admission?: Partial<SemanticPatchBundleAdmission>;
186
202
  readonly metadata?: Record<string, unknown>;
@@ -237,6 +253,24 @@ export interface SemanticPatchBundleRecordQuery {
237
253
  readonly operationContentHashes?: readonly string[];
238
254
  readonly editContentHash?: string | readonly string[];
239
255
  readonly editContentHashes?: readonly string[];
256
+ readonly semanticTransformId?: string | readonly string[];
257
+ readonly semanticTransformIds?: readonly string[];
258
+ readonly semanticTransformKey?: string | readonly string[];
259
+ readonly semanticTransformKeys?: readonly string[];
260
+ readonly semanticTransformIdentityHash?: string | readonly string[];
261
+ readonly semanticTransformIdentityHashes?: readonly string[];
262
+ readonly semanticTransformContentHash?: string | readonly string[];
263
+ readonly semanticTransformContentHashes?: readonly string[];
264
+ readonly projectionIdentityHash?: string | readonly string[];
265
+ readonly projectionIdentityHashes?: readonly string[];
266
+ readonly transformSourceLanguage?: string | readonly string[];
267
+ readonly transformSourceLanguages?: readonly string[];
268
+ readonly transformTargetLanguage?: string | readonly string[];
269
+ readonly transformTargetLanguages?: readonly string[];
270
+ readonly transformSourcePath?: string | readonly string[];
271
+ readonly transformSourcePaths?: readonly string[];
272
+ readonly transformTargetPath?: string | readonly string[];
273
+ readonly transformTargetPaths?: readonly string[];
240
274
  readonly readiness?: SemanticMergeReadiness | string | readonly string[];
241
275
  readonly readinesses?: readonly string[];
242
276
  readonly admissionStatus?: SemanticPatchBundleAdmissionStatus | readonly string[];
@@ -0,0 +1,57 @@
1
+ import type { FrontierSourceLanguage } from '@shapeshift-labs/frontier-lang-kernel';
2
+
3
+ export interface SemanticTransformIdentityRecord {
4
+ readonly kind: 'frontier.lang.semanticTransformIdentityRecord';
5
+ readonly version: 1;
6
+ readonly schema: 'frontier.lang.semanticTransformIdentityRecord.v1';
7
+ readonly id: string;
8
+ readonly sourceLanguage?: FrontierSourceLanguage | string;
9
+ readonly targetLanguage?: FrontierSourceLanguage | string;
10
+ readonly sourcePath?: string;
11
+ readonly targetPath?: string;
12
+ readonly baseHash?: string;
13
+ readonly targetHash?: string;
14
+ readonly semanticKey?: string;
15
+ readonly transformKey?: string;
16
+ readonly semanticIdentityHash?: string;
17
+ readonly sourceIdentityHash?: string;
18
+ readonly operationContentHash?: string;
19
+ readonly editContentHash?: string;
20
+ readonly transformIdentityHash?: string;
21
+ readonly projectionIdentityHash?: string;
22
+ readonly transformContentHash?: string;
23
+ readonly readiness?: string;
24
+ readonly confidence?: number;
25
+ readonly evidenceIds?: readonly string[];
26
+ readonly metadata?: {
27
+ readonly autoMergeClaim: false;
28
+ readonly semanticEquivalenceClaim: false;
29
+ readonly sourceTransformId?: string;
30
+ readonly [key: string]: unknown;
31
+ };
32
+ }
33
+
34
+ export interface CreateSemanticTransformIdentityRecordOptions extends Partial<SemanticTransformIdentityRecord> {
35
+ readonly language?: FrontierSourceLanguage | string;
36
+ readonly projectedLanguage?: FrontierSourceLanguage | string;
37
+ readonly originalSourcePath?: string;
38
+ readonly targetSourcePath?: string;
39
+ readonly projectedSourcePath?: string;
40
+ readonly symbolName?: string;
41
+ readonly symbolKind?: string;
42
+ readonly anchorKey?: string;
43
+ readonly regionId?: string;
44
+ readonly operationId?: string;
45
+ }
46
+
47
+ export type CreateSemanticTransformIdentityRecordInput =
48
+ | Partial<SemanticTransformIdentityRecord>
49
+ | Record<string, unknown>;
50
+
51
+ export declare function createSemanticTransformIdentityRecord(
52
+ input?: CreateSemanticTransformIdentityRecordInput,
53
+ options?: CreateSemanticTransformIdentityRecordOptions
54
+ ): SemanticTransformIdentityRecord;
55
+ export declare function semanticTransformIdentityFields(
56
+ record?: SemanticTransformIdentityRecord | Record<string, unknown>
57
+ ): SemanticTransformIdentityRecord;
package/dist/index.d.ts CHANGED
@@ -20,6 +20,8 @@ export * from './declarations/semantic-edit-script.js';
20
20
  export * from './declarations/semantic-lineage.js';
21
21
  export * from './declarations/semantic-history.js';
22
22
  export * from './declarations/semantic-patch-bundle.js';
23
+ export * from './declarations/semantic-patch-bundle-overlaps.js';
24
+ export * from './declarations/semantic-transform-identity.js';
23
25
  export * from './declarations/bidirectional-target-change.js';
24
26
  export * from './declarations/semantic-impact.js';
25
27
  export * from './declarations/semantic-sidecar.js';
package/dist/index.js CHANGED
@@ -67,6 +67,8 @@ export { projectNativeImportToSource } from './internal/index-impl/projectNative
67
67
  export { queryNativeParserFeatureMatrix } from './internal/index-impl/queryNativeParserFeatureMatrix.js';
68
68
  export { queryProjectionReadinessMatrix } from './internal/index-impl/queryProjectionReadinessMatrix.js';
69
69
  export { createSemanticPatchBundleRecord, querySemanticPatchBundleRecords, SemanticPatchBundleAdmissionStatuses } from './internal/index-impl/semanticPatchBundleRecords.js';
70
+ export { compareSemanticPatchBundleRecords, querySemanticPatchBundleOverlaps, SemanticPatchBundleOverlapKinds, SemanticPatchBundleOverlapStatuses } from './internal/index-impl/semanticPatchBundleOverlaps.js';
71
+ export { createSemanticTransformIdentityRecord, semanticTransformIdentityFields } from './internal/index-impl/semanticTransformIdentityRecords.js';
70
72
  export { createSemanticMergeCandidateAdmissionRecord, decorateSemanticMergeCandidateForAdmission, querySemanticMergeCandidateAdmissionOverlaps, SemanticMergeCandidateProjectionRisks, semanticMergeCandidateReadinessSortKey, sortSemanticMergeCandidateAdmissionRecords } from './internal/index-impl/semanticMergeCandidateRecords.js';
71
73
  export { querySemanticMergeConflictClasses, SemanticMergeConflictClasses, semanticMergeConflictRiskScore, sortSemanticMergeCandidatesByConflictRisk, summarizeSemanticMergeConflicts } from './internal/index-impl/semanticMergeConflicts.js';
72
74
  export { createSemanticEditScript, SemanticEditScriptAdmissionStatuses } from './internal/index-impl/semanticEditScripts.js';
@@ -0,0 +1,191 @@
1
+ import{idFragment,uniqueStrings as uniqueRawStrings}from'../../native-import-utils.js';
2
+
3
+ export const SemanticPatchBundleOverlapKinds=Object.freeze([
4
+ 'operation-content',
5
+ 'edit-content',
6
+ 'semantic-edit-key',
7
+ 'semantic-identity',
8
+ 'source-identity',
9
+ 'transform-content',
10
+ 'semantic-transform',
11
+ 'projection-identity',
12
+ 'region',
13
+ 'conflict-key',
14
+ 'source-path'
15
+ ]);
16
+
17
+ export const SemanticPatchBundleOverlapStatuses=Object.freeze([
18
+ 'duplicate',
19
+ 'semantic-overlap',
20
+ 'source-overlap',
21
+ 'independent'
22
+ ]);
23
+
24
+ const KIND_FIELDS=Object.freeze({
25
+ 'operation-content':'operationContentHashes',
26
+ 'edit-content':'editContentHashes',
27
+ 'semantic-edit-key':'semanticEditKeys',
28
+ 'semantic-identity':'semanticIdentityHashes',
29
+ 'source-identity':'sourceIdentityHashes',
30
+ 'transform-content':'semanticTransformContentHashes',
31
+ 'semantic-transform':'semanticTransformIdentityHashes',
32
+ 'projection-identity':'projectionIdentityHashes',
33
+ region:'regionKeys',
34
+ 'conflict-key':'conflictKeys',
35
+ 'source-path':'sourcePaths'
36
+ });
37
+
38
+ export function compareSemanticPatchBundleRecords(left={},right={},options={}){
39
+ const leftIndex=bundleIndex(left);
40
+ const rightIndex=bundleIndex(right);
41
+ const shared=sharedIndex(leftIndex,rightIndex,options);
42
+ const overlapKinds=SemanticPatchBundleOverlapKinds
43
+ .filter((kind)=>shared[KIND_FIELDS[kind]]?.length);
44
+ const admission=overlapAdmission(shared,{leftIndex,rightIndex,options});
45
+ return{
46
+ kind:'frontier.lang.semanticPatchBundleOverlapRecord',
47
+ version:1,
48
+ schema:'frontier.lang.semanticPatchBundleOverlapRecord.v1',
49
+ id:options.id??`semantic_patch_bundle_overlap_${idFragment(left?.id??'left')}_${idFragment(right?.id??'right')}`,
50
+ leftBundleId:String(left?.id??'left'),
51
+ rightBundleId:String(right?.id??'right'),
52
+ overlapKinds,
53
+ shared,
54
+ admission,
55
+ score:overlapScore(admission.status,shared,admission.reasonCodes),
56
+ summary:{
57
+ sharedKeys:countShared(shared),
58
+ duplicateSignals:shared.operationContentHashes.length+shared.editContentHashes.length+shared.semanticTransformContentHashes.length,
59
+ semanticSignals:shared.semanticEditKeys.length+shared.semanticIdentityHashes.length+shared.sourceIdentityHashes.length+shared.semanticTransformIdentityHashes.length+shared.projectionIdentityHashes.length,
60
+ sourceSignals:shared.regionKeys.length+shared.conflictKeys.length+shared.sourcePaths.length,
61
+ baseHashMismatch:admission.reasonCodes.includes('base-hash-mismatch'),
62
+ targetHashMismatch:admission.reasonCodes.includes('target-hash-mismatch')
63
+ },
64
+ metadata:compactRecord(options.metadata)
65
+ };
66
+ }
67
+
68
+ export function querySemanticPatchBundleOverlaps(records,query={}){
69
+ const list=array(records).filter(Boolean);
70
+ const result=[];
71
+ const compareOptions={
72
+ includeSourcePaths:query.includeSourcePaths,
73
+ reviewIndependent:query.reviewIndependent,
74
+ metadata:query.metadata
75
+ };
76
+ for(let leftIndex=0;leftIndex<list.length;leftIndex+=1){
77
+ for(let rightIndex=leftIndex+1;rightIndex<list.length;rightIndex+=1){
78
+ const overlap=compareSemanticPatchBundleRecords(list[leftIndex],list[rightIndex],compareOptions);
79
+ if(matchesOverlap(overlap,query))result.push(overlap);
80
+ }
81
+ }
82
+ return result.sort((left,right)=>right.score-left.score||left.leftBundleId.localeCompare(right.leftBundleId)
83
+ ||left.rightBundleId.localeCompare(right.rightBundleId));
84
+ }
85
+
86
+ function sharedIndex(left,right,options){
87
+ return{
88
+ operationContentHashes:intersect(left.operationContentHashes,right.operationContentHashes),
89
+ editContentHashes:intersect(left.editContentHashes,right.editContentHashes),
90
+ semanticEditKeys:intersect(left.semanticEditKeys,right.semanticEditKeys),
91
+ semanticIdentityHashes:intersect(left.semanticIdentityHashes,right.semanticIdentityHashes),
92
+ sourceIdentityHashes:intersect(left.sourceIdentityHashes,right.sourceIdentityHashes),
93
+ semanticTransformContentHashes:intersect(left.semanticTransformContentHashes,right.semanticTransformContentHashes),
94
+ semanticTransformIdentityHashes:intersect(left.semanticTransformIdentityHashes,right.semanticTransformIdentityHashes),
95
+ projectionIdentityHashes:intersect(left.projectionIdentityHashes,right.projectionIdentityHashes),
96
+ regionKeys:intersect(left.regionKeys,right.regionKeys),
97
+ conflictKeys:intersect(left.conflictKeys,right.conflictKeys),
98
+ sourcePaths:options.includeSourcePaths===false?[]:intersect(left.sourcePaths,right.sourcePaths),
99
+ baseHashes:intersect(left.baseHashes,right.baseHashes),
100
+ targetHashes:intersect(left.targetHashes,right.targetHashes)
101
+ };
102
+ }
103
+
104
+ function overlapAdmission(shared,{leftIndex,rightIndex,options}){
105
+ const duplicate=shared.operationContentHashes.length||shared.editContentHashes.length||shared.semanticTransformContentHashes.length;
106
+ const semantic=shared.semanticEditKeys.length||shared.semanticIdentityHashes.length||shared.sourceIdentityHashes.length||shared.semanticTransformIdentityHashes.length||shared.projectionIdentityHashes.length;
107
+ const source=shared.regionKeys.length||shared.conflictKeys.length||shared.sourcePaths.length;
108
+ const status=duplicate?'duplicate':semantic?'semantic-overlap':source?'source-overlap':'independent';
109
+ const reasonCodes=uniqueStrings([
110
+ shared.operationContentHashes.length?'same-operation-content':undefined,
111
+ shared.editContentHashes.length?'same-edit-content':undefined,
112
+ shared.semanticTransformContentHashes.length?'same-transform-content':undefined,
113
+ shared.semanticEditKeys.length?'same-semantic-edit-key':undefined,
114
+ shared.semanticIdentityHashes.length?'same-semantic-identity':undefined,
115
+ shared.sourceIdentityHashes.length?'same-source-identity':undefined,
116
+ shared.semanticTransformIdentityHashes.length?'same-semantic-transform':undefined,
117
+ shared.projectionIdentityHashes.length?'same-projection-identity':undefined,
118
+ shared.regionKeys.length?'same-region-key':undefined,
119
+ shared.conflictKeys.length?'same-conflict-key':undefined,
120
+ shared.sourcePaths.length?'same-source-path':undefined,
121
+ status!=='independent'&&disjointNonEmpty(leftIndex.baseHashes,rightIndex.baseHashes)?'base-hash-mismatch':undefined,
122
+ status!=='independent'&&disjointNonEmpty(leftIndex.targetHashes,rightIndex.targetHashes)?'target-hash-mismatch':undefined
123
+ ]);
124
+ return{
125
+ status,
126
+ reviewRequired:options.reviewIndependent?true:status!=='independent',
127
+ autoMergeClaim:false,
128
+ reasonCodes,
129
+ sharedKeyCount:countShared(shared)
130
+ };
131
+ }
132
+
133
+ function bundleIndex(record){
134
+ const index=record?.index??{};
135
+ return{
136
+ baseHashes:uniqueStrings([record?.baseHash,...strings(index.baseHashes)]),
137
+ targetHashes:uniqueStrings([record?.targetHash,...strings(index.targetHashes)]),
138
+ sourcePaths:uniqueStrings([record?.sourcePath,...strings(index.sourcePaths)]),
139
+ regionKeys:uniqueStrings(index.regionKeys),
140
+ conflictKeys:uniqueStrings(index.conflictKeys),
141
+ semanticEditKeys:uniqueStrings(index.semanticEditKeys),
142
+ semanticIdentityHashes:uniqueStrings(index.semanticIdentityHashes),
143
+ sourceIdentityHashes:uniqueStrings(index.sourceIdentityHashes),
144
+ semanticTransformContentHashes:uniqueStrings(index.semanticTransformContentHashes),
145
+ semanticTransformIdentityHashes:uniqueStrings(index.semanticTransformIdentityHashes),
146
+ projectionIdentityHashes:uniqueStrings(index.projectionIdentityHashes),
147
+ operationContentHashes:uniqueStrings(index.operationContentHashes),
148
+ editContentHashes:uniqueStrings(index.editContentHashes)
149
+ };
150
+ }
151
+
152
+ function matchesOverlap(overlap,query){
153
+ const statusFilters=queryValues(query.status,query.statuses,query.admissionStatus,query.admissionStatuses);
154
+ const includeIndependent=query.includeIndependent===true||statusFilters.includes('independent');
155
+ if(!includeIndependent&&overlap.admission.status==='independent')return false;
156
+ return matchAny(queryValues(query.id,query.ids),[overlap.id])
157
+ &&matchAny(queryValues(query.bundleId,query.bundleIds),[overlap.leftBundleId,overlap.rightBundleId])
158
+ &&matchAny(statusFilters,[overlap.admission.status])
159
+ &&matchAny(queryValues(query.overlapKind,query.overlapKinds),overlap.overlapKinds)
160
+ &&matchAny(queryValues(query.reasonCode,query.reasonCodes),overlap.admission.reasonCodes)
161
+ &&matchAny(queryValues(query.sourcePath,query.sourcePaths),overlap.shared.sourcePaths)
162
+ &&matchAny(queryValues(query.conflictKey,query.conflictKeys),overlap.shared.conflictKeys)
163
+ &&matchAny(queryValues(query.semanticEditKey,query.semanticEditKeys),overlap.shared.semanticEditKeys)
164
+ &&matchAny(queryValues(query.semanticTransformIdentityHash,query.semanticTransformIdentityHashes),overlap.shared.semanticTransformIdentityHashes)
165
+ &&matchAny(queryValues(query.semanticTransformContentHash,query.semanticTransformContentHashes),overlap.shared.semanticTransformContentHashes)
166
+ &&matchAny(queryValues(query.projectionIdentityHash,query.projectionIdentityHashes),overlap.shared.projectionIdentityHashes)
167
+ &&matchAny(queryValues(query.operationContentHash,query.operationContentHashes),overlap.shared.operationContentHashes)
168
+ &&matchAny(queryValues(query.editContentHash,query.editContentHashes),overlap.shared.editContentHashes)
169
+ &&(query.reviewRequired===undefined||overlap.admission.reviewRequired===query.reviewRequired)
170
+ &&(query.minScore===undefined||overlap.score>=Number(query.minScore));
171
+ }
172
+
173
+ function overlapScore(status,shared,reasonCodes){
174
+ const base=status==='duplicate'?100:status==='semantic-overlap'?75:status==='source-overlap'?35:0;
175
+ const sharedBonus=Math.min(20,countShared(shared));
176
+ const stalePenalty=reasonCodes.includes('base-hash-mismatch')||reasonCodes.includes('target-hash-mismatch')?15:0;
177
+ return Math.max(0,base+sharedBonus-stalePenalty);
178
+ }
179
+
180
+ function countShared(shared){
181
+ return Object.values(shared).reduce((total,values)=>total+(Array.isArray(values)?values.length:0),0);
182
+ }
183
+
184
+ function intersect(left,right){const rightSet=new Set(right??[]);return uniqueStrings((left??[]).filter((value)=>rightSet.has(value)));}
185
+ function disjointNonEmpty(left,right){return Boolean(left?.length&&right?.length&&intersect(left,right).length===0);}
186
+ function queryValues(...values){return uniqueStrings(values.flatMap((value)=>strings(value)));}
187
+ function matchAny(filters,values){if(filters.length===0)return true;const valueSet=new Set(strings(values));return filters.some((filter)=>valueSet.has(filter));}
188
+ function array(value){if(value===undefined||value===null)return[];return Array.isArray(value)?value:[value];}
189
+ function strings(value){return array(value).map((entry)=>String(entry??'')).filter(Boolean);}
190
+ function uniqueStrings(values){return uniqueRawStrings((values??[]).filter((entry)=>entry!==undefined&&entry!==null&&String(entry)!==''));}
191
+ function compactRecord(value){return Object.fromEntries(Object.entries(value??{}).filter(([,entry])=>entry!==undefined&&(!Array.isArray(entry)||entry.length>0)));}
@@ -1,4 +1,5 @@
1
1
  import{idFragment,normalizeSemanticMergeReadiness,uniqueStrings}from'../../native-import-utils.js';
2
+ import{normalizeSemanticTransformIdentityRecords,semanticTransformInputs,semanticTransformRecordIndex,semanticTransformSummary}from'./semanticTransformIdentityRecords.js';
2
3
 
3
4
  export const SemanticPatchBundleAdmissionStatuses=Object.freeze(['proposed','queued','admitted','needs-review','blocked','rejected']);
4
5
 
@@ -9,6 +10,9 @@ export function createSemanticPatchBundleRecord(input={},options={}){
9
10
  const semanticEditScripts=array(options.semanticEditScripts??source.semanticEditScripts??source.semanticEditScript);
10
11
  const semanticEditProjections=array(options.semanticEditProjections??source.semanticEditProjections??source.semanticEditProjection);
11
12
  const semanticEditIndex=semanticEditRecordIndex(semanticEditScripts,semanticEditProjections,source);
13
+ const transformContext={sourceLanguage:options.sourceLanguage??source.sourceLanguage??source.language,targetLanguage:options.targetLanguage??source.targetLanguage};
14
+ const semanticTransformIdentities=normalizeSemanticTransformIdentityRecords(semanticTransformInputs(source,options),transformContext);
15
+ const semanticTransformIndex=semanticTransformRecordIndex(semanticTransformIdentities,source);
12
16
  const regionInputs=array(options.changedRegions??source.changedRegions??source.regions);
13
17
  const sourceMapLinks=normalizeSourceMapLinks([
14
18
  ...array(options.sourceMapLinks??source.sourceMapLinks),
@@ -43,7 +47,7 @@ export function createSemanticPatchBundleRecord(input={},options={}){
43
47
  ??`semantic_patch_bundle_${idFragment(firstString(source.id,patchId,mergeCandidateId,source.sourcePath,source.language,'record'))}`;
44
48
  const language=options.language??source.language??mergeCandidate?.language??sources.find((item)=>item.language)?.language;
45
49
  const sourcePath=options.sourcePath??source.sourcePath??mergeCandidate?.sourcePath??sources.find((item)=>item.sourcePath)?.sourcePath;
46
- const index=recordIndex({baseHash,targetHash,sources,changedRegions,sourceMapLinks,evidenceIds,proofIds,historyIds,semanticOperationIds,patchId,mergeCandidateId,admission,semanticEditIndex});
50
+ const index=recordIndex({baseHash,targetHash,sources,changedRegions,sourceMapLinks,evidenceIds,proofIds,historyIds,semanticOperationIds,patchId,mergeCandidateId,admission,semanticEditIndex,semanticTransformIndex});
47
51
  return{
48
52
  kind:'frontier.lang.semanticPatchBundleRecord',
49
53
  version:1,
@@ -65,9 +69,10 @@ export function createSemanticPatchBundleRecord(input={},options={}){
65
69
  semanticOperationIds,
66
70
  semanticEditScriptIds:semanticEditIndex.semanticEditScriptIds,
67
71
  semanticEditProjectionIds:semanticEditIndex.semanticEditProjectionIds,
72
+ semanticTransformIdentityIds:semanticTransformIndex.semanticTransformIds,
68
73
  admission,
69
74
  index,
70
- summary:{changedRegions:changedRegions.length,sourceMapLinks:sourceMapLinks.length,evidenceIds:evidenceIds.length,proofIds:proofIds.length,historyIds:historyIds.length,semanticOperations:semanticOperationIds.length,semanticEditScripts:semanticEditScripts.length,semanticEditProjections:semanticEditProjections.length,semanticEditProjectionEdits:semanticEditIndex.semanticEditProjectionEditCount,reviewRequired:admission.reviewRequired,autoMergeClaim:admission.autoMergeClaim},
75
+ summary:{changedRegions:changedRegions.length,sourceMapLinks:sourceMapLinks.length,evidenceIds:evidenceIds.length,proofIds:proofIds.length,historyIds:historyIds.length,semanticOperations:semanticOperationIds.length,semanticEditScripts:semanticEditScripts.length,semanticEditProjections:semanticEditProjections.length,semanticEditProjectionEdits:semanticEditIndex.semanticEditProjectionEditCount,semanticTransformIdentities:semanticTransformIdentities.length,reviewRequired:admission.reviewRequired,autoMergeClaim:admission.autoMergeClaim},
71
76
  metadata:compactRecord({
72
77
  sourceChangeSetId:source.kind==='frontier.lang.nativeSourceChangeSet'?source.id:undefined,
73
78
  patchRisk:patch?.risk,
@@ -75,6 +80,7 @@ export function createSemanticPatchBundleRecord(input={},options={}){
75
80
  changedRegionProjectionSummary:source.metadata?.changedRegionProjectionSummary,
76
81
  semanticMergeConflictSummary:source.metadata?.semanticMergeConflictSummary,
77
82
  semanticEditSummary:semanticEditSummary(semanticEditIndex),
83
+ semanticTransformSummary:semanticTransformSummary(semanticTransformIndex),
78
84
  ...options.metadata
79
85
  })
80
86
  };
@@ -197,11 +203,12 @@ function normalizeAdmission(input={},context){
197
203
 
198
204
  function recordIndex(parts){
199
205
  const semanticEditIndex=parts.semanticEditIndex??semanticEditRecordIndex([],[]);
206
+ const semanticTransformIndex=parts.semanticTransformIndex??semanticTransformRecordIndex([],parts);
200
207
  return{
201
208
  baseHashes:uniqueStrings([parts.baseHash,...parts.sources.map((item)=>item.baseHash)]),
202
209
  targetHashes:uniqueStrings([parts.targetHash,...parts.sources.map((item)=>item.targetHash)]),
203
210
  sourceHashes:uniqueStrings(parts.sources.map((item)=>item.sourceHash)),
204
- sourcePaths:uniqueStrings([...parts.sources.map((item)=>item.sourcePath),...semanticEditIndex.projectedSourcePaths]),
211
+ sourcePaths:uniqueStrings([...parts.sources.map((item)=>item.sourcePath),...semanticEditIndex.projectedSourcePaths,...semanticTransformIndex.transformSourcePaths,...semanticTransformIndex.transformTargetPaths]),
205
212
  regionKeys:uniqueStrings([...parts.changedRegions.map((region)=>region.key),...semanticEditIndex.anchorKeys]),
206
213
  regionKinds:uniqueStrings(parts.changedRegions.map((region)=>region.regionKind)),
207
214
  conflictKeys:uniqueStrings([...parts.changedRegions.flatMap((region)=>[region.conflictKey,...array(region.admission?.conflictKeys)]),...semanticEditIndex.conflictKeys]),
@@ -219,6 +226,15 @@ function recordIndex(parts){
219
226
  sourceIdentityHashes:semanticEditIndex.sourceIdentityHashes,
220
227
  operationContentHashes:semanticEditIndex.operationContentHashes,
221
228
  editContentHashes:semanticEditIndex.editContentHashes,
229
+ semanticTransformIds:semanticTransformIndex.semanticTransformIds,
230
+ semanticTransformKeys:semanticTransformIndex.semanticTransformKeys,
231
+ semanticTransformIdentityHashes:semanticTransformIndex.semanticTransformIdentityHashes,
232
+ semanticTransformContentHashes:semanticTransformIndex.semanticTransformContentHashes,
233
+ projectionIdentityHashes:semanticTransformIndex.projectionIdentityHashes,
234
+ transformSourceLanguages:semanticTransformIndex.transformSourceLanguages,
235
+ transformTargetLanguages:semanticTransformIndex.transformTargetLanguages,
236
+ transformSourcePaths:semanticTransformIndex.transformSourcePaths,
237
+ transformTargetPaths:semanticTransformIndex.transformTargetPaths,
222
238
  patchIds:uniqueStrings([parts.patchId]),
223
239
  mergeCandidateIds:uniqueStrings([parts.mergeCandidateId]),
224
240
  readinesses:uniqueStrings([parts.admission.readiness,...parts.changedRegions.map((region)=>region.admission?.readiness)]),
@@ -252,6 +268,15 @@ function matchesRecord(record,query){
252
268
  &&matchAny(queryValues(query.sourceIdentityHash,query.sourceIdentityHashes),index.sourceIdentityHashes)
253
269
  &&matchAny(queryValues(query.operationContentHash,query.operationContentHashes),index.operationContentHashes)
254
270
  &&matchAny(queryValues(query.editContentHash,query.editContentHashes),index.editContentHashes)
271
+ &&matchAny(queryValues(query.semanticTransformId,query.semanticTransformIds),index.semanticTransformIds)
272
+ &&matchAny(queryValues(query.semanticTransformKey,query.semanticTransformKeys),index.semanticTransformKeys)
273
+ &&matchAny(queryValues(query.semanticTransformIdentityHash,query.semanticTransformIdentityHashes),index.semanticTransformIdentityHashes)
274
+ &&matchAny(queryValues(query.semanticTransformContentHash,query.semanticTransformContentHashes),index.semanticTransformContentHashes)
275
+ &&matchAny(queryValues(query.projectionIdentityHash,query.projectionIdentityHashes),index.projectionIdentityHashes)
276
+ &&matchAny(queryValues(query.transformSourceLanguage,query.transformSourceLanguages),index.transformSourceLanguages)
277
+ &&matchAny(queryValues(query.transformTargetLanguage,query.transformTargetLanguages),index.transformTargetLanguages)
278
+ &&matchAny(queryValues(query.transformSourcePath,query.transformSourcePaths),index.transformSourcePaths)
279
+ &&matchAny(queryValues(query.transformTargetPath,query.transformTargetPaths),index.transformTargetPaths)
255
280
  &&matchAny(queryValues(query.readiness,query.readinesses),index.readinesses)
256
281
  &&matchAny(queryValues(query.admissionStatus,query.admissionStatuses),index.admissionStatuses);
257
282
  }
@@ -0,0 +1,127 @@
1
+ import { hashSemanticValue } from '@shapeshift-labs/frontier-lang-kernel';
2
+ import { idFragment, uniqueStrings as uniqueRawStrings } from '../../native-import-utils.js';
3
+ import { semanticEditIdentityFields } from './semanticEditIdentityRecords.js';
4
+
5
+ export function createSemanticTransformIdentityRecord(input = {}, options = {}) {
6
+ const source = input?.transform ?? input;
7
+ const merged = { ...source, ...options };
8
+ const editIdentity = semanticEditIdentityFields(merged);
9
+ const semanticKey = firstString(merged.semanticKey, editIdentity.semanticKey);
10
+ const transformKey = firstString(merged.transformKey, semanticTransformKey({ ...merged, semanticKey }));
11
+ const sourceLanguage = firstString(merged.sourceLanguage, merged.language);
12
+ const targetLanguage = firstString(merged.targetLanguage, merged.projectedLanguage);
13
+ const sourcePath = firstString(merged.sourcePath, merged.originalSourcePath);
14
+ const targetPath = firstString(merged.targetPath, merged.targetSourcePath, merged.projectedSourcePath);
15
+ const semanticIdentityHash = firstString(merged.semanticIdentityHash, editIdentity.semanticIdentityHash);
16
+ const sourceIdentityHash = firstString(merged.sourceIdentityHash, editIdentity.sourceIdentityHash);
17
+ const transformIdentityHash = firstString(merged.transformIdentityHash, hashSemanticValue(compactRecord({
18
+ transformKey,
19
+ semanticIdentityHash,
20
+ sourceLanguage,
21
+ targetLanguage
22
+ })));
23
+ const projectionIdentityHash = firstString(merged.projectionIdentityHash, hashSemanticValue(compactRecord({
24
+ transformIdentityHash,
25
+ sourceIdentityHash,
26
+ sourcePath,
27
+ targetPath
28
+ })));
29
+ const operationContentHash = firstString(merged.operationContentHash);
30
+ const editContentHash = firstString(merged.editContentHash);
31
+ const transformContentHash = firstString(
32
+ merged.transformContentHash,
33
+ operationContentHash || editContentHash ? hashSemanticValue(compactRecord({ transformIdentityHash, operationContentHash, editContentHash })) : undefined
34
+ );
35
+ const id = merged.id && source.kind === 'frontier.lang.semanticTransformIdentityRecord'
36
+ ? merged.id
37
+ : firstString(merged.id, `semantic_transform_${idFragment(firstString(transformKey, semanticKey, sourcePath, targetPath, 'record'))}`);
38
+ return compactRecord({
39
+ kind: 'frontier.lang.semanticTransformIdentityRecord',
40
+ version: 1,
41
+ schema: 'frontier.lang.semanticTransformIdentityRecord.v1',
42
+ id,
43
+ sourceLanguage,
44
+ targetLanguage,
45
+ sourcePath,
46
+ targetPath,
47
+ baseHash: firstString(merged.baseHash),
48
+ targetHash: firstString(merged.targetHash, merged.projectedHash),
49
+ semanticKey,
50
+ transformKey,
51
+ semanticIdentityHash,
52
+ sourceIdentityHash,
53
+ operationContentHash,
54
+ editContentHash,
55
+ transformIdentityHash,
56
+ projectionIdentityHash,
57
+ transformContentHash,
58
+ readiness: firstString(merged.readiness),
59
+ confidence: typeof merged.confidence === 'number' ? merged.confidence : undefined,
60
+ evidenceIds: uniqueStrings(merged.evidenceIds),
61
+ metadata: compactRecord({
62
+ autoMergeClaim: false,
63
+ semanticEquivalenceClaim: false,
64
+ sourceTransformId: source.kind === 'frontier.lang.semanticTransformIdentityRecord' ? source.id : undefined,
65
+ ...merged.metadata
66
+ })
67
+ });
68
+ }
69
+
70
+ export function semanticTransformIdentityFields(record = {}) {
71
+ return createSemanticTransformIdentityRecord(record);
72
+ }
73
+
74
+ export function normalizeSemanticTransformIdentityRecords(records, context = {}) {
75
+ return array(records).filter(Boolean).map((record) => createSemanticTransformIdentityRecord(record, context));
76
+ }
77
+
78
+ export function semanticTransformInputs(source = {}, options = {}) {
79
+ return [
80
+ ...array(options.semanticTransformIdentities ?? options.semanticTransformIdentity),
81
+ ...array(source.semanticTransformIdentities ?? source.semanticTransformIdentity ?? source.semanticTransforms),
82
+ ...array(source.index?.semanticTransformIdentities)
83
+ ];
84
+ }
85
+
86
+ export function semanticTransformRecordIndex(records, source = {}) {
87
+ const index = source.index ?? {};
88
+ return {
89
+ semanticTransformIds: uniqueStrings([...strings(source.semanticTransformIds), ...strings(index.semanticTransformIds), ...records.map((record) => record.id)]),
90
+ semanticTransformKeys: uniqueStrings([...strings(source.semanticTransformKeys), ...strings(index.semanticTransformKeys), ...records.map((record) => record.transformKey)]),
91
+ semanticTransformIdentityHashes: uniqueStrings([...strings(source.semanticTransformIdentityHashes), ...strings(index.semanticTransformIdentityHashes), ...records.map((record) => record.transformIdentityHash)]),
92
+ semanticTransformContentHashes: uniqueStrings([...strings(source.semanticTransformContentHashes), ...strings(index.semanticTransformContentHashes), ...records.map((record) => record.transformContentHash)]),
93
+ projectionIdentityHashes: uniqueStrings([...strings(source.projectionIdentityHashes), ...strings(index.projectionIdentityHashes), ...records.map((record) => record.projectionIdentityHash)]),
94
+ transformSourceLanguages: uniqueStrings([...strings(source.transformSourceLanguages), ...strings(index.transformSourceLanguages), ...records.map((record) => record.sourceLanguage)]),
95
+ transformTargetLanguages: uniqueStrings([...strings(source.transformTargetLanguages), ...strings(index.transformTargetLanguages), ...records.map((record) => record.targetLanguage)]),
96
+ transformSourcePaths: uniqueStrings([...strings(source.transformSourcePaths), ...strings(index.transformSourcePaths), ...records.map((record) => record.sourcePath)]),
97
+ transformTargetPaths: uniqueStrings([...strings(source.transformTargetPaths), ...strings(index.transformTargetPaths), ...records.map((record) => record.targetPath)])
98
+ };
99
+ }
100
+
101
+ export function semanticTransformSummary(index) {
102
+ if (!index.semanticTransformIds.length && !index.semanticTransformKeys.length) return undefined;
103
+ return compactRecord({
104
+ ids: index.semanticTransformIds,
105
+ keys: index.semanticTransformKeys,
106
+ identityHashes: index.semanticTransformIdentityHashes,
107
+ contentHashes: index.semanticTransformContentHashes,
108
+ projectionIdentityHashes: index.projectionIdentityHashes,
109
+ sourceLanguages: index.transformSourceLanguages,
110
+ targetLanguages: index.transformTargetLanguages,
111
+ targetPaths: index.transformTargetPaths
112
+ });
113
+ }
114
+
115
+ function semanticTransformKey(record) {
116
+ const scope = record.semanticKey ?? (record.symbolName
117
+ ? `${record.symbolKind ?? 'symbol'}:${record.symbolName}`
118
+ : record.anchorKey ?? record.regionId ?? record.operationId ?? record.id);
119
+ const route = [record.sourceLanguage ?? record.language, record.targetLanguage ?? record.projectedLanguage].filter(Boolean).join('->');
120
+ return ['semantic-transform', route, scope].filter(Boolean).join(':');
121
+ }
122
+
123
+ function array(value) { if (value === undefined || value === null) return []; return Array.isArray(value) ? value : [value]; }
124
+ function strings(value) { return array(value).map((entry) => String(entry ?? '')).filter(Boolean); }
125
+ function firstString(...values) { return values.map((value) => value === undefined || value === null ? '' : String(value)).find(Boolean); }
126
+ function uniqueStrings(values) { return uniqueRawStrings((values ?? []).filter((entry) => entry !== undefined && entry !== null && String(entry) !== '')); }
127
+ function compactRecord(value) { return Object.fromEntries(Object.entries(value ?? {}).filter(([, entry]) => entry !== undefined && (!Array.isArray(entry) || entry.length > 0))); }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-compiler",
3
- "version": "0.2.87",
3
+ "version": "0.2.89",
4
4
  "description": "Compiler facade for Frontier Lang source documents and language projection adapters.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",