@shapeshift-labs/frontier-lang-compiler 0.2.33 → 0.2.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/bench/smoke.mjs +20 -0
- package/dist/index.d.ts +200 -1
- package/dist/index.js +847 -3
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -6,7 +6,9 @@ import {
|
|
|
6
6
|
createSemanticIndexRecord,
|
|
7
7
|
createSemanticMergeCandidateRecord,
|
|
8
8
|
createSourceMapRecord,
|
|
9
|
+
createSourcePreservationRecord,
|
|
9
10
|
createUniversalAstEnvelope,
|
|
11
|
+
explainSourcePreservation,
|
|
10
12
|
hashDocumentBase,
|
|
11
13
|
hashSemanticValue,
|
|
12
14
|
nativeSourceNode,
|
|
@@ -277,6 +279,24 @@ export const ProjectionTargetLossClasses = Object.freeze([
|
|
|
277
279
|
'missingAdapter'
|
|
278
280
|
]);
|
|
279
281
|
|
|
282
|
+
export const NativeParserFeatureCategories = Object.freeze([
|
|
283
|
+
'syntax',
|
|
284
|
+
'semantic',
|
|
285
|
+
'type',
|
|
286
|
+
'controlFlow',
|
|
287
|
+
'macroMetaprogramming',
|
|
288
|
+
'sourcePreservation'
|
|
289
|
+
]);
|
|
290
|
+
|
|
291
|
+
export const NativeParserFeatureCoverageStatuses = Object.freeze([
|
|
292
|
+
'full',
|
|
293
|
+
'partial',
|
|
294
|
+
'evidence-required',
|
|
295
|
+
'missing',
|
|
296
|
+
'blocked',
|
|
297
|
+
'not-applicable'
|
|
298
|
+
]);
|
|
299
|
+
|
|
280
300
|
export const NativeImportLanguageProfiles = Object.freeze([
|
|
281
301
|
nativeImportLanguageProfile('javascript', {
|
|
282
302
|
aliases: ['js', 'mjs', 'cjs', 'jsx'],
|
|
@@ -2369,6 +2389,78 @@ export function createNativeParserAstFormatMatrix(input = {}) {
|
|
|
2369
2389
|
};
|
|
2370
2390
|
}
|
|
2371
2391
|
|
|
2392
|
+
export function createNativeParserFeatureMatrix(input = {}) {
|
|
2393
|
+
const imports = input.imports ?? [];
|
|
2394
|
+
const adapters = input.adapters ?? [];
|
|
2395
|
+
const profiles = mergeNativeImportProfiles(input.languages ?? NativeImportLanguageProfiles, imports, adapters);
|
|
2396
|
+
const parsers = nativeParserFeatureRowsForProfiles(profiles, {
|
|
2397
|
+
imports,
|
|
2398
|
+
adapters,
|
|
2399
|
+
requiredFeatures: input.requiredFeatures,
|
|
2400
|
+
minimumReadiness: input.minimumReadiness,
|
|
2401
|
+
includeEmptyParsers: input.includeEmptyParsers
|
|
2402
|
+
});
|
|
2403
|
+
const summary = nativeParserFeatureMatrixSummary(parsers);
|
|
2404
|
+
return {
|
|
2405
|
+
kind: 'frontier.lang.nativeParserFeatureMatrix',
|
|
2406
|
+
version: 1,
|
|
2407
|
+
generatedAt: input.generatedAt ?? Date.now(),
|
|
2408
|
+
parsers,
|
|
2409
|
+
languages: summarizeNativeParserFeatureLanguages(profiles, parsers),
|
|
2410
|
+
summary,
|
|
2411
|
+
metadata: {
|
|
2412
|
+
categories: [...NativeParserFeatureCategories],
|
|
2413
|
+
statuses: [...NativeParserFeatureCoverageStatuses],
|
|
2414
|
+
requiredFeatures: normalizeNativeParserRequiredFeatures(input.requiredFeatures),
|
|
2415
|
+
minimumReadiness: normalizeSemanticMergeReadiness(input.minimumReadiness ?? 'ready'),
|
|
2416
|
+
note: 'Native parser feature coverage is admission evidence per language/parser. It does not promote lightweight scans or host adapters beyond their declared and observed capabilities.'
|
|
2417
|
+
}
|
|
2418
|
+
};
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
export function queryNativeParserFeatureMatrix(matrixOrInput = {}, query = {}) {
|
|
2422
|
+
const matrix = matrixOrInput?.kind === 'frontier.lang.nativeParserFeatureMatrix'
|
|
2423
|
+
? matrixOrInput
|
|
2424
|
+
: createNativeParserFeatureMatrix(matrixOrInput);
|
|
2425
|
+
const language = normalizeNativeLanguageId(query.language);
|
|
2426
|
+
const parser = query.parser === undefined ? undefined : parserAstFormatIdForParser(query.parser);
|
|
2427
|
+
const requiredFeatures = normalizeNativeParserRequiredFeatures(query.requiredFeatures ?? matrix.metadata?.requiredFeatures);
|
|
2428
|
+
const minimumReadiness = normalizeSemanticMergeReadiness(query.minimumReadiness ?? matrix.metadata?.minimumReadiness ?? 'ready');
|
|
2429
|
+
const row = matrix.parsers.find((entry) => {
|
|
2430
|
+
if (language && normalizeNativeLanguageId(entry.language) !== language && !(entry.aliases ?? []).map(normalizeNativeLanguageId).includes(language)) {
|
|
2431
|
+
return false;
|
|
2432
|
+
}
|
|
2433
|
+
if (!parser) return true;
|
|
2434
|
+
const parserIds = [
|
|
2435
|
+
entry.parser,
|
|
2436
|
+
entry.parserFormat,
|
|
2437
|
+
...(entry.parserAliases ?? []),
|
|
2438
|
+
...(entry.parserAdapters ?? [])
|
|
2439
|
+
].map(parserAstFormatIdForParser);
|
|
2440
|
+
return parserIds.includes(parser);
|
|
2441
|
+
});
|
|
2442
|
+
const merge = row
|
|
2443
|
+
? nativeParserFeatureMergeAssessment(row, { requiredFeatures, minimumReadiness })
|
|
2444
|
+
: {
|
|
2445
|
+
mergeReady: false,
|
|
2446
|
+
readiness: 'blocked',
|
|
2447
|
+
requiredFeatures,
|
|
2448
|
+
minimumReadiness,
|
|
2449
|
+
blockingFeatures: requiredFeatures,
|
|
2450
|
+
reviewFeatures: [],
|
|
2451
|
+
reasons: [`No native parser feature coverage row matched language=${query.language ?? '*'} parser=${query.parser ?? '*'}.`]
|
|
2452
|
+
};
|
|
2453
|
+
return {
|
|
2454
|
+
kind: 'frontier.lang.nativeParserFeatureQuery',
|
|
2455
|
+
version: 1,
|
|
2456
|
+
found: Boolean(row),
|
|
2457
|
+
language: row?.language ?? language,
|
|
2458
|
+
parser: row?.parser ?? parser,
|
|
2459
|
+
row,
|
|
2460
|
+
merge
|
|
2461
|
+
};
|
|
2462
|
+
}
|
|
2463
|
+
|
|
2372
2464
|
export function createProjectionTargetLossMatrix(input = {}) {
|
|
2373
2465
|
const imports = input.imports ?? [];
|
|
2374
2466
|
const adapters = input.adapters ?? [];
|
|
@@ -2472,6 +2564,7 @@ export function createSemanticImportSidecar(importResult, options = {}) {
|
|
|
2472
2564
|
const mergeCandidates = imports.flatMap((imported) => imported?.mergeCandidates ?? []);
|
|
2473
2565
|
const lossSummary = summarizeNativeImportLosses(losses, { evidence });
|
|
2474
2566
|
const regionTaxonomy = summarizeSemanticImportRegionTaxonomy(ownershipRegions);
|
|
2567
|
+
const sourcePreservation = summarizeKernelSourcePreservation(importResult, imports);
|
|
2475
2568
|
const readiness = mergeCandidates.reduce(
|
|
2476
2569
|
(current, candidate) => maxSemanticMergeReadiness(current, candidate.readiness),
|
|
2477
2570
|
lossSummary.semanticMergeReadiness
|
|
@@ -2492,6 +2585,7 @@ export function createSemanticImportSidecar(importResult, options = {}) {
|
|
|
2492
2585
|
mappings: sourceMapMappings.length,
|
|
2493
2586
|
ids: sourceMaps.map((sourceMap) => sourceMap.id).filter(Boolean)
|
|
2494
2587
|
},
|
|
2588
|
+
sourcePreservation,
|
|
2495
2589
|
patchHints,
|
|
2496
2590
|
mergeCandidates: mergeCandidates.map((candidate) => ({
|
|
2497
2591
|
id: candidate.id,
|
|
@@ -2520,6 +2614,7 @@ export function createSemanticImportSidecar(importResult, options = {}) {
|
|
|
2520
2614
|
ownershipRegions: ownershipRegions.length,
|
|
2521
2615
|
regionKinds: regionTaxonomy.presentKinds.length,
|
|
2522
2616
|
sourceMapMappings: sourceMapMappings.length,
|
|
2617
|
+
sourcePreservationRecords: sourcePreservation.total,
|
|
2523
2618
|
readiness,
|
|
2524
2619
|
emptySemanticIndex: symbols.length === 0
|
|
2525
2620
|
},
|
|
@@ -3719,6 +3814,7 @@ export function importNativeSource(input) {
|
|
|
3719
3814
|
nativeSource,
|
|
3720
3815
|
evidence,
|
|
3721
3816
|
losses,
|
|
3817
|
+
sourcePreservation,
|
|
3722
3818
|
target: input.target,
|
|
3723
3819
|
targetPath,
|
|
3724
3820
|
targetHash
|
|
@@ -3753,6 +3849,7 @@ export function importNativeSource(input) {
|
|
|
3753
3849
|
semanticIndex,
|
|
3754
3850
|
evidence,
|
|
3755
3851
|
losses,
|
|
3852
|
+
sourcePreservation,
|
|
3756
3853
|
target: input.target,
|
|
3757
3854
|
targetPath: inferredTargetPath,
|
|
3758
3855
|
targetHash,
|
|
@@ -3760,6 +3857,20 @@ export function importNativeSource(input) {
|
|
|
3760
3857
|
sourceHash,
|
|
3761
3858
|
defaultSourceMapId: `source_map_${importIdPart}`
|
|
3762
3859
|
});
|
|
3860
|
+
const sourcePreservationRecords = createKernelSourcePreservationRecords({
|
|
3861
|
+
idPart: importIdPart,
|
|
3862
|
+
language,
|
|
3863
|
+
sourcePath,
|
|
3864
|
+
sourceHash,
|
|
3865
|
+
sourcePreservation,
|
|
3866
|
+
sourceMaps,
|
|
3867
|
+
losses,
|
|
3868
|
+
evidence,
|
|
3869
|
+
nativeSource,
|
|
3870
|
+
nativeAst,
|
|
3871
|
+
semanticIndex
|
|
3872
|
+
});
|
|
3873
|
+
const kernelSourcePreservationSummary = summarizeKernelSourcePreservationRecords(sourcePreservationRecords);
|
|
3763
3874
|
const resultSourceMapMappings = sourceMaps.flatMap((sourceMap) => sourceMap.mappings ?? []);
|
|
3764
3875
|
const universalAst = createUniversalAstEnvelope({
|
|
3765
3876
|
id: input.universalAstId ?? `universal_ast_${importIdPart}`,
|
|
@@ -3778,6 +3889,11 @@ export function importNativeSource(input) {
|
|
|
3778
3889
|
sourcePreservationId: sourcePreservation.id,
|
|
3779
3890
|
sourcePreservation
|
|
3780
3891
|
} : {}),
|
|
3892
|
+
...(sourcePreservationRecords.length ? {
|
|
3893
|
+
sourcePreservationRecords,
|
|
3894
|
+
kernelSourcePreservationRecords: sourcePreservationRecords,
|
|
3895
|
+
kernelSourcePreservationSummary
|
|
3896
|
+
} : {}),
|
|
3781
3897
|
...(declaredSourceHash && declaredSourceHash !== sourceHash ? {
|
|
3782
3898
|
declaredSourceHash,
|
|
3783
3899
|
sourceHashVerified: false
|
|
@@ -3805,6 +3921,10 @@ export function importNativeSource(input) {
|
|
|
3805
3921
|
sourcePreservationId: sourcePreservation.id,
|
|
3806
3922
|
sourcePreservationSummary: sourcePreservation.summary
|
|
3807
3923
|
} : {}),
|
|
3924
|
+
...(sourcePreservationRecords.length ? {
|
|
3925
|
+
kernelSourcePreservationRecordIds: sourcePreservationRecords.map((record) => record.id),
|
|
3926
|
+
kernelSourcePreservationSummary
|
|
3927
|
+
} : {}),
|
|
3808
3928
|
...(declaredSourceHash && declaredSourceHash !== sourceHash ? {
|
|
3809
3929
|
declaredSourceHash,
|
|
3810
3930
|
sourceHashVerified: false
|
|
@@ -3835,6 +3955,11 @@ export function importNativeSource(input) {
|
|
|
3835
3955
|
sourcePreservationId: sourcePreservation.id,
|
|
3836
3956
|
sourcePreservation
|
|
3837
3957
|
} : {}),
|
|
3958
|
+
...(sourcePreservationRecords.length ? {
|
|
3959
|
+
sourcePreservationRecords,
|
|
3960
|
+
kernelSourcePreservationRecords: sourcePreservationRecords,
|
|
3961
|
+
kernelSourcePreservationSummary
|
|
3962
|
+
} : {}),
|
|
3838
3963
|
...(declaredSourceHash && declaredSourceHash !== sourceHash ? {
|
|
3839
3964
|
declaredSourceHash,
|
|
3840
3965
|
sourceHashVerified: false
|
|
@@ -6481,6 +6606,8 @@ function normalizeSourceMapMappings(mappings, context) {
|
|
|
6481
6606
|
const sourceSpan = mapping.sourceSpan ?? occurrence?.span ?? nativeNode?.span;
|
|
6482
6607
|
const target = mapping.target ?? mapping.generatedSpan?.target ?? context.target;
|
|
6483
6608
|
const generatedSpan = normalizeGeneratedSpan(mapping.generatedSpan, target, context.targetPath, context.targetHash);
|
|
6609
|
+
const mappingLossIds = normalizeReferenceIds(mapping.lossIds, lossIdsForNativeNode(context.losses ?? nativeAst?.losses ?? [], nativeAstNodeId));
|
|
6610
|
+
const precision = normalizeSourceMapPrecision(mapping.precision, sourceSpan, generatedSpan);
|
|
6484
6611
|
if (
|
|
6485
6612
|
!nativeAstNodeId &&
|
|
6486
6613
|
!mapping.semanticNodeId &&
|
|
@@ -6503,11 +6630,17 @@ function normalizeSourceMapMappings(mappings, context) {
|
|
|
6503
6630
|
generatedSpan,
|
|
6504
6631
|
target,
|
|
6505
6632
|
evidenceIds: normalizeReferenceIds(mapping.evidenceIds, evidenceIds),
|
|
6506
|
-
lossIds:
|
|
6633
|
+
lossIds: mappingLossIds,
|
|
6507
6634
|
ownershipRegionId: mapping.ownershipRegionId ?? symbol?.metadata?.ownershipRegionId,
|
|
6508
6635
|
ownershipRegionKey: mapping.ownershipRegionKey ?? symbol?.metadata?.ownershipRegionKey,
|
|
6509
6636
|
ownershipRegionKind: mapping.ownershipRegionKind ?? symbol?.metadata?.ownershipRegionKind,
|
|
6510
|
-
precision
|
|
6637
|
+
precision,
|
|
6638
|
+
preservation: normalizeSourcePreservationLevel(mapping.preservation, {
|
|
6639
|
+
precision,
|
|
6640
|
+
lossIds: mappingLossIds,
|
|
6641
|
+
losses: context.losses ?? nativeAst?.losses ?? [],
|
|
6642
|
+
sourcePreservation: context.sourcePreservation
|
|
6643
|
+
})
|
|
6511
6644
|
};
|
|
6512
6645
|
return {
|
|
6513
6646
|
...normalizedMapping,
|
|
@@ -6588,10 +6721,19 @@ function normalizeSourceMapPrecision(value, sourceSpan, generatedSpan) {
|
|
|
6588
6721
|
const explicit = value === undefined || value === null ? '' : String(value).trim();
|
|
6589
6722
|
if (explicit) {
|
|
6590
6723
|
const normalized = explicit.toLowerCase();
|
|
6591
|
-
if (normalized === 'exact'
|
|
6724
|
+
if (normalized === 'exact') {
|
|
6725
|
+
return hasExactSpan(sourceSpan) && hasExactSpan(generatedSpan)
|
|
6726
|
+
? 'exact'
|
|
6727
|
+
: inferSourceMapPrecisionFromSpans(sourceSpan, generatedSpan);
|
|
6728
|
+
}
|
|
6729
|
+
if (normalized === 'declaration' || normalized === 'line' || normalized === 'estimated' || normalized === 'unknown') return normalized;
|
|
6592
6730
|
if (normalized === 'estimate' || normalized === 'approx' || normalized === 'approximate' || normalized === 'approximated') return 'estimated';
|
|
6593
6731
|
return explicit;
|
|
6594
6732
|
}
|
|
6733
|
+
return inferSourceMapPrecisionFromSpans(sourceSpan, generatedSpan);
|
|
6734
|
+
}
|
|
6735
|
+
|
|
6736
|
+
function inferSourceMapPrecisionFromSpans(sourceSpan, generatedSpan) {
|
|
6595
6737
|
if (hasExactSpan(sourceSpan) && hasExactSpan(generatedSpan)) return 'exact';
|
|
6596
6738
|
if (sourceSpan?.startLine && generatedSpan?.startLine) return 'line';
|
|
6597
6739
|
if (sourceSpan?.startLine) return 'declaration';
|
|
@@ -6599,6 +6741,25 @@ function normalizeSourceMapPrecision(value, sourceSpan, generatedSpan) {
|
|
|
6599
6741
|
return 'unknown';
|
|
6600
6742
|
}
|
|
6601
6743
|
|
|
6744
|
+
function normalizeSourcePreservationLevel(value, context = {}) {
|
|
6745
|
+
const explicit = value === undefined || value === null ? '' : String(value).trim();
|
|
6746
|
+
if (explicit) {
|
|
6747
|
+
const normalized = explicit.toLowerCase();
|
|
6748
|
+
if (normalized === 'exact' || normalized === 'declaration' || normalized === 'estimated' || normalized === 'blocked') return normalized;
|
|
6749
|
+
if (normalized === 'estimate' || normalized === 'approx' || normalized === 'approximate' || normalized === 'approximated' || normalized === 'line') return 'estimated';
|
|
6750
|
+
return explicit;
|
|
6751
|
+
}
|
|
6752
|
+
|
|
6753
|
+
const lossIds = new Set(context.lossIds ?? []);
|
|
6754
|
+
const linkedLosses = (context.losses ?? []).filter((loss) => lossIds.has(loss.id));
|
|
6755
|
+
if (linkedLosses.some((loss) => loss.severity === 'error')) return 'blocked';
|
|
6756
|
+
if (context.precision === 'exact') return 'exact';
|
|
6757
|
+
if (context.precision === 'declaration') return 'declaration';
|
|
6758
|
+
if (context.precision === 'line' || context.precision === 'estimated' || context.precision === 'unknown') return 'estimated';
|
|
6759
|
+
if (context.sourcePreservation?.summary?.exactSourceAvailable === true) return 'estimated';
|
|
6760
|
+
return 'estimated';
|
|
6761
|
+
}
|
|
6762
|
+
|
|
6602
6763
|
function hasExactSpan(span) {
|
|
6603
6764
|
return Boolean(span && (
|
|
6604
6765
|
(typeof span.start === 'number' && typeof span.end === 'number') ||
|
|
@@ -7312,6 +7473,12 @@ function nativeSourceCompilePreservedMappings(input) {
|
|
|
7312
7473
|
ownershipRegionKey: mapping.ownershipRegionKey,
|
|
7313
7474
|
ownershipRegionKind: mapping.ownershipRegionKind,
|
|
7314
7475
|
precision: exact ? 'exact' : mapping.precision === 'exact' ? 'line' : mapping.precision ?? 'line',
|
|
7476
|
+
preservation: exact ? 'exact' : normalizeSourcePreservationLevel(mapping.preservation, {
|
|
7477
|
+
precision: mapping.precision === 'exact' ? 'line' : mapping.precision ?? 'line',
|
|
7478
|
+
lossIds: mapping.lossIds,
|
|
7479
|
+
losses: input.losses ?? [],
|
|
7480
|
+
sourcePreservation: input.importResult.metadata?.sourcePreservation
|
|
7481
|
+
}),
|
|
7315
7482
|
metadata: {
|
|
7316
7483
|
...mapping.metadata,
|
|
7317
7484
|
compileResultId: input.compileResultId,
|
|
@@ -7339,6 +7506,7 @@ function nativeSourceCompileDeclarationMappings(input) {
|
|
|
7339
7506
|
ownershipRegionKey: declaration.metadata?.ownershipRegionKey,
|
|
7340
7507
|
ownershipRegionKind: declaration.metadata?.ownershipRegionKind,
|
|
7341
7508
|
precision: generated.exactName ? 'declaration' : 'estimated',
|
|
7509
|
+
preservation: generated.exactName ? 'declaration' : 'estimated',
|
|
7342
7510
|
metadata: {
|
|
7343
7511
|
...declaration.metadata,
|
|
7344
7512
|
compileResultId: input.compileResultId,
|
|
@@ -7361,6 +7529,7 @@ function nativeSourceCompileFileMapping(input) {
|
|
|
7361
7529
|
target: input.target,
|
|
7362
7530
|
evidenceIds: (input.evidence ?? []).map((record) => record.id).filter(Boolean),
|
|
7363
7531
|
precision: input.projection.mode === 'preserved-source' && input.outputHash === input.projection.sourceHash ? 'line' : 'estimated',
|
|
7532
|
+
preservation: input.losses?.some((loss) => loss.severity === 'error') ? 'blocked' : 'estimated',
|
|
7364
7533
|
metadata: {
|
|
7365
7534
|
compileResultId: input.compileResultId,
|
|
7366
7535
|
sourceMapOrigin: 'file-fallback'
|
|
@@ -7523,6 +7692,557 @@ function normalizeParserAstFormatId(format) {
|
|
|
7523
7692
|
return String(format ?? '').trim().toLowerCase().replace(/[_\s]+/g, '-');
|
|
7524
7693
|
}
|
|
7525
7694
|
|
|
7695
|
+
const nativeParserMacroMetaprogrammingLossKinds = new Set([
|
|
7696
|
+
'macroExpansion',
|
|
7697
|
+
'macroHygiene',
|
|
7698
|
+
'preprocessor',
|
|
7699
|
+
'conditionalCompilation',
|
|
7700
|
+
'metaprogramming',
|
|
7701
|
+
'reflection',
|
|
7702
|
+
'generatedCode'
|
|
7703
|
+
]);
|
|
7704
|
+
|
|
7705
|
+
const nativeParserTypeCoverageLossKinds = new Set([
|
|
7706
|
+
'typeInference',
|
|
7707
|
+
'overloadResolution',
|
|
7708
|
+
'overloadTypeInference',
|
|
7709
|
+
'unsupportedSemantic'
|
|
7710
|
+
]);
|
|
7711
|
+
|
|
7712
|
+
function nativeParserFeatureRowsForProfiles(profiles, context) {
|
|
7713
|
+
const rows = [];
|
|
7714
|
+
for (const profile of profiles) {
|
|
7715
|
+
const matchingImports = nativeParserFeatureImportsForProfile(profile, context.imports);
|
|
7716
|
+
const matchingAdapters = nativeParserFeatureAdapterSummariesForProfile(profile, context.adapters);
|
|
7717
|
+
for (const parser of nativeParserFeatureParserSlots(profile, matchingImports, matchingAdapters)) {
|
|
7718
|
+
const row = nativeParserFeatureRowForParser(profile, parser, {
|
|
7719
|
+
...context,
|
|
7720
|
+
imports: matchingImports.filter((imported) => nativeParserFeatureParserMatches(nativeParserParserForImport(imported), parser)),
|
|
7721
|
+
adapters: matchingAdapters.filter((adapter) => nativeParserFeatureParserMatches(adapter.parser, parser))
|
|
7722
|
+
});
|
|
7723
|
+
if (context.includeEmptyParsers === false && row.imports.total === 0 && row.adapters.total === 0) continue;
|
|
7724
|
+
rows.push(row);
|
|
7725
|
+
}
|
|
7726
|
+
}
|
|
7727
|
+
return rows.sort((left, right) => {
|
|
7728
|
+
const languageOrder = left.language.localeCompare(right.language);
|
|
7729
|
+
return languageOrder || left.parser.localeCompare(right.parser);
|
|
7730
|
+
});
|
|
7731
|
+
}
|
|
7732
|
+
|
|
7733
|
+
function nativeParserFeatureRowForParser(profile, parser, context) {
|
|
7734
|
+
const imports = context.imports ?? [];
|
|
7735
|
+
const adapters = context.adapters ?? [];
|
|
7736
|
+
const parserFormat = parserAstFormatIdForParser(parser);
|
|
7737
|
+
const parserProfile = getNativeParserAstFormatProfile(parserFormat);
|
|
7738
|
+
const adapterCoverage = summarizeNativeImporterAdapterCoverageEntries([
|
|
7739
|
+
...imports.map((imported) => nativeImporterAdapterCoverageEntryFromImport(imported)).filter(Boolean),
|
|
7740
|
+
...adapters.map((adapter) => ({
|
|
7741
|
+
adapterId: adapter.id,
|
|
7742
|
+
language: adapter.language,
|
|
7743
|
+
parser: adapter.parser,
|
|
7744
|
+
coverage: adapter.coverage
|
|
7745
|
+
}))
|
|
7746
|
+
]);
|
|
7747
|
+
const losses = imports.flatMap((imported) => imported?.losses ?? imported?.nativeAst?.losses ?? []);
|
|
7748
|
+
const evidence = imports.flatMap((imported) => imported?.evidence ?? []);
|
|
7749
|
+
const lossSummary = summarizeNativeImportLosses(losses, { evidence, parser });
|
|
7750
|
+
const semanticEvidence = nativeParserFeatureSemanticEvidence(imports);
|
|
7751
|
+
const sourceMaps = imports.flatMap((imported) => imported?.sourceMaps ?? imported?.universalAst?.sourceMaps ?? []);
|
|
7752
|
+
const sourceMapMappings = sourceMaps.reduce((sum, sourceMap) => sum + (sourceMap?.mappings?.length ?? 0), 0);
|
|
7753
|
+
const sourcePreservation = summarizeImportSourcePreservation(undefined, imports);
|
|
7754
|
+
const nativeAstNodes = imports.reduce((sum, imported) => sum + Object.keys(imported?.nativeAst?.nodes ?? imported?.nativeSource?.ast?.nodes ?? {}).length, 0);
|
|
7755
|
+
const featureContext = {
|
|
7756
|
+
profile,
|
|
7757
|
+
parser,
|
|
7758
|
+
parserFormat,
|
|
7759
|
+
parserProfile,
|
|
7760
|
+
imports,
|
|
7761
|
+
adapters,
|
|
7762
|
+
adapterCoverage,
|
|
7763
|
+
losses,
|
|
7764
|
+
evidence,
|
|
7765
|
+
lossSummary,
|
|
7766
|
+
semanticEvidence,
|
|
7767
|
+
sourceMaps,
|
|
7768
|
+
sourceMapMappings,
|
|
7769
|
+
sourcePreservation,
|
|
7770
|
+
nativeAstNodes
|
|
7771
|
+
};
|
|
7772
|
+
const features = {
|
|
7773
|
+
syntax: nativeParserSyntaxFeature(featureContext),
|
|
7774
|
+
semantic: nativeParserSemanticFeature(featureContext),
|
|
7775
|
+
type: nativeParserTypeFeature(featureContext),
|
|
7776
|
+
controlFlow: nativeParserControlFlowFeature(featureContext),
|
|
7777
|
+
macroMetaprogramming: nativeParserMacroMetaprogrammingFeature(featureContext),
|
|
7778
|
+
sourcePreservation: nativeParserSourcePreservationFeature(featureContext)
|
|
7779
|
+
};
|
|
7780
|
+
const importReadiness = imports.length
|
|
7781
|
+
? lossSummary.semanticMergeReadiness
|
|
7782
|
+
: adapters.length ? 'needs-review' : normalizeSemanticMergeReadiness(profile.defaultReadiness) ?? 'needs-review';
|
|
7783
|
+
const row = {
|
|
7784
|
+
language: profile.language,
|
|
7785
|
+
aliases: profile.aliases,
|
|
7786
|
+
parser,
|
|
7787
|
+
parserFormat,
|
|
7788
|
+
parserAliases: uniqueStrings([...(parserProfile?.aliases ?? []), ...(parserProfile?.parserAdapters ?? [])]),
|
|
7789
|
+
parserAdapters: uniqueStrings([parser, ...(parserProfile?.parserAdapters ?? [])]),
|
|
7790
|
+
extensions: profile.extensions,
|
|
7791
|
+
supportsLightweightScan: profile.supportsLightweightScan,
|
|
7792
|
+
projectionTargets: profile.projectionTargets,
|
|
7793
|
+
knownLossKinds: uniqueStrings([...(profile.knownLossKinds ?? []), ...Object.keys(lossSummary.byKind)]),
|
|
7794
|
+
defaultReadiness: profile.defaultReadiness,
|
|
7795
|
+
notes: uniqueStrings([...(profile.notes ?? []), ...(parserProfile?.notes ?? [])]),
|
|
7796
|
+
adapters: {
|
|
7797
|
+
total: adapters.length,
|
|
7798
|
+
ids: adapters.map((adapter) => adapter.id),
|
|
7799
|
+
versions: uniqueStrings(adapters.map((adapter) => adapter.version).filter(Boolean)),
|
|
7800
|
+
exactness: uniqueStrings(adapters.map((adapter) => adapter.coverage?.exactness).filter(Boolean)),
|
|
7801
|
+
coverage: adapterCoverage
|
|
7802
|
+
},
|
|
7803
|
+
imports: {
|
|
7804
|
+
total: imports.length,
|
|
7805
|
+
sourcePaths: uniqueStrings(imports.map((imported) => imported?.sourcePath ?? imported?.nativeSource?.sourcePath ?? imported?.nativeAst?.sourcePath).filter(Boolean)),
|
|
7806
|
+
readiness: importReadiness,
|
|
7807
|
+
readinessReasons: imports.length ? lossSummary.readinessReasons : nativeImportCoverageReasons(profile),
|
|
7808
|
+
nativeAstNodes,
|
|
7809
|
+
symbols: semanticEvidence.symbols,
|
|
7810
|
+
references: semanticEvidence.references,
|
|
7811
|
+
types: semanticEvidence.types,
|
|
7812
|
+
controlFlow: semanticEvidence.controlFlow,
|
|
7813
|
+
sourceMaps: sourceMaps.length,
|
|
7814
|
+
sourceMapMappings,
|
|
7815
|
+
losses: lossSummary.total,
|
|
7816
|
+
lossKinds: lossSummary.byKind,
|
|
7817
|
+
lossCategories: lossSummary.categories,
|
|
7818
|
+
sourcePreservation
|
|
7819
|
+
},
|
|
7820
|
+
features
|
|
7821
|
+
};
|
|
7822
|
+
return {
|
|
7823
|
+
...row,
|
|
7824
|
+
merge: nativeParserFeatureMergeAssessment(row, {
|
|
7825
|
+
requiredFeatures: context.requiredFeatures,
|
|
7826
|
+
minimumReadiness: context.minimumReadiness
|
|
7827
|
+
})
|
|
7828
|
+
};
|
|
7829
|
+
}
|
|
7830
|
+
|
|
7831
|
+
function nativeParserSyntaxFeature(context) {
|
|
7832
|
+
const blockingSyntaxLosses = context.losses.filter((loss) => loss.severity === 'error' && (loss.kind === 'unsupportedSyntax' || loss.kind === 'parserDiagnostic'));
|
|
7833
|
+
const exactAst = context.adapterCoverage.effective.exactAst ?? 0;
|
|
7834
|
+
const sourceRanges = context.adapterCoverage.effective.sourceRanges ?? 0;
|
|
7835
|
+
const parserDiagnostics = context.adapterCoverage.effective.parserDiagnostics ?? 0;
|
|
7836
|
+
let status = 'missing';
|
|
7837
|
+
const reasons = [];
|
|
7838
|
+
if (blockingSyntaxLosses.length) {
|
|
7839
|
+
status = 'blocked';
|
|
7840
|
+
reasons.push('Parser diagnostics or unsupported syntax errors block syntax coverage.');
|
|
7841
|
+
} else if (exactAst > 0 && (sourceRanges > 0 || context.sourceMapMappings > 0)) {
|
|
7842
|
+
status = 'full';
|
|
7843
|
+
reasons.push('Exact parser AST and source-range evidence are available.');
|
|
7844
|
+
} else if (exactAst > 0 || sourceRanges > 0 || context.nativeAstNodes > 1 || context.sourceMapMappings > 0) {
|
|
7845
|
+
status = 'partial';
|
|
7846
|
+
reasons.push('Syntax evidence exists, but exact AST/source-range coverage is incomplete.');
|
|
7847
|
+
} else if (context.adapters.length || context.parserProfile) {
|
|
7848
|
+
status = 'evidence-required';
|
|
7849
|
+
reasons.push('Parser slot is declared, but no observed syntax import evidence is attached.');
|
|
7850
|
+
} else {
|
|
7851
|
+
reasons.push('No syntax parser coverage is declared or observed.');
|
|
7852
|
+
}
|
|
7853
|
+
return nativeParserFeatureCoverage('syntax', status, {
|
|
7854
|
+
capabilities: {
|
|
7855
|
+
exactAst,
|
|
7856
|
+
sourceRanges,
|
|
7857
|
+
parserDiagnostics,
|
|
7858
|
+
nativeAstNodes: context.nativeAstNodes,
|
|
7859
|
+
sourceMapMappings: context.sourceMapMappings
|
|
7860
|
+
},
|
|
7861
|
+
gaps: nativeParserFeatureCapabilityGaps(context.adapterCoverage, ['exactAst', 'sourceRanges', 'parserDiagnostics']),
|
|
7862
|
+
lossKinds: nativeParserFeatureLossKindCounts(context.losses, ['unsupportedSyntax', 'parserDiagnostic']),
|
|
7863
|
+
reasons,
|
|
7864
|
+
notes: ['Syntax coverage covers parser AST/CST structure, diagnostics, source ranges, and source-map anchors.']
|
|
7865
|
+
});
|
|
7866
|
+
}
|
|
7867
|
+
|
|
7868
|
+
function nativeParserSemanticFeature(context) {
|
|
7869
|
+
const declarations = (context.adapterCoverage.effective.semanticDeclarations ?? 0) + context.semanticEvidence.declarations;
|
|
7870
|
+
const symbols = (context.adapterCoverage.effective.semanticSymbols ?? 0) + context.semanticEvidence.symbols;
|
|
7871
|
+
let status = 'missing';
|
|
7872
|
+
const reasons = [];
|
|
7873
|
+
if (symbols > 0 && declarations > 0) {
|
|
7874
|
+
status = 'full';
|
|
7875
|
+
reasons.push('Declaration and symbol evidence are available.');
|
|
7876
|
+
} else if (symbols > 0 || declarations > 0 || context.nativeAstNodes > 1) {
|
|
7877
|
+
status = 'partial';
|
|
7878
|
+
reasons.push('Semantic evidence is present, but declaration/symbol coverage is incomplete.');
|
|
7879
|
+
} else if (context.adapters.length || context.imports.length) {
|
|
7880
|
+
status = 'evidence-required';
|
|
7881
|
+
reasons.push('Import evidence exists, but no semantic declarations or symbols were observed.');
|
|
7882
|
+
} else {
|
|
7883
|
+
reasons.push('No semantic index evidence is declared or observed.');
|
|
7884
|
+
}
|
|
7885
|
+
return nativeParserFeatureCoverage('semantic', status, {
|
|
7886
|
+
capabilities: {
|
|
7887
|
+
declarations,
|
|
7888
|
+
symbols,
|
|
7889
|
+
semanticIndexLevel: nativeParserFeatureSemanticLevel(context.adapterCoverage, context.semanticEvidence)
|
|
7890
|
+
},
|
|
7891
|
+
gaps: nativeParserFeatureCapabilityGaps(context.adapterCoverage, ['semanticDeclarations', 'semanticSymbols']),
|
|
7892
|
+
lossKinds: nativeParserFeatureLossKindCounts(context.losses, ['partialSemanticIndex', 'unsupportedSemantic']),
|
|
7893
|
+
reasons,
|
|
7894
|
+
notes: ['Semantic coverage covers declaration and symbol evidence. References, types, and control flow are reported separately.']
|
|
7895
|
+
});
|
|
7896
|
+
}
|
|
7897
|
+
|
|
7898
|
+
function nativeParserTypeFeature(context) {
|
|
7899
|
+
const types = (context.adapterCoverage.effective.types ?? 0) + context.semanticEvidence.types;
|
|
7900
|
+
const typeLossKinds = nativeParserFeaturePresentLossKinds(context, nativeParserTypeCoverageLossKinds);
|
|
7901
|
+
let status = 'missing';
|
|
7902
|
+
const reasons = [];
|
|
7903
|
+
if (types > 0) {
|
|
7904
|
+
status = 'full';
|
|
7905
|
+
reasons.push('Resolved or declared type evidence is available.');
|
|
7906
|
+
} else if (typeLossKinds.length > 0 || context.semanticEvidence.symbols > 0) {
|
|
7907
|
+
status = 'evidence-required';
|
|
7908
|
+
reasons.push('Type-sensitive coverage needs compiler or language-server evidence.');
|
|
7909
|
+
} else {
|
|
7910
|
+
reasons.push('No type evidence is declared or observed.');
|
|
7911
|
+
}
|
|
7912
|
+
return nativeParserFeatureCoverage('type', status, {
|
|
7913
|
+
capabilities: { types },
|
|
7914
|
+
gaps: nativeParserFeatureCapabilityGaps(context.adapterCoverage, ['types']),
|
|
7915
|
+
lossKinds: nativeParserFeatureLossKindCounts(context.losses, [...nativeParserTypeCoverageLossKinds]),
|
|
7916
|
+
reasons,
|
|
7917
|
+
notes: ['Type coverage covers declared/inferred type facts and overload or inference evidence.']
|
|
7918
|
+
});
|
|
7919
|
+
}
|
|
7920
|
+
|
|
7921
|
+
function nativeParserControlFlowFeature(context) {
|
|
7922
|
+
const controlFlow = (context.adapterCoverage.effective.controlFlow ?? 0) + context.semanticEvidence.controlFlow;
|
|
7923
|
+
let status = 'missing';
|
|
7924
|
+
const reasons = [];
|
|
7925
|
+
if (controlFlow > 0) {
|
|
7926
|
+
status = 'full';
|
|
7927
|
+
reasons.push('Control-flow or CFG evidence is available.');
|
|
7928
|
+
} else if (context.imports.length || context.adapters.length) {
|
|
7929
|
+
status = 'evidence-required';
|
|
7930
|
+
reasons.push('Control-flow evidence was not observed for this parser row.');
|
|
7931
|
+
} else {
|
|
7932
|
+
reasons.push('No control-flow evidence is declared or observed.');
|
|
7933
|
+
}
|
|
7934
|
+
return nativeParserFeatureCoverage('controlFlow', status, {
|
|
7935
|
+
capabilities: { controlFlow },
|
|
7936
|
+
gaps: nativeParserFeatureCapabilityGaps(context.adapterCoverage, ['controlFlow']),
|
|
7937
|
+
lossKinds: {},
|
|
7938
|
+
reasons,
|
|
7939
|
+
notes: ['Control-flow coverage covers call/branch/CFG facts supplied by host parsers or semantic indexers.']
|
|
7940
|
+
});
|
|
7941
|
+
}
|
|
7942
|
+
|
|
7943
|
+
function nativeParserMacroMetaprogrammingFeature(context) {
|
|
7944
|
+
const macroLossKinds = nativeParserFeaturePresentLossKinds(context, nativeParserMacroMetaprogrammingLossKinds);
|
|
7945
|
+
const macroLosses = context.losses.filter((loss) => nativeParserMacroMetaprogrammingLossKinds.has(loss.kind));
|
|
7946
|
+
const featureEvidence = summarizeNativeImportFeatureEvidence(macroLosses, { evidence: context.evidence });
|
|
7947
|
+
const generatedRanges = context.adapterCoverage.effective.generatedRanges ?? 0;
|
|
7948
|
+
let status = 'not-applicable';
|
|
7949
|
+
const reasons = [];
|
|
7950
|
+
if (!macroLossKinds.length) {
|
|
7951
|
+
reasons.push('No macro, preprocessor, generator, or metaprogramming coverage risk is declared for this parser row.');
|
|
7952
|
+
} else if (macroLosses.some((loss) => loss.severity === 'error')) {
|
|
7953
|
+
status = 'blocked';
|
|
7954
|
+
reasons.push('Macro or metaprogramming evidence includes blocking loss records.');
|
|
7955
|
+
} else if (featureEvidence.missingRequiredEvidence.length > 0 || generatedRanges === 0) {
|
|
7956
|
+
status = 'evidence-required';
|
|
7957
|
+
reasons.push('Macro/metaprogramming coverage requires generated-range and policy evidence before merge admission.');
|
|
7958
|
+
} else {
|
|
7959
|
+
status = 'partial';
|
|
7960
|
+
reasons.push('Macro/metaprogramming risk has attached evidence, but this facade still treats generated behavior as review-required.');
|
|
7961
|
+
}
|
|
7962
|
+
return nativeParserFeatureCoverage('macroMetaprogramming', status, {
|
|
7963
|
+
capabilities: {
|
|
7964
|
+
generatedRanges,
|
|
7965
|
+
policyKinds: featureEvidence.policyKinds,
|
|
7966
|
+
highestRisk: featureEvidence.highestRisk
|
|
7967
|
+
},
|
|
7968
|
+
gaps: nativeParserFeatureCapabilityGaps(context.adapterCoverage, ['generatedRanges']),
|
|
7969
|
+
lossKinds: nativeParserFeatureLossKindCounts(context.losses, [...nativeParserMacroMetaprogrammingLossKinds]),
|
|
7970
|
+
reasons: uniqueStrings([...reasons, ...featureEvidence.reasons]),
|
|
7971
|
+
notes: ['Macro/metaprogramming coverage covers macros, preprocessors, generated code, reflection, and conditional compilation evidence.']
|
|
7972
|
+
});
|
|
7973
|
+
}
|
|
7974
|
+
|
|
7975
|
+
function nativeParserSourcePreservationFeature(context) {
|
|
7976
|
+
const exactSource = context.sourcePreservation.exactSourceAvailable;
|
|
7977
|
+
const tokens = context.sourcePreservation.tokens + (context.adapterCoverage.effective.tokens ?? 0);
|
|
7978
|
+
const trivia = context.sourcePreservation.trivia + (context.adapterCoverage.effective.trivia ?? 0);
|
|
7979
|
+
const sourceRanges = context.adapterCoverage.effective.sourceRanges ?? 0;
|
|
7980
|
+
let status = 'missing';
|
|
7981
|
+
const reasons = [];
|
|
7982
|
+
if (exactSource > 0 && (tokens > 0 || trivia > 0 || sourceRanges > 0)) {
|
|
7983
|
+
status = 'full';
|
|
7984
|
+
reasons.push('Exact source text and token/trivia or source-range evidence are available.');
|
|
7985
|
+
} else if (exactSource > 0 || tokens > 0 || trivia > 0 || sourceRanges > 0) {
|
|
7986
|
+
status = 'partial';
|
|
7987
|
+
reasons.push('Source-preservation evidence exists, but exact source, tokens, trivia, or ranges are incomplete.');
|
|
7988
|
+
} else if (context.imports.length || context.adapters.length) {
|
|
7989
|
+
status = 'evidence-required';
|
|
7990
|
+
reasons.push('Import or adapter evidence exists, but no exact source-preservation record was observed.');
|
|
7991
|
+
} else {
|
|
7992
|
+
reasons.push('No source-preservation evidence is declared or observed.');
|
|
7993
|
+
}
|
|
7994
|
+
return nativeParserFeatureCoverage('sourcePreservation', status, {
|
|
7995
|
+
capabilities: {
|
|
7996
|
+
exactSourceAvailable: exactSource,
|
|
7997
|
+
tokens,
|
|
7998
|
+
trivia,
|
|
7999
|
+
comments: context.sourcePreservation.comments,
|
|
8000
|
+
whitespace: context.sourcePreservation.whitespace,
|
|
8001
|
+
directives: context.sourcePreservation.directives,
|
|
8002
|
+
sourceRanges
|
|
8003
|
+
},
|
|
8004
|
+
gaps: nativeParserFeatureCapabilityGaps(context.adapterCoverage, ['tokens', 'trivia', 'sourceRanges']),
|
|
8005
|
+
lossKinds: nativeParserFeatureLossKindCounts(context.losses, ['sourcePreservation', 'commentsTrivia', 'sourceMapApproximation']),
|
|
8006
|
+
reasons,
|
|
8007
|
+
notes: ['Source-preservation coverage covers exact source text, token/trivia retention, comments, whitespace, directives, and source ranges.']
|
|
8008
|
+
});
|
|
8009
|
+
}
|
|
8010
|
+
|
|
8011
|
+
function nativeParserFeatureCoverage(category, status, input = {}) {
|
|
8012
|
+
const normalizedStatus = NativeParserFeatureCoverageStatuses.includes(status) ? status : 'missing';
|
|
8013
|
+
return Object.freeze({
|
|
8014
|
+
category,
|
|
8015
|
+
status: normalizedStatus,
|
|
8016
|
+
readiness: nativeParserFeatureReadinessForStatus(normalizedStatus),
|
|
8017
|
+
mergeReady: nativeParserFeatureStatusMergeReady(normalizedStatus),
|
|
8018
|
+
supported: normalizedStatus === 'full' || normalizedStatus === 'partial' || normalizedStatus === 'not-applicable',
|
|
8019
|
+
capabilities: Object.freeze(input.capabilities ?? {}),
|
|
8020
|
+
gaps: Object.freeze(uniqueStrings(input.gaps ?? [])),
|
|
8021
|
+
lossKinds: Object.freeze(input.lossKinds ?? {}),
|
|
8022
|
+
reasons: Object.freeze(uniqueStrings(input.reasons ?? [])),
|
|
8023
|
+
notes: Object.freeze(uniqueStrings(input.notes ?? []))
|
|
8024
|
+
});
|
|
8025
|
+
}
|
|
8026
|
+
|
|
8027
|
+
function nativeParserFeatureReadinessForStatus(status) {
|
|
8028
|
+
if (status === 'full' || status === 'not-applicable') return 'ready';
|
|
8029
|
+
if (status === 'partial') return 'ready-with-losses';
|
|
8030
|
+
if (status === 'blocked') return 'blocked';
|
|
8031
|
+
return 'needs-review';
|
|
8032
|
+
}
|
|
8033
|
+
|
|
8034
|
+
function nativeParserFeatureStatusMergeReady(status) {
|
|
8035
|
+
return status === 'full' || status === 'not-applicable';
|
|
8036
|
+
}
|
|
8037
|
+
|
|
8038
|
+
function nativeParserFeatureMergeAssessment(row, input = {}) {
|
|
8039
|
+
const requiredFeatures = normalizeNativeParserRequiredFeatures(input.requiredFeatures);
|
|
8040
|
+
const minimumReadiness = normalizeSemanticMergeReadiness(input.minimumReadiness ?? 'ready') ?? 'ready';
|
|
8041
|
+
const featureReadiness = requiredFeatures.reduce(
|
|
8042
|
+
(current, category) => maxSemanticMergeReadiness(current, row.features?.[category]?.readiness ?? 'blocked'),
|
|
8043
|
+
'ready'
|
|
8044
|
+
);
|
|
8045
|
+
const readiness = maxSemanticMergeReadiness(row.imports?.readiness ?? 'needs-review', featureReadiness);
|
|
8046
|
+
const blockingFeatures = requiredFeatures.filter((category) => !nativeParserFeatureStatusMergeReady(row.features?.[category]?.status));
|
|
8047
|
+
const reviewFeatures = requiredFeatures.filter((category) => {
|
|
8048
|
+
const featureReadiness = row.features?.[category]?.readiness ?? 'blocked';
|
|
8049
|
+
return semanticMergeReadinessRank[featureReadiness] > semanticMergeReadinessRank.ready
|
|
8050
|
+
&& semanticMergeReadinessRank[featureReadiness] <= semanticMergeReadinessRank['needs-review'];
|
|
8051
|
+
});
|
|
8052
|
+
const reasons = [];
|
|
8053
|
+
if ((row.imports?.total ?? 0) === 0) reasons.push('No native import evidence matched this language/parser row.');
|
|
8054
|
+
for (const category of blockingFeatures) {
|
|
8055
|
+
const feature = row.features?.[category];
|
|
8056
|
+
reasons.push(`${category} coverage is ${feature?.status ?? 'missing'}: ${(feature?.reasons ?? []).join(' ')}`);
|
|
8057
|
+
}
|
|
8058
|
+
if (semanticMergeReadinessRank[readiness] > semanticMergeReadinessRank[minimumReadiness]) {
|
|
8059
|
+
reasons.push(`Readiness ${readiness} is weaker than required threshold ${minimumReadiness}.`);
|
|
8060
|
+
}
|
|
8061
|
+
const mergeReady = (row.imports?.total ?? 0) > 0
|
|
8062
|
+
&& blockingFeatures.length === 0
|
|
8063
|
+
&& semanticMergeReadinessRank[readiness] <= semanticMergeReadinessRank[minimumReadiness];
|
|
8064
|
+
if (mergeReady) reasons.push(`Native import is merge-ready for required features: ${requiredFeatures.join(', ')}.`);
|
|
8065
|
+
return Object.freeze({
|
|
8066
|
+
mergeReady,
|
|
8067
|
+
readiness,
|
|
8068
|
+
requiredFeatures,
|
|
8069
|
+
minimumReadiness,
|
|
8070
|
+
blockingFeatures,
|
|
8071
|
+
reviewFeatures,
|
|
8072
|
+
reasons: uniqueStrings(reasons)
|
|
8073
|
+
});
|
|
8074
|
+
}
|
|
8075
|
+
|
|
8076
|
+
function normalizeNativeParserRequiredFeatures(value) {
|
|
8077
|
+
const requested = normalizeStringList(value);
|
|
8078
|
+
const features = requested.length ? requested : ['syntax', 'semantic', 'sourcePreservation'];
|
|
8079
|
+
return uniqueStrings(features.map(normalizeNativeParserFeatureCategory).filter((feature) => NativeParserFeatureCategories.includes(feature)));
|
|
8080
|
+
}
|
|
8081
|
+
|
|
8082
|
+
function normalizeNativeParserFeatureCategory(value) {
|
|
8083
|
+
const normalized = String(value ?? '').trim().replace(/[-_\s]+([a-zA-Z])/g, (_, letter) => letter.toUpperCase());
|
|
8084
|
+
if (normalized.toLowerCase() === 'macrometaprogramming' || normalized.toLowerCase() === 'macro') return 'macroMetaprogramming';
|
|
8085
|
+
if (normalized.toLowerCase() === 'controlflow' || normalized.toLowerCase() === 'cfg') return 'controlFlow';
|
|
8086
|
+
if (normalized.toLowerCase() === 'sourcepreservation' || normalized.toLowerCase() === 'source') return 'sourcePreservation';
|
|
8087
|
+
if (normalized.toLowerCase() === 'types') return 'type';
|
|
8088
|
+
return normalized;
|
|
8089
|
+
}
|
|
8090
|
+
|
|
8091
|
+
function nativeParserFeatureMatrixSummary(rows) {
|
|
8092
|
+
const summary = {
|
|
8093
|
+
languages: new Set(),
|
|
8094
|
+
parsers: rows.length,
|
|
8095
|
+
imports: 0,
|
|
8096
|
+
adapters: 0,
|
|
8097
|
+
mergeReady: 0,
|
|
8098
|
+
byReadiness: {},
|
|
8099
|
+
byFeatureStatus: {},
|
|
8100
|
+
byFeatureReadiness: {}
|
|
8101
|
+
};
|
|
8102
|
+
for (const row of rows) {
|
|
8103
|
+
summary.languages.add(row.language);
|
|
8104
|
+
summary.imports += row.imports.total;
|
|
8105
|
+
summary.adapters += row.adapters.total;
|
|
8106
|
+
if (row.merge.mergeReady) summary.mergeReady += 1;
|
|
8107
|
+
summary.byReadiness[row.merge.readiness] = (summary.byReadiness[row.merge.readiness] ?? 0) + 1;
|
|
8108
|
+
for (const [category, feature] of Object.entries(row.features)) {
|
|
8109
|
+
summary.byFeatureStatus[category] ??= {};
|
|
8110
|
+
summary.byFeatureReadiness[category] ??= {};
|
|
8111
|
+
summary.byFeatureStatus[category][feature.status] = (summary.byFeatureStatus[category][feature.status] ?? 0) + 1;
|
|
8112
|
+
summary.byFeatureReadiness[category][feature.readiness] = (summary.byFeatureReadiness[category][feature.readiness] ?? 0) + 1;
|
|
8113
|
+
}
|
|
8114
|
+
}
|
|
8115
|
+
return {
|
|
8116
|
+
...summary,
|
|
8117
|
+
languages: summary.languages.size
|
|
8118
|
+
};
|
|
8119
|
+
}
|
|
8120
|
+
|
|
8121
|
+
function summarizeNativeParserFeatureLanguages(profiles, rows) {
|
|
8122
|
+
return profiles.map((profile) => {
|
|
8123
|
+
const languageRows = rows.filter((row) => row.language === profile.language);
|
|
8124
|
+
return {
|
|
8125
|
+
language: profile.language,
|
|
8126
|
+
aliases: profile.aliases,
|
|
8127
|
+
parserRows: languageRows.length,
|
|
8128
|
+
parsers: languageRows.map((row) => row.parser),
|
|
8129
|
+
imports: languageRows.reduce((sum, row) => sum + row.imports.total, 0),
|
|
8130
|
+
adapters: languageRows.reduce((sum, row) => sum + row.adapters.total, 0),
|
|
8131
|
+
mergeReadyParsers: languageRows.filter((row) => row.merge.mergeReady).map((row) => row.parser),
|
|
8132
|
+
readiness: languageRows.reduce((current, row) => maxSemanticMergeReadiness(current, row.merge.readiness), 'ready')
|
|
8133
|
+
};
|
|
8134
|
+
});
|
|
8135
|
+
}
|
|
8136
|
+
|
|
8137
|
+
function nativeParserFeatureParserSlots(profile, imports, adapters) {
|
|
8138
|
+
const slots = [
|
|
8139
|
+
...(profile.parserAdapters ?? []),
|
|
8140
|
+
...adapters.map((adapter) => adapter.parser),
|
|
8141
|
+
...imports.map(nativeParserParserForImport)
|
|
8142
|
+
].filter(Boolean);
|
|
8143
|
+
if (!slots.length && profile.supportsLightweightScan) slots.push(`${profile.language}.lightweight-declaration-scan`);
|
|
8144
|
+
const seen = new Set();
|
|
8145
|
+
const result = [];
|
|
8146
|
+
for (const slot of slots) {
|
|
8147
|
+
const key = `${normalizeParserAstFormatId(slot)}#${parserAstFormatIdForParser(slot)}`;
|
|
8148
|
+
if (seen.has(key)) continue;
|
|
8149
|
+
seen.add(key);
|
|
8150
|
+
result.push(String(slot));
|
|
8151
|
+
}
|
|
8152
|
+
return result;
|
|
8153
|
+
}
|
|
8154
|
+
|
|
8155
|
+
function nativeParserFeatureImportsForProfile(profile, imports = []) {
|
|
8156
|
+
const languages = nativeParserFeatureLanguageSet(profile);
|
|
8157
|
+
return imports.filter((imported) => languages.has(normalizeNativeLanguageId(imported?.language ?? imported?.nativeAst?.language ?? imported?.nativeSource?.language)));
|
|
8158
|
+
}
|
|
8159
|
+
|
|
8160
|
+
function nativeParserFeatureAdapterSummariesForProfile(profile, adapters = []) {
|
|
8161
|
+
const languages = nativeParserFeatureLanguageSet(profile);
|
|
8162
|
+
return adapters
|
|
8163
|
+
.map((adapter) => safeNativeImporterAdapterSummary(adapter))
|
|
8164
|
+
.filter(Boolean)
|
|
8165
|
+
.filter((adapter) => languages.has(normalizeNativeLanguageId(adapter.language)));
|
|
8166
|
+
}
|
|
8167
|
+
|
|
8168
|
+
function nativeParserFeatureLanguageSet(profile) {
|
|
8169
|
+
return new Set([profile.language, ...(profile.aliases ?? [])].map(normalizeNativeLanguageId).filter(Boolean));
|
|
8170
|
+
}
|
|
8171
|
+
|
|
8172
|
+
function nativeParserParserForImport(imported) {
|
|
8173
|
+
return imported?.adapter?.parser
|
|
8174
|
+
?? imported?.metadata?.adapterCoverage?.parser
|
|
8175
|
+
?? imported?.nativeAst?.parser
|
|
8176
|
+
?? imported?.nativeSource?.parser
|
|
8177
|
+
?? imported?.parser
|
|
8178
|
+
?? imported?.metadata?.parser;
|
|
8179
|
+
}
|
|
8180
|
+
|
|
8181
|
+
function nativeParserFeatureParserMatches(candidateParser, rowParser) {
|
|
8182
|
+
if (!candidateParser || !rowParser) return false;
|
|
8183
|
+
const candidate = normalizeParserAstFormatId(candidateParser);
|
|
8184
|
+
const row = normalizeParserAstFormatId(rowParser);
|
|
8185
|
+
return candidate === row || parserAstFormatIdForParser(candidateParser) === parserAstFormatIdForParser(rowParser);
|
|
8186
|
+
}
|
|
8187
|
+
|
|
8188
|
+
function nativeParserFeatureSemanticEvidence(imports) {
|
|
8189
|
+
const totals = {
|
|
8190
|
+
declarations: 0,
|
|
8191
|
+
symbols: 0,
|
|
8192
|
+
references: 0,
|
|
8193
|
+
types: 0,
|
|
8194
|
+
controlFlow: 0
|
|
8195
|
+
};
|
|
8196
|
+
for (const imported of imports) {
|
|
8197
|
+
const semanticIndex = imported?.semanticIndex ?? imported?.universalAst?.semanticIndex;
|
|
8198
|
+
const evidence = observeNativeImporterSemanticEvidence(semanticIndex);
|
|
8199
|
+
totals.declarations += evidence.declarations;
|
|
8200
|
+
totals.symbols += semanticIndex?.symbols?.length ?? 0;
|
|
8201
|
+
totals.references += evidence.references;
|
|
8202
|
+
totals.types += evidence.types;
|
|
8203
|
+
totals.controlFlow += evidence.controlFlow;
|
|
8204
|
+
}
|
|
8205
|
+
return totals;
|
|
8206
|
+
}
|
|
8207
|
+
|
|
8208
|
+
function nativeParserFeatureSemanticLevel(adapterCoverage, semanticEvidence) {
|
|
8209
|
+
if ((adapterCoverage.effective.types ?? 0) > 0 || (adapterCoverage.effective.controlFlow ?? 0) > 0 || semanticEvidence.types > 0 || semanticEvidence.controlFlow > 0 || semanticEvidence.references > 0) {
|
|
8210
|
+
return 'semantic-index';
|
|
8211
|
+
}
|
|
8212
|
+
if ((adapterCoverage.effective.semanticDeclarations ?? 0) > 0 || (adapterCoverage.effective.semanticSymbols ?? 0) > 0 || semanticEvidence.declarations > 0 || semanticEvidence.symbols > 0) {
|
|
8213
|
+
return 'declaration-index';
|
|
8214
|
+
}
|
|
8215
|
+
return 'native-ast';
|
|
8216
|
+
}
|
|
8217
|
+
|
|
8218
|
+
function nativeParserFeatureCapabilityGaps(adapterCoverage, capabilities) {
|
|
8219
|
+
const gaps = new Set();
|
|
8220
|
+
for (const capability of capabilities) {
|
|
8221
|
+
if ((adapterCoverage.effective?.[capability] ?? 0) === 0) gaps.add(capability);
|
|
8222
|
+
}
|
|
8223
|
+
for (const capability of Object.keys(adapterCoverage.gaps ?? {})) {
|
|
8224
|
+
if (capabilities.includes(capability)) gaps.add(capability);
|
|
8225
|
+
}
|
|
8226
|
+
return [...gaps];
|
|
8227
|
+
}
|
|
8228
|
+
|
|
8229
|
+
function nativeParserFeatureLossKindCounts(losses, kinds) {
|
|
8230
|
+
const wanted = new Set(kinds);
|
|
8231
|
+
const counts = {};
|
|
8232
|
+
for (const loss of losses) {
|
|
8233
|
+
if (!wanted.has(loss?.kind)) continue;
|
|
8234
|
+
counts[loss.kind] = (counts[loss.kind] ?? 0) + 1;
|
|
8235
|
+
}
|
|
8236
|
+
return counts;
|
|
8237
|
+
}
|
|
8238
|
+
|
|
8239
|
+
function nativeParserFeaturePresentLossKinds(context, kindSet) {
|
|
8240
|
+
return uniqueStrings([
|
|
8241
|
+
...(context.profile.knownLossKinds ?? []),
|
|
8242
|
+
...Object.keys(context.lossSummary.byKind ?? {})
|
|
8243
|
+
].filter((kind) => kindSet.has(kind)));
|
|
8244
|
+
}
|
|
8245
|
+
|
|
7526
8246
|
function mergeNativeParserAstFormatProfiles(profiles, imports, adapters) {
|
|
7527
8247
|
const byId = new Map((profiles ?? []).map((profile) => [normalizeParserAstFormatId(profile.id ?? profile), nativeParserAstFormatProfile(normalizeParserAstFormatId(profile.id ?? profile), profile)]));
|
|
7528
8248
|
for (const adapter of adapters ?? []) {
|
|
@@ -7856,6 +8576,7 @@ function semanticImportSidecarEntry(imported, index, options) {
|
|
|
7856
8576
|
const nativeAst = imported?.nativeAst ?? imported?.nativeSource?.ast;
|
|
7857
8577
|
const sourceMaps = imported?.sourceMaps ?? imported?.universalAst?.sourceMaps ?? [];
|
|
7858
8578
|
const sourceMapMappings = sourceMaps.flatMap((sourceMap) => sourceMap?.mappings ?? []);
|
|
8579
|
+
const sourcePreservationRecords = collectKernelSourcePreservationFromImport(imported);
|
|
7859
8580
|
const mappingsBySymbolId = new Map();
|
|
7860
8581
|
for (const mapping of sourceMapMappings) {
|
|
7861
8582
|
if (mapping.semanticSymbolId && !mappingsBySymbolId.has(mapping.semanticSymbolId)) {
|
|
@@ -7900,6 +8621,8 @@ function semanticImportSidecarEntry(imported, index, options) {
|
|
|
7900
8621
|
symbolCount: symbols.length,
|
|
7901
8622
|
sourceMapCount: sourceMaps.length,
|
|
7902
8623
|
sourceMapMappingCount: sourceMapMappings.length,
|
|
8624
|
+
sourcePreservationRecordCount: sourcePreservationRecords.length,
|
|
8625
|
+
sourcePreservationLevels: uniqueStrings(sourcePreservationRecords.map((record) => record.level).filter(Boolean)),
|
|
7903
8626
|
readiness: imported?.metadata?.semanticMergeReadiness ?? imported?.mergeCandidates?.[0]?.readiness ?? 'needs-review',
|
|
7904
8627
|
emptySemanticIndex: symbols.length === 0,
|
|
7905
8628
|
regionTaxonomy,
|
|
@@ -8294,6 +9017,127 @@ function summarizeImportRegions(importResult, imports, options = {}) {
|
|
|
8294
9017
|
};
|
|
8295
9018
|
}
|
|
8296
9019
|
|
|
9020
|
+
function createKernelSourcePreservationRecords(input) {
|
|
9021
|
+
const records = [];
|
|
9022
|
+
if (input.sourcePreservation) {
|
|
9023
|
+
const exactSource = input.sourcePreservation.summary?.exactSourceAvailable === true &&
|
|
9024
|
+
(!input.sourceHash || input.sourcePreservation.sourceHash === input.sourceHash);
|
|
9025
|
+
const hashMismatch = input.sourceHash &&
|
|
9026
|
+
input.sourcePreservation.sourceHash &&
|
|
9027
|
+
input.sourcePreservation.sourceHash !== input.sourceHash;
|
|
9028
|
+
records.push(createSourcePreservationRecord({
|
|
9029
|
+
id: `source_preservation_${idFragment(input.idPart ?? input.sourcePath ?? input.language)}_file`,
|
|
9030
|
+
level: hashMismatch ? 'blocked' : exactSource ? 'exact' : 'estimated',
|
|
9031
|
+
precision: exactSource ? 'exact' : 'estimated',
|
|
9032
|
+
nativeSourceId: input.nativeSource?.id,
|
|
9033
|
+
nativeAstNodeId: input.nativeAst?.rootId,
|
|
9034
|
+
sourceSpan: {
|
|
9035
|
+
sourceId: input.sourceHash,
|
|
9036
|
+
path: input.sourcePath,
|
|
9037
|
+
startLine: 1,
|
|
9038
|
+
startColumn: 1
|
|
9039
|
+
},
|
|
9040
|
+
lossIds: (input.losses ?? []).filter((loss) => loss.kind === 'sourcePreservation' || loss.sourceMapId).map((loss) => loss.id),
|
|
9041
|
+
evidenceIds: (input.evidence ?? []).map((record) => record.id).filter(Boolean),
|
|
9042
|
+
losses: input.losses ?? [],
|
|
9043
|
+
evidence: input.evidence ?? [],
|
|
9044
|
+
reasons: hashMismatch
|
|
9045
|
+
? [`Preserved source hash ${input.sourcePreservation.sourceHash} does not match import hash ${input.sourceHash}.`]
|
|
9046
|
+
: exactSource
|
|
9047
|
+
? ['Exact native source text is preserved for source-level replay and semantic merge review.']
|
|
9048
|
+
: ['Native source preservation metadata exists, but exact source text is unavailable or unverified.'],
|
|
9049
|
+
metadata: {
|
|
9050
|
+
compilerRecord: 'nativeSourcePreservation',
|
|
9051
|
+
nativeSourcePreservationId: input.sourcePreservation.id,
|
|
9052
|
+
sourceBytes: input.sourcePreservation.sourceBytes,
|
|
9053
|
+
lineCount: input.sourcePreservation.lineCount,
|
|
9054
|
+
tokens: input.sourcePreservation.summary?.tokens ?? 0,
|
|
9055
|
+
trivia: input.sourcePreservation.summary?.trivia ?? 0,
|
|
9056
|
+
directives: input.sourcePreservation.summary?.directives ?? 0,
|
|
9057
|
+
comments: input.sourcePreservation.summary?.comments ?? 0,
|
|
9058
|
+
whitespace: input.sourcePreservation.summary?.whitespace ?? 0,
|
|
9059
|
+
truncated: input.sourcePreservation.summary?.truncated === true
|
|
9060
|
+
}
|
|
9061
|
+
}));
|
|
9062
|
+
}
|
|
9063
|
+
|
|
9064
|
+
for (const sourceMap of input.sourceMaps ?? []) {
|
|
9065
|
+
for (const mapping of sourceMap.mappings ?? []) {
|
|
9066
|
+
records.push(explainSourcePreservation({
|
|
9067
|
+
id: `source_preservation_${idFragment(sourceMap.id)}_${idFragment(mapping.id)}`,
|
|
9068
|
+
sourceMap,
|
|
9069
|
+
mapping,
|
|
9070
|
+
level: mapping.preservation,
|
|
9071
|
+
losses: input.losses ?? [],
|
|
9072
|
+
evidence: uniqueRecordsById([...(input.evidence ?? []), ...(sourceMap.evidence ?? [])]),
|
|
9073
|
+
metadata: {
|
|
9074
|
+
compilerRecord: 'sourceMapMapping',
|
|
9075
|
+
language: input.language,
|
|
9076
|
+
semanticIndexId: input.semanticIndex?.id,
|
|
9077
|
+
sourceMapId: sourceMap.id,
|
|
9078
|
+
sourceMapMappingId: mapping.id
|
|
9079
|
+
}
|
|
9080
|
+
}));
|
|
9081
|
+
}
|
|
9082
|
+
}
|
|
9083
|
+
|
|
9084
|
+
return uniqueRecordsById(records);
|
|
9085
|
+
}
|
|
9086
|
+
|
|
9087
|
+
function summarizeKernelSourcePreservationRecords(records) {
|
|
9088
|
+
const compactRecords = records.map(compactKernelSourcePreservationRecord);
|
|
9089
|
+
const byLevel = countBy(compactRecords.map((record) => record.level ?? 'unknown'));
|
|
9090
|
+
return {
|
|
9091
|
+
total: compactRecords.length,
|
|
9092
|
+
ids: compactRecords.map((record) => record.id).filter(Boolean),
|
|
9093
|
+
byLevel,
|
|
9094
|
+
exact: byLevel.exact ?? 0,
|
|
9095
|
+
declaration: byLevel.declaration ?? 0,
|
|
9096
|
+
estimated: byLevel.estimated ?? 0,
|
|
9097
|
+
blocked: byLevel.blocked ?? 0,
|
|
9098
|
+
sourcePaths: uniqueStrings(compactRecords.map((record) => record.sourcePath).filter(Boolean)),
|
|
9099
|
+
sourceMapIds: uniqueStrings(compactRecords.map((record) => record.sourceMapId).filter(Boolean)),
|
|
9100
|
+
sourceMapMappingIds: uniqueStrings(compactRecords.map((record) => record.sourceMapMappingId).filter(Boolean)),
|
|
9101
|
+
records: compactRecords
|
|
9102
|
+
};
|
|
9103
|
+
}
|
|
9104
|
+
|
|
9105
|
+
function collectKernelSourcePreservationFromImport(imported) {
|
|
9106
|
+
return uniqueRecordsById([
|
|
9107
|
+
...(imported?.metadata?.kernelSourcePreservationRecords ?? []),
|
|
9108
|
+
...(imported?.metadata?.sourcePreservationRecords ?? []),
|
|
9109
|
+
...(imported?.universalAst?.metadata?.kernelSourcePreservationRecords ?? []),
|
|
9110
|
+
...(imported?.universalAst?.metadata?.sourcePreservationRecords ?? [])
|
|
9111
|
+
].filter((record) => record?.kind === 'frontier.lang.sourcePreservation'));
|
|
9112
|
+
}
|
|
9113
|
+
|
|
9114
|
+
function summarizeKernelSourcePreservation(importResult, imports) {
|
|
9115
|
+
return summarizeKernelSourcePreservationRecords(uniqueRecordsById([
|
|
9116
|
+
...collectKernelSourcePreservationFromImport(importResult),
|
|
9117
|
+
...imports.flatMap((imported) => collectKernelSourcePreservationFromImport(imported))
|
|
9118
|
+
]));
|
|
9119
|
+
}
|
|
9120
|
+
|
|
9121
|
+
function compactKernelSourcePreservationRecord(record) {
|
|
9122
|
+
return {
|
|
9123
|
+
id: record.id,
|
|
9124
|
+
level: record.level,
|
|
9125
|
+
precision: record.precision,
|
|
9126
|
+
sourceMapId: record.sourceMapId,
|
|
9127
|
+
sourceMapMappingId: record.sourceMapMappingId,
|
|
9128
|
+
semanticNodeId: record.semanticNodeId,
|
|
9129
|
+
nativeSourceId: record.nativeSourceId,
|
|
9130
|
+
nativeAstNodeId: record.nativeAstNodeId,
|
|
9131
|
+
semanticSymbolId: record.semanticSymbolId,
|
|
9132
|
+
semanticOccurrenceId: record.semanticOccurrenceId,
|
|
9133
|
+
sourcePath: record.sourceSpan?.path,
|
|
9134
|
+
generatedPath: record.generatedSpan?.path ?? record.generatedSpan?.targetPath,
|
|
9135
|
+
lossIds: record.lossIds ?? [],
|
|
9136
|
+
evidenceIds: record.evidenceIds ?? [],
|
|
9137
|
+
reasons: record.reasons ?? []
|
|
9138
|
+
};
|
|
9139
|
+
}
|
|
9140
|
+
|
|
8297
9141
|
function summarizeImportSourcePreservation(importResult, imports) {
|
|
8298
9142
|
const records = uniqueSourcePreservationRecords([
|
|
8299
9143
|
...collectSourcePreservationFromImport(importResult),
|