@shapeshift-labs/frontier-lang-compiler 0.2.100 → 0.2.101
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-evidence.d.ts +299 -0
- package/dist/declarations/bidirectional-target-change.d.ts +19 -120
- package/dist/declarations/native-project-admission.d.ts +43 -22
- package/dist/declarations/semantic-edit-replay-diagnostics.d.ts +24 -0
- package/dist/declarations/semantic-edit-script.d.ts +20 -15
- package/dist/declarations/semantic-lineage.d.ts +3 -21
- package/dist/declarations/semantic-merge-candidates.d.ts +39 -0
- package/dist/declarations/semantic-sidecar-admission.d.ts +14 -0
- package/dist/declarations/semantic-sidecar.d.ts +12 -14
- package/dist/internal/index-impl/bidirectionalTargetRoundtripEvidence.js +200 -0
- package/dist/internal/index-impl/createBidirectionalTargetChangeRecord.js +62 -17
- package/dist/internal/index-impl/createNativeSourcePreservation.js +16 -1
- package/dist/internal/index-impl/createProjectImportAdmissionRecord.js +151 -1
- package/dist/internal/index-impl/createSemanticImportSidecar.js +5 -0
- package/dist/internal/index-impl/createSemanticImportSidecarAdmission.js +29 -11
- package/dist/internal/index-impl/nativeChangeProjectionEndpoint.js +56 -16
- package/dist/internal/index-impl/projectImportAdmissionMergeScore.js +26 -74
- package/dist/internal/index-impl/projectImportAdmissionProjectionCoverage.js +74 -0
- package/dist/internal/index-impl/projectSemanticEditScriptToSource.js +39 -13
- package/dist/internal/index-impl/replaySemanticEditProjection.js +65 -23
- package/dist/internal/index-impl/semanticEditInsertionAnchors.js +8 -5
- package/dist/internal/index-impl/semanticEditReplayDiagnostics.js +167 -0
- package/dist/internal/index-impl/semanticEditSourceRanges.js +94 -15
- package/dist/internal/index-impl/semanticHistoryLineageResolution.js +21 -2
- package/dist/internal/index-impl/semanticLineageHashEvidence.js +97 -0
- package/dist/internal/index-impl/semanticLineageInferenceMatching.js +8 -0
- package/dist/internal/index-impl/semanticLineageResolutionRecords.js +18 -1
- package/dist/internal/index-impl/semanticMergeCandidateRecords.js +22 -2
- package/dist/internal/index-impl/semanticMergeCandidateScoreFacets.js +221 -0
- package/dist/internal/index-impl/semanticPatchBundleOverlaps.js +23 -1
- package/dist/internal/index-impl/sourcePreservationFromProjectionContext.js +9 -2
- package/dist/native-import-language-profiles.js +10 -2
- package/dist/native-region-scanner-js-helpers.js +8 -2
- package/dist/native-region-scanner-js-imports.js +7 -0
- package/dist/native-region-scanner-js.js +4 -4
- package/dist/native-region-scanner.js +2 -1
- package/dist/semantic-import-regions.js +6 -4
- package/dist/semantic-import-sidecar-admission-types.d.ts +14 -0
- package/dist/semantic-import-sidecar-entry.js +151 -7
- package/dist/semantic-import-sidecar-types.d.ts +18 -13
- package/dist/semantic-import-source-preservation-utils.js +55 -0
- package/dist/semantic-import-source-preservation.js +98 -3
- package/package.json +1 -1
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { semanticImportSidecarQualityRecord } from '../../semantic-import-sidecar-entry.js';
|
|
2
|
+
|
|
1
3
|
function sidecarSourcePaths(importEntries) {
|
|
2
4
|
return [...new Set(importEntries.map((entry) => entry.sourcePath).filter(Boolean))];
|
|
3
5
|
}
|
|
@@ -15,10 +17,19 @@ function sidecarQualityWarning(code, message, action, sourcePaths) {
|
|
|
15
17
|
export function createSemanticImportSidecarQuality(input) {
|
|
16
18
|
const { importEntries, symbols, ownershipRegions, patchHints, proofSpec, evidence, readiness } = input;
|
|
17
19
|
const expected = input.expected === true;
|
|
20
|
+
const expectedEmpty = input.expectedEmpty === true || input.semanticImportExpectedEmpty === true;
|
|
18
21
|
const sourcePaths = sidecarSourcePaths(importEntries);
|
|
19
22
|
const importCount = importEntries.length;
|
|
23
|
+
const record = semanticImportSidecarQualityRecord({
|
|
24
|
+
expected,
|
|
25
|
+
expectedEmpty,
|
|
26
|
+
importCount,
|
|
27
|
+
symbolCount: symbols.length,
|
|
28
|
+
sourcePaths
|
|
29
|
+
});
|
|
30
|
+
const expectedEmptySatisfied = record.classification === 'expected-empty';
|
|
20
31
|
const warnings = [];
|
|
21
|
-
if (expected && importCount === 0) warnings.push(sidecarQualityWarning(
|
|
32
|
+
if ((expected || expectedEmpty) && importCount === 0) warnings.push(sidecarQualityWarning(
|
|
22
33
|
'expected-semantic-import-missing',
|
|
23
34
|
'Semantic import was expected but no import entries were selected.',
|
|
24
35
|
'check-semantic-import-include-globs-and-workspace-paths',
|
|
@@ -30,31 +41,31 @@ export function createSemanticImportSidecarQuality(input) {
|
|
|
30
41
|
'run-native-import',
|
|
31
42
|
sourcePaths
|
|
32
43
|
));
|
|
33
|
-
if (expected && importCount > 0 && symbols.length === 0) warnings.push(sidecarQualityWarning(
|
|
44
|
+
if (!expectedEmptySatisfied && expected && importCount > 0 && symbols.length === 0) warnings.push(sidecarQualityWarning(
|
|
34
45
|
'expected-semantic-import-empty',
|
|
35
46
|
'Semantic import was expected but selected imports produced zero semantic symbols.',
|
|
36
47
|
'rerun-importer-with-semantic-source-selection',
|
|
37
48
|
sourcePaths
|
|
38
49
|
));
|
|
39
|
-
if (importCount > 0 && symbols.length === 0) warnings.push(sidecarQualityWarning(
|
|
50
|
+
if (!expectedEmptySatisfied && importCount > 0 && symbols.length === 0) warnings.push(sidecarQualityWarning(
|
|
40
51
|
'empty-semantic-index',
|
|
41
52
|
'Semantic sidecar has import entries but no semantic symbols.',
|
|
42
53
|
'rerun-importer-with-semantic-index',
|
|
43
54
|
sourcePaths
|
|
44
55
|
));
|
|
45
|
-
if (importCount > 0 && ownershipRegions.length === 0) warnings.push(sidecarQualityWarning(
|
|
56
|
+
if (!expectedEmptySatisfied && importCount > 0 && ownershipRegions.length === 0) warnings.push(sidecarQualityWarning(
|
|
46
57
|
'missing-ownership-regions',
|
|
47
58
|
'Semantic sidecar has no ownership regions for safe merge ownership.',
|
|
48
59
|
'rerun-sidecar-generation-with-ownership-regions',
|
|
49
60
|
sourcePaths
|
|
50
61
|
));
|
|
51
|
-
if (importCount > 0 && patchHints.length === 0) warnings.push(sidecarQualityWarning(
|
|
62
|
+
if (!expectedEmptySatisfied && importCount > 0 && patchHints.length === 0) warnings.push(sidecarQualityWarning(
|
|
52
63
|
'missing-patch-hints',
|
|
53
64
|
'Semantic sidecar has no patch hints.',
|
|
54
65
|
'generate-semantic-patch-hints',
|
|
55
66
|
sourcePaths
|
|
56
67
|
));
|
|
57
|
-
if (importCount > 0 && evidence.length === 0) warnings.push(sidecarQualityWarning(
|
|
68
|
+
if (!expectedEmptySatisfied && importCount > 0 && evidence.length === 0) warnings.push(sidecarQualityWarning(
|
|
58
69
|
'empty-evidence',
|
|
59
70
|
'Semantic sidecar has no evidence records.',
|
|
60
71
|
'attach-semantic-import-evidence',
|
|
@@ -116,16 +127,18 @@ export function createSemanticImportSidecarQuality(input) {
|
|
|
116
127
|
warning.code === 'missing-ownership-regions' ||
|
|
117
128
|
warning.code === 'missing-patch-hints'
|
|
118
129
|
));
|
|
119
|
-
const
|
|
120
|
-
?
|
|
121
|
-
:
|
|
122
|
-
const expectedSatisfied = !expected || (
|
|
130
|
+
const expectedSatisfied = expectedEmpty
|
|
131
|
+
? expectedEmptySatisfied
|
|
132
|
+
: !expected || (
|
|
123
133
|
importCount > 0 &&
|
|
124
134
|
symbols.length > 0 &&
|
|
125
135
|
ownershipRegions.length > 0 &&
|
|
126
136
|
patchHints.length > 0 &&
|
|
127
137
|
evidence.length > 0
|
|
128
138
|
);
|
|
139
|
+
const expectedMissingReasonCodes = (expected || expectedEmpty) && !expectedSatisfied
|
|
140
|
+
? emptyEvidenceWarnings.map((warning) => warning.code)
|
|
141
|
+
: [];
|
|
129
142
|
const proofSummary = {
|
|
130
143
|
total: proofSpec.total,
|
|
131
144
|
obligations: proofSpec.obligations,
|
|
@@ -143,12 +156,14 @@ export function createSemanticImportSidecarQuality(input) {
|
|
|
143
156
|
return {
|
|
144
157
|
schema: 'frontier.lang.semanticSidecarQuality.v1',
|
|
145
158
|
expected,
|
|
159
|
+
expectedEmpty,
|
|
146
160
|
expectedSatisfied,
|
|
147
161
|
expectedMissingReasonCodes,
|
|
148
162
|
selected: importCount > 0,
|
|
149
|
-
eligible:
|
|
163
|
+
eligible: record.classification === 'useful' && emptyEvidenceWarnings.length === 0 && proofSpec.failed === 0 && readiness !== 'blocked',
|
|
150
164
|
imported: importCount > 0,
|
|
151
165
|
importCount,
|
|
166
|
+
record,
|
|
152
167
|
symbolCount: symbols.length,
|
|
153
168
|
ownershipRegionCount: ownershipRegions.length,
|
|
154
169
|
patchHintCount: patchHints.length,
|
|
@@ -164,6 +179,7 @@ export function createSemanticImportSidecarAdmission(quality, readiness) {
|
|
|
164
179
|
return {
|
|
165
180
|
schema: 'frontier.lang.semanticSidecarAdmission.v1',
|
|
166
181
|
expected: quality.expected,
|
|
182
|
+
expectedEmpty: quality.expectedEmpty,
|
|
167
183
|
expectedSatisfied: quality.expectedSatisfied,
|
|
168
184
|
expectedMissingReasonCodes: quality.expectedMissingReasonCodes,
|
|
169
185
|
selected: quality.selected,
|
|
@@ -172,6 +188,7 @@ export function createSemanticImportSidecarAdmission(quality, readiness) {
|
|
|
172
188
|
importCount: quality.importCount,
|
|
173
189
|
readiness,
|
|
174
190
|
action: sidecarAdmissionAction(quality, readiness),
|
|
191
|
+
record: quality.record,
|
|
175
192
|
counts: {
|
|
176
193
|
symbols: quality.symbolCount,
|
|
177
194
|
ownershipRegions: quality.ownershipRegionCount,
|
|
@@ -191,6 +208,7 @@ function sidecarAdmissionAction(quality, readiness) {
|
|
|
191
208
|
if (!quality.imported) return 'reject-missing-imports';
|
|
192
209
|
if (readiness === 'blocked') return 'reject-blocked';
|
|
193
210
|
if (quality.proofSummary.failed > 0) return 'reject-failed-proof';
|
|
211
|
+
if (quality.record?.classification === 'expected-empty') return 'skip-expected-empty';
|
|
194
212
|
if (quality.emptyEvidenceWarnings.length > 0) return 'reject-empty-evidence';
|
|
195
213
|
if (!quality.eligible) return 'reject-quality';
|
|
196
214
|
if (sidecarProofReviewObligations(quality.proofSummary) > 0) return 'review-proof-obligations';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{nativeChangeMappingTouchesRegion}from'./nativeChangeMappingTouchesRegion.js';import{nativeImportSourcePreservationRecord}from'./nativeImportSourcePreservationRecord.js';
|
|
1
|
+
import{uniqueStrings}from'../../native-import-utils.js';import{nativeChangeMappingTouchesRegion}from'./nativeChangeMappingTouchesRegion.js';import{nativeImportSourcePreservationRecord}from'./nativeImportSourcePreservationRecord.js';
|
|
2
2
|
export function nativeChangeProjectionEndpoint(imported, sidecar, region, side) {
|
|
3
3
|
if (!imported && !region) return undefined;
|
|
4
4
|
const preservation = nativeImportSourcePreservationRecord(imported);
|
|
@@ -6,23 +6,63 @@ export function nativeChangeProjectionEndpoint(imported, sidecar, region, side)
|
|
|
6
6
|
const regionMappings = sourceMaps
|
|
7
7
|
.flatMap((sourceMap) => (sourceMap?.mappings ?? []).map((mapping) => ({ sourceMap, mapping })))
|
|
8
8
|
.filter(({ mapping }) => nativeChangeMappingTouchesRegion(mapping, region, []));
|
|
9
|
+
const sourceMapIds = uniqueStrings(sourceMaps.map((sourceMap) => sourceMap?.id));
|
|
10
|
+
const sourceMapMappingIds = uniqueStrings(regionMappings.map(({ mapping }) => mapping?.id));
|
|
11
|
+
const importId = imported?.id;
|
|
12
|
+
const nativeSourceId = imported?.nativeSource?.id;
|
|
13
|
+
const nativeAstId = imported?.nativeAst?.id;
|
|
14
|
+
const semanticIndexId = imported?.semanticIndex?.id;
|
|
15
|
+
const universalAstId = imported?.universalAst?.id;
|
|
16
|
+
const sourcePath = imported?.sourcePath ?? region?.sourcePath;
|
|
17
|
+
const sourceHash = imported?.nativeSource?.sourceHash ?? imported?.nativeAst?.sourceHash ?? region?.sourceHash;
|
|
18
|
+
const sourcePreservationId = preservation?.id;
|
|
19
|
+
const exactSourceAvailable = preservation?.summary?.exactSourceAvailable === true;
|
|
20
|
+
const ownershipRegionId = region?.id;
|
|
21
|
+
const ownershipKey = region?.key;
|
|
22
|
+
const ownershipRegionKind = region?.regionKind;
|
|
23
|
+
const sourceSpan = region?.sourceSpan;
|
|
24
|
+
const identity = compactRecord({
|
|
25
|
+
schema: 'frontier.lang.nativeChangeProjectionEndpointIdentity.v1',
|
|
26
|
+
version: 1,
|
|
27
|
+
side,
|
|
28
|
+
importId,
|
|
29
|
+
nativeSourceId,
|
|
30
|
+
nativeAstId,
|
|
31
|
+
semanticIndexId,
|
|
32
|
+
universalAstId,
|
|
33
|
+
sourcePath,
|
|
34
|
+
sourceHash,
|
|
35
|
+
sourcePreservationId,
|
|
36
|
+
exactSourceAvailable,
|
|
37
|
+
ownershipRegionId,
|
|
38
|
+
ownershipKey,
|
|
39
|
+
ownershipRegionKind,
|
|
40
|
+
sourceSpan,
|
|
41
|
+
sourceMapIds,
|
|
42
|
+
sourceMapMappingIds
|
|
43
|
+
});
|
|
9
44
|
return {
|
|
10
45
|
side,
|
|
11
|
-
importId
|
|
46
|
+
importId,
|
|
12
47
|
sidecarId: sidecar?.id,
|
|
13
|
-
nativeSourceId
|
|
14
|
-
nativeAstId
|
|
15
|
-
semanticIndexId
|
|
16
|
-
universalAstId
|
|
17
|
-
sourcePath
|
|
18
|
-
sourceHash
|
|
19
|
-
sourcePreservationId
|
|
20
|
-
exactSourceAvailable
|
|
21
|
-
ownershipRegionId
|
|
22
|
-
ownershipKey
|
|
23
|
-
ownershipRegionKind
|
|
24
|
-
sourceSpan
|
|
25
|
-
sourceMapIds
|
|
26
|
-
sourceMapMappingIds
|
|
48
|
+
nativeSourceId,
|
|
49
|
+
nativeAstId,
|
|
50
|
+
semanticIndexId,
|
|
51
|
+
universalAstId,
|
|
52
|
+
sourcePath,
|
|
53
|
+
sourceHash,
|
|
54
|
+
sourcePreservationId,
|
|
55
|
+
exactSourceAvailable,
|
|
56
|
+
ownershipRegionId,
|
|
57
|
+
ownershipKey,
|
|
58
|
+
ownershipRegionKind,
|
|
59
|
+
sourceSpan,
|
|
60
|
+
sourceMapIds,
|
|
61
|
+
sourceMapMappingIds,
|
|
62
|
+
identity
|
|
27
63
|
};
|
|
28
64
|
}
|
|
65
|
+
|
|
66
|
+
function compactRecord(value) {
|
|
67
|
+
return Object.fromEntries(Object.entries(value ?? {}).filter(([, entry]) => entry !== undefined && (!Array.isArray(entry) || entry.length > 0)));
|
|
68
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import{uniqueRecordsById,uniqueStrings}from'../../native-import-utils.js';
|
|
2
|
+
import{targetProjectionCoverageSignals}from'./projectImportAdmissionProjectionCoverage.js';
|
|
2
3
|
|
|
3
4
|
const scoreWeights=Object.freeze({
|
|
4
5
|
semanticEvidence:22,
|
|
@@ -95,15 +96,35 @@ function sourcePreservationScore(input){
|
|
|
95
96
|
|
|
96
97
|
function sourceFreshnessScore(input){
|
|
97
98
|
const sourceCount=Math.max(input.sourceCount??0,input.sourcePreservation.total,1);
|
|
98
|
-
const
|
|
99
|
+
const sourceStaleness=input.sourceStaleness??{};
|
|
100
|
+
const stale=sourceStaleness.stale??input.sourcePreservation.stale;
|
|
101
|
+
const contentHashStale=sourceStaleness.contentHashStale??input.sourcePreservation.contentHashStale??0;
|
|
102
|
+
const baseHashStale=sourceStaleness.baseHashStale??input.sourcePreservation.baseHashStale??0;
|
|
103
|
+
const dirtyWorkspace=sourceStaleness.dirtyWorkspace??input.sourcePreservation.dirtyWorkspace??0;
|
|
104
|
+
const fresh=Math.max(0,sourceCount-stale);
|
|
99
105
|
const score=roundScore(fresh*100/sourceCount);
|
|
100
106
|
return scoreComponent('sourceFreshness',score,[
|
|
101
|
-
...(
|
|
102
|
-
`Project import has stale
|
|
107
|
+
...(contentHashStale?[
|
|
108
|
+
`Project import has stale content hashes for ${contentHashStale} source(s).`
|
|
109
|
+
]:[]),
|
|
110
|
+
...(baseHashStale?[
|
|
111
|
+
`Project import has stale base hashes for ${baseHashStale} source(s).`
|
|
112
|
+
]:[]),
|
|
113
|
+
...(!contentHashStale&&!baseHashStale&&stale?[
|
|
114
|
+
`Project import has stale source hashes for ${stale} source(s).`
|
|
115
|
+
]:[]),
|
|
116
|
+
...(dirtyWorkspace&&!stale?[
|
|
117
|
+
`Project workspace is marked dirty for ${dirtyWorkspace} source(s), but no content or base hash staleness was detected.`
|
|
103
118
|
]:[])
|
|
104
119
|
],{
|
|
105
|
-
stale
|
|
106
|
-
|
|
120
|
+
stale,
|
|
121
|
+
contentHashStale,
|
|
122
|
+
baseHashStale,
|
|
123
|
+
dirtyWorkspace,
|
|
124
|
+
staleSourcePaths:sourceStaleness.staleSourcePaths??input.sourcePreservation.staleSourcePaths,
|
|
125
|
+
contentHashStaleSourcePaths:sourceStaleness.contentHashStaleSourcePaths??input.sourcePreservation.contentHashStaleSourcePaths??[],
|
|
126
|
+
baseHashStaleSourcePaths:sourceStaleness.baseHashStaleSourcePaths??input.sourcePreservation.baseHashStaleSourcePaths??[],
|
|
127
|
+
dirtyWorkspaceSourcePaths:sourceStaleness.dirtyWorkspaceSourcePaths??input.sourcePreservation.dirtyWorkspaceSourcePaths??[],
|
|
107
128
|
checkedSources:sourceCount
|
|
108
129
|
});
|
|
109
130
|
}
|
|
@@ -186,75 +207,6 @@ function targetProjectionCoverageScore(input){
|
|
|
186
207
|
],coverage);
|
|
187
208
|
}
|
|
188
209
|
|
|
189
|
-
function targetProjectionCoverageSignals(input){
|
|
190
|
-
const entries=targetProjectionEntries(input.projectResult,input.imports);
|
|
191
|
-
const matrices=projectionMatrices(input.projectResult,input.imports);
|
|
192
|
-
for(const matrix of matrices){
|
|
193
|
-
for(const language of matrix?.languages??[]) entries.push(...(language?.targets??[]));
|
|
194
|
-
}
|
|
195
|
-
const sourceMapSummary=input.contract?.sourceMaps??{};
|
|
196
|
-
const summary=matrices.reduce((current,matrix)=>{
|
|
197
|
-
current.exactSourceProjection+=matrix?.summary?.exactSourceProjection??0;
|
|
198
|
-
current.targetAdapterProjection+=matrix?.summary?.targetAdapterProjection??0;
|
|
199
|
-
current.missingAdapters+=matrix?.summary?.missingAdapters??0;
|
|
200
|
-
current.unsupportedTargetFeatures+=matrix?.summary?.unsupportedTargetFeatures??0;
|
|
201
|
-
return current;
|
|
202
|
-
},{exactSourceProjection:0,targetAdapterProjection:0,missingAdapters:0,unsupportedTargetFeatures:0});
|
|
203
|
-
const targetEntries=entries.length;
|
|
204
|
-
const supportedTargets=entries.filter((entry)=>entry?.supported===true).length;
|
|
205
|
-
const adapterProjectionTargets=entries.filter((entry)=>
|
|
206
|
-
entry?.lossClass==='targetAdapterProjection'||entry?.lossClass==='exactSourceProjection'||entry?.adapter||entry?.adapterKind==='targetProjection'
|
|
207
|
-
).length+summary.targetAdapterProjection+summary.exactSourceProjection;
|
|
208
|
-
const readinessValues=entries.map((entry)=>readinessScore[entry?.readiness]??45);
|
|
209
|
-
const readinessAverage=readinessValues.length?readinessValues.reduce((sum,value)=>sum+value,0)/readinessValues.length:0;
|
|
210
|
-
return {
|
|
211
|
-
targetEntries,
|
|
212
|
-
supportedTargets,
|
|
213
|
-
adapterProjectionTargets,
|
|
214
|
-
exactSourceProjection:Math.max(summary.exactSourceProjection,input.sourcePreservation.exactSourceAvailable??0),
|
|
215
|
-
targetAdapterProjection:summary.targetAdapterProjection,
|
|
216
|
-
missingAdapters:summary.missingAdapters+entries.filter((entry)=>entry?.lossClass==='missingAdapter'||entry?.supported===false).length,
|
|
217
|
-
unsupportedTargetFeatures:summary.unsupportedTargetFeatures+entries.filter((entry)=>entry?.lossClass==='unsupportedTargetFeatures').length,
|
|
218
|
-
readinessScore:roundScore(readinessAverage),
|
|
219
|
-
sourceMapMappings:sourceMapSummary.mappingCount??0,
|
|
220
|
-
generatedRangeMappings:sourceMapSummary.generatedRangeMappings??0,
|
|
221
|
-
targetPaths:sourceMapSummary.targetPaths?.length??0,
|
|
222
|
-
adapterGeneratedRanges:input.contract?.adapterCoverage?.generatedRanges??0
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
function targetProjectionEntries(projectResult,imports){
|
|
227
|
-
return [
|
|
228
|
-
projectResult?.targetCoverage,
|
|
229
|
-
projectResult?.metadata?.targetCoverage,
|
|
230
|
-
projectResult?.metadata?.targetProjectionCoverage,
|
|
231
|
-
...(projectResult?.targetCoverages??[]),
|
|
232
|
-
...(projectResult?.metadata?.targetCoverages??[]),
|
|
233
|
-
...(imports??[]).flatMap((imported)=>[
|
|
234
|
-
imported?.targetCoverage,
|
|
235
|
-
imported?.metadata?.targetCoverage,
|
|
236
|
-
imported?.metadata?.targetProjectionCoverage,
|
|
237
|
-
...(imported?.targetCoverages??[]),
|
|
238
|
-
...(imported?.metadata?.targetCoverages??[])
|
|
239
|
-
])
|
|
240
|
-
].flatMap((entry)=>Array.isArray(entry)?entry:[entry]).filter((entry)=>entry&&typeof entry==='object'&&(entry.target||entry.lossClass||entry.supported!==undefined));
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
function projectionMatrices(projectResult,imports){
|
|
244
|
-
return [
|
|
245
|
-
projectResult?.projectionMatrix,
|
|
246
|
-
projectResult?.metadata?.projectionMatrix,
|
|
247
|
-
...(projectResult?.projectionMatrices??[]),
|
|
248
|
-
...(projectResult?.metadata?.projectionMatrices??[]),
|
|
249
|
-
...(imports??[]).flatMap((imported)=>[
|
|
250
|
-
imported?.projectionMatrix,
|
|
251
|
-
imported?.metadata?.projectionMatrix,
|
|
252
|
-
...(imported?.projectionMatrices??[]),
|
|
253
|
-
...(imported?.metadata?.projectionMatrices??[])
|
|
254
|
-
])
|
|
255
|
-
].filter((matrix)=>matrix?.kind==='frontier.lang.projectionTargetLossMatrix'||Array.isArray(matrix?.languages));
|
|
256
|
-
}
|
|
257
|
-
|
|
258
210
|
function admissionEvidenceRecords(projectResult,imports){
|
|
259
211
|
return uniqueRecordsById([
|
|
260
212
|
...(projectResult?.evidence??[]),
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const readinessScore = Object.freeze({ ready: 100, 'ready-with-losses': 75, 'needs-review': 45, blocked: 0 });
|
|
2
|
+
|
|
3
|
+
export function targetProjectionCoverageSignals(input) {
|
|
4
|
+
const entries = targetProjectionEntries(input.projectResult, input.imports);
|
|
5
|
+
const matrices = projectionMatrices(input.projectResult, input.imports);
|
|
6
|
+
for (const matrix of matrices) {
|
|
7
|
+
for (const language of matrix?.languages ?? []) entries.push(...(language?.targets ?? []));
|
|
8
|
+
}
|
|
9
|
+
const sourceMapSummary = input.contract?.sourceMaps ?? {};
|
|
10
|
+
const summary = matrices.reduce((current, matrix) => {
|
|
11
|
+
current.exactSourceProjection += matrix?.summary?.exactSourceProjection ?? 0;
|
|
12
|
+
current.targetAdapterProjection += matrix?.summary?.targetAdapterProjection ?? 0;
|
|
13
|
+
current.missingAdapters += matrix?.summary?.missingAdapters ?? 0;
|
|
14
|
+
current.unsupportedTargetFeatures += matrix?.summary?.unsupportedTargetFeatures ?? 0;
|
|
15
|
+
return current;
|
|
16
|
+
}, { exactSourceProjection: 0, targetAdapterProjection: 0, missingAdapters: 0, unsupportedTargetFeatures: 0 });
|
|
17
|
+
const targetEntries = entries.length;
|
|
18
|
+
const supportedTargets = entries.filter((entry) => entry?.supported === true).length;
|
|
19
|
+
const adapterProjectionTargets = entries.filter((entry) =>
|
|
20
|
+
entry?.lossClass === 'targetAdapterProjection' || entry?.lossClass === 'exactSourceProjection' || entry?.adapter || entry?.adapterKind === 'targetProjection'
|
|
21
|
+
).length + summary.targetAdapterProjection + summary.exactSourceProjection;
|
|
22
|
+
const readinessValues = entries.map((entry) => readinessScore[entry?.readiness] ?? 45);
|
|
23
|
+
const readinessAverage = readinessValues.length ? readinessValues.reduce((sum, value) => sum + value, 0) / readinessValues.length : 0;
|
|
24
|
+
return {
|
|
25
|
+
targetEntries,
|
|
26
|
+
supportedTargets,
|
|
27
|
+
adapterProjectionTargets,
|
|
28
|
+
exactSourceProjection: Math.max(summary.exactSourceProjection, input.sourcePreservation.exactSourceAvailable ?? 0),
|
|
29
|
+
targetAdapterProjection: summary.targetAdapterProjection,
|
|
30
|
+
missingAdapters: summary.missingAdapters + entries.filter((entry) => entry?.lossClass === 'missingAdapter' || entry?.supported === false).length,
|
|
31
|
+
unsupportedTargetFeatures: summary.unsupportedTargetFeatures + entries.filter((entry) => entry?.lossClass === 'unsupportedTargetFeatures').length,
|
|
32
|
+
readinessScore: roundScore(readinessAverage),
|
|
33
|
+
sourceMapMappings: sourceMapSummary.mappingCount ?? 0,
|
|
34
|
+
generatedRangeMappings: sourceMapSummary.generatedRangeMappings ?? 0,
|
|
35
|
+
targetPaths: sourceMapSummary.targetPaths?.length ?? 0,
|
|
36
|
+
adapterGeneratedRanges: input.contract?.adapterCoverage?.generatedRanges ?? 0
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function targetProjectionEntries(projectResult, imports) {
|
|
41
|
+
return [
|
|
42
|
+
projectResult?.targetCoverage,
|
|
43
|
+
projectResult?.metadata?.targetCoverage,
|
|
44
|
+
projectResult?.metadata?.targetProjectionCoverage,
|
|
45
|
+
...(projectResult?.targetCoverages ?? []),
|
|
46
|
+
...(projectResult?.metadata?.targetCoverages ?? []),
|
|
47
|
+
...(imports ?? []).flatMap((imported) => [
|
|
48
|
+
imported?.targetCoverage,
|
|
49
|
+
imported?.metadata?.targetCoverage,
|
|
50
|
+
imported?.metadata?.targetProjectionCoverage,
|
|
51
|
+
...(imported?.targetCoverages ?? []),
|
|
52
|
+
...(imported?.metadata?.targetCoverages ?? [])
|
|
53
|
+
])
|
|
54
|
+
].flatMap((entry) => Array.isArray(entry) ? entry : [entry]).filter((entry) => entry && typeof entry === 'object' && (entry.target || entry.lossClass || entry.supported !== undefined));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function projectionMatrices(projectResult, imports) {
|
|
58
|
+
return [
|
|
59
|
+
projectResult?.projectionMatrix,
|
|
60
|
+
projectResult?.metadata?.projectionMatrix,
|
|
61
|
+
...(projectResult?.projectionMatrices ?? []),
|
|
62
|
+
...(projectResult?.metadata?.projectionMatrices ?? []),
|
|
63
|
+
...(imports ?? []).flatMap((imported) => [
|
|
64
|
+
imported?.projectionMatrix,
|
|
65
|
+
imported?.metadata?.projectionMatrix,
|
|
66
|
+
...(imported?.projectionMatrices ?? []),
|
|
67
|
+
...(imported?.metadata?.projectionMatrices ?? [])
|
|
68
|
+
])
|
|
69
|
+
].filter((matrix) => matrix?.kind === 'frontier.lang.projectionTargetLossMatrix' || Array.isArray(matrix?.languages));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function roundScore(value) {
|
|
73
|
+
return Math.round((Number.isFinite(value) ? value : 0) * 100) / 100;
|
|
74
|
+
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { hashSemanticValue } from '@shapeshift-labs/frontier-lang-kernel';
|
|
2
|
-
import { idFragment, uniqueStrings } from '../../native-import-utils.js';
|
|
2
|
+
import { idFragment, normalizeNativeLanguageId, uniqueStrings } from '../../native-import-utils.js';
|
|
3
|
+
import { createSemanticImportSidecar } from './createSemanticImportSidecar.js';
|
|
4
|
+
import { mapDiffSymbols } from './mapDiffSymbols.js';
|
|
5
|
+
import { normalizeNativeDiffImport } from './normalizeNativeDiffImport.js';
|
|
3
6
|
import { semanticEditIdentityFields } from './semanticEditIdentityRecords.js';
|
|
4
7
|
import {
|
|
5
8
|
insertionOffset,
|
|
@@ -10,7 +13,6 @@ import {
|
|
|
10
13
|
spanOffsets
|
|
11
14
|
} from './semanticEditSourceRanges.js';
|
|
12
15
|
import { applySourceEdits, dedupeSourceEdits, validateSourceEdits } from './semanticSourceEditDedupe.js';
|
|
13
|
-
|
|
14
16
|
export function projectSemanticEditScriptToSource(input = {}) {
|
|
15
17
|
const script = input.script;
|
|
16
18
|
const workerSourceText = input.workerSourceText;
|
|
@@ -19,6 +21,15 @@ export function projectSemanticEditScriptToSource(input = {}) {
|
|
|
19
21
|
if (!script) throw new Error('projectSemanticEditScriptToSource requires a script');
|
|
20
22
|
if (typeof workerSourceText !== 'string') reasonCodes.push('missing-worker-source-text');
|
|
21
23
|
if (typeof headSourceText !== 'string') reasonCodes.push('missing-head-source-text');
|
|
24
|
+
const language = normalizeNativeLanguageId(script.language);
|
|
25
|
+
const headSymbols = typeof headSourceText === 'string' && isJavaScriptLike(language)
|
|
26
|
+
? sourceSymbolIndex({
|
|
27
|
+
sourceText: headSourceText,
|
|
28
|
+
sourcePath: input.headSourcePath ?? script.sourcePath,
|
|
29
|
+
language,
|
|
30
|
+
parser: input.parser
|
|
31
|
+
})
|
|
32
|
+
: [];
|
|
22
33
|
const edits = [];
|
|
23
34
|
const coveredOperationIds = [];
|
|
24
35
|
const projectionCoveredOperationIds = projectionCoveredContainerOperationIds(script.operations ?? [], workerSourceText);
|
|
@@ -27,7 +38,10 @@ export function projectSemanticEditScriptToSource(input = {}) {
|
|
|
27
38
|
coveredOperationIds.push(operation.id);
|
|
28
39
|
continue;
|
|
29
40
|
}
|
|
30
|
-
const edit = sourceEditForOperation(operation, workerSourceText, headSourceText, index,
|
|
41
|
+
const edit = sourceEditForOperation(operation, workerSourceText, headSourceText, index, {
|
|
42
|
+
headSourcePath: input.headSourcePath,
|
|
43
|
+
headSymbols
|
|
44
|
+
});
|
|
31
45
|
if (edit.ok) edits.push(edit.value);
|
|
32
46
|
else reasonCodes.push(...edit.reasonCodes);
|
|
33
47
|
}
|
|
@@ -67,20 +81,20 @@ export function projectSemanticEditScriptToSource(input = {}) {
|
|
|
67
81
|
appliedEditCount: deduped.edits.filter((edit) => !edit.alreadyApplied).length,
|
|
68
82
|
alreadyAppliedEditCount: deduped.edits.filter((edit) => edit.alreadyApplied).length,
|
|
69
83
|
dedupedEditCount: deduped.skippedOperationIds.length,
|
|
84
|
+
anchorMode: headSymbols.length ? 'javascript-like-symbols' : 'offsets',
|
|
70
85
|
...input.metadata
|
|
71
86
|
})
|
|
72
87
|
};
|
|
73
88
|
return { ...core, hash: hashSemanticValue(core) };
|
|
74
89
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const identity = projectionIdentity(operation, headSourcePath);
|
|
90
|
+
function sourceEditForOperation(operation, workerSourceText, headSourceText, order, context) {
|
|
91
|
+
const identity = projectionIdentity(operation, context.headSourcePath);
|
|
78
92
|
if (operation.status === 'already-applied') {
|
|
79
93
|
return { ok: true, value: { ...identity, operationId: operation.id, order, start: 0, end: 0, replacement: '', current: '', alreadyApplied: true } };
|
|
80
94
|
}
|
|
81
95
|
if (operation.status !== 'portable') return { ok: false, reasonCodes: [`operation-not-portable:${operation.id}`] };
|
|
82
96
|
if (operation.changeKind === 'added' || String(operation.kind ?? '').startsWith('add')) {
|
|
83
|
-
return insertionEditForOperation(operation, identity, workerSourceText, headSourceText, order);
|
|
97
|
+
return insertionEditForOperation(operation, identity, workerSourceText, headSourceText, order, context);
|
|
84
98
|
}
|
|
85
99
|
if (operation.changeKind === 'removed' || String(operation.kind ?? '').startsWith('remove')) {
|
|
86
100
|
return removalEditForOperation(operation, identity, headSourceText, order);
|
|
@@ -131,7 +145,6 @@ function sourceEditForOperation(operation, workerSourceText, headSourceText, ord
|
|
|
131
145
|
}
|
|
132
146
|
};
|
|
133
147
|
}
|
|
134
|
-
|
|
135
148
|
function removalEditForOperation(operation, identity, headSourceText, order) {
|
|
136
149
|
const headOffsets = spanOffsets(headSourceText, operation.spans?.head ?? operation.spans?.base ?? operation.anchor?.sourceSpan);
|
|
137
150
|
const reasons = [];
|
|
@@ -158,12 +171,11 @@ function removalEditForOperation(operation, identity, headSourceText, order) {
|
|
|
158
171
|
}
|
|
159
172
|
};
|
|
160
173
|
}
|
|
161
|
-
|
|
162
|
-
function insertionEditForOperation(operation, identity, workerSourceText, headSourceText, order) {
|
|
174
|
+
function insertionEditForOperation(operation, identity, workerSourceText, headSourceText, order, context) {
|
|
163
175
|
const workerOffsets = spanOffsets(workerSourceText, operation.spans?.worker);
|
|
164
176
|
const reasons = [];
|
|
165
177
|
if (!workerOffsets) reasons.push(`worker-span-not-resolvable:${operation.id}`);
|
|
166
|
-
const insertion = insertionOffset(headSourceText, operation.insertion);
|
|
178
|
+
const insertion = insertionOffset(headSourceText, operation.insertion, { symbols: context.headSymbols });
|
|
167
179
|
if (!insertion.ok) reasons.push(...insertion.reasonCodes.map((reason) => `${reason}:${operation.id}`));
|
|
168
180
|
if (reasons.length) return { ok: false, reasonCodes: reasons };
|
|
169
181
|
const spanText = workerSourceText.slice(workerOffsets.start, workerOffsets.end);
|
|
@@ -189,7 +201,6 @@ function insertionEditForOperation(operation, identity, workerSourceText, headSo
|
|
|
189
201
|
}
|
|
190
202
|
};
|
|
191
203
|
}
|
|
192
|
-
|
|
193
204
|
function projectionIdentity(operation, headSourcePath) {
|
|
194
205
|
const identity = semanticEditIdentity(operation);
|
|
195
206
|
const sourcePath = operation.reanchor?.toSourcePath ?? headSourcePath ?? operation.insertion?.sourcePath ?? identity.sourcePath;
|
|
@@ -201,7 +212,6 @@ function projectionIdentity(operation, headSourcePath) {
|
|
|
201
212
|
: identity.targetSourcePath;
|
|
202
213
|
return { ...identity, sourcePath, originalSourcePath, targetSourcePath };
|
|
203
214
|
}
|
|
204
|
-
|
|
205
215
|
function projectionEditRecord(edit) {
|
|
206
216
|
const deletedTextHash = hashSemanticValue(edit.current);
|
|
207
217
|
const replacementTextHash = hashSemanticValue(edit.replacement);
|
|
@@ -255,10 +265,25 @@ function projectionEditRecord(edit) {
|
|
|
255
265
|
insertionAnchorKey: edit.insertion?.anchorKey,
|
|
256
266
|
insertionAnchorSymbolName: edit.insertion?.anchorSymbolName,
|
|
257
267
|
insertionAnchorSymbolKind: edit.insertion?.anchorSymbolKind,
|
|
268
|
+
insertionAnchorCandidates: edit.insertion?.anchorCandidates,
|
|
258
269
|
replacementText: edit.replacement
|
|
259
270
|
});
|
|
260
271
|
}
|
|
261
272
|
|
|
273
|
+
function sourceSymbolIndex(input) {
|
|
274
|
+
try {
|
|
275
|
+
const imported = normalizeNativeDiffImport({
|
|
276
|
+
language: input.language,
|
|
277
|
+
sourcePath: input.sourcePath,
|
|
278
|
+
sourceText: input.sourceText,
|
|
279
|
+
parser: input.parser
|
|
280
|
+
}, input, 'head');
|
|
281
|
+
return [...mapDiffSymbols(imported, createSemanticImportSidecar(imported)).values()];
|
|
282
|
+
} catch {
|
|
283
|
+
return [];
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
262
287
|
function semanticEditIdentity(operation) {
|
|
263
288
|
const anchor = operation.anchor ?? {};
|
|
264
289
|
return compactRecord({
|
|
@@ -288,6 +313,7 @@ function projectedSourcePath(script, edits) {
|
|
|
288
313
|
return edits.map((edit) => edit.sourcePath).find(Boolean) ?? script.sourcePath;
|
|
289
314
|
}
|
|
290
315
|
|
|
316
|
+
function isJavaScriptLike(language) { return language === 'javascript' || language === 'typescript'; }
|
|
291
317
|
function compactRecord(value) {
|
|
292
318
|
return Object.fromEntries(Object.entries(value ?? {}).filter(([, entry]) => entry !== undefined && (!Array.isArray(entry) || entry.length > 0)));
|
|
293
319
|
}
|