@shapeshift-labs/frontier-lang-compiler 0.2.86 → 0.2.88

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,112 @@
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
+ | 'region'
10
+ | 'conflict-key'
11
+ | 'source-path'
12
+ | string;
13
+
14
+ export type SemanticPatchBundleOverlapStatus =
15
+ | 'duplicate'
16
+ | 'semantic-overlap'
17
+ | 'source-overlap'
18
+ | 'independent'
19
+ | string;
20
+
21
+ export interface SemanticPatchBundleOverlapShared {
22
+ readonly operationContentHashes: readonly string[];
23
+ readonly editContentHashes: readonly string[];
24
+ readonly semanticEditKeys: readonly string[];
25
+ readonly semanticIdentityHashes: readonly string[];
26
+ readonly sourceIdentityHashes: readonly string[];
27
+ readonly regionKeys: readonly string[];
28
+ readonly conflictKeys: readonly string[];
29
+ readonly sourcePaths: readonly string[];
30
+ readonly baseHashes: readonly string[];
31
+ readonly targetHashes: readonly string[];
32
+ }
33
+
34
+ export interface SemanticPatchBundleOverlapAdmission {
35
+ readonly status: SemanticPatchBundleOverlapStatus;
36
+ readonly reviewRequired: boolean;
37
+ readonly autoMergeClaim: false;
38
+ readonly reasonCodes: readonly string[];
39
+ readonly sharedKeyCount: number;
40
+ }
41
+
42
+ export interface SemanticPatchBundleOverlapRecord {
43
+ readonly kind: 'frontier.lang.semanticPatchBundleOverlapRecord';
44
+ readonly version: 1;
45
+ readonly schema: 'frontier.lang.semanticPatchBundleOverlapRecord.v1';
46
+ readonly id: string;
47
+ readonly leftBundleId: string;
48
+ readonly rightBundleId: string;
49
+ readonly overlapKinds: readonly SemanticPatchBundleOverlapKind[];
50
+ readonly shared: SemanticPatchBundleOverlapShared;
51
+ readonly admission: SemanticPatchBundleOverlapAdmission;
52
+ readonly score: number;
53
+ readonly summary: {
54
+ readonly sharedKeys: number;
55
+ readonly duplicateSignals: number;
56
+ readonly semanticSignals: number;
57
+ readonly sourceSignals: number;
58
+ readonly baseHashMismatch: boolean;
59
+ readonly targetHashMismatch: boolean;
60
+ };
61
+ readonly metadata?: Record<string, unknown>;
62
+ }
63
+
64
+ export interface CompareSemanticPatchBundleRecordsOptions {
65
+ readonly id?: string;
66
+ readonly includeSourcePaths?: boolean;
67
+ readonly reviewIndependent?: boolean;
68
+ readonly metadata?: Record<string, unknown>;
69
+ }
70
+
71
+ export interface SemanticPatchBundleOverlapQuery {
72
+ readonly includeIndependent?: boolean;
73
+ readonly includeSourcePaths?: boolean;
74
+ readonly reviewIndependent?: boolean;
75
+ readonly metadata?: Record<string, unknown>;
76
+ readonly id?: string | readonly string[];
77
+ readonly ids?: readonly string[];
78
+ readonly bundleId?: string | readonly string[];
79
+ readonly bundleIds?: readonly string[];
80
+ readonly status?: SemanticPatchBundleOverlapStatus | readonly string[];
81
+ readonly statuses?: readonly string[];
82
+ readonly admissionStatus?: SemanticPatchBundleOverlapStatus | readonly string[];
83
+ readonly admissionStatuses?: readonly string[];
84
+ readonly overlapKind?: SemanticPatchBundleOverlapKind | readonly string[];
85
+ readonly overlapKinds?: readonly string[];
86
+ readonly reasonCode?: string | readonly string[];
87
+ readonly reasonCodes?: readonly string[];
88
+ readonly sourcePath?: string | readonly string[];
89
+ readonly sourcePaths?: readonly string[];
90
+ readonly conflictKey?: string | readonly string[];
91
+ readonly conflictKeys?: readonly string[];
92
+ readonly semanticEditKey?: string | readonly string[];
93
+ readonly semanticEditKeys?: readonly string[];
94
+ readonly operationContentHash?: string | readonly string[];
95
+ readonly operationContentHashes?: readonly string[];
96
+ readonly editContentHash?: string | readonly string[];
97
+ readonly editContentHashes?: readonly string[];
98
+ readonly reviewRequired?: boolean;
99
+ readonly minScore?: number;
100
+ }
101
+
102
+ export declare const SemanticPatchBundleOverlapKinds: readonly SemanticPatchBundleOverlapKind[];
103
+ export declare const SemanticPatchBundleOverlapStatuses: readonly SemanticPatchBundleOverlapStatus[];
104
+ export declare function compareSemanticPatchBundleRecords(
105
+ left?: SemanticPatchBundleRecord | Record<string, unknown>,
106
+ right?: SemanticPatchBundleRecord | Record<string, unknown>,
107
+ options?: CompareSemanticPatchBundleRecordsOptions
108
+ ): SemanticPatchBundleOverlapRecord;
109
+ export declare function querySemanticPatchBundleOverlaps(
110
+ records: SemanticPatchBundleRecord | readonly SemanticPatchBundleRecord[],
111
+ query?: SemanticPatchBundleOverlapQuery
112
+ ): readonly SemanticPatchBundleOverlapRecord[];
@@ -7,6 +7,7 @@ import type {
7
7
  SourceSpan
8
8
  } from '@shapeshift-labs/frontier-lang-kernel';
9
9
  import type { NativeSourceChangeKind, NativeSourceChangeSet } from './native-diff.js';
10
+ import type { SemanticEditProjection, SemanticEditScript } from './semantic-edit-script.js';
10
11
 
11
12
  export type SemanticPatchBundleAdmissionStatus = 'proposed' | 'queued' | 'admitted' | 'needs-review' | 'blocked' | 'rejected' | string;
12
13
 
@@ -102,6 +103,13 @@ export interface SemanticPatchBundleRecordIndex {
102
103
  readonly proofIds: readonly string[];
103
104
  readonly historyIds: readonly string[];
104
105
  readonly semanticOperationIds: readonly string[];
106
+ readonly semanticEditScriptIds: readonly string[];
107
+ readonly semanticEditProjectionIds: readonly string[];
108
+ readonly semanticEditKeys: readonly string[];
109
+ readonly semanticIdentityHashes: readonly string[];
110
+ readonly sourceIdentityHashes: readonly string[];
111
+ readonly operationContentHashes: readonly string[];
112
+ readonly editContentHashes: readonly string[];
105
113
  readonly patchIds: readonly string[];
106
114
  readonly mergeCandidateIds: readonly string[];
107
115
  readonly readinesses: readonly string[];
@@ -127,6 +135,8 @@ export interface SemanticPatchBundleRecord {
127
135
  readonly proofIds: readonly string[];
128
136
  readonly historyIds: readonly string[];
129
137
  readonly semanticOperationIds: readonly string[];
138
+ readonly semanticEditScriptIds: readonly string[];
139
+ readonly semanticEditProjectionIds: readonly string[];
130
140
  readonly admission: SemanticPatchBundleAdmission;
131
141
  readonly index: SemanticPatchBundleRecordIndex;
132
142
  readonly summary: {
@@ -136,6 +146,9 @@ export interface SemanticPatchBundleRecord {
136
146
  readonly proofIds: number;
137
147
  readonly historyIds: number;
138
148
  readonly semanticOperations: number;
149
+ readonly semanticEditScripts: number;
150
+ readonly semanticEditProjections: number;
151
+ readonly semanticEditProjectionEdits: number;
139
152
  readonly reviewRequired: boolean;
140
153
  readonly autoMergeClaim: false;
141
154
  };
@@ -164,6 +177,10 @@ export interface CreateSemanticPatchBundleRecordOptions {
164
177
  readonly historyIds?: readonly string[] | string;
165
178
  readonly semanticOperationId?: string;
166
179
  readonly semanticOperationIds?: readonly string[] | string;
180
+ readonly semanticEditScript?: SemanticEditScript;
181
+ readonly semanticEditScripts?: readonly SemanticEditScript[] | SemanticEditScript;
182
+ readonly semanticEditProjection?: SemanticEditProjection;
183
+ readonly semanticEditProjections?: readonly SemanticEditProjection[] | SemanticEditProjection;
167
184
  readonly conflictKeys?: readonly string[] | string;
168
185
  readonly admission?: Partial<SemanticPatchBundleAdmission>;
169
186
  readonly metadata?: Record<string, unknown>;
@@ -206,6 +223,20 @@ export interface SemanticPatchBundleRecordQuery {
206
223
  readonly historyIds?: readonly string[];
207
224
  readonly semanticOperationId?: string | readonly string[];
208
225
  readonly semanticOperationIds?: readonly string[];
226
+ readonly semanticEditScriptId?: string | readonly string[];
227
+ readonly semanticEditScriptIds?: readonly string[];
228
+ readonly semanticEditProjectionId?: string | readonly string[];
229
+ readonly semanticEditProjectionIds?: readonly string[];
230
+ readonly semanticEditKey?: string | readonly string[];
231
+ readonly semanticEditKeys?: readonly string[];
232
+ readonly semanticIdentityHash?: string | readonly string[];
233
+ readonly semanticIdentityHashes?: readonly string[];
234
+ readonly sourceIdentityHash?: string | readonly string[];
235
+ readonly sourceIdentityHashes?: readonly string[];
236
+ readonly operationContentHash?: string | readonly string[];
237
+ readonly operationContentHashes?: readonly string[];
238
+ readonly editContentHash?: string | readonly string[];
239
+ readonly editContentHashes?: readonly string[];
209
240
  readonly readiness?: SemanticMergeReadiness | string | readonly string[];
210
241
  readonly readinesses?: readonly string[];
211
242
  readonly admissionStatus?: SemanticPatchBundleAdmissionStatus | readonly string[];
package/dist/index.d.ts CHANGED
@@ -20,6 +20,7 @@ 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';
23
24
  export * from './declarations/bidirectional-target-change.js';
24
25
  export * from './declarations/semantic-impact.js';
25
26
  export * from './declarations/semantic-sidecar.js';
package/dist/index.js CHANGED
@@ -67,6 +67,7 @@ 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';
70
71
  export { createSemanticMergeCandidateAdmissionRecord, decorateSemanticMergeCandidateForAdmission, querySemanticMergeCandidateAdmissionOverlaps, SemanticMergeCandidateProjectionRisks, semanticMergeCandidateReadinessSortKey, sortSemanticMergeCandidateAdmissionRecords } from './internal/index-impl/semanticMergeCandidateRecords.js';
71
72
  export { querySemanticMergeConflictClasses, SemanticMergeConflictClasses, semanticMergeConflictRiskScore, sortSemanticMergeCandidatesByConflictRisk, summarizeSemanticMergeConflicts } from './internal/index-impl/semanticMergeConflicts.js';
72
73
  export { createSemanticEditScript, SemanticEditScriptAdmissionStatuses } from './internal/index-impl/semanticEditScripts.js';
@@ -0,0 +1,173 @@
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
+ 'region',
10
+ 'conflict-key',
11
+ 'source-path'
12
+ ]);
13
+
14
+ export const SemanticPatchBundleOverlapStatuses=Object.freeze([
15
+ 'duplicate',
16
+ 'semantic-overlap',
17
+ 'source-overlap',
18
+ 'independent'
19
+ ]);
20
+
21
+ const KIND_FIELDS=Object.freeze({
22
+ 'operation-content':'operationContentHashes',
23
+ 'edit-content':'editContentHashes',
24
+ 'semantic-edit-key':'semanticEditKeys',
25
+ 'semantic-identity':'semanticIdentityHashes',
26
+ 'source-identity':'sourceIdentityHashes',
27
+ region:'regionKeys',
28
+ 'conflict-key':'conflictKeys',
29
+ 'source-path':'sourcePaths'
30
+ });
31
+
32
+ export function compareSemanticPatchBundleRecords(left={},right={},options={}){
33
+ const leftIndex=bundleIndex(left);
34
+ const rightIndex=bundleIndex(right);
35
+ const shared=sharedIndex(leftIndex,rightIndex,options);
36
+ const overlapKinds=SemanticPatchBundleOverlapKinds
37
+ .filter((kind)=>shared[KIND_FIELDS[kind]]?.length);
38
+ const admission=overlapAdmission(shared,{leftIndex,rightIndex,options});
39
+ return{
40
+ kind:'frontier.lang.semanticPatchBundleOverlapRecord',
41
+ version:1,
42
+ schema:'frontier.lang.semanticPatchBundleOverlapRecord.v1',
43
+ id:options.id??`semantic_patch_bundle_overlap_${idFragment(left?.id??'left')}_${idFragment(right?.id??'right')}`,
44
+ leftBundleId:String(left?.id??'left'),
45
+ rightBundleId:String(right?.id??'right'),
46
+ overlapKinds,
47
+ shared,
48
+ admission,
49
+ score:overlapScore(admission.status,shared,admission.reasonCodes),
50
+ summary:{
51
+ sharedKeys:countShared(shared),
52
+ duplicateSignals:shared.operationContentHashes.length+shared.editContentHashes.length,
53
+ semanticSignals:shared.semanticEditKeys.length+shared.semanticIdentityHashes.length+shared.sourceIdentityHashes.length,
54
+ sourceSignals:shared.regionKeys.length+shared.conflictKeys.length+shared.sourcePaths.length,
55
+ baseHashMismatch:admission.reasonCodes.includes('base-hash-mismatch'),
56
+ targetHashMismatch:admission.reasonCodes.includes('target-hash-mismatch')
57
+ },
58
+ metadata:compactRecord(options.metadata)
59
+ };
60
+ }
61
+
62
+ export function querySemanticPatchBundleOverlaps(records,query={}){
63
+ const list=array(records).filter(Boolean);
64
+ const result=[];
65
+ const compareOptions={
66
+ includeSourcePaths:query.includeSourcePaths,
67
+ reviewIndependent:query.reviewIndependent,
68
+ metadata:query.metadata
69
+ };
70
+ for(let leftIndex=0;leftIndex<list.length;leftIndex+=1){
71
+ for(let rightIndex=leftIndex+1;rightIndex<list.length;rightIndex+=1){
72
+ const overlap=compareSemanticPatchBundleRecords(list[leftIndex],list[rightIndex],compareOptions);
73
+ if(matchesOverlap(overlap,query))result.push(overlap);
74
+ }
75
+ }
76
+ return result.sort((left,right)=>right.score-left.score||left.leftBundleId.localeCompare(right.leftBundleId)
77
+ ||left.rightBundleId.localeCompare(right.rightBundleId));
78
+ }
79
+
80
+ function sharedIndex(left,right,options){
81
+ return{
82
+ operationContentHashes:intersect(left.operationContentHashes,right.operationContentHashes),
83
+ editContentHashes:intersect(left.editContentHashes,right.editContentHashes),
84
+ semanticEditKeys:intersect(left.semanticEditKeys,right.semanticEditKeys),
85
+ semanticIdentityHashes:intersect(left.semanticIdentityHashes,right.semanticIdentityHashes),
86
+ sourceIdentityHashes:intersect(left.sourceIdentityHashes,right.sourceIdentityHashes),
87
+ regionKeys:intersect(left.regionKeys,right.regionKeys),
88
+ conflictKeys:intersect(left.conflictKeys,right.conflictKeys),
89
+ sourcePaths:options.includeSourcePaths===false?[]:intersect(left.sourcePaths,right.sourcePaths),
90
+ baseHashes:intersect(left.baseHashes,right.baseHashes),
91
+ targetHashes:intersect(left.targetHashes,right.targetHashes)
92
+ };
93
+ }
94
+
95
+ function overlapAdmission(shared,{leftIndex,rightIndex,options}){
96
+ const duplicate=shared.operationContentHashes.length||shared.editContentHashes.length;
97
+ const semantic=shared.semanticEditKeys.length||shared.semanticIdentityHashes.length||shared.sourceIdentityHashes.length;
98
+ const source=shared.regionKeys.length||shared.conflictKeys.length||shared.sourcePaths.length;
99
+ const status=duplicate?'duplicate':semantic?'semantic-overlap':source?'source-overlap':'independent';
100
+ const reasonCodes=uniqueStrings([
101
+ shared.operationContentHashes.length?'same-operation-content':undefined,
102
+ shared.editContentHashes.length?'same-edit-content':undefined,
103
+ shared.semanticEditKeys.length?'same-semantic-edit-key':undefined,
104
+ shared.semanticIdentityHashes.length?'same-semantic-identity':undefined,
105
+ shared.sourceIdentityHashes.length?'same-source-identity':undefined,
106
+ shared.regionKeys.length?'same-region-key':undefined,
107
+ shared.conflictKeys.length?'same-conflict-key':undefined,
108
+ shared.sourcePaths.length?'same-source-path':undefined,
109
+ status!=='independent'&&disjointNonEmpty(leftIndex.baseHashes,rightIndex.baseHashes)?'base-hash-mismatch':undefined,
110
+ status!=='independent'&&disjointNonEmpty(leftIndex.targetHashes,rightIndex.targetHashes)?'target-hash-mismatch':undefined
111
+ ]);
112
+ return{
113
+ status,
114
+ reviewRequired:options.reviewIndependent?true:status!=='independent',
115
+ autoMergeClaim:false,
116
+ reasonCodes,
117
+ sharedKeyCount:countShared(shared)
118
+ };
119
+ }
120
+
121
+ function bundleIndex(record){
122
+ const index=record?.index??{};
123
+ return{
124
+ baseHashes:uniqueStrings([record?.baseHash,...strings(index.baseHashes)]),
125
+ targetHashes:uniqueStrings([record?.targetHash,...strings(index.targetHashes)]),
126
+ sourcePaths:uniqueStrings([record?.sourcePath,...strings(index.sourcePaths)]),
127
+ regionKeys:uniqueStrings(index.regionKeys),
128
+ conflictKeys:uniqueStrings(index.conflictKeys),
129
+ semanticEditKeys:uniqueStrings(index.semanticEditKeys),
130
+ semanticIdentityHashes:uniqueStrings(index.semanticIdentityHashes),
131
+ sourceIdentityHashes:uniqueStrings(index.sourceIdentityHashes),
132
+ operationContentHashes:uniqueStrings(index.operationContentHashes),
133
+ editContentHashes:uniqueStrings(index.editContentHashes)
134
+ };
135
+ }
136
+
137
+ function matchesOverlap(overlap,query){
138
+ const statusFilters=queryValues(query.status,query.statuses,query.admissionStatus,query.admissionStatuses);
139
+ const includeIndependent=query.includeIndependent===true||statusFilters.includes('independent');
140
+ if(!includeIndependent&&overlap.admission.status==='independent')return false;
141
+ return matchAny(queryValues(query.id,query.ids),[overlap.id])
142
+ &&matchAny(queryValues(query.bundleId,query.bundleIds),[overlap.leftBundleId,overlap.rightBundleId])
143
+ &&matchAny(statusFilters,[overlap.admission.status])
144
+ &&matchAny(queryValues(query.overlapKind,query.overlapKinds),overlap.overlapKinds)
145
+ &&matchAny(queryValues(query.reasonCode,query.reasonCodes),overlap.admission.reasonCodes)
146
+ &&matchAny(queryValues(query.sourcePath,query.sourcePaths),overlap.shared.sourcePaths)
147
+ &&matchAny(queryValues(query.conflictKey,query.conflictKeys),overlap.shared.conflictKeys)
148
+ &&matchAny(queryValues(query.semanticEditKey,query.semanticEditKeys),overlap.shared.semanticEditKeys)
149
+ &&matchAny(queryValues(query.operationContentHash,query.operationContentHashes),overlap.shared.operationContentHashes)
150
+ &&matchAny(queryValues(query.editContentHash,query.editContentHashes),overlap.shared.editContentHashes)
151
+ &&(query.reviewRequired===undefined||overlap.admission.reviewRequired===query.reviewRequired)
152
+ &&(query.minScore===undefined||overlap.score>=Number(query.minScore));
153
+ }
154
+
155
+ function overlapScore(status,shared,reasonCodes){
156
+ const base=status==='duplicate'?100:status==='semantic-overlap'?75:status==='source-overlap'?35:0;
157
+ const sharedBonus=Math.min(20,countShared(shared));
158
+ const stalePenalty=reasonCodes.includes('base-hash-mismatch')||reasonCodes.includes('target-hash-mismatch')?15:0;
159
+ return Math.max(0,base+sharedBonus-stalePenalty);
160
+ }
161
+
162
+ function countShared(shared){
163
+ return Object.values(shared).reduce((total,values)=>total+(Array.isArray(values)?values.length:0),0);
164
+ }
165
+
166
+ function intersect(left,right){const rightSet=new Set(right??[]);return uniqueStrings((left??[]).filter((value)=>rightSet.has(value)));}
167
+ function disjointNonEmpty(left,right){return Boolean(left?.length&&right?.length&&intersect(left,right).length===0);}
168
+ function queryValues(...values){return uniqueStrings(values.flatMap((value)=>strings(value)));}
169
+ function matchAny(filters,values){if(filters.length===0)return true;const valueSet=new Set(strings(values));return filters.some((filter)=>valueSet.has(filter));}
170
+ function array(value){if(value===undefined||value===null)return[];return Array.isArray(value)?value:[value];}
171
+ function strings(value){return array(value).map((entry)=>String(entry??'')).filter(Boolean);}
172
+ function uniqueStrings(values){return uniqueRawStrings((values??[]).filter((entry)=>entry!==undefined&&entry!==null&&String(entry)!==''));}
173
+ function compactRecord(value){return Object.fromEntries(Object.entries(value??{}).filter(([,entry])=>entry!==undefined&&(!Array.isArray(entry)||entry.length>0)));}
@@ -6,6 +6,9 @@ export function createSemanticPatchBundleRecord(input={},options={}){
6
6
  const source=input?.changeSet??input;
7
7
  const patch=options.patch??source.patch??source.semanticPatch??source.patchBundle;
8
8
  const mergeCandidate=options.mergeCandidate??source.mergeCandidate??source.candidate;
9
+ const semanticEditScripts=array(options.semanticEditScripts??source.semanticEditScripts??source.semanticEditScript);
10
+ const semanticEditProjections=array(options.semanticEditProjections??source.semanticEditProjections??source.semanticEditProjection);
11
+ const semanticEditIndex=semanticEditRecordIndex(semanticEditScripts,semanticEditProjections,source);
9
12
  const regionInputs=array(options.changedRegions??source.changedRegions??source.regions);
10
13
  const sourceMapLinks=normalizeSourceMapLinks([
11
14
  ...array(options.sourceMapLinks??source.sourceMapLinks),
@@ -17,7 +20,7 @@ export function createSemanticPatchBundleRecord(input={},options={}){
17
20
  sourceRef(source.before,'before',source.beforeHash),
18
21
  sourceRef(source.after,'after',source.afterHash)
19
22
  ],source);
20
- const evidenceRecords=[...array(options.evidence??source.evidence),...array(patch?.evidence),...array(mergeCandidate?.evidence)];
23
+ const evidenceRecords=[...array(options.evidence??source.evidence),...array(patch?.evidence),...array(mergeCandidate?.evidence),...semanticEditScripts.flatMap((script)=>array(script.evidence))];
21
24
  const patchId=firstString(options.patchId,source.patchId,patch?.id,mergeCandidate?.patchId);
22
25
  const mergeCandidateId=firstString(options.mergeCandidateId,source.mergeCandidateId,mergeCandidate?.id);
23
26
  const baseHash=firstString(options.baseHash,source.baseHash,source.beforeHash,patch?.baseHash,mergeCandidate?.baseHash,...sources.map((item)=>item.baseHash));
@@ -27,7 +30,7 @@ export function createSemanticPatchBundleRecord(input={},options={}){
27
30
  const evidenceIds=uniqueStrings([...strings(options.evidenceIds),...strings(source.evidenceIds),...evidenceRecords.map((record)=>record?.id),...strings(mergeCandidate?.evidenceIds)]);
28
31
  const proofIds=uniqueStrings([...strings(options.proofIds),...strings(source.proofIds),...evidenceRecords.filter((record)=>record?.kind==='proof').map((record)=>record.id),...strings(mergeCandidate?.proofIds)]);
29
32
  const historyIds=uniqueStrings([...strings(options.historyIds),...strings(options.historyId),...strings(source.historyIds),...strings(source.historyId)]);
30
- const semanticOperationIds=uniqueStrings([...strings(options.semanticOperationIds),...strings(options.semanticOperationId),...strings(source.semanticOperationIds),...strings(source.semanticOperationId),...strings(patch?.semanticOperationIds),...strings(mergeCandidate?.semanticOperationIds)]);
33
+ const semanticOperationIds=uniqueStrings([...strings(options.semanticOperationIds),...strings(options.semanticOperationId),...strings(source.semanticOperationIds),...strings(source.semanticOperationId),...strings(patch?.semanticOperationIds),...strings(mergeCandidate?.semanticOperationIds),...semanticEditIndex.semanticEditOperationIds]);
31
34
  const conflictKeys=uniqueStrings([
32
35
  ...strings(options.conflictKeys),
33
36
  ...strings(source.conflictKeys),
@@ -40,7 +43,7 @@ export function createSemanticPatchBundleRecord(input={},options={}){
40
43
  ??`semantic_patch_bundle_${idFragment(firstString(source.id,patchId,mergeCandidateId,source.sourcePath,source.language,'record'))}`;
41
44
  const language=options.language??source.language??mergeCandidate?.language??sources.find((item)=>item.language)?.language;
42
45
  const sourcePath=options.sourcePath??source.sourcePath??mergeCandidate?.sourcePath??sources.find((item)=>item.sourcePath)?.sourcePath;
43
- const index=recordIndex({baseHash,targetHash,sources,changedRegions,sourceMapLinks,evidenceIds,proofIds,historyIds,semanticOperationIds,patchId,mergeCandidateId,admission});
46
+ const index=recordIndex({baseHash,targetHash,sources,changedRegions,sourceMapLinks,evidenceIds,proofIds,historyIds,semanticOperationIds,patchId,mergeCandidateId,admission,semanticEditIndex});
44
47
  return{
45
48
  kind:'frontier.lang.semanticPatchBundleRecord',
46
49
  version:1,
@@ -60,15 +63,18 @@ export function createSemanticPatchBundleRecord(input={},options={}){
60
63
  proofIds,
61
64
  historyIds,
62
65
  semanticOperationIds,
66
+ semanticEditScriptIds:semanticEditIndex.semanticEditScriptIds,
67
+ semanticEditProjectionIds:semanticEditIndex.semanticEditProjectionIds,
63
68
  admission,
64
69
  index,
65
- summary:{changedRegions:changedRegions.length,sourceMapLinks:sourceMapLinks.length,evidenceIds:evidenceIds.length,proofIds:proofIds.length,historyIds:historyIds.length,semanticOperations:semanticOperationIds.length,reviewRequired:admission.reviewRequired,autoMergeClaim:admission.autoMergeClaim},
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},
66
71
  metadata:compactRecord({
67
72
  sourceChangeSetId:source.kind==='frontier.lang.nativeSourceChangeSet'?source.id:undefined,
68
73
  patchRisk:patch?.risk,
69
74
  nativeChangeSummary:source.summary,
70
75
  changedRegionProjectionSummary:source.metadata?.changedRegionProjectionSummary,
71
76
  semanticMergeConflictSummary:source.metadata?.semanticMergeConflictSummary,
77
+ semanticEditSummary:semanticEditSummary(semanticEditIndex),
72
78
  ...options.metadata
73
79
  })
74
80
  };
@@ -190,14 +196,15 @@ function normalizeAdmission(input={},context){
190
196
  }
191
197
 
192
198
  function recordIndex(parts){
199
+ const semanticEditIndex=parts.semanticEditIndex??semanticEditRecordIndex([],[]);
193
200
  return{
194
201
  baseHashes:uniqueStrings([parts.baseHash,...parts.sources.map((item)=>item.baseHash)]),
195
202
  targetHashes:uniqueStrings([parts.targetHash,...parts.sources.map((item)=>item.targetHash)]),
196
203
  sourceHashes:uniqueStrings(parts.sources.map((item)=>item.sourceHash)),
197
- sourcePaths:uniqueStrings(parts.sources.map((item)=>item.sourcePath)),
198
- regionKeys:uniqueStrings(parts.changedRegions.map((region)=>region.key)),
204
+ sourcePaths:uniqueStrings([...parts.sources.map((item)=>item.sourcePath),...semanticEditIndex.projectedSourcePaths]),
205
+ regionKeys:uniqueStrings([...parts.changedRegions.map((region)=>region.key),...semanticEditIndex.anchorKeys]),
199
206
  regionKinds:uniqueStrings(parts.changedRegions.map((region)=>region.regionKind)),
200
- conflictKeys:uniqueStrings(parts.changedRegions.flatMap((region)=>[region.conflictKey,...array(region.admission?.conflictKeys)])),
207
+ conflictKeys:uniqueStrings([...parts.changedRegions.flatMap((region)=>[region.conflictKey,...array(region.admission?.conflictKeys)]),...semanticEditIndex.conflictKeys]),
201
208
  sourceMapIds:uniqueStrings([...parts.sourceMapLinks.map((link)=>link.sourceMapId),...parts.changedRegions.flatMap((region)=>region.sourceMapIds??[])]),
202
209
  sourceMapMappingIds:uniqueStrings([...parts.sourceMapLinks.map((link)=>link.sourceMapMappingId),...parts.changedRegions.flatMap((region)=>region.sourceMapMappingIds??[])]),
203
210
  sourceMapLinkIds:uniqueStrings(parts.sourceMapLinks.map((link)=>link.id)),
@@ -205,6 +212,13 @@ function recordIndex(parts){
205
212
  proofIds:parts.proofIds,
206
213
  historyIds:parts.historyIds,
207
214
  semanticOperationIds:uniqueStrings(parts.semanticOperationIds),
215
+ semanticEditScriptIds:semanticEditIndex.semanticEditScriptIds,
216
+ semanticEditProjectionIds:semanticEditIndex.semanticEditProjectionIds,
217
+ semanticEditKeys:semanticEditIndex.semanticEditKeys,
218
+ semanticIdentityHashes:semanticEditIndex.semanticIdentityHashes,
219
+ sourceIdentityHashes:semanticEditIndex.sourceIdentityHashes,
220
+ operationContentHashes:semanticEditIndex.operationContentHashes,
221
+ editContentHashes:semanticEditIndex.editContentHashes,
208
222
  patchIds:uniqueStrings([parts.patchId]),
209
223
  mergeCandidateIds:uniqueStrings([parts.mergeCandidateId]),
210
224
  readinesses:uniqueStrings([parts.admission.readiness,...parts.changedRegions.map((region)=>region.admission?.readiness)]),
@@ -231,11 +245,48 @@ function matchesRecord(record,query){
231
245
  &&matchAny(queryValues(query.proofId,query.proofIds),index.proofIds)
232
246
  &&matchAny(queryValues(query.historyId,query.historyIds),index.historyIds)
233
247
  &&matchAny(queryValues(query.semanticOperationId,query.semanticOperationIds),index.semanticOperationIds)
248
+ &&matchAny(queryValues(query.semanticEditScriptId,query.semanticEditScriptIds),index.semanticEditScriptIds)
249
+ &&matchAny(queryValues(query.semanticEditProjectionId,query.semanticEditProjectionIds),index.semanticEditProjectionIds)
250
+ &&matchAny(queryValues(query.semanticEditKey,query.semanticEditKeys),index.semanticEditKeys)
251
+ &&matchAny(queryValues(query.semanticIdentityHash,query.semanticIdentityHashes),index.semanticIdentityHashes)
252
+ &&matchAny(queryValues(query.sourceIdentityHash,query.sourceIdentityHashes),index.sourceIdentityHashes)
253
+ &&matchAny(queryValues(query.operationContentHash,query.operationContentHashes),index.operationContentHashes)
254
+ &&matchAny(queryValues(query.editContentHash,query.editContentHashes),index.editContentHashes)
234
255
  &&matchAny(queryValues(query.readiness,query.readinesses),index.readinesses)
235
256
  &&matchAny(queryValues(query.admissionStatus,query.admissionStatuses),index.admissionStatuses);
236
257
  }
237
258
 
238
259
  function admissionStatusForReadiness(readiness){return readiness==='blocked'?'blocked':readiness==='needs-review'?'needs-review':'proposed';}
260
+ function semanticEditRecordIndex(scripts,projections,source={}){
261
+ const operations=scripts.flatMap((script)=>array(script.operations));
262
+ const edits=projections.flatMap((projection)=>array(projection.edits));
263
+ const index=source.index??{};
264
+ return{
265
+ semanticEditScriptIds:uniqueStrings([...strings(source.semanticEditScriptIds),...strings(source.semanticEditScriptId),...strings(index.semanticEditScriptIds),...scripts.map((script)=>script.id)]),
266
+ semanticEditProjectionIds:uniqueStrings([...strings(source.semanticEditProjectionIds),...strings(source.semanticEditProjectionId),...strings(index.semanticEditProjectionIds),...projections.map((projection)=>projection.id)]),
267
+ semanticEditOperationIds:uniqueStrings([...strings(source.semanticOperationIds),...strings(index.semanticOperationIds),...operations.map((operation)=>operation.id)]),
268
+ semanticEditProjectionEditCount:edits.length,
269
+ semanticEditKeys:uniqueStrings([...strings(source.semanticEditKeys),...strings(index.semanticEditKeys),...operations.map((operation)=>operation.semanticKey),...edits.map((edit)=>edit.semanticKey)]),
270
+ semanticIdentityHashes:uniqueStrings([...strings(source.semanticIdentityHashes),...strings(index.semanticIdentityHashes),...operations.map((operation)=>operation.semanticIdentityHash),...edits.map((edit)=>edit.semanticIdentityHash)]),
271
+ sourceIdentityHashes:uniqueStrings([...strings(source.sourceIdentityHashes),...strings(index.sourceIdentityHashes),...operations.map((operation)=>operation.sourceIdentityHash),...edits.map((edit)=>edit.sourceIdentityHash)]),
272
+ operationContentHashes:uniqueStrings([...strings(source.operationContentHashes),...strings(index.operationContentHashes),...operations.map((operation)=>operation.operationContentHash),...edits.map((edit)=>edit.operationContentHash)]),
273
+ editContentHashes:uniqueStrings([...strings(source.editContentHashes),...strings(index.editContentHashes),...edits.map((edit)=>edit.editContentHash)]),
274
+ anchorKeys:uniqueStrings([...operations.map((operation)=>operation.anchor?.key),...edits.map((edit)=>edit.anchorKey)]),
275
+ conflictKeys:uniqueStrings([...operations.map((operation)=>operation.anchor?.conflictKey),...edits.map((edit)=>edit.conflictKey)]),
276
+ projectedSourcePaths:uniqueStrings([...projections.map((projection)=>projection.sourcePath),...edits.flatMap((edit)=>[edit.sourcePath,edit.targetSourcePath])])
277
+ };
278
+ }
279
+ function semanticEditSummary(index){
280
+ if(!index.semanticEditScriptIds.length&&!index.semanticEditProjectionIds.length)return undefined;
281
+ return compactRecord({
282
+ scriptIds:index.semanticEditScriptIds,
283
+ projectionIds:index.semanticEditProjectionIds,
284
+ semanticEditKeys:index.semanticEditKeys,
285
+ operationContentHashes:index.operationContentHashes,
286
+ editContentHashes:index.editContentHashes,
287
+ projectedSourcePaths:index.projectedSourcePaths
288
+ });
289
+ }
239
290
  function queryValues(...values){return uniqueStrings(values.flatMap((value)=>strings(value)));}
240
291
  function matchAny(filters,values){if(filters.length===0)return true;const valueSet=new Set(strings(values));return filters.some((filter)=>valueSet.has(filter));}
241
292
  function array(value){if(value===undefined||value===null)return[];return Array.isArray(value)?value:[value];}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-compiler",
3
- "version": "0.2.86",
3
+ "version": "0.2.88",
4
4
  "description": "Compiler facade for Frontier Lang source documents and language projection adapters.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",