@shapeshift-labs/frontier-lang-compiler 0.2.10 → 0.2.11
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/index.d.ts +58 -0
- package/dist/index.js +223 -3
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -112,6 +112,7 @@ export type NativeImportKnownLossKind =
|
|
|
112
112
|
| 'parserDiagnostic'
|
|
113
113
|
| 'unsupportedSyntax'
|
|
114
114
|
| 'unsupportedSemantic'
|
|
115
|
+
| 'unverifiedNativeAst'
|
|
115
116
|
| 'partialSemanticIndex'
|
|
116
117
|
| 'sourceMapApproximation'
|
|
117
118
|
| 'targetProjectionLoss'
|
|
@@ -511,6 +512,7 @@ export interface ImportNativeSourceOptions {
|
|
|
511
512
|
readonly sourceMaps?: readonly SourceMapRecord[];
|
|
512
513
|
readonly universalAstId?: string;
|
|
513
514
|
readonly universalAstMetadata?: Record<string, unknown>;
|
|
515
|
+
readonly exactAst?: boolean;
|
|
514
516
|
readonly metadata?: Record<string, unknown>;
|
|
515
517
|
}
|
|
516
518
|
|
|
@@ -724,7 +726,62 @@ export interface NativeSourceProjectionResult {
|
|
|
724
726
|
readonly metadata: Record<string, unknown>;
|
|
725
727
|
}
|
|
726
728
|
|
|
729
|
+
export type NativeImportRoundtripReadinessStatus =
|
|
730
|
+
| 'exact'
|
|
731
|
+
| 'preserved-source'
|
|
732
|
+
| 'stub-only'
|
|
733
|
+
| 'blocked'
|
|
734
|
+
| 'needs-review';
|
|
735
|
+
|
|
736
|
+
export interface NativeImportRoundtripReadinessOptions extends ProjectNativeImportToSourceOptions {
|
|
737
|
+
readonly projection?: NativeSourceProjectionResult;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
export interface NativeImportRoundtripReadinessClassification {
|
|
741
|
+
readonly kind: 'frontier.lang.nativeImportRoundtripReadiness';
|
|
742
|
+
readonly version: 1;
|
|
743
|
+
readonly status: NativeImportRoundtripReadinessStatus;
|
|
744
|
+
readonly semanticMergeReadiness: SemanticMergeReadiness;
|
|
745
|
+
readonly reasons: readonly string[];
|
|
746
|
+
readonly importReadiness: NativeImportReadinessClassification;
|
|
747
|
+
readonly projectionReadiness: NativeImportReadinessClassification;
|
|
748
|
+
readonly projectionMode: NativeSourceProjectionMode;
|
|
749
|
+
readonly checks: {
|
|
750
|
+
readonly nativeImport: {
|
|
751
|
+
readonly imports: number;
|
|
752
|
+
readonly exactAst: boolean;
|
|
753
|
+
readonly losses: number;
|
|
754
|
+
readonly readiness: SemanticMergeReadiness;
|
|
755
|
+
};
|
|
756
|
+
readonly universalAst: {
|
|
757
|
+
readonly present: boolean;
|
|
758
|
+
readonly valid: boolean;
|
|
759
|
+
readonly issues: readonly string[];
|
|
760
|
+
readonly nativeSources: number;
|
|
761
|
+
readonly semanticSymbols: number;
|
|
762
|
+
readonly sourceMaps: number;
|
|
763
|
+
readonly sourceMapMappings: number;
|
|
764
|
+
};
|
|
765
|
+
readonly projectedSource: {
|
|
766
|
+
readonly mode: NativeSourceProjectionMode;
|
|
767
|
+
readonly outputHash: string;
|
|
768
|
+
readonly expectedSourceHash?: string;
|
|
769
|
+
readonly sourceHashVerified: boolean;
|
|
770
|
+
readonly declarations: number;
|
|
771
|
+
readonly losses: number;
|
|
772
|
+
readonly readiness: SemanticMergeReadiness;
|
|
773
|
+
};
|
|
774
|
+
};
|
|
775
|
+
readonly evidence: {
|
|
776
|
+
readonly importEvidenceIds: readonly string[];
|
|
777
|
+
readonly projectionEvidenceIds: readonly string[];
|
|
778
|
+
readonly failedEvidenceIds: readonly string[];
|
|
779
|
+
};
|
|
780
|
+
readonly metadata: Record<string, unknown>;
|
|
781
|
+
}
|
|
782
|
+
|
|
727
783
|
export declare const FrontierCompileTargets: readonly FrontierCompileTarget[];
|
|
784
|
+
export declare const NativeImportRoundtripReadinessStatuses: readonly NativeImportRoundtripReadinessStatus[];
|
|
728
785
|
export declare const NativeImportTaxonomyKinds: readonly NativeImportTaxonomyKind[];
|
|
729
786
|
export declare const NativeImportLossKinds: readonly NativeImportKnownLossKind[];
|
|
730
787
|
export declare const NativeImportReadinessBySeverity: Readonly<Record<NativeImportLossSummary['highestSeverity'], SemanticMergeReadiness>>;
|
|
@@ -737,6 +794,7 @@ export declare function renderTargetAst(ast: FrontierTargetAst, target?: Frontie
|
|
|
737
794
|
export declare function resolveCapabilityAdapters(document: FrontierLangDocument, target?: FrontierCompileOptions['target'], options?: { readonly platform?: string }): readonly CapabilityResolution[];
|
|
738
795
|
export declare function summarizeNativeImportLosses(losses?: readonly NativeAstLossRecord[], options?: NativeImportLossSummaryOptions): NativeImportLossSummary;
|
|
739
796
|
export declare function classifyNativeImportReadiness(losses?: readonly NativeAstLossRecord[], options?: NativeImportLossSummaryOptions): NativeImportReadinessClassification;
|
|
797
|
+
export declare function classifyNativeImportRoundtripReadiness(importResult: NativeSourceImportResult | NativeProjectImportResult, options?: NativeImportRoundtripReadinessOptions): NativeImportRoundtripReadinessClassification;
|
|
740
798
|
export declare function createNativeImportCoverageMatrix(options?: NativeImportCoverageMatrixOptions): NativeImportCoverageMatrix;
|
|
741
799
|
export declare function createNativeSourcePreservation(options: CreateNativeSourcePreservationOptions): NativeSourcePreservation;
|
|
742
800
|
export declare function createSemanticImportSidecar(importResult: NativeSourceImportResult | NativeProjectImportResult, options?: SemanticImportSidecarOptions): SemanticImportSidecar;
|
package/dist/index.js
CHANGED
|
@@ -67,6 +67,14 @@ const semanticMergeReadinessRank = Object.freeze({
|
|
|
67
67
|
blocked: 3
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
+
export const NativeImportRoundtripReadinessStatuses = Object.freeze([
|
|
71
|
+
'exact',
|
|
72
|
+
'preserved-source',
|
|
73
|
+
'stub-only',
|
|
74
|
+
'blocked',
|
|
75
|
+
'needs-review'
|
|
76
|
+
]);
|
|
77
|
+
|
|
70
78
|
export const NativeImportTaxonomyKinds = Object.freeze([
|
|
71
79
|
'exactAstImport',
|
|
72
80
|
'declarationsOnly',
|
|
@@ -106,6 +114,7 @@ export const NativeImportLossKinds = Object.freeze([
|
|
|
106
114
|
'parserDiagnostic',
|
|
107
115
|
'unsupportedSyntax',
|
|
108
116
|
'unsupportedSemantic',
|
|
117
|
+
'unverifiedNativeAst',
|
|
109
118
|
'partialSemanticIndex',
|
|
110
119
|
'sourceMapApproximation',
|
|
111
120
|
'targetProjectionLoss'
|
|
@@ -327,6 +336,134 @@ export function classifyNativeImportReadiness(losses = [], options = {}) {
|
|
|
327
336
|
};
|
|
328
337
|
}
|
|
329
338
|
|
|
339
|
+
export function classifyNativeImportRoundtripReadiness(importResult, options = {}) {
|
|
340
|
+
if (!importResult || typeof importResult !== 'object') {
|
|
341
|
+
throw new Error('classifyNativeImportRoundtripReadiness requires a native import result');
|
|
342
|
+
}
|
|
343
|
+
const imports = nativeImportEntries(importResult);
|
|
344
|
+
const importLosses = uniqueByLossId([
|
|
345
|
+
...(importResult.losses ?? []),
|
|
346
|
+
...imports.flatMap((imported) => imported?.losses ?? [])
|
|
347
|
+
]);
|
|
348
|
+
const importEvidence = uniqueByEvidenceId([
|
|
349
|
+
...(importResult.evidence ?? []),
|
|
350
|
+
...imports.flatMap((imported) => imported?.evidence ?? [])
|
|
351
|
+
]);
|
|
352
|
+
const exactAst = imports.length > 0 && imports.every((imported) => nativeImportHasExactAstCoverage(imported));
|
|
353
|
+
const importReadiness = classifyNativeImportReadiness(importLosses, {
|
|
354
|
+
exactAst,
|
|
355
|
+
evidence: importEvidence,
|
|
356
|
+
parser: nativeImportRoundtripParser(importResult, imports),
|
|
357
|
+
scanKind: importResult.metadata?.nativeImportLossSummary?.scanKind,
|
|
358
|
+
semanticStatus: importResult.metadata?.semanticStatus ?? importResult.universalAst?.metadata?.semanticStatus
|
|
359
|
+
});
|
|
360
|
+
const projection = options.projection ?? projectNativeImportToSource(importResult, options);
|
|
361
|
+
const projectionReadiness = projection.readiness ?? classifyNativeImportReadiness(projection.losses ?? [], {
|
|
362
|
+
evidence: projection.evidence,
|
|
363
|
+
parser: projection.metadata?.nativeImportLossSummary?.parser,
|
|
364
|
+
scanKind: 'native-source-projection'
|
|
365
|
+
});
|
|
366
|
+
const universalAst = importResult.universalAst;
|
|
367
|
+
const universalAstIssues = universalAst
|
|
368
|
+
? validateUniversalAstEnvelope(universalAst)
|
|
369
|
+
: ['missing-universal-ast'];
|
|
370
|
+
const universalAstNativeSources = universalAst?.nativeSources?.length ?? importResult.nativeSources?.length ?? (importResult.nativeSource ? 1 : 0);
|
|
371
|
+
const semanticIndex = importResult.semanticIndex ?? universalAst?.semanticIndex;
|
|
372
|
+
const semanticSymbols = semanticIndex?.symbols?.length ?? 0;
|
|
373
|
+
const sourceMaps = importResult.sourceMaps ?? universalAst?.sourceMaps ?? [];
|
|
374
|
+
const sourceMapMappings = sourceMaps.reduce((sum, sourceMap) => sum + (sourceMap?.mappings?.length ?? 0), 0);
|
|
375
|
+
const projectionMatchesSourceHash = Boolean(projection.sourceHash && projection.outputHash === projection.sourceHash);
|
|
376
|
+
const preservedSource = projection.mode === 'preserved-source';
|
|
377
|
+
const failedEvidenceIds = uniqueStrings([
|
|
378
|
+
...importEvidence.filter((record) => record?.status === 'failed').map((record) => record.id),
|
|
379
|
+
...(projection.evidence ?? []).filter((record) => record?.status === 'failed').map((record) => record.id)
|
|
380
|
+
]);
|
|
381
|
+
const blockingReasons = [
|
|
382
|
+
...(importReadiness.readiness === 'blocked' ? importReadiness.reasons : []),
|
|
383
|
+
...(projectionReadiness.readiness === 'blocked' ? projectionReadiness.reasons : []),
|
|
384
|
+
...(failedEvidenceIds.length ? [`Failed evidence prevents native roundtrip readiness: ${failedEvidenceIds.join(', ')}`] : []),
|
|
385
|
+
...(universalAstIssues.length ? [`Universal AST validation failed: ${universalAstIssues.join('; ')}`] : [])
|
|
386
|
+
];
|
|
387
|
+
const reviewReasons = [
|
|
388
|
+
...(semanticSymbols === 0 ? ['Universal AST semantic index has no symbols for source projection review.'] : []),
|
|
389
|
+
...(sourceMapMappings === 0 ? ['Universal AST has no native source-map mappings for roundtrip review.'] : []),
|
|
390
|
+
...(preservedSource && !projectionMatchesSourceHash ? ['Projected source was preserved without a verified import source hash match.'] : []),
|
|
391
|
+
...importReadiness.reasons.filter((reason) => importReadiness.readiness !== 'ready' || !exactAst),
|
|
392
|
+
...projectionReadiness.reasons.filter((reason) => projectionReadiness.readiness !== 'ready')
|
|
393
|
+
];
|
|
394
|
+
let status;
|
|
395
|
+
if (blockingReasons.length) {
|
|
396
|
+
status = 'blocked';
|
|
397
|
+
} else if (projection.mode === 'native-source-stubs') {
|
|
398
|
+
status = 'stub-only';
|
|
399
|
+
} else if (reviewReasons.some((reason) => reason.startsWith('Universal AST')) || (preservedSource && !projectionMatchesSourceHash)) {
|
|
400
|
+
status = 'needs-review';
|
|
401
|
+
} else if (exactAst && preservedSource && projectionMatchesSourceHash && projectionReadiness.readiness === 'ready') {
|
|
402
|
+
status = 'exact';
|
|
403
|
+
} else if (preservedSource && projectionMatchesSourceHash) {
|
|
404
|
+
status = 'preserved-source';
|
|
405
|
+
} else {
|
|
406
|
+
status = 'needs-review';
|
|
407
|
+
}
|
|
408
|
+
const reasons = nativeImportRoundtripReasons(status, {
|
|
409
|
+
blockingReasons,
|
|
410
|
+
reviewReasons,
|
|
411
|
+
projection,
|
|
412
|
+
importReadiness,
|
|
413
|
+
projectionReadiness
|
|
414
|
+
});
|
|
415
|
+
return {
|
|
416
|
+
kind: 'frontier.lang.nativeImportRoundtripReadiness',
|
|
417
|
+
version: 1,
|
|
418
|
+
status,
|
|
419
|
+
semanticMergeReadiness: maxSemanticMergeReadiness(importReadiness.readiness, projectionReadiness.readiness),
|
|
420
|
+
reasons,
|
|
421
|
+
importReadiness,
|
|
422
|
+
projectionReadiness,
|
|
423
|
+
projectionMode: projection.mode,
|
|
424
|
+
checks: {
|
|
425
|
+
nativeImport: {
|
|
426
|
+
imports: imports.length,
|
|
427
|
+
exactAst,
|
|
428
|
+
losses: importReadiness.summary.total,
|
|
429
|
+
readiness: importReadiness.readiness
|
|
430
|
+
},
|
|
431
|
+
universalAst: {
|
|
432
|
+
present: Boolean(universalAst),
|
|
433
|
+
valid: universalAstIssues.length === 0,
|
|
434
|
+
issues: universalAstIssues,
|
|
435
|
+
nativeSources: universalAstNativeSources,
|
|
436
|
+
semanticSymbols,
|
|
437
|
+
sourceMaps: sourceMaps.length,
|
|
438
|
+
sourceMapMappings
|
|
439
|
+
},
|
|
440
|
+
projectedSource: {
|
|
441
|
+
mode: projection.mode,
|
|
442
|
+
outputHash: projection.outputHash,
|
|
443
|
+
expectedSourceHash: projection.sourceHash,
|
|
444
|
+
sourceHashVerified: projectionMatchesSourceHash,
|
|
445
|
+
declarations: projection.declarations?.length ?? 0,
|
|
446
|
+
losses: projection.lossSummary?.total ?? projection.losses?.length ?? 0,
|
|
447
|
+
readiness: projectionReadiness.readiness
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
evidence: {
|
|
451
|
+
importEvidenceIds: importEvidence.map((record) => record.id).filter(Boolean),
|
|
452
|
+
projectionEvidenceIds: (projection.evidence ?? []).map((record) => record.id).filter(Boolean),
|
|
453
|
+
failedEvidenceIds
|
|
454
|
+
},
|
|
455
|
+
metadata: {
|
|
456
|
+
nativeImportId: importResult.id,
|
|
457
|
+
universalAstId: universalAst?.id,
|
|
458
|
+
projectionId: projection.id,
|
|
459
|
+
sourcePath: projection.sourcePath ?? importResult.sourcePath,
|
|
460
|
+
language: projection.language ?? importResult.language,
|
|
461
|
+
sourcePreservationId: projection.metadata?.sourcePreservationId,
|
|
462
|
+
...options.metadata
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
|
|
330
467
|
export function createNativeImportCoverageMatrix(input = {}) {
|
|
331
468
|
const imports = input.imports ?? [];
|
|
332
469
|
const adapters = input.adapters ?? [];
|
|
@@ -917,7 +1054,17 @@ export function importNativeSource(input) {
|
|
|
917
1054
|
const frontierNodeIds = input.frontierNodeIds ?? input.semanticNodes?.map((node) => node.id) ?? [];
|
|
918
1055
|
const semanticNodes = input.semanticNodes ?? [];
|
|
919
1056
|
const semanticStatus = input.semanticStatus ?? (semanticNodes.length ? 'mapped' : 'native-only');
|
|
920
|
-
const
|
|
1057
|
+
const nativeAstExact = hasNativeExactAstEvidence(input, nativeAst, lightweight);
|
|
1058
|
+
const baseLosses = normalizeNativeLossRecords(input.losses ?? nativeAst.losses ?? lightweight?.losses ?? []);
|
|
1059
|
+
const losses = normalizeNativeLossRecords([
|
|
1060
|
+
...baseLosses,
|
|
1061
|
+
...unverifiedNativeAstLosses(input, nativeAst, {
|
|
1062
|
+
importIdPart,
|
|
1063
|
+
exactAst: nativeAstExact,
|
|
1064
|
+
hasLosses: baseLosses.length > 0,
|
|
1065
|
+
lightweight
|
|
1066
|
+
})
|
|
1067
|
+
]);
|
|
921
1068
|
const nativeSource = nativeSourceNode({
|
|
922
1069
|
id: input.nativeSourceId ?? `native_source_${importIdPart}`,
|
|
923
1070
|
name: input.name ?? sourcePath?.split(/[\\/]/).filter(Boolean).at(-1) ?? `${language}NativeSource`,
|
|
@@ -978,7 +1125,7 @@ export function importNativeSource(input) {
|
|
|
978
1125
|
}
|
|
979
1126
|
}];
|
|
980
1127
|
const lossSummary = summarizeNativeImportLosses(losses, {
|
|
981
|
-
exactAst:
|
|
1128
|
+
exactAst: nativeAstExact,
|
|
982
1129
|
evidence: baseEvidence,
|
|
983
1130
|
parser: nativeAst.parser,
|
|
984
1131
|
scanKind: lightweight?.metadata?.scanKind,
|
|
@@ -3106,7 +3253,7 @@ function nativeImportCategoryForLossKind(kind) {
|
|
|
3106
3253
|
if (kind === 'sourcePreservation' || kind === 'commentsTrivia' || kind === 'nonRoundTrippable') return 'sourcePreservation';
|
|
3107
3254
|
if (kind === 'parserDiagnostic') return 'parserDiagnostics';
|
|
3108
3255
|
if (kind === 'unsupportedSyntax' || kind === 'unsupportedSemantic') return 'unsupportedSyntax';
|
|
3109
|
-
if (kind === 'partialSemanticIndex') return 'partialSemanticIndex';
|
|
3256
|
+
if (kind === 'partialSemanticIndex' || kind === 'unverifiedNativeAst') return 'partialSemanticIndex';
|
|
3110
3257
|
if (kind === 'sourceMapApproximation') return 'sourceMapApproximation';
|
|
3111
3258
|
if (kind === 'targetProjectionLoss') return 'targetProjectionLoss';
|
|
3112
3259
|
return String(kind ?? 'opaqueNative');
|
|
@@ -3392,6 +3539,36 @@ function attachNativeImportLossSummary(evidence, lossSummary) {
|
|
|
3392
3539
|
}));
|
|
3393
3540
|
}
|
|
3394
3541
|
|
|
3542
|
+
function hasNativeExactAstEvidence(input, nativeAst, lightweight) {
|
|
3543
|
+
if (lightweight) return false;
|
|
3544
|
+
if (!(input?.nativeAst || input?.nodes)) return false;
|
|
3545
|
+
if (input.exactAst === true || input.metadata?.exactAst === true || input.nativeAstMetadata?.exactAst === true) return true;
|
|
3546
|
+
const coverage = input.metadata?.adapterCoverage
|
|
3547
|
+
?? input.nativeAstMetadata?.adapterCoverage
|
|
3548
|
+
?? input.nativeSourceMetadata?.adapterCoverage
|
|
3549
|
+
?? nativeAst?.metadata?.adapterCoverage;
|
|
3550
|
+
if (coverage?.exactAst !== true) return false;
|
|
3551
|
+
const observedNodes = coverage.observed?.nativeAstNodes;
|
|
3552
|
+
return observedNodes === undefined || observedNodes > 0;
|
|
3553
|
+
}
|
|
3554
|
+
|
|
3555
|
+
function unverifiedNativeAstLosses(input, nativeAst, context) {
|
|
3556
|
+
if (context.lightweight || context.exactAst || context.hasLosses) return [];
|
|
3557
|
+
if (!(input?.nativeAst || input?.nodes)) return [];
|
|
3558
|
+
return [{
|
|
3559
|
+
id: `loss_${context.importIdPart}_unverified_native_ast`,
|
|
3560
|
+
severity: 'warning',
|
|
3561
|
+
kind: 'unverifiedNativeAst',
|
|
3562
|
+
nodeId: nativeAst?.rootId,
|
|
3563
|
+
message: 'Caller supplied native AST nodes without explicit exactAst or adapter coverage evidence.',
|
|
3564
|
+
metadata: {
|
|
3565
|
+
reason: 'missing-exact-ast-evidence',
|
|
3566
|
+
nativeAstId: nativeAst?.id,
|
|
3567
|
+
parser: nativeAst?.parser
|
|
3568
|
+
}
|
|
3569
|
+
}];
|
|
3570
|
+
}
|
|
3571
|
+
|
|
3395
3572
|
function withNativeImportReadiness(importResult, lossSummary) {
|
|
3396
3573
|
const mergeCandidates = (importResult.mergeCandidates ?? []).map((candidate) => {
|
|
3397
3574
|
const readiness = maxSemanticMergeReadiness(candidate.readiness, lossSummary.semanticMergeReadiness);
|
|
@@ -3427,6 +3604,49 @@ function withNativeImportReadiness(importResult, lossSummary) {
|
|
|
3427
3604
|
};
|
|
3428
3605
|
}
|
|
3429
3606
|
|
|
3607
|
+
function nativeImportEntries(importResult) {
|
|
3608
|
+
if (Array.isArray(importResult?.imports)) return importResult.imports.filter(Boolean);
|
|
3609
|
+
return [importResult].filter(Boolean);
|
|
3610
|
+
}
|
|
3611
|
+
|
|
3612
|
+
function nativeImportHasExactAstCoverage(imported) {
|
|
3613
|
+
if (imported?.metadata?.nativeImportLossSummary?.exactAst === true) return true;
|
|
3614
|
+
if (imported?.adapter?.coverage?.exactAst === true && !(imported?.losses?.length)) return true;
|
|
3615
|
+
return false;
|
|
3616
|
+
}
|
|
3617
|
+
|
|
3618
|
+
function nativeImportRoundtripParser(importResult, imports) {
|
|
3619
|
+
const parsers = uniqueStrings([
|
|
3620
|
+
importResult.nativeAst?.parser,
|
|
3621
|
+
importResult.nativeSource?.parser,
|
|
3622
|
+
importResult.metadata?.parser,
|
|
3623
|
+
...imports.map((imported) => imported?.nativeAst?.parser ?? imported?.nativeSource?.parser ?? imported?.metadata?.parser)
|
|
3624
|
+
].filter(Boolean));
|
|
3625
|
+
return parsers.length === 1 ? parsers[0] : parsers.length ? parsers.join(',') : undefined;
|
|
3626
|
+
}
|
|
3627
|
+
|
|
3628
|
+
function nativeImportRoundtripReasons(status, input) {
|
|
3629
|
+
if (status === 'blocked') return uniqueStrings(input.blockingReasons);
|
|
3630
|
+
if (status === 'stub-only') {
|
|
3631
|
+
return uniqueStrings([
|
|
3632
|
+
`Native source projection emitted declaration stubs in ${input.projection.mode} mode.`,
|
|
3633
|
+
...input.projectionReadiness.reasons,
|
|
3634
|
+
...input.importReadiness.reasons.filter((reason) => input.importReadiness.readiness !== 'ready')
|
|
3635
|
+
]);
|
|
3636
|
+
}
|
|
3637
|
+
if (status === 'needs-review') return uniqueStrings(input.reviewReasons);
|
|
3638
|
+
if (status === 'exact') {
|
|
3639
|
+
return ['Exact native AST import and verified preserved source projection are available.'];
|
|
3640
|
+
}
|
|
3641
|
+
if (status === 'preserved-source') {
|
|
3642
|
+
return uniqueStrings([
|
|
3643
|
+
'Verified native source text is preserved for projection; semantic import evidence may still require review.',
|
|
3644
|
+
...input.importReadiness.reasons.filter((reason) => input.importReadiness.readiness !== 'ready')
|
|
3645
|
+
]);
|
|
3646
|
+
}
|
|
3647
|
+
return ['Native import roundtrip readiness requires review.'];
|
|
3648
|
+
}
|
|
3649
|
+
|
|
3430
3650
|
function maxSemanticMergeReadiness(left, right) {
|
|
3431
3651
|
const leftRank = semanticMergeReadinessRank[left] ?? semanticMergeReadinessRank['needs-review'];
|
|
3432
3652
|
const rightRank = semanticMergeReadinessRank[right] ?? semanticMergeReadinessRank['needs-review'];
|
package/package.json
CHANGED