@shapeshift-labs/frontier-lang-compiler 0.2.38 → 0.2.40
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 +61 -1
- package/bench/smoke.mjs +40 -1
- package/dist/index.d.ts +278 -0
- package/dist/index.js +1122 -0
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -2488,6 +2488,62 @@ export function createProjectionTargetLossMatrix(input = {}) {
|
|
|
2488
2488
|
};
|
|
2489
2489
|
}
|
|
2490
2490
|
|
|
2491
|
+
export function createUniversalCapabilityMatrix(input = {}) {
|
|
2492
|
+
const generatedAt = input.generatedAt ?? Date.now();
|
|
2493
|
+
const imports = input.imports ?? [];
|
|
2494
|
+
const adapters = input.adapters ?? [];
|
|
2495
|
+
const targetAdapters = input.targetAdapters ?? [];
|
|
2496
|
+
const languages = input.languages ?? NativeImportLanguageProfiles;
|
|
2497
|
+
const targets = input.targets ?? FrontierCompileTargets;
|
|
2498
|
+
const importCoverage = createNativeImportCoverageMatrix({ languages, imports, adapters, generatedAt });
|
|
2499
|
+
const parserFormats = createNativeParserAstFormatMatrix({
|
|
2500
|
+
formats: input.formats,
|
|
2501
|
+
imports,
|
|
2502
|
+
adapters,
|
|
2503
|
+
generatedAt
|
|
2504
|
+
});
|
|
2505
|
+
const parserFeatures = createNativeParserFeatureMatrix({
|
|
2506
|
+
languages,
|
|
2507
|
+
imports,
|
|
2508
|
+
adapters,
|
|
2509
|
+
requiredFeatures: input.requiredFeatures,
|
|
2510
|
+
minimumReadiness: input.minimumReadiness,
|
|
2511
|
+
includeEmptyParsers: input.includeEmptyParsers,
|
|
2512
|
+
generatedAt
|
|
2513
|
+
});
|
|
2514
|
+
const projectionTargets = createProjectionTargetLossMatrix({
|
|
2515
|
+
languages,
|
|
2516
|
+
imports,
|
|
2517
|
+
adapters,
|
|
2518
|
+
targetAdapters,
|
|
2519
|
+
targets,
|
|
2520
|
+
generatedAt
|
|
2521
|
+
});
|
|
2522
|
+
const rows = importCoverage.languages.map((entry) => universalCapabilityLanguageRow(entry, {
|
|
2523
|
+
parserFeatures,
|
|
2524
|
+
projectionTargets
|
|
2525
|
+
}));
|
|
2526
|
+
return {
|
|
2527
|
+
kind: 'frontier.lang.universalCapabilityMatrix',
|
|
2528
|
+
version: 1,
|
|
2529
|
+
generatedAt,
|
|
2530
|
+
languages: rows,
|
|
2531
|
+
summary: universalCapabilityMatrixSummary(rows),
|
|
2532
|
+
matrices: {
|
|
2533
|
+
importCoverage,
|
|
2534
|
+
parserFormats,
|
|
2535
|
+
parserFeatures,
|
|
2536
|
+
projectionTargets
|
|
2537
|
+
},
|
|
2538
|
+
metadata: {
|
|
2539
|
+
requiredFeatures: parserFeatures.metadata.requiredFeatures,
|
|
2540
|
+
minimumReadiness: parserFeatures.metadata.minimumReadiness,
|
|
2541
|
+
compileTargets: projectionTargets.metadata.compileTargets,
|
|
2542
|
+
note: 'Universal capability coverage composes import, parser, source-preservation, and projection evidence. It identifies gaps; it is not a proof that every language feature is losslessly portable.'
|
|
2543
|
+
}
|
|
2544
|
+
};
|
|
2545
|
+
}
|
|
2546
|
+
|
|
2491
2547
|
export function createNativeSourcePreservation(options) {
|
|
2492
2548
|
if (!options || typeof options.sourceText !== 'string') {
|
|
2493
2549
|
throw new Error('createNativeSourcePreservation requires sourceText');
|
|
@@ -4155,6 +4211,867 @@ export function diffNativeSourceImports(input) {
|
|
|
4155
4211
|
};
|
|
4156
4212
|
}
|
|
4157
4213
|
|
|
4214
|
+
export function createSemanticSlice(input, options = {}) {
|
|
4215
|
+
const context = semanticSliceContext(input, options);
|
|
4216
|
+
const sidecar = context.sidecar ?? (context.importResult ? createSemanticImportSidecar(context.importResult, {
|
|
4217
|
+
generatedAt: options.generatedAt,
|
|
4218
|
+
regionPrefix: options.regionPrefix
|
|
4219
|
+
}) : undefined);
|
|
4220
|
+
const records = semanticSliceRecords(context, sidecar);
|
|
4221
|
+
const entryRefs = uniqueStrings([
|
|
4222
|
+
...readStringArray(options.entryRefs),
|
|
4223
|
+
...readStringArray(options.semanticRefs),
|
|
4224
|
+
...readStringArray(options.refs),
|
|
4225
|
+
...(options.symbol ? [`symbol:${options.symbol}`] : []),
|
|
4226
|
+
...(options.region ? [`region:${options.region}`] : []),
|
|
4227
|
+
...(options.nativeNodeId ? [`native:${options.nativeNodeId}`] : []),
|
|
4228
|
+
...(options.sourcePath ? [`path:${options.sourcePath}`] : [])
|
|
4229
|
+
]);
|
|
4230
|
+
const selection = selectSemanticSliceRecords(records, {
|
|
4231
|
+
entryRefs,
|
|
4232
|
+
includeDependencies: options.includeDependencies !== false,
|
|
4233
|
+
maxDependencyDepth: Number.isFinite(options.maxDependencyDepth) ? Math.max(0, Math.floor(options.maxDependencyDepth)) : 2
|
|
4234
|
+
});
|
|
4235
|
+
const sourceSpans = semanticSliceSourceSpans(selection);
|
|
4236
|
+
const sourceFiles = semanticSliceSourceFiles(sourceSpans, context, options);
|
|
4237
|
+
const sourceMapLinks = semanticSliceSourceMapLinks(selection);
|
|
4238
|
+
const conflictKeys = uniqueStrings([
|
|
4239
|
+
...selection.regions.map((region) => region.conflictKey),
|
|
4240
|
+
...selection.regions.map((region) => region.key ? `region:${region.key}` : region.id ? `region:${region.id}` : undefined),
|
|
4241
|
+
...selection.symbols.map((symbol) => symbol.metadata?.ownershipRegionKey ? `region:${symbol.metadata.ownershipRegionKey}` : undefined),
|
|
4242
|
+
...selection.symbols.map((symbol) => symbol.id ? `symbol:${symbol.id}` : undefined),
|
|
4243
|
+
...sourceFiles.map((file) => file.path ? `source:${file.path}` : undefined)
|
|
4244
|
+
].filter(Boolean));
|
|
4245
|
+
const unresolvedEntryRefs = entryRefs.filter((entryRef) => !selection.matchedEntryRefs.includes(entryRef));
|
|
4246
|
+
const readiness = semanticSliceReadiness(context, selection, unresolvedEntryRefs);
|
|
4247
|
+
const reasons = semanticSliceReasons(context, selection, unresolvedEntryRefs, readiness);
|
|
4248
|
+
const idPart = idFragment(options.id ?? entryRefs.join('_') ?? context.sourcePath ?? context.language ?? context.importResult?.id ?? context.universalAst?.id ?? 'semantic_slice');
|
|
4249
|
+
const evidence = [{
|
|
4250
|
+
id: options.evidenceId ?? `evidence_${idPart}_semantic_slice`,
|
|
4251
|
+
kind: 'semantic-slice',
|
|
4252
|
+
status: readiness === 'blocked' ? 'failed' : 'passed',
|
|
4253
|
+
path: context.sourcePath,
|
|
4254
|
+
summary: `Created semantic slice with ${selection.symbols.length} symbol(s), ${selection.regions.length} ownership region(s), and ${sourceMapLinks.length} source-map link(s).`,
|
|
4255
|
+
metadata: {
|
|
4256
|
+
entryRefs,
|
|
4257
|
+
unresolvedEntryRefs,
|
|
4258
|
+
importId: context.importResult?.id,
|
|
4259
|
+
universalAstId: context.universalAst?.id,
|
|
4260
|
+
semanticIndexId: context.semanticIndex?.id,
|
|
4261
|
+
sidecarId: sidecar?.id
|
|
4262
|
+
}
|
|
4263
|
+
}];
|
|
4264
|
+
const mergeCandidate = createSemanticMergeCandidateRecord({
|
|
4265
|
+
id: options.mergeCandidateId ?? `merge_candidate_${idPart}_semantic_slice`,
|
|
4266
|
+
importResultId: context.importResult?.id,
|
|
4267
|
+
language: context.language,
|
|
4268
|
+
sourcePath: context.sourcePath,
|
|
4269
|
+
touchedSymbols: selection.symbols.map(semanticSliceTouchedSymbol),
|
|
4270
|
+
touchedSemanticNodes: [],
|
|
4271
|
+
nativeSpans: sourceSpans,
|
|
4272
|
+
conflictKeys,
|
|
4273
|
+
readiness,
|
|
4274
|
+
reasons,
|
|
4275
|
+
evidence,
|
|
4276
|
+
metadata: {
|
|
4277
|
+
kind: 'semantic-slice',
|
|
4278
|
+
sidecarId: sidecar?.id,
|
|
4279
|
+
sourceMapLinks: sourceMapLinks.length,
|
|
4280
|
+
nativeNodeIds: selection.nativeNodes.map((node) => node.id),
|
|
4281
|
+
dependencyRelationIds: selection.relations.map((relation) => relation.id).filter(Boolean),
|
|
4282
|
+
autoMergeClaim: false
|
|
4283
|
+
}
|
|
4284
|
+
});
|
|
4285
|
+
return {
|
|
4286
|
+
kind: 'frontier.lang.semanticSlice',
|
|
4287
|
+
version: 1,
|
|
4288
|
+
id: options.id ?? `semantic_slice_${idPart}`,
|
|
4289
|
+
generatedAt: options.generatedAt ?? Date.now(),
|
|
4290
|
+
language: context.language,
|
|
4291
|
+
sourcePath: context.sourcePath,
|
|
4292
|
+
importId: context.importResult?.id,
|
|
4293
|
+
universalAstId: context.universalAst?.id,
|
|
4294
|
+
semanticIndexId: context.semanticIndex?.id,
|
|
4295
|
+
sidecarId: sidecar?.id,
|
|
4296
|
+
entryRefs,
|
|
4297
|
+
matchedEntryRefs: selection.matchedEntryRefs,
|
|
4298
|
+
unresolvedEntryRefs,
|
|
4299
|
+
symbols: selection.symbols,
|
|
4300
|
+
ownershipRegions: selection.regions,
|
|
4301
|
+
nativeNodes: selection.nativeNodes,
|
|
4302
|
+
relations: selection.relations,
|
|
4303
|
+
occurrences: selection.occurrences,
|
|
4304
|
+
sourceMapLinks,
|
|
4305
|
+
sourceSpans,
|
|
4306
|
+
sourceFiles,
|
|
4307
|
+
losses: selection.losses,
|
|
4308
|
+
evidence,
|
|
4309
|
+
mergeCandidate,
|
|
4310
|
+
verification: {
|
|
4311
|
+
focusedCommands: readStringArray(options.focusedCommands),
|
|
4312
|
+
fixtureHints: readStringArray(options.fixtureHints),
|
|
4313
|
+
expectedAssertions: semanticSliceExpectedAssertions(selection, unresolvedEntryRefs)
|
|
4314
|
+
},
|
|
4315
|
+
summary: {
|
|
4316
|
+
symbols: selection.symbols.length,
|
|
4317
|
+
ownershipRegions: selection.regions.length,
|
|
4318
|
+
nativeNodes: selection.nativeNodes.length,
|
|
4319
|
+
relations: selection.relations.length,
|
|
4320
|
+
occurrences: selection.occurrences.length,
|
|
4321
|
+
sourceMapLinks: sourceMapLinks.length,
|
|
4322
|
+
sourceFiles: sourceFiles.length,
|
|
4323
|
+
losses: selection.losses.length,
|
|
4324
|
+
conflictKeys: conflictKeys.length,
|
|
4325
|
+
readiness,
|
|
4326
|
+
unresolvedEntryRefs: unresolvedEntryRefs.length,
|
|
4327
|
+
sourceTextAvailable: sourceFiles.some((file) => file.excerptCount > 0)
|
|
4328
|
+
},
|
|
4329
|
+
mergeAdmission: {
|
|
4330
|
+
autoMergeClaim: false,
|
|
4331
|
+
reviewRequired: readiness !== 'ready',
|
|
4332
|
+
readiness,
|
|
4333
|
+
reasons,
|
|
4334
|
+
conflictKeys,
|
|
4335
|
+
ownershipKeys: uniqueStrings(selection.regions.map((region) => region.key).filter(Boolean)),
|
|
4336
|
+
sourceHashes: sourceFiles.map((file) => ({ path: file.path, sourceHash: file.sourceHash })).filter((file) => file.path || file.sourceHash),
|
|
4337
|
+
staleCheck: {
|
|
4338
|
+
mode: 'source-hash',
|
|
4339
|
+
requiresCurrentSource: sourceFiles.some((file) => file.sourceHash),
|
|
4340
|
+
sourceFiles: sourceFiles.length
|
|
4341
|
+
}
|
|
4342
|
+
},
|
|
4343
|
+
metadata: {
|
|
4344
|
+
note: 'Semantic slices are focused source-addressable evidence for agent isolation and merge admission; they are not correctness proofs.',
|
|
4345
|
+
...options.metadata
|
|
4346
|
+
}
|
|
4347
|
+
};
|
|
4348
|
+
}
|
|
4349
|
+
|
|
4350
|
+
export function testSemanticSlice(slice, options = {}) {
|
|
4351
|
+
const assertions = [];
|
|
4352
|
+
assertions.push(semanticSliceAssertion('kind', slice?.kind === 'frontier.lang.semanticSlice', 'Input is a Frontier semantic slice.'));
|
|
4353
|
+
assertions.push(semanticSliceAssertion('entryRefsResolved', (slice?.unresolvedEntryRefs?.length ?? 0) === 0, 'All requested semantic entry refs resolved.', {
|
|
4354
|
+
unresolvedEntryRefs: slice?.unresolvedEntryRefs ?? []
|
|
4355
|
+
}));
|
|
4356
|
+
assertions.push(semanticSliceAssertion('nonEmptySelection', (slice?.symbols?.length ?? 0) + (slice?.ownershipRegions?.length ?? 0) + (slice?.nativeNodes?.length ?? 0) > 0, 'Slice selected at least one symbol, ownership region, or native node.'));
|
|
4357
|
+
assertions.push(semanticSliceAssertion('sourceMapLinks', options.requireSourceMapLinks === false || (slice?.sourceMapLinks?.length ?? 0) > 0, 'Slice has source-map links or the requirement was disabled.'));
|
|
4358
|
+
assertions.push(semanticSliceAssertion('conflictKeys', (slice?.mergeAdmission?.conflictKeys?.length ?? 0) > 0, 'Slice exposes merge-admission conflict keys.'));
|
|
4359
|
+
const sourceHashAssertions = semanticSliceSourceHashAssertions(slice, options.currentSources);
|
|
4360
|
+
assertions.push(...sourceHashAssertions);
|
|
4361
|
+
const failed = assertions.filter((assertion) => assertion.status === 'failed');
|
|
4362
|
+
const warnings = assertions.filter((assertion) => assertion.status === 'warning');
|
|
4363
|
+
const readiness = failed.length
|
|
4364
|
+
? 'blocked'
|
|
4365
|
+
: maxSemanticMergeReadiness(slice?.mergeAdmission?.readiness ?? slice?.summary?.readiness ?? 'ready', warnings.length ? 'needs-review' : 'ready');
|
|
4366
|
+
return {
|
|
4367
|
+
kind: 'frontier.lang.semanticSliceTestResult',
|
|
4368
|
+
version: 1,
|
|
4369
|
+
id: options.id ?? `semantic_slice_test_${idFragment(slice?.id ?? 'slice')}`,
|
|
4370
|
+
generatedAt: options.generatedAt ?? Date.now(),
|
|
4371
|
+
sliceId: slice?.id,
|
|
4372
|
+
status: failed.length ? 'failed' : warnings.length ? 'needs-review' : 'passed',
|
|
4373
|
+
readiness,
|
|
4374
|
+
assertions,
|
|
4375
|
+
summary: {
|
|
4376
|
+
assertions: assertions.length,
|
|
4377
|
+
passed: assertions.filter((assertion) => assertion.status === 'passed').length,
|
|
4378
|
+
warnings: warnings.length,
|
|
4379
|
+
failed: failed.length,
|
|
4380
|
+
sourceHashChecks: sourceHashAssertions.length,
|
|
4381
|
+
symbols: slice?.summary?.symbols ?? slice?.symbols?.length ?? 0,
|
|
4382
|
+
ownershipRegions: slice?.summary?.ownershipRegions ?? slice?.ownershipRegions?.length ?? 0,
|
|
4383
|
+
sourceMapLinks: slice?.summary?.sourceMapLinks ?? slice?.sourceMapLinks?.length ?? 0
|
|
4384
|
+
},
|
|
4385
|
+
metadata: {
|
|
4386
|
+
sliceReadiness: slice?.mergeAdmission?.readiness ?? slice?.summary?.readiness,
|
|
4387
|
+
...options.metadata
|
|
4388
|
+
}
|
|
4389
|
+
};
|
|
4390
|
+
}
|
|
4391
|
+
|
|
4392
|
+
export function readSemanticSliceJson(source) {
|
|
4393
|
+
const slice = JSON.parse(source);
|
|
4394
|
+
if (slice?.kind !== 'frontier.lang.semanticSlice') {
|
|
4395
|
+
throw new Error('Invalid Frontier semantic slice JSON: expected kind frontier.lang.semanticSlice');
|
|
4396
|
+
}
|
|
4397
|
+
return slice;
|
|
4398
|
+
}
|
|
4399
|
+
|
|
4400
|
+
export function writeSemanticSliceJson(slice) {
|
|
4401
|
+
if (slice?.kind !== 'frontier.lang.semanticSlice') {
|
|
4402
|
+
throw new Error('Invalid Frontier semantic slice: expected kind frontier.lang.semanticSlice');
|
|
4403
|
+
}
|
|
4404
|
+
return stableUniversalAstJson(slice);
|
|
4405
|
+
}
|
|
4406
|
+
|
|
4407
|
+
function semanticSliceContext(input, options = {}) {
|
|
4408
|
+
const value = input?.importResult ?? input?.import ?? input?.source ?? input;
|
|
4409
|
+
const imported = semanticSliceImportResult(value, options);
|
|
4410
|
+
const universalAst = imported?.universalAst ?? (value?.kind === 'frontier.lang.universalAst' ? value : value?.universalAst);
|
|
4411
|
+
const sidecar = value?.kind === 'frontier.lang.semanticImportSidecar' ? value : input?.sidecar ?? options.sidecar;
|
|
4412
|
+
const nativeSource = imported?.nativeSource ?? universalAst?.nativeSources?.[0];
|
|
4413
|
+
const nativeAst = imported?.nativeAst ?? nativeSource?.ast;
|
|
4414
|
+
const semanticIndex = imported?.semanticIndex ?? universalAst?.semanticIndex;
|
|
4415
|
+
const language = options.language ?? imported?.language ?? universalAst?.metadata?.sourceLanguage ?? nativeSource?.language ?? sidecar?.language;
|
|
4416
|
+
const sourcePath = options.sourcePath ?? imported?.sourcePath ?? universalAst?.metadata?.sourcePath ?? nativeSource?.sourcePath ?? semanticIndex?.documents?.[0]?.path;
|
|
4417
|
+
return {
|
|
4418
|
+
importResult: imported,
|
|
4419
|
+
universalAst,
|
|
4420
|
+
sidecar,
|
|
4421
|
+
nativeSource,
|
|
4422
|
+
nativeAst,
|
|
4423
|
+
semanticIndex,
|
|
4424
|
+
language,
|
|
4425
|
+
sourcePath,
|
|
4426
|
+
sourceTexts: semanticSliceSourceTextMap(imported, universalAst, value, options),
|
|
4427
|
+
sourceHashes: semanticSliceSourceHashMap(imported, universalAst, value, options)
|
|
4428
|
+
};
|
|
4429
|
+
}
|
|
4430
|
+
|
|
4431
|
+
function semanticSliceImportResult(value, options = {}) {
|
|
4432
|
+
if (!value) return undefined;
|
|
4433
|
+
if (value.kind === 'frontier.lang.importResult') return value;
|
|
4434
|
+
if (value.kind === 'frontier.lang.universalAst') {
|
|
4435
|
+
const nativeSource = value.nativeSources?.[0];
|
|
4436
|
+
return {
|
|
4437
|
+
kind: 'frontier.lang.importResult',
|
|
4438
|
+
version: 1,
|
|
4439
|
+
id: value.metadata?.nativeImportId ?? `import_${idFragment(value.id)}`,
|
|
4440
|
+
language: value.metadata?.sourceLanguage ?? nativeSource?.language ?? options.language,
|
|
4441
|
+
sourcePath: value.metadata?.sourcePath ?? nativeSource?.sourcePath ?? options.sourcePath,
|
|
4442
|
+
document: value.document,
|
|
4443
|
+
nativeSource,
|
|
4444
|
+
nativeAst: nativeSource?.ast,
|
|
4445
|
+
semanticIndex: value.semanticIndex,
|
|
4446
|
+
universalAst: value,
|
|
4447
|
+
sourceMaps: value.sourceMaps ?? [],
|
|
4448
|
+
losses: value.losses ?? [],
|
|
4449
|
+
evidence: value.evidence ?? [],
|
|
4450
|
+
mergeCandidates: value.mergeCandidates ?? [],
|
|
4451
|
+
metadata: value.metadata ?? {}
|
|
4452
|
+
};
|
|
4453
|
+
}
|
|
4454
|
+
if (value.kind === 'frontier.lang.semanticImportSidecar') return undefined;
|
|
4455
|
+
if (value.universalAst || value.semanticIndex || value.nativeSource || value.nativeAst) return value;
|
|
4456
|
+
if (value.sourceText || value.nodes || value.nativeAst) return importNativeSource(value);
|
|
4457
|
+
return undefined;
|
|
4458
|
+
}
|
|
4459
|
+
|
|
4460
|
+
function semanticSliceRecords(context, sidecar) {
|
|
4461
|
+
const imports = context.importResult ? nativeImportEntries(context.importResult) : [];
|
|
4462
|
+
const universalAst = context.universalAst;
|
|
4463
|
+
const semanticIndexes = [
|
|
4464
|
+
context.semanticIndex,
|
|
4465
|
+
universalAst?.semanticIndex,
|
|
4466
|
+
...imports.map((imported) => imported?.semanticIndex ?? imported?.universalAst?.semanticIndex)
|
|
4467
|
+
].filter(Boolean);
|
|
4468
|
+
const sourceMaps = uniqueRecordsById([
|
|
4469
|
+
...(context.importResult?.sourceMaps ?? []),
|
|
4470
|
+
...(universalAst?.sourceMaps ?? []),
|
|
4471
|
+
...imports.flatMap((imported) => imported?.sourceMaps ?? imported?.universalAst?.sourceMaps ?? [])
|
|
4472
|
+
]);
|
|
4473
|
+
const symbols = mergeSemanticSliceSymbols([
|
|
4474
|
+
...(sidecar?.symbols ?? []),
|
|
4475
|
+
...semanticIndexes.flatMap((index) => index.symbols ?? [])
|
|
4476
|
+
]);
|
|
4477
|
+
const regions = uniqueSemanticSliceRegions([
|
|
4478
|
+
...(sidecar?.ownershipRegions ?? []),
|
|
4479
|
+
...symbols.map((symbol) => semanticSliceRegionFromSymbol(symbol, context)).filter(Boolean),
|
|
4480
|
+
...sourceMaps.flatMap((sourceMap) => (sourceMap.mappings ?? []).map((mapping) => semanticSliceRegionFromMapping(mapping, context)).filter(Boolean))
|
|
4481
|
+
]);
|
|
4482
|
+
const nativeNodes = uniqueSemanticSliceNativeNodes([
|
|
4483
|
+
...imports.flatMap((imported) => nativeAstNodes(imported?.nativeAst ?? imported?.nativeSource?.ast)),
|
|
4484
|
+
...nativeAstNodes(context.nativeAst),
|
|
4485
|
+
...((universalAst?.nativeSources ?? []).flatMap((source) => nativeAstNodes(source?.ast)))
|
|
4486
|
+
]);
|
|
4487
|
+
const mappings = sourceMaps.flatMap((sourceMap) => (sourceMap.mappings ?? []).map((mapping) => ({
|
|
4488
|
+
...mapping,
|
|
4489
|
+
sourceMapId: mapping.sourceMapId ?? sourceMap.id,
|
|
4490
|
+
sourceMapSourcePath: sourceMap.sourcePath,
|
|
4491
|
+
sourceMapSourceHash: sourceMap.sourceHash,
|
|
4492
|
+
sourceMapTargetPath: sourceMap.targetPath,
|
|
4493
|
+
sourceMapTargetHash: sourceMap.targetHash
|
|
4494
|
+
})));
|
|
4495
|
+
const losses = uniqueByLossId([
|
|
4496
|
+
...(context.importResult?.losses ?? []),
|
|
4497
|
+
...(universalAst?.losses ?? []),
|
|
4498
|
+
...imports.flatMap((imported) => imported?.losses ?? imported?.nativeAst?.losses ?? [])
|
|
4499
|
+
]);
|
|
4500
|
+
const evidence = uniqueByEvidenceId([
|
|
4501
|
+
...(context.importResult?.evidence ?? []),
|
|
4502
|
+
...(universalAst?.evidence ?? []),
|
|
4503
|
+
...imports.flatMap((imported) => imported?.evidence ?? [])
|
|
4504
|
+
]);
|
|
4505
|
+
return {
|
|
4506
|
+
symbols,
|
|
4507
|
+
symbolById: new Map(symbols.map((symbol) => [symbol.id, symbol])),
|
|
4508
|
+
regions,
|
|
4509
|
+
nativeNodes,
|
|
4510
|
+
nativeNodeById: new Map(nativeNodes.map((node) => [node.id, node])),
|
|
4511
|
+
mappings,
|
|
4512
|
+
sourceMaps,
|
|
4513
|
+
relations: uniqueRecordsById(semanticIndexes.flatMap((index) => index.relations ?? [])),
|
|
4514
|
+
occurrences: uniqueRecordsById(semanticIndexes.flatMap((index) => index.occurrences ?? [])),
|
|
4515
|
+
losses,
|
|
4516
|
+
evidence,
|
|
4517
|
+
sidecar
|
|
4518
|
+
};
|
|
4519
|
+
}
|
|
4520
|
+
|
|
4521
|
+
function selectSemanticSliceRecords(records, options) {
|
|
4522
|
+
const selectedSymbols = new Set();
|
|
4523
|
+
const selectedRegions = new Set();
|
|
4524
|
+
const selectedNativeNodes = new Set();
|
|
4525
|
+
const selectedMappings = new Set();
|
|
4526
|
+
const selectedRelations = new Set();
|
|
4527
|
+
const selectedOccurrences = new Set();
|
|
4528
|
+
const matchedEntryRefs = [];
|
|
4529
|
+
const entryRefs = options.entryRefs ?? [];
|
|
4530
|
+
if (entryRefs.length === 0) {
|
|
4531
|
+
for (const symbol of records.symbols) selectedSymbols.add(symbol.id);
|
|
4532
|
+
for (const region of records.regions) selectedRegions.add(region.id);
|
|
4533
|
+
for (const node of records.nativeNodes) selectedNativeNodes.add(node.id);
|
|
4534
|
+
for (const mapping of records.mappings) selectedMappings.add(mapping.id);
|
|
4535
|
+
} else {
|
|
4536
|
+
for (const ref of entryRefs) {
|
|
4537
|
+
let matched = false;
|
|
4538
|
+
for (const symbol of records.symbols) {
|
|
4539
|
+
if (!semanticSliceSymbolMatchesRef(symbol, ref)) continue;
|
|
4540
|
+
selectedSymbols.add(symbol.id);
|
|
4541
|
+
matched = true;
|
|
4542
|
+
}
|
|
4543
|
+
for (const region of records.regions) {
|
|
4544
|
+
if (!semanticSliceRegionMatchesRef(region, ref)) continue;
|
|
4545
|
+
selectedRegions.add(region.id);
|
|
4546
|
+
matched = true;
|
|
4547
|
+
}
|
|
4548
|
+
for (const node of records.nativeNodes) {
|
|
4549
|
+
if (!semanticSliceNativeNodeMatchesRef(node, ref)) continue;
|
|
4550
|
+
selectedNativeNodes.add(node.id);
|
|
4551
|
+
matched = true;
|
|
4552
|
+
}
|
|
4553
|
+
for (const mapping of records.mappings) {
|
|
4554
|
+
if (!semanticSliceMappingMatchesRef(mapping, ref)) continue;
|
|
4555
|
+
selectedMappings.add(mapping.id);
|
|
4556
|
+
matched = true;
|
|
4557
|
+
}
|
|
4558
|
+
if (matched) matchedEntryRefs.push(ref);
|
|
4559
|
+
}
|
|
4560
|
+
}
|
|
4561
|
+
expandSemanticSliceSelection(records, {
|
|
4562
|
+
selectedSymbols,
|
|
4563
|
+
selectedRegions,
|
|
4564
|
+
selectedNativeNodes,
|
|
4565
|
+
selectedMappings,
|
|
4566
|
+
selectedRelations,
|
|
4567
|
+
selectedOccurrences,
|
|
4568
|
+
includeDependencies: options.includeDependencies,
|
|
4569
|
+
maxDependencyDepth: options.maxDependencyDepth
|
|
4570
|
+
});
|
|
4571
|
+
const symbols = records.symbols.filter((symbol) => selectedSymbols.has(symbol.id));
|
|
4572
|
+
const regions = records.regions.filter((region) => selectedRegions.has(region.id));
|
|
4573
|
+
const nativeNodes = records.nativeNodes.filter((node) => selectedNativeNodes.has(node.id));
|
|
4574
|
+
const mappings = records.mappings.filter((mapping) => selectedMappings.has(mapping.id));
|
|
4575
|
+
const relations = records.relations.filter((relation) => selectedRelations.has(relation.id));
|
|
4576
|
+
const occurrences = records.occurrences.filter((occurrence) => selectedOccurrences.has(occurrence.id));
|
|
4577
|
+
const selectedNodeIds = new Set(nativeNodes.map((node) => node.id));
|
|
4578
|
+
const losses = records.losses.filter((loss) => !loss.nodeId || selectedNodeIds.has(loss.nodeId) || semanticSliceSpanTouchesSelection(loss.span, mappings, regions));
|
|
4579
|
+
return {
|
|
4580
|
+
matchedEntryRefs,
|
|
4581
|
+
symbols,
|
|
4582
|
+
regions,
|
|
4583
|
+
nativeNodes,
|
|
4584
|
+
mappings,
|
|
4585
|
+
relations,
|
|
4586
|
+
occurrences,
|
|
4587
|
+
losses
|
|
4588
|
+
};
|
|
4589
|
+
}
|
|
4590
|
+
|
|
4591
|
+
function expandSemanticSliceSelection(records, selection) {
|
|
4592
|
+
let changed = true;
|
|
4593
|
+
let depth = 0;
|
|
4594
|
+
const childToParent = semanticSliceNativeParentMap(records.nativeNodes);
|
|
4595
|
+
while (changed && depth <= selection.maxDependencyDepth) {
|
|
4596
|
+
changed = false;
|
|
4597
|
+
for (const mapping of records.mappings) {
|
|
4598
|
+
if (!semanticSliceMappingTouchesSets(mapping, selection)) continue;
|
|
4599
|
+
changed = addSet(selection.selectedMappings, mapping.id) || changed;
|
|
4600
|
+
if (mapping.semanticSymbolId) changed = addSet(selection.selectedSymbols, mapping.semanticSymbolId) || changed;
|
|
4601
|
+
if (mapping.nativeAstNodeId) changed = addSet(selection.selectedNativeNodes, mapping.nativeAstNodeId) || changed;
|
|
4602
|
+
if (mapping.ownershipRegionId) changed = addSet(selection.selectedRegions, mapping.ownershipRegionId) || changed;
|
|
4603
|
+
}
|
|
4604
|
+
for (const symbol of records.symbols) {
|
|
4605
|
+
if (!semanticSliceSymbolTouchesSets(symbol, selection)) continue;
|
|
4606
|
+
changed = addSet(selection.selectedSymbols, symbol.id) || changed;
|
|
4607
|
+
if (symbol.nativeAstNodeId) changed = addSet(selection.selectedNativeNodes, symbol.nativeAstNodeId) || changed;
|
|
4608
|
+
const regionId = symbol.ownershipRegionId ?? symbol.metadata?.ownershipRegionId;
|
|
4609
|
+
if (regionId) changed = addSet(selection.selectedRegions, regionId) || changed;
|
|
4610
|
+
}
|
|
4611
|
+
for (const region of records.regions) {
|
|
4612
|
+
if (!semanticSliceRegionTouchesSets(region, selection)) continue;
|
|
4613
|
+
changed = addSet(selection.selectedRegions, region.id) || changed;
|
|
4614
|
+
if (region.symbolId) changed = addSet(selection.selectedSymbols, region.symbolId) || changed;
|
|
4615
|
+
if (region.nativeAstNodeId) changed = addSet(selection.selectedNativeNodes, region.nativeAstNodeId) || changed;
|
|
4616
|
+
}
|
|
4617
|
+
for (const occurrence of records.occurrences) {
|
|
4618
|
+
if (!selection.selectedSymbols.has(occurrence.symbolId) && !selection.selectedNativeNodes.has(occurrence.nativeAstNodeId)) continue;
|
|
4619
|
+
changed = addSet(selection.selectedOccurrences, occurrence.id) || changed;
|
|
4620
|
+
if (occurrence.symbolId) changed = addSet(selection.selectedSymbols, occurrence.symbolId) || changed;
|
|
4621
|
+
if (occurrence.nativeAstNodeId) changed = addSet(selection.selectedNativeNodes, occurrence.nativeAstNodeId) || changed;
|
|
4622
|
+
}
|
|
4623
|
+
if (selection.includeDependencies) {
|
|
4624
|
+
for (const relation of records.relations) {
|
|
4625
|
+
const touches = selection.selectedSymbols.has(relation.sourceId) || selection.selectedSymbols.has(relation.targetId);
|
|
4626
|
+
if (!touches) continue;
|
|
4627
|
+
changed = addSet(selection.selectedRelations, relation.id) || changed;
|
|
4628
|
+
if (relation.sourceId && records.symbolById.has(relation.sourceId)) changed = addSet(selection.selectedSymbols, relation.sourceId) || changed;
|
|
4629
|
+
if (relation.targetId && records.symbolById.has(relation.targetId)) changed = addSet(selection.selectedSymbols, relation.targetId) || changed;
|
|
4630
|
+
}
|
|
4631
|
+
for (const node of records.nativeNodes) {
|
|
4632
|
+
if (!selection.selectedNativeNodes.has(node.id)) continue;
|
|
4633
|
+
for (const child of node.children ?? []) changed = addSet(selection.selectedNativeNodes, child) || changed;
|
|
4634
|
+
const parent = childToParent.get(node.id);
|
|
4635
|
+
if (parent) changed = addSet(selection.selectedNativeNodes, parent) || changed;
|
|
4636
|
+
}
|
|
4637
|
+
}
|
|
4638
|
+
depth += 1;
|
|
4639
|
+
}
|
|
4640
|
+
}
|
|
4641
|
+
|
|
4642
|
+
function semanticSliceSourceSpans(selection) {
|
|
4643
|
+
return uniqueSemanticSliceSpans([
|
|
4644
|
+
...selection.symbols.map(semanticSliceSymbolSpan),
|
|
4645
|
+
...selection.regions.map((region) => region.sourceSpan),
|
|
4646
|
+
...selection.nativeNodes.map((node) => node.span ?? node.sourceSpan),
|
|
4647
|
+
...selection.mappings.map((mapping) => mapping.sourceSpan)
|
|
4648
|
+
].filter(Boolean));
|
|
4649
|
+
}
|
|
4650
|
+
|
|
4651
|
+
function semanticSliceSourceFiles(spans, context, options = {}) {
|
|
4652
|
+
const byPath = new Map();
|
|
4653
|
+
const includeExcerpts = options.includeSourceText !== false;
|
|
4654
|
+
const maxExcerptBytes = Number.isFinite(options.maxExcerptBytes) ? Math.max(0, Math.floor(options.maxExcerptBytes)) : 4000;
|
|
4655
|
+
for (const span of spans) {
|
|
4656
|
+
const path = span.path ?? span.sourceId ?? context.sourcePath ?? 'unknown';
|
|
4657
|
+
const record = byPath.get(path) ?? {
|
|
4658
|
+
path,
|
|
4659
|
+
sourceHash: context.sourceHashes.get(path) ?? context.sourceHashes.get('') ?? span.sourceHash,
|
|
4660
|
+
spans: [],
|
|
4661
|
+
excerpts: []
|
|
4662
|
+
};
|
|
4663
|
+
record.spans.push(span);
|
|
4664
|
+
const sourceText = context.sourceTexts.get(path) ?? context.sourceTexts.get('');
|
|
4665
|
+
const excerpt = includeExcerpts ? sourceTextForSpan(sourceText, span) : undefined;
|
|
4666
|
+
if (typeof excerpt === 'string') {
|
|
4667
|
+
const clipped = excerpt.length > maxExcerptBytes ? excerpt.slice(0, maxExcerptBytes) : excerpt;
|
|
4668
|
+
record.excerpts.push({
|
|
4669
|
+
span,
|
|
4670
|
+
text: clipped,
|
|
4671
|
+
textHash: hashSemanticValue(excerpt),
|
|
4672
|
+
truncated: clipped.length !== excerpt.length
|
|
4673
|
+
});
|
|
4674
|
+
}
|
|
4675
|
+
byPath.set(path, record);
|
|
4676
|
+
}
|
|
4677
|
+
return [...byPath.values()].map((file) => ({
|
|
4678
|
+
...file,
|
|
4679
|
+
spanCount: file.spans.length,
|
|
4680
|
+
excerptCount: file.excerpts.length,
|
|
4681
|
+
sourceTextAvailable: file.excerpts.length > 0
|
|
4682
|
+
}));
|
|
4683
|
+
}
|
|
4684
|
+
|
|
4685
|
+
function semanticSliceSourceMapLinks(selection) {
|
|
4686
|
+
return selection.mappings.map((mapping) => ({
|
|
4687
|
+
id: mapping.id,
|
|
4688
|
+
sourceMapId: mapping.sourceMapId,
|
|
4689
|
+
sourcePath: mapping.sourceSpan?.path ?? mapping.sourceMapSourcePath,
|
|
4690
|
+
sourceHash: mapping.sourceMapSourceHash,
|
|
4691
|
+
targetPath: mapping.generatedSpan?.targetPath ?? mapping.sourceMapTargetPath,
|
|
4692
|
+
targetHash: mapping.generatedSpan?.targetHash ?? mapping.sourceMapTargetHash,
|
|
4693
|
+
semanticSymbolId: mapping.semanticSymbolId,
|
|
4694
|
+
semanticOccurrenceId: mapping.semanticOccurrenceId,
|
|
4695
|
+
semanticNodeId: mapping.semanticNodeId,
|
|
4696
|
+
nativeSourceId: mapping.nativeSourceId,
|
|
4697
|
+
nativeAstNodeId: mapping.nativeAstNodeId,
|
|
4698
|
+
precision: mapping.precision,
|
|
4699
|
+
sourceSpan: mapping.sourceSpan,
|
|
4700
|
+
generatedSpan: mapping.generatedSpan,
|
|
4701
|
+
ownershipRegionId: mapping.ownershipRegionId,
|
|
4702
|
+
ownershipRegionKey: mapping.ownershipRegionKey,
|
|
4703
|
+
ownershipRegionKind: mapping.ownershipRegionKind
|
|
4704
|
+
}));
|
|
4705
|
+
}
|
|
4706
|
+
|
|
4707
|
+
function semanticSliceReadiness(context, selection, unresolvedEntryRefs) {
|
|
4708
|
+
if (unresolvedEntryRefs.length) return 'blocked';
|
|
4709
|
+
if (selection.symbols.length + selection.regions.length + selection.nativeNodes.length === 0) return 'blocked';
|
|
4710
|
+
const lossReadiness = summarizeNativeImportLosses(selection.losses, { evidence: context.importResult?.evidence }).semanticMergeReadiness;
|
|
4711
|
+
return [
|
|
4712
|
+
context.importResult?.metadata?.semanticMergeReadiness,
|
|
4713
|
+
context.importResult?.metadata?.nativeImportLossSummary?.semanticMergeReadiness,
|
|
4714
|
+
context.sidecar?.summary?.readiness,
|
|
4715
|
+
...(context.importResult?.mergeCandidates ?? []).map((candidate) => candidate.readiness),
|
|
4716
|
+
lossReadiness
|
|
4717
|
+
].reduce((current, value) => maxSemanticMergeReadiness(current, value ?? 'ready'), 'ready');
|
|
4718
|
+
}
|
|
4719
|
+
|
|
4720
|
+
function semanticSliceReasons(context, selection, unresolvedEntryRefs, readiness) {
|
|
4721
|
+
return uniqueStrings([
|
|
4722
|
+
unresolvedEntryRefs.length ? `Unresolved semantic slice entry refs: ${unresolvedEntryRefs.join(', ')}` : undefined,
|
|
4723
|
+
selection.symbols.length + selection.regions.length + selection.nativeNodes.length === 0 ? 'Semantic slice selected no reviewable records.' : undefined,
|
|
4724
|
+
selection.mappings.length === 0 ? 'Semantic slice has no source-map links; source review may need file-level fallback.' : undefined,
|
|
4725
|
+
selection.losses.length ? `Semantic slice carries ${selection.losses.length} native import loss record(s).` : undefined,
|
|
4726
|
+
readiness !== 'ready' ? `Semantic slice readiness is ${readiness}.` : undefined,
|
|
4727
|
+
context.importResult?.metadata?.nativeImportLossSummary?.semanticMergeReadiness === 'needs-review' ? 'Parent native import requires review.' : undefined
|
|
4728
|
+
].filter(Boolean));
|
|
4729
|
+
}
|
|
4730
|
+
|
|
4731
|
+
function semanticSliceExpectedAssertions(selection, unresolvedEntryRefs) {
|
|
4732
|
+
return [
|
|
4733
|
+
{ id: 'entryRefsResolved', expected: unresolvedEntryRefs.length === 0 },
|
|
4734
|
+
{ id: 'nonEmptySelection', expected: selection.symbols.length + selection.regions.length + selection.nativeNodes.length > 0 },
|
|
4735
|
+
{ id: 'sourceMapLinks', expected: selection.mappings.length > 0 },
|
|
4736
|
+
{ id: 'conflictKeys', expected: true }
|
|
4737
|
+
];
|
|
4738
|
+
}
|
|
4739
|
+
|
|
4740
|
+
function semanticSliceTouchedSymbol(symbol) {
|
|
4741
|
+
return {
|
|
4742
|
+
id: symbol.id,
|
|
4743
|
+
name: symbol.name,
|
|
4744
|
+
kind: symbol.kind,
|
|
4745
|
+
nativeAstNodeId: symbol.nativeAstNodeId,
|
|
4746
|
+
span: semanticSliceSymbolSpan(symbol),
|
|
4747
|
+
conflictKey: symbol.metadata?.ownershipRegionKey ? `region:${symbol.metadata.ownershipRegionKey}` : `symbol:${symbol.id}`,
|
|
4748
|
+
metadata: {
|
|
4749
|
+
ownershipRegionId: symbol.ownershipRegionId ?? symbol.metadata?.ownershipRegionId,
|
|
4750
|
+
ownershipRegionKind: symbol.ownershipRegionKind ?? symbol.metadata?.ownershipRegionKind,
|
|
4751
|
+
signatureHash: symbol.signatureHash
|
|
4752
|
+
}
|
|
4753
|
+
};
|
|
4754
|
+
}
|
|
4755
|
+
|
|
4756
|
+
function semanticSliceAssertion(id, ok, summary, metadata = {}) {
|
|
4757
|
+
return {
|
|
4758
|
+
id,
|
|
4759
|
+
status: ok ? 'passed' : 'failed',
|
|
4760
|
+
summary,
|
|
4761
|
+
metadata
|
|
4762
|
+
};
|
|
4763
|
+
}
|
|
4764
|
+
|
|
4765
|
+
function semanticSliceSourceHashAssertions(slice, currentSources) {
|
|
4766
|
+
if (!currentSources) return [];
|
|
4767
|
+
const assertions = [];
|
|
4768
|
+
for (const file of slice?.sourceFiles ?? []) {
|
|
4769
|
+
if (!file.sourceHash || !file.path) continue;
|
|
4770
|
+
const currentSource = semanticSliceCurrentSource(currentSources, file.path);
|
|
4771
|
+
if (typeof currentSource !== 'string') {
|
|
4772
|
+
assertions.push({
|
|
4773
|
+
id: `sourceHash:${file.path}`,
|
|
4774
|
+
status: 'warning',
|
|
4775
|
+
summary: `Current source text was not supplied for ${file.path}.`,
|
|
4776
|
+
metadata: { path: file.path, expectedSourceHash: file.sourceHash }
|
|
4777
|
+
});
|
|
4778
|
+
continue;
|
|
4779
|
+
}
|
|
4780
|
+
const actualSourceHash = hashSemanticValue(currentSource);
|
|
4781
|
+
assertions.push({
|
|
4782
|
+
id: `sourceHash:${file.path}`,
|
|
4783
|
+
status: actualSourceHash === file.sourceHash ? 'passed' : 'failed',
|
|
4784
|
+
summary: actualSourceHash === file.sourceHash ? `Source hash matched for ${file.path}.` : `Source hash changed for ${file.path}.`,
|
|
4785
|
+
metadata: { path: file.path, expectedSourceHash: file.sourceHash, actualSourceHash }
|
|
4786
|
+
});
|
|
4787
|
+
}
|
|
4788
|
+
return assertions;
|
|
4789
|
+
}
|
|
4790
|
+
|
|
4791
|
+
function semanticSliceCurrentSource(currentSources, path) {
|
|
4792
|
+
if (currentSources instanceof Map) return currentSources.get(path);
|
|
4793
|
+
return currentSources[path] ?? currentSources[`./${path}`];
|
|
4794
|
+
}
|
|
4795
|
+
|
|
4796
|
+
function semanticSliceSourceTextMap(imported, universalAst, value, options) {
|
|
4797
|
+
const entries = new Map();
|
|
4798
|
+
const add = (path, sourceText) => {
|
|
4799
|
+
if (typeof sourceText !== 'string') return;
|
|
4800
|
+
entries.set(path ?? '', sourceText);
|
|
4801
|
+
};
|
|
4802
|
+
add(options.sourcePath, options.sourceText);
|
|
4803
|
+
add(value?.sourcePath, value?.sourceText);
|
|
4804
|
+
for (const item of [imported, ...(imported ? nativeImportEntries(imported) : [])]) {
|
|
4805
|
+
add(item?.sourcePath, nativeImportSourceText(item));
|
|
4806
|
+
add(item?.nativeSource?.sourcePath, item?.nativeSource?.metadata?.sourcePreservation?.sourceText);
|
|
4807
|
+
}
|
|
4808
|
+
for (const nativeSource of universalAst?.nativeSources ?? []) {
|
|
4809
|
+
add(nativeSource?.sourcePath, nativeSource?.metadata?.sourcePreservation?.sourceText);
|
|
4810
|
+
add(nativeSource?.sourcePath, nativeSource?.ast?.metadata?.sourcePreservation?.sourceText);
|
|
4811
|
+
}
|
|
4812
|
+
return entries;
|
|
4813
|
+
}
|
|
4814
|
+
|
|
4815
|
+
function semanticSliceSourceHashMap(imported, universalAst, value, options) {
|
|
4816
|
+
const entries = new Map();
|
|
4817
|
+
const add = (path, sourceHash) => {
|
|
4818
|
+
if (!sourceHash) return;
|
|
4819
|
+
entries.set(path ?? '', sourceHash);
|
|
4820
|
+
};
|
|
4821
|
+
add(options.sourcePath, options.sourceHash);
|
|
4822
|
+
add(value?.sourcePath, value?.sourceHash);
|
|
4823
|
+
for (const item of [imported, ...(imported ? nativeImportEntries(imported) : [])]) {
|
|
4824
|
+
add(item?.sourcePath, item?.nativeSource?.sourceHash ?? item?.nativeAst?.sourceHash ?? item?.sourceHash);
|
|
4825
|
+
}
|
|
4826
|
+
for (const nativeSource of universalAst?.nativeSources ?? []) {
|
|
4827
|
+
add(nativeSource?.sourcePath, nativeSource?.sourceHash ?? nativeSource?.ast?.sourceHash);
|
|
4828
|
+
}
|
|
4829
|
+
for (const sourceMap of universalAst?.sourceMaps ?? []) add(sourceMap.sourcePath, sourceMap.sourceHash);
|
|
4830
|
+
return entries;
|
|
4831
|
+
}
|
|
4832
|
+
|
|
4833
|
+
function mergeSemanticSliceSymbols(symbols) {
|
|
4834
|
+
const byId = new Map();
|
|
4835
|
+
for (const symbol of symbols ?? []) {
|
|
4836
|
+
if (!symbol?.id) continue;
|
|
4837
|
+
const existing = byId.get(symbol.id);
|
|
4838
|
+
byId.set(symbol.id, {
|
|
4839
|
+
...(existing ?? {}),
|
|
4840
|
+
...symbol,
|
|
4841
|
+
metadata: {
|
|
4842
|
+
...(existing?.metadata ?? {}),
|
|
4843
|
+
...(symbol.metadata ?? {})
|
|
4844
|
+
}
|
|
4845
|
+
});
|
|
4846
|
+
}
|
|
4847
|
+
return [...byId.values()];
|
|
4848
|
+
}
|
|
4849
|
+
|
|
4850
|
+
function uniqueSemanticSliceRegions(regions) {
|
|
4851
|
+
const seen = new Set();
|
|
4852
|
+
const result = [];
|
|
4853
|
+
for (const region of regions ?? []) {
|
|
4854
|
+
if (!region) continue;
|
|
4855
|
+
const id = region.id ?? `region_${idFragment(region.key ?? region.sourcePath ?? region.symbolId ?? result.length)}`;
|
|
4856
|
+
const key = region.key ?? id;
|
|
4857
|
+
const dedupeKey = `${id}:${key}`;
|
|
4858
|
+
if (seen.has(dedupeKey)) continue;
|
|
4859
|
+
seen.add(dedupeKey);
|
|
4860
|
+
result.push({ ...region, id, key });
|
|
4861
|
+
}
|
|
4862
|
+
return result;
|
|
4863
|
+
}
|
|
4864
|
+
|
|
4865
|
+
function uniqueSemanticSliceNativeNodes(nodes) {
|
|
4866
|
+
const seen = new Set();
|
|
4867
|
+
const result = [];
|
|
4868
|
+
for (const node of nodes ?? []) {
|
|
4869
|
+
const id = node?.id ?? node?.nodeId;
|
|
4870
|
+
if (!id || seen.has(id)) continue;
|
|
4871
|
+
seen.add(id);
|
|
4872
|
+
result.push({ ...node, id });
|
|
4873
|
+
}
|
|
4874
|
+
return result;
|
|
4875
|
+
}
|
|
4876
|
+
|
|
4877
|
+
function uniqueSemanticSliceSpans(spans) {
|
|
4878
|
+
const seen = new Set();
|
|
4879
|
+
const result = [];
|
|
4880
|
+
for (const span of spans ?? []) {
|
|
4881
|
+
if (!span) continue;
|
|
4882
|
+
const key = [
|
|
4883
|
+
span.path,
|
|
4884
|
+
span.sourceId,
|
|
4885
|
+
span.start,
|
|
4886
|
+
span.end,
|
|
4887
|
+
span.startLine,
|
|
4888
|
+
span.startColumn,
|
|
4889
|
+
span.endLine,
|
|
4890
|
+
span.endColumn
|
|
4891
|
+
].join(':');
|
|
4892
|
+
if (seen.has(key)) continue;
|
|
4893
|
+
seen.add(key);
|
|
4894
|
+
result.push(span);
|
|
4895
|
+
}
|
|
4896
|
+
return result;
|
|
4897
|
+
}
|
|
4898
|
+
|
|
4899
|
+
function nativeAstNodes(nativeAst) {
|
|
4900
|
+
if (!nativeAst?.nodes) return [];
|
|
4901
|
+
return Object.values(nativeAst.nodes);
|
|
4902
|
+
}
|
|
4903
|
+
|
|
4904
|
+
function semanticSliceRegionFromSymbol(symbol, context) {
|
|
4905
|
+
const regionId = symbol.ownershipRegionId ?? symbol.metadata?.ownershipRegionId;
|
|
4906
|
+
const regionKey = symbol.ownershipKey ?? symbol.metadata?.ownershipRegionKey;
|
|
4907
|
+
if (!regionId && !regionKey) return undefined;
|
|
4908
|
+
return {
|
|
4909
|
+
id: regionId,
|
|
4910
|
+
key: regionKey,
|
|
4911
|
+
regionKind: symbol.ownershipRegionKind ?? symbol.metadata?.ownershipRegionKind ?? symbol.kind,
|
|
4912
|
+
granularity: 'symbol',
|
|
4913
|
+
language: symbol.language ?? context.language,
|
|
4914
|
+
sourcePath: semanticSliceSymbolSpan(symbol)?.path ?? context.sourcePath,
|
|
4915
|
+
sourceSpan: semanticSliceSymbolSpan(symbol),
|
|
4916
|
+
symbolId: symbol.id,
|
|
4917
|
+
symbolName: symbol.name,
|
|
4918
|
+
symbolKind: symbol.kind,
|
|
4919
|
+
nativeAstNodeId: symbol.nativeAstNodeId,
|
|
4920
|
+
precision: 'symbol',
|
|
4921
|
+
mergePolicy: 'semantic-region-review'
|
|
4922
|
+
};
|
|
4923
|
+
}
|
|
4924
|
+
|
|
4925
|
+
function semanticSliceRegionFromMapping(mapping, context) {
|
|
4926
|
+
if (!mapping.ownershipRegionId && !mapping.ownershipRegionKey) return undefined;
|
|
4927
|
+
return {
|
|
4928
|
+
id: mapping.ownershipRegionId,
|
|
4929
|
+
key: mapping.ownershipRegionKey,
|
|
4930
|
+
regionKind: mapping.ownershipRegionKind,
|
|
4931
|
+
granularity: 'source-map',
|
|
4932
|
+
language: context.language,
|
|
4933
|
+
sourcePath: mapping.sourceSpan?.path ?? context.sourcePath,
|
|
4934
|
+
sourceSpan: mapping.sourceSpan,
|
|
4935
|
+
symbolId: mapping.semanticSymbolId,
|
|
4936
|
+
nativeAstNodeId: mapping.nativeAstNodeId,
|
|
4937
|
+
precision: mapping.precision,
|
|
4938
|
+
mergePolicy: 'source-map-region-review'
|
|
4939
|
+
};
|
|
4940
|
+
}
|
|
4941
|
+
|
|
4942
|
+
function semanticSliceSymbolSpan(symbol) {
|
|
4943
|
+
return symbol.sourceSpan ?? symbol.definitionSpan ?? symbol.span;
|
|
4944
|
+
}
|
|
4945
|
+
|
|
4946
|
+
function semanticSliceSymbolMatchesRef(symbol, ref) {
|
|
4947
|
+
const normalized = normalizeSemanticSliceRef(ref, 'symbol');
|
|
4948
|
+
return [
|
|
4949
|
+
symbol.id,
|
|
4950
|
+
symbol.name,
|
|
4951
|
+
symbol.displayName,
|
|
4952
|
+
symbol.signature,
|
|
4953
|
+
symbol.nativeAstNodeId,
|
|
4954
|
+
symbol.metadata?.ownershipRegionId,
|
|
4955
|
+
symbol.metadata?.ownershipRegionKey
|
|
4956
|
+
].filter(Boolean).some((value) => semanticSliceValueMatches(value, normalized));
|
|
4957
|
+
}
|
|
4958
|
+
|
|
4959
|
+
function semanticSliceRegionMatchesRef(region, ref) {
|
|
4960
|
+
const normalized = normalizeSemanticSliceRef(ref, 'region');
|
|
4961
|
+
return [
|
|
4962
|
+
region.id,
|
|
4963
|
+
region.key,
|
|
4964
|
+
region.symbolId,
|
|
4965
|
+
region.symbolName,
|
|
4966
|
+
region.nativeAstNodeId,
|
|
4967
|
+
region.sourcePath
|
|
4968
|
+
].filter(Boolean).some((value) => semanticSliceValueMatches(value, normalized));
|
|
4969
|
+
}
|
|
4970
|
+
|
|
4971
|
+
function semanticSliceNativeNodeMatchesRef(node, ref) {
|
|
4972
|
+
const normalized = normalizeSemanticSliceRef(ref, 'native');
|
|
4973
|
+
return [
|
|
4974
|
+
node.id,
|
|
4975
|
+
node.nodeId,
|
|
4976
|
+
node.name,
|
|
4977
|
+
node.symbolId,
|
|
4978
|
+
node.kind,
|
|
4979
|
+
node.languageKind
|
|
4980
|
+
].filter(Boolean).some((value) => semanticSliceValueMatches(value, normalized));
|
|
4981
|
+
}
|
|
4982
|
+
|
|
4983
|
+
function semanticSliceMappingMatchesRef(mapping, ref) {
|
|
4984
|
+
const pathRef = normalizeSemanticSliceRef(ref, 'path');
|
|
4985
|
+
const normalized = normalizeSemanticSliceRef(ref, 'mapping');
|
|
4986
|
+
return [
|
|
4987
|
+
mapping.id,
|
|
4988
|
+
mapping.semanticSymbolId,
|
|
4989
|
+
mapping.semanticOccurrenceId,
|
|
4990
|
+
mapping.semanticNodeId,
|
|
4991
|
+
mapping.nativeAstNodeId,
|
|
4992
|
+
mapping.ownershipRegionId,
|
|
4993
|
+
mapping.ownershipRegionKey
|
|
4994
|
+
].filter(Boolean).some((value) => semanticSliceValueMatches(value, normalized))
|
|
4995
|
+
|| semanticSliceValueMatches(mapping.sourceSpan?.path ?? mapping.sourceMapSourcePath, pathRef);
|
|
4996
|
+
}
|
|
4997
|
+
|
|
4998
|
+
function normalizeSemanticSliceRef(ref, prefix) {
|
|
4999
|
+
const text = String(ref ?? '');
|
|
5000
|
+
return text.startsWith(`${prefix}:`) ? text.slice(prefix.length + 1) : text;
|
|
5001
|
+
}
|
|
5002
|
+
|
|
5003
|
+
function semanticSliceValueMatches(value, ref) {
|
|
5004
|
+
if (!value || !ref) return false;
|
|
5005
|
+
const left = String(value);
|
|
5006
|
+
const right = String(ref);
|
|
5007
|
+
return left === right || left.endsWith(`:${right}`) || left.includes(right);
|
|
5008
|
+
}
|
|
5009
|
+
|
|
5010
|
+
function semanticSliceMappingTouchesSets(mapping, selection) {
|
|
5011
|
+
return selection.selectedMappings.has(mapping.id)
|
|
5012
|
+
|| selection.selectedSymbols.has(mapping.semanticSymbolId)
|
|
5013
|
+
|| selection.selectedNativeNodes.has(mapping.nativeAstNodeId)
|
|
5014
|
+
|| selection.selectedRegions.has(mapping.ownershipRegionId)
|
|
5015
|
+
|| selection.selectedRegions.has(mapping.ownershipRegionKey);
|
|
5016
|
+
}
|
|
5017
|
+
|
|
5018
|
+
function semanticSliceSymbolTouchesSets(symbol, selection) {
|
|
5019
|
+
return selection.selectedSymbols.has(symbol.id)
|
|
5020
|
+
|| selection.selectedNativeNodes.has(symbol.nativeAstNodeId)
|
|
5021
|
+
|| selection.selectedRegions.has(symbol.ownershipRegionId)
|
|
5022
|
+
|| selection.selectedRegions.has(symbol.metadata?.ownershipRegionId)
|
|
5023
|
+
|| selection.selectedRegions.has(symbol.metadata?.ownershipRegionKey);
|
|
5024
|
+
}
|
|
5025
|
+
|
|
5026
|
+
function semanticSliceRegionTouchesSets(region, selection) {
|
|
5027
|
+
return selection.selectedRegions.has(region.id)
|
|
5028
|
+
|| selection.selectedRegions.has(region.key)
|
|
5029
|
+
|| selection.selectedSymbols.has(region.symbolId)
|
|
5030
|
+
|| selection.selectedNativeNodes.has(region.nativeAstNodeId);
|
|
5031
|
+
}
|
|
5032
|
+
|
|
5033
|
+
function semanticSliceSpanTouchesSelection(span, mappings, regions) {
|
|
5034
|
+
if (!span) return false;
|
|
5035
|
+
return mappings.some((mapping) => mapping.sourceSpan === span || semanticSliceSpansOverlap(mapping.sourceSpan, span))
|
|
5036
|
+
|| regions.some((region) => semanticSliceSpansOverlap(region.sourceSpan, span));
|
|
5037
|
+
}
|
|
5038
|
+
|
|
5039
|
+
function semanticSliceSpansOverlap(left, right) {
|
|
5040
|
+
if (!left || !right) return false;
|
|
5041
|
+
const leftPath = left.path ?? left.sourceId;
|
|
5042
|
+
const rightPath = right.path ?? right.sourceId;
|
|
5043
|
+
if (leftPath && rightPath && leftPath !== rightPath) return false;
|
|
5044
|
+
if (typeof left.start === 'number' && typeof left.end === 'number' && typeof right.start === 'number' && typeof right.end === 'number') {
|
|
5045
|
+
return left.start <= right.end && right.start <= left.end;
|
|
5046
|
+
}
|
|
5047
|
+
if (typeof left.startLine === 'number' && typeof right.startLine === 'number') {
|
|
5048
|
+
const leftEnd = left.endLine ?? left.startLine;
|
|
5049
|
+
const rightEnd = right.endLine ?? right.startLine;
|
|
5050
|
+
return left.startLine <= rightEnd && right.startLine <= leftEnd;
|
|
5051
|
+
}
|
|
5052
|
+
return false;
|
|
5053
|
+
}
|
|
5054
|
+
|
|
5055
|
+
function semanticSliceNativeParentMap(nativeNodes) {
|
|
5056
|
+
const parents = new Map();
|
|
5057
|
+
for (const node of nativeNodes ?? []) {
|
|
5058
|
+
for (const child of node.children ?? []) parents.set(child, node.id);
|
|
5059
|
+
}
|
|
5060
|
+
return parents;
|
|
5061
|
+
}
|
|
5062
|
+
|
|
5063
|
+
function addSet(set, value) {
|
|
5064
|
+
if (!value || set.has(value)) return false;
|
|
5065
|
+
set.add(value);
|
|
5066
|
+
return true;
|
|
5067
|
+
}
|
|
5068
|
+
|
|
5069
|
+
function readStringArray(value) {
|
|
5070
|
+
if (value === undefined || value === null) return [];
|
|
5071
|
+
if (Array.isArray(value)) return value.flatMap((entry) => readStringArray(entry));
|
|
5072
|
+
return String(value).split(',').map((entry) => entry.trim()).filter(Boolean);
|
|
5073
|
+
}
|
|
5074
|
+
|
|
4158
5075
|
function normalizeNativeDiffImport(value, input, side) {
|
|
4159
5076
|
if (!value) return undefined;
|
|
4160
5077
|
if (value.kind === 'frontier.lang.importResult' && value.nativeSource) return value;
|
|
@@ -7191,6 +8108,211 @@ function projectionTargetLossMatrixSummary(languages) {
|
|
|
7191
8108
|
};
|
|
7192
8109
|
}
|
|
7193
8110
|
|
|
8111
|
+
function universalCapabilityLanguageRow(importCoverage, context) {
|
|
8112
|
+
const languageIds = universalLanguageIds(importCoverage);
|
|
8113
|
+
const parserRows = (context.parserFeatures.parsers ?? []).filter((row) => universalLanguageIds(row).some((id) => languageIds.includes(id)));
|
|
8114
|
+
const parserLanguage = (context.parserFeatures.languages ?? []).find((row) => universalLanguageIds(row).some((id) => languageIds.includes(id)));
|
|
8115
|
+
const projection = (context.projectionTargets.languages ?? []).find((row) => universalLanguageIds(row).some((id) => languageIds.includes(id)));
|
|
8116
|
+
const parserReadiness = parserRows.length
|
|
8117
|
+
? parserRows.reduce((current, row) => maxSemanticMergeReadiness(current, row.merge?.readiness ?? row.imports?.readiness ?? 'blocked'), 'ready')
|
|
8118
|
+
: 'blocked';
|
|
8119
|
+
const sourceProjectionReadiness = [projection?.sourceProjection?.exactSource, projection?.sourceProjection?.stubs]
|
|
8120
|
+
.filter(Boolean)
|
|
8121
|
+
.reduce((current, entry) => maxSemanticMergeReadiness(current, entry.readiness ?? 'blocked'), 'ready');
|
|
8122
|
+
const targetReadiness = (projection?.targets ?? []).length
|
|
8123
|
+
? projection.targets.reduce((current, entry) => maxSemanticMergeReadiness(current, entry.readiness ?? 'blocked'), 'ready')
|
|
8124
|
+
: 'blocked';
|
|
8125
|
+
const projectionReadiness = maxSemanticMergeReadiness(sourceProjectionReadiness, targetReadiness);
|
|
8126
|
+
const readiness = maxSemanticMergeReadiness(importCoverage.imports.readiness, maxSemanticMergeReadiness(parserReadiness, projectionReadiness));
|
|
8127
|
+
const parserBlockingFeatures = uniqueStrings(parserRows.flatMap((row) => row.merge?.blockingFeatures ?? []));
|
|
8128
|
+
const parserReviewFeatures = uniqueStrings(parserRows.flatMap((row) => row.merge?.reviewFeatures ?? []));
|
|
8129
|
+
const missingTargets = (projection?.targets ?? []).filter((entry) => entry.lossClass === 'missingAdapter').map((entry) => entry.target);
|
|
8130
|
+
const unsupportedTargets = (projection?.targets ?? []).filter((entry) => entry.lossClass === 'unsupportedTargetFeatures').map((entry) => entry.target);
|
|
8131
|
+
const blockers = universalCapabilityBlockers({
|
|
8132
|
+
importCoverage,
|
|
8133
|
+
parserRows,
|
|
8134
|
+
parserReadiness,
|
|
8135
|
+
parserBlockingFeatures,
|
|
8136
|
+
projection,
|
|
8137
|
+
missingTargets,
|
|
8138
|
+
readiness
|
|
8139
|
+
});
|
|
8140
|
+
const review = universalCapabilityReviewReasons({
|
|
8141
|
+
importCoverage,
|
|
8142
|
+
parserRows,
|
|
8143
|
+
parserReviewFeatures,
|
|
8144
|
+
unsupportedTargets,
|
|
8145
|
+
readiness
|
|
8146
|
+
});
|
|
8147
|
+
return {
|
|
8148
|
+
language: importCoverage.language,
|
|
8149
|
+
aliases: importCoverage.aliases,
|
|
8150
|
+
extensions: importCoverage.extensions,
|
|
8151
|
+
readiness,
|
|
8152
|
+
imports: {
|
|
8153
|
+
total: importCoverage.imports.total,
|
|
8154
|
+
readiness: importCoverage.imports.readiness,
|
|
8155
|
+
symbols: importCoverage.imports.symbols,
|
|
8156
|
+
sourceMaps: importCoverage.imports.sourceMaps,
|
|
8157
|
+
sourceMapMappings: importCoverage.imports.sourceMapMappings,
|
|
8158
|
+
losses: importCoverage.imports.losses,
|
|
8159
|
+
lossKinds: importCoverage.imports.lossKinds,
|
|
8160
|
+
readinessReasons: importCoverage.imports.readinessReasons
|
|
8161
|
+
},
|
|
8162
|
+
parser: {
|
|
8163
|
+
readiness: parserReadiness,
|
|
8164
|
+
rows: parserRows.length,
|
|
8165
|
+
parsers: parserRows.map((row) => row.parser),
|
|
8166
|
+
mergeReadyParsers: parserRows.filter((row) => row.merge?.mergeReady).map((row) => row.parser),
|
|
8167
|
+
blockingFeatures: parserBlockingFeatures,
|
|
8168
|
+
reviewFeatures: parserReviewFeatures,
|
|
8169
|
+
languageSummary: parserLanguage
|
|
8170
|
+
},
|
|
8171
|
+
projection: {
|
|
8172
|
+
readiness: projectionReadiness,
|
|
8173
|
+
sourceProjection: projection?.sourceProjection,
|
|
8174
|
+
targets: projection?.targets ?? [],
|
|
8175
|
+
summary: projection?.summary ?? {
|
|
8176
|
+
imports: 0,
|
|
8177
|
+
parserAdapters: 0,
|
|
8178
|
+
targetEntries: 0,
|
|
8179
|
+
byLossClass: {},
|
|
8180
|
+
exactSourceImports: 0,
|
|
8181
|
+
stubDeclarationImports: 0
|
|
8182
|
+
},
|
|
8183
|
+
missingTargets,
|
|
8184
|
+
unsupportedTargets
|
|
8185
|
+
},
|
|
8186
|
+
evidence: {
|
|
8187
|
+
parserAdapters: importCoverage.parserAdapters.length,
|
|
8188
|
+
adapterCoverageSummaries: importCoverage.adapterCoverage.total,
|
|
8189
|
+
adapterCoverageGaps: importCoverage.adapterCoverage.gaps,
|
|
8190
|
+
knownLossKinds: importCoverage.knownLossKinds,
|
|
8191
|
+
sourceMapMappings: importCoverage.imports.sourceMapMappings
|
|
8192
|
+
},
|
|
8193
|
+
blockers,
|
|
8194
|
+
review
|
|
8195
|
+
};
|
|
8196
|
+
}
|
|
8197
|
+
|
|
8198
|
+
function universalCapabilityBlockers(input) {
|
|
8199
|
+
const blockers = [];
|
|
8200
|
+
if ((input.importCoverage.imports.total ?? 0) === 0) {
|
|
8201
|
+
blockers.push('No native import evidence observed for this language.');
|
|
8202
|
+
}
|
|
8203
|
+
if (!input.parserRows.length) {
|
|
8204
|
+
blockers.push('No parser feature row matched this language.');
|
|
8205
|
+
}
|
|
8206
|
+
if (input.parserReadiness === 'blocked') {
|
|
8207
|
+
blockers.push('Parser feature readiness is blocked.');
|
|
8208
|
+
}
|
|
8209
|
+
for (const feature of input.parserBlockingFeatures) {
|
|
8210
|
+
blockers.push(`Required parser feature is not merge-ready: ${feature}.`);
|
|
8211
|
+
}
|
|
8212
|
+
if (!input.projection) {
|
|
8213
|
+
blockers.push('No projection coverage row matched this language.');
|
|
8214
|
+
}
|
|
8215
|
+
for (const target of input.missingTargets) {
|
|
8216
|
+
blockers.push(`Missing native-to-target projection adapter for ${target}.`);
|
|
8217
|
+
}
|
|
8218
|
+
if (input.readiness === 'blocked' && blockers.length === 0) {
|
|
8219
|
+
blockers.push('Combined universal capability readiness is blocked.');
|
|
8220
|
+
}
|
|
8221
|
+
return uniqueStrings(blockers);
|
|
8222
|
+
}
|
|
8223
|
+
|
|
8224
|
+
function universalCapabilityReviewReasons(input) {
|
|
8225
|
+
const review = [];
|
|
8226
|
+
if ((input.importCoverage.imports.losses ?? 0) > 0) {
|
|
8227
|
+
review.push(`Native import evidence carries ${input.importCoverage.imports.losses} loss record(s).`);
|
|
8228
|
+
}
|
|
8229
|
+
for (const reason of input.importCoverage.imports.readinessReasons ?? []) {
|
|
8230
|
+
review.push(reason);
|
|
8231
|
+
}
|
|
8232
|
+
for (const feature of input.parserReviewFeatures) {
|
|
8233
|
+
review.push(`Parser feature needs review: ${feature}.`);
|
|
8234
|
+
}
|
|
8235
|
+
for (const target of input.unsupportedTargets) {
|
|
8236
|
+
review.push(`Target projection has unsupported feature losses for ${target}.`);
|
|
8237
|
+
}
|
|
8238
|
+
if (input.readiness === 'needs-review') {
|
|
8239
|
+
review.push('Combined universal capability readiness requires review.');
|
|
8240
|
+
} else if (input.readiness === 'ready-with-losses') {
|
|
8241
|
+
review.push('Combined universal capability readiness is ready with disclosed losses.');
|
|
8242
|
+
}
|
|
8243
|
+
return uniqueStrings(review);
|
|
8244
|
+
}
|
|
8245
|
+
|
|
8246
|
+
function universalCapabilityMatrixSummary(rows) {
|
|
8247
|
+
const byReadiness = {};
|
|
8248
|
+
const byImportReadiness = {};
|
|
8249
|
+
const byParserReadiness = {};
|
|
8250
|
+
const byProjectionReadiness = {};
|
|
8251
|
+
let imports = 0;
|
|
8252
|
+
let symbols = 0;
|
|
8253
|
+
let sourceMapMappings = 0;
|
|
8254
|
+
let losses = 0;
|
|
8255
|
+
let parserRows = 0;
|
|
8256
|
+
let parserMergeReady = 0;
|
|
8257
|
+
let targetEntries = 0;
|
|
8258
|
+
let missingAdapters = 0;
|
|
8259
|
+
let unsupportedTargetFeatures = 0;
|
|
8260
|
+
let exactSourceProjection = 0;
|
|
8261
|
+
let nativeSourceStubs = 0;
|
|
8262
|
+
let blockers = 0;
|
|
8263
|
+
let reviewReasons = 0;
|
|
8264
|
+
for (const row of rows) {
|
|
8265
|
+
byReadiness[row.readiness] = (byReadiness[row.readiness] ?? 0) + 1;
|
|
8266
|
+
byImportReadiness[row.imports.readiness] = (byImportReadiness[row.imports.readiness] ?? 0) + 1;
|
|
8267
|
+
byParserReadiness[row.parser.readiness] = (byParserReadiness[row.parser.readiness] ?? 0) + 1;
|
|
8268
|
+
byProjectionReadiness[row.projection.readiness] = (byProjectionReadiness[row.projection.readiness] ?? 0) + 1;
|
|
8269
|
+
imports += row.imports.total;
|
|
8270
|
+
symbols += row.imports.symbols;
|
|
8271
|
+
sourceMapMappings += row.imports.sourceMapMappings;
|
|
8272
|
+
losses += row.imports.losses;
|
|
8273
|
+
parserRows += row.parser.rows;
|
|
8274
|
+
parserMergeReady += row.parser.mergeReadyParsers.length;
|
|
8275
|
+
targetEntries += row.projection.targets.length;
|
|
8276
|
+
missingAdapters += row.projection.missingTargets.length;
|
|
8277
|
+
unsupportedTargetFeatures += row.projection.unsupportedTargets.length;
|
|
8278
|
+
exactSourceProjection += row.projection.summary.byLossClass?.exactSourceProjection ?? 0;
|
|
8279
|
+
nativeSourceStubs += row.projection.summary.byLossClass?.nativeSourceStubs ?? 0;
|
|
8280
|
+
blockers += row.blockers.length;
|
|
8281
|
+
reviewReasons += row.review.length;
|
|
8282
|
+
}
|
|
8283
|
+
return {
|
|
8284
|
+
languages: rows.length,
|
|
8285
|
+
imports,
|
|
8286
|
+
symbols,
|
|
8287
|
+
sourceMapMappings,
|
|
8288
|
+
losses,
|
|
8289
|
+
parserRows,
|
|
8290
|
+
parserMergeReady,
|
|
8291
|
+
targetEntries,
|
|
8292
|
+
missingAdapters,
|
|
8293
|
+
unsupportedTargetFeatures,
|
|
8294
|
+
exactSourceProjection,
|
|
8295
|
+
nativeSourceStubs,
|
|
8296
|
+
blockers,
|
|
8297
|
+
reviewReasons,
|
|
8298
|
+
readyLanguages: rows.filter((row) => row.readiness === 'ready').length,
|
|
8299
|
+
readyWithLossesLanguages: rows.filter((row) => row.readiness === 'ready-with-losses').length,
|
|
8300
|
+
reviewLanguages: rows.filter((row) => row.readiness === 'needs-review').length,
|
|
8301
|
+
blockedLanguages: rows.filter((row) => row.readiness === 'blocked').length,
|
|
8302
|
+
byReadiness,
|
|
8303
|
+
byImportReadiness,
|
|
8304
|
+
byParserReadiness,
|
|
8305
|
+
byProjectionReadiness
|
|
8306
|
+
};
|
|
8307
|
+
}
|
|
8308
|
+
|
|
8309
|
+
function universalLanguageIds(entry) {
|
|
8310
|
+
return uniqueStrings([
|
|
8311
|
+
entry?.language,
|
|
8312
|
+
...(entry?.aliases ?? [])
|
|
8313
|
+
].map(normalizeNativeLanguageId).filter(Boolean));
|
|
8314
|
+
}
|
|
8315
|
+
|
|
7194
8316
|
function countProjectionLossClasses(entries) {
|
|
7195
8317
|
const counts = {};
|
|
7196
8318
|
for (const entry of entries ?? []) {
|