@shapeshift-labs/frontier-lang-compiler 0.2.66 → 0.2.68
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 +6 -2
- package/bench/smoke.mjs +15 -1
- package/bench/universal-fixture-suite.mjs +183 -0
- package/dist/declarations/native-project-admission.d.ts +115 -0
- package/dist/declarations/roundtrip-audit.d.ts +186 -0
- package/dist/declarations/roundtrip.d.ts +2 -53
- package/dist/declarations/runtime.d.ts +0 -11
- package/dist/declarations/semantic-history-records.d.ts +277 -0
- package/dist/declarations/semantic-history.d.ts +45 -92
- package/dist/declarations/semantic-slice-admission.d.ts +111 -0
- package/dist/declarations/semantic-slice.d.ts +36 -1
- package/dist/declarations/universal-conversion-plan.d.ts +59 -0
- package/dist/declarations/universal-runtime-capabilities.d.ts +171 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/internal/index-impl/createNativeRoundtripEvidence.js +54 -49
- package/dist/internal/index-impl/createSemanticSlice.js +1 -1
- package/dist/internal/index-impl/createSemanticSliceAdmissionRecord.js +10 -1
- package/dist/internal/index-impl/expandSemanticSliceSelection.js +0 -1
- package/dist/internal/index-impl/nativeRoundtripAudit.js +217 -0
- package/dist/internal/index-impl/projectImportAdmissionImportEvidence.js +160 -0
- package/dist/internal/index-impl/projectImportAdmissionLanguageSummaries.js +247 -0
- package/dist/internal/index-impl/projectImportAdmissionRanks.js +52 -0
- package/dist/internal/index-impl/projectImportAdmissionSummaries.js +46 -111
- package/dist/internal/index-impl/projectImportAdmissionTasks.js +239 -0
- package/dist/internal/index-impl/semanticHistoryRecordNormalizers.js +151 -0
- package/dist/internal/index-impl/semanticHistoryRecordOverlaps.js +113 -0
- package/dist/internal/index-impl/semanticHistoryRecords.js +210 -149
- package/dist/internal/index-impl/semanticSliceAdmissionSurface.js +142 -0
- package/dist/internal/index-impl/semanticSliceExpectationAssertions.js +100 -0
- package/dist/internal/index-impl/semanticSliceExpectationRecords.js +75 -0
- package/dist/internal/index-impl/semanticSliceExpectedAssertions.js +5 -2
- package/dist/internal/index-impl/testSemanticSlice.js +4 -1
- package/dist/language-adapter-package-contracts.js +12 -57
- package/dist/language-adapter-package-rows.js +116 -0
- package/dist/universal-conversion-plan-summary.js +42 -0
- package/dist/universal-conversion-plan.js +46 -40
- package/dist/universal-runtime-capabilities.js +92 -0
- package/dist/universal-runtime-host-selectors.js +192 -0
- package/dist/universal-runtime-profiles.js +109 -0
- package/dist/universal-runtime-route-records.js +162 -0
- package/examples/js-frontier-rust-workbench-client.mjs +58 -1
- package/examples/js-frontier-rust-workbench-convert.mjs +161 -0
- package/examples/js-frontier-rust-workbench-route-styles.mjs +126 -0
- package/examples/js-frontier-rust-workbench-route.mjs +190 -0
- package/examples/js-frontier-rust-workbench-styles.mjs +3 -38
- package/examples/js-frontier-rust-workbench.mjs +22 -128
- package/package.json +1 -1
|
@@ -9,6 +9,10 @@ import {
|
|
|
9
9
|
normalizeProjectionMatrixTargets
|
|
10
10
|
} from './coverage-matrix-profiles.js';
|
|
11
11
|
import { createUniversalCapabilityMatrix } from './universal-capability-matrix.js';
|
|
12
|
+
import {
|
|
13
|
+
createUniversalRuntimeCapabilityMatrix,
|
|
14
|
+
runtimeRouteForConversion
|
|
15
|
+
} from './universal-runtime-capabilities.js';
|
|
12
16
|
import {
|
|
13
17
|
conversionMergeRefs,
|
|
14
18
|
importsForConversionLanguage
|
|
@@ -17,6 +21,7 @@ import {
|
|
|
17
21
|
conversionMergeScore,
|
|
18
22
|
conversionScoreComponents
|
|
19
23
|
} from './universal-conversion-plan-scoring.js';
|
|
24
|
+
import { conversionPlanSummary } from './universal-conversion-plan-summary.js';
|
|
20
25
|
|
|
21
26
|
export function createUniversalConversionPlan(input = {}, context = {}) {
|
|
22
27
|
const generatedAt = input.generatedAt ?? Date.now();
|
|
@@ -25,12 +30,21 @@ export function createUniversalConversionPlan(input = {}, context = {}) {
|
|
|
25
30
|
? input.universalCapabilityMatrix
|
|
26
31
|
: createUniversalCapabilityMatrix({ ...input, generatedAt }, context);
|
|
27
32
|
const targets = conversionTargets(input, matrix, context);
|
|
33
|
+
const runtimeMatrix = input.universalRuntimeCapabilityMatrix?.kind === 'frontier.lang.universalRuntimeCapabilityMatrix'
|
|
34
|
+
? input.universalRuntimeCapabilityMatrix
|
|
35
|
+
: createUniversalRuntimeCapabilityMatrix({
|
|
36
|
+
...input,
|
|
37
|
+
generatedAt,
|
|
38
|
+
sourceLanguages: matrix.languages,
|
|
39
|
+
targets
|
|
40
|
+
}, context);
|
|
28
41
|
const evidence = input.evidence ?? [];
|
|
29
42
|
const routes = (matrix.languages ?? []).flatMap((language) => targets.map((target) => conversionRoute(language, target, {
|
|
30
43
|
evidence,
|
|
31
44
|
generatedAt,
|
|
32
45
|
imports: input.imports ?? [],
|
|
33
|
-
matrix
|
|
46
|
+
matrix,
|
|
47
|
+
runtimeMatrix
|
|
34
48
|
}, id)));
|
|
35
49
|
return {
|
|
36
50
|
kind: 'frontier.lang.universalConversionPlan',
|
|
@@ -41,6 +55,7 @@ export function createUniversalConversionPlan(input = {}, context = {}) {
|
|
|
41
55
|
summary: conversionPlanSummary(routes),
|
|
42
56
|
matrices: {
|
|
43
57
|
universalCapability: matrix,
|
|
58
|
+
runtimeCapabilities: runtimeMatrix,
|
|
44
59
|
projectionReadiness: matrix.matrices?.projectionReadiness,
|
|
45
60
|
projectionTargets: matrix.matrices?.projectionTargets
|
|
46
61
|
},
|
|
@@ -90,6 +105,8 @@ function conversionRoute(language, target, input, planId) {
|
|
|
90
105
|
const sourceTarget = nativeLanguageCompileTarget(language.language, language.aliases) ?? normalizeNativeLanguageId(language.language);
|
|
91
106
|
const targetCell = (language.projection?.targets ?? []).find((entry) => entry.target === target);
|
|
92
107
|
const readinessCell = projectionReadinessCell(input.matrix, language, target);
|
|
108
|
+
const runtimeRoute = runtimeRouteForConversion(input.runtimeMatrix, language, target);
|
|
109
|
+
const runtime = conversionRuntime(runtimeRoute);
|
|
93
110
|
const mode = conversionMode(language, target, sourceTarget, targetCell);
|
|
94
111
|
const blockers = conversionBlockers(language, targetCell, mode);
|
|
95
112
|
const review = conversionReviewReasons(language, targetCell, mode);
|
|
@@ -115,6 +132,8 @@ function conversionRoute(language, target, input, planId) {
|
|
|
115
132
|
adapterKind: targetCell?.adapterKind,
|
|
116
133
|
sourceProjection: language.projection?.sourceProjection,
|
|
117
134
|
projectionReadiness: readinessCell,
|
|
135
|
+
runtime,
|
|
136
|
+
runtimeAdapterRequirements: runtime.adapterRequirements,
|
|
118
137
|
evidence: conversionEvidence(language, targetCell),
|
|
119
138
|
missingEvidence: conversionMissingEvidence(language, targetCell, mode),
|
|
120
139
|
blockers,
|
|
@@ -172,6 +191,32 @@ function conversionReviewReasons(language, targetCell, mode) {
|
|
|
172
191
|
]);
|
|
173
192
|
}
|
|
174
193
|
|
|
194
|
+
function conversionRuntime(runtimeRoute) {
|
|
195
|
+
if (!runtimeRoute) {
|
|
196
|
+
return {
|
|
197
|
+
requiredCapabilities: [],
|
|
198
|
+
satisfiedCapabilities: [],
|
|
199
|
+
adapterRequirements: [],
|
|
200
|
+
missingCapabilities: [],
|
|
201
|
+
readiness: 'ready',
|
|
202
|
+
blockers: [],
|
|
203
|
+
review: []
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
routeId: runtimeRoute.id,
|
|
208
|
+
source: runtimeRoute.source,
|
|
209
|
+
target: runtimeRoute.target,
|
|
210
|
+
requiredCapabilities: runtimeRoute.requiredCapabilities,
|
|
211
|
+
satisfiedCapabilities: runtimeRoute.satisfiedCapabilities,
|
|
212
|
+
adapterRequirements: runtimeRoute.adapterRequirements,
|
|
213
|
+
missingCapabilities: runtimeRoute.missingCapabilities,
|
|
214
|
+
readiness: runtimeRoute.readiness,
|
|
215
|
+
blockers: runtimeRoute.blockers,
|
|
216
|
+
review: runtimeRoute.review
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
175
220
|
function projectionReadinessCell(matrix, language, target) {
|
|
176
221
|
const ids = uniqueStrings([language.language, ...(language.aliases ?? [])].map(normalizeNativeLanguageId));
|
|
177
222
|
return (matrix.matrices?.projectionReadiness?.languages ?? [])
|
|
@@ -238,42 +283,3 @@ function conversionTasks(language, target, mode, blockers, review) {
|
|
|
238
283
|
...(blockers.length || review.length ? [`collect proof, replay, or oracle evidence for ${language.language} to ${target}`] : [])
|
|
239
284
|
]);
|
|
240
285
|
}
|
|
241
|
-
|
|
242
|
-
function conversionPlanSummary(routes) {
|
|
243
|
-
const summary = {
|
|
244
|
-
routes: routes.length,
|
|
245
|
-
byMode: {},
|
|
246
|
-
byReadiness: {},
|
|
247
|
-
byAdmissionAction: {},
|
|
248
|
-
readyRoutes: 0,
|
|
249
|
-
reviewRoutes: 0,
|
|
250
|
-
blockedRoutes: 0,
|
|
251
|
-
preserveSourceRoutes: 0,
|
|
252
|
-
targetAdapterRoutes: 0,
|
|
253
|
-
stubOnlyRoutes: 0,
|
|
254
|
-
semanticIndexOnlyRoutes: 0,
|
|
255
|
-
missingEvidence: 0,
|
|
256
|
-
blockers: 0,
|
|
257
|
-
reviewReasons: 0,
|
|
258
|
-
autoMergeClaims: 0,
|
|
259
|
-
semanticEquivalenceClaims: 0
|
|
260
|
-
};
|
|
261
|
-
for (const route of routes) {
|
|
262
|
-
summary.byMode[route.mode] = (summary.byMode[route.mode] ?? 0) + 1;
|
|
263
|
-
summary.byReadiness[route.readiness] = (summary.byReadiness[route.readiness] ?? 0) + 1;
|
|
264
|
-
summary.byAdmissionAction[route.admissionAction] = (summary.byAdmissionAction[route.admissionAction] ?? 0) + 1;
|
|
265
|
-
if (route.readiness === 'ready') summary.readyRoutes += 1;
|
|
266
|
-
if (route.readiness === 'needs-review' || route.readiness === 'ready-with-losses') summary.reviewRoutes += 1;
|
|
267
|
-
if (route.readiness === 'blocked') summary.blockedRoutes += 1;
|
|
268
|
-
if (route.mode === 'preserve-source') summary.preserveSourceRoutes += 1;
|
|
269
|
-
if (route.mode === 'target-adapter') summary.targetAdapterRoutes += 1;
|
|
270
|
-
if (route.mode === 'stub-only') summary.stubOnlyRoutes += 1;
|
|
271
|
-
if (route.mode === 'semantic-index-only') summary.semanticIndexOnlyRoutes += 1;
|
|
272
|
-
summary.missingEvidence += route.missingEvidence.length;
|
|
273
|
-
summary.blockers += route.blockers.length;
|
|
274
|
-
summary.reviewReasons += route.review.length;
|
|
275
|
-
if (route.autoMergeClaim) summary.autoMergeClaims += 1;
|
|
276
|
-
if (route.semanticEquivalenceClaim) summary.semanticEquivalenceClaims += 1;
|
|
277
|
-
}
|
|
278
|
-
return summary;
|
|
279
|
-
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import {
|
|
2
|
+
normalizeNativeLanguageId,
|
|
3
|
+
uniqueStrings
|
|
4
|
+
} from './native-import-utils.js';
|
|
5
|
+
import {
|
|
6
|
+
normalizeProjectionMatrixTargets
|
|
7
|
+
} from './coverage-matrix-profiles.js';
|
|
8
|
+
import {
|
|
9
|
+
UniversalRuntimeCapabilityKinds,
|
|
10
|
+
UniversalRuntimeHostProfiles
|
|
11
|
+
} from './universal-runtime-profiles.js';
|
|
12
|
+
import {
|
|
13
|
+
normalizeRuntimeCapabilityKind,
|
|
14
|
+
normalizeRuntimeHostProfiles,
|
|
15
|
+
normalizeRuntimeId,
|
|
16
|
+
normalizeRuntimeRequirements,
|
|
17
|
+
runtimeSourceHosts,
|
|
18
|
+
runtimeTargetHosts
|
|
19
|
+
} from './universal-runtime-host-selectors.js';
|
|
20
|
+
import {
|
|
21
|
+
runtimeCapabilityMatrixSummary,
|
|
22
|
+
runtimeRoute
|
|
23
|
+
} from './universal-runtime-route-records.js';
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
UniversalRuntimeCapabilityKinds,
|
|
27
|
+
UniversalRuntimeHostProfiles
|
|
28
|
+
} from './universal-runtime-profiles.js';
|
|
29
|
+
|
|
30
|
+
export function createUniversalRuntimeCapabilityMatrix(input = {}, context = {}) {
|
|
31
|
+
const generatedAt = input.generatedAt ?? Date.now();
|
|
32
|
+
const hostProfiles = normalizeRuntimeHostProfiles(input.hostProfiles ?? input.runtimeHosts ?? UniversalRuntimeHostProfiles);
|
|
33
|
+
const sourceHosts = runtimeSourceHosts(input, hostProfiles);
|
|
34
|
+
const targetHosts = runtimeTargetHosts(input, hostProfiles, context);
|
|
35
|
+
const requirements = normalizeRuntimeRequirements(input, hostProfiles);
|
|
36
|
+
const routes = sourceHosts.flatMap((sourceHost) => targetHosts.map((targetHost) => runtimeRoute(sourceHost, targetHost, {
|
|
37
|
+
generatedAt,
|
|
38
|
+
requirements
|
|
39
|
+
})));
|
|
40
|
+
return {
|
|
41
|
+
kind: 'frontier.lang.universalRuntimeCapabilityMatrix',
|
|
42
|
+
version: 1,
|
|
43
|
+
generatedAt,
|
|
44
|
+
hostProfiles,
|
|
45
|
+
routes,
|
|
46
|
+
summary: runtimeCapabilityMatrixSummary(routes),
|
|
47
|
+
metadata: {
|
|
48
|
+
capabilityKinds: [...UniversalRuntimeCapabilityKinds],
|
|
49
|
+
sourceHosts: sourceHosts.map((host) => host.id),
|
|
50
|
+
targetHosts: targetHosts.map((host) => host.id),
|
|
51
|
+
note: 'Runtime capability coverage is declarative host evidence for adapter planning. It does not import, polyfill, or execute host APIs.'
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function queryUniversalRuntimeCapabilityMatrix(matrixOrInput = {}, query = {}, context = {}) {
|
|
57
|
+
const matrix = matrixOrInput?.kind === 'frontier.lang.universalRuntimeCapabilityMatrix'
|
|
58
|
+
? matrixOrInput
|
|
59
|
+
: createUniversalRuntimeCapabilityMatrix(matrixOrInput, context);
|
|
60
|
+
const sourceLanguage = normalizeNativeLanguageId(query.sourceLanguage ?? query.language);
|
|
61
|
+
const target = normalizeProjectionMatrixTargets(query.target ? [query.target] : [])[0];
|
|
62
|
+
const sourceRuntime = normalizeRuntimeId(query.sourceRuntime ?? query.runtime);
|
|
63
|
+
const targetRuntime = normalizeRuntimeId(query.targetRuntime);
|
|
64
|
+
const capability = normalizeRuntimeCapabilityKind(query.capability);
|
|
65
|
+
const routes = (matrix.routes ?? []).filter((route) => {
|
|
66
|
+
if (sourceLanguage && !route.source.languageIds.includes(sourceLanguage)) return false;
|
|
67
|
+
if (target && route.target.target !== target) return false;
|
|
68
|
+
if (sourceRuntime && route.source.runtime !== sourceRuntime && route.source.id !== sourceRuntime) return false;
|
|
69
|
+
if (targetRuntime && route.target.runtime !== targetRuntime && route.target.id !== targetRuntime) return false;
|
|
70
|
+
if (capability && !route.requiredCapabilities.includes(capability)) return false;
|
|
71
|
+
if (query.requiresAdapter === true && route.adapterRequirements.length === 0) return false;
|
|
72
|
+
if (query.requiresAdapter === false && route.adapterRequirements.length > 0) return false;
|
|
73
|
+
return true;
|
|
74
|
+
});
|
|
75
|
+
return {
|
|
76
|
+
kind: 'frontier.lang.universalRuntimeCapabilityMatrixQuery',
|
|
77
|
+
version: 1,
|
|
78
|
+
found: routes.length > 0,
|
|
79
|
+
routes,
|
|
80
|
+
bestRoute: routes[0],
|
|
81
|
+
reasons: routes.length ? [] : [`No runtime capability route matched source=${query.sourceLanguage ?? query.language ?? '*'} target=${query.target ?? '*'}.`]
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function runtimeRouteForConversion(runtimeMatrix, language, target) {
|
|
86
|
+
const languageIds = uniqueStrings([language?.language, ...(language?.aliases ?? [])].map(normalizeNativeLanguageId));
|
|
87
|
+
const normalizedTarget = normalizeProjectionMatrixTargets([target])[0] ?? String(target ?? '');
|
|
88
|
+
return (runtimeMatrix?.routes ?? []).find((route) => {
|
|
89
|
+
if (normalizedTarget && route.target.target !== normalizedTarget) return false;
|
|
90
|
+
return route.source.languageIds.some((id) => languageIds.includes(id));
|
|
91
|
+
});
|
|
92
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import {
|
|
2
|
+
normalizeNativeLanguageId,
|
|
3
|
+
uniqueStrings
|
|
4
|
+
} from './native-import-utils.js';
|
|
5
|
+
import {
|
|
6
|
+
nativeLanguageCompileTarget,
|
|
7
|
+
normalizeProjectionMatrixTargets
|
|
8
|
+
} from './coverage-matrix-profiles.js';
|
|
9
|
+
|
|
10
|
+
export function normalizeRuntimeHostProfiles(profiles) {
|
|
11
|
+
return (profiles ?? []).map((profile) => {
|
|
12
|
+
const language = normalizeNativeLanguageId(profile.language);
|
|
13
|
+
const runtime = normalizeRuntimeId(profile.runtime ?? profile.host ?? 'host');
|
|
14
|
+
const id = profile.id ?? `${language}:${runtime}`;
|
|
15
|
+
const aliases = uniqueStrings((profile.aliases ?? []).map(normalizeNativeLanguageId));
|
|
16
|
+
const capabilities = Object.fromEntries(Object.entries(profile.capabilities ?? {})
|
|
17
|
+
.map(([kind, value]) => {
|
|
18
|
+
const normalizedKind = normalizeRuntimeCapabilityKind(value?.kind ?? kind);
|
|
19
|
+
return [normalizedKind, {
|
|
20
|
+
kind: normalizedKind,
|
|
21
|
+
support: normalizeCapabilitySupport(value?.support),
|
|
22
|
+
binding: String(value?.binding ?? `${id}.${normalizedKind}`),
|
|
23
|
+
notes: uniqueStrings(value?.notes ?? [])
|
|
24
|
+
}];
|
|
25
|
+
}));
|
|
26
|
+
return {
|
|
27
|
+
id,
|
|
28
|
+
language,
|
|
29
|
+
aliases,
|
|
30
|
+
languageIds: uniqueStrings([language, ...aliases]),
|
|
31
|
+
runtime,
|
|
32
|
+
host: String(profile.host ?? runtime),
|
|
33
|
+
target: normalizeProjectionMatrixTargets([profile.target ?? nativeLanguageCompileTarget(language, aliases) ?? language])[0] ?? language,
|
|
34
|
+
capabilities,
|
|
35
|
+
notes: uniqueStrings(profile.notes ?? [])
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function runtimeSourceHosts(input, hostProfiles) {
|
|
41
|
+
const explicit = normalizeHostSelectors(input.sourceHosts ?? input.sourceRuntimeHosts, hostProfiles);
|
|
42
|
+
if (explicit.length) return explicit;
|
|
43
|
+
const languages = uniqueStrings([
|
|
44
|
+
...(input.sourceLanguages ?? input.languages ?? []).map((entry) => entry?.language ?? entry),
|
|
45
|
+
...(input.imports ?? []).map((entry) => entry?.language ?? entry?.nativeAst?.language ?? entry?.nativeSource?.language),
|
|
46
|
+
...runtimeRequirementRecords(input).map((entry) => entry.sourceLanguage ?? entry.language)
|
|
47
|
+
].map(normalizeNativeLanguageId));
|
|
48
|
+
return (languages.length ? languages : ['javascript'])
|
|
49
|
+
.map((language) => defaultHostForLanguage(language, hostProfiles, input.sourceRuntimes?.[language] ?? input.sourceRuntime))
|
|
50
|
+
.filter(Boolean);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function runtimeTargetHosts(input, hostProfiles, context) {
|
|
54
|
+
const explicit = normalizeHostSelectors(input.targetHosts ?? input.targetRuntimeHosts, hostProfiles);
|
|
55
|
+
if (explicit.length) return explicit;
|
|
56
|
+
const targets = normalizeProjectionMatrixTargets(input.targets ?? context.compileTargets ?? []);
|
|
57
|
+
const targetList = targets.length ? targets : ['javascript'];
|
|
58
|
+
return targetList.map((target) => defaultHostForTarget(target, hostProfiles, input.targetRuntimes?.[target] ?? input.targetRuntime));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function normalizeHostSelectors(value, hostProfiles) {
|
|
62
|
+
if (!value) return [];
|
|
63
|
+
if (Array.isArray(value)) return value.map((entry) => resolveHostSelector(entry, hostProfiles)).filter(Boolean);
|
|
64
|
+
if (typeof value === 'object') return Object.values(value).map((entry) => resolveHostSelector(entry, hostProfiles)).filter(Boolean);
|
|
65
|
+
return [resolveHostSelector(value, hostProfiles)].filter(Boolean);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function resolveHostSelector(value, hostProfiles) {
|
|
69
|
+
if (!value) return undefined;
|
|
70
|
+
if (typeof value === 'object') return normalizeRuntimeHostProfiles([value])[0];
|
|
71
|
+
const normalized = normalizeRuntimeId(value);
|
|
72
|
+
return hostProfiles.find((profile) => profile.id === normalized)
|
|
73
|
+
?? hostProfiles.find((profile) => `${profile.language}:${profile.runtime}` === normalized)
|
|
74
|
+
?? hostProfiles.find((profile) => profile.language === normalized)
|
|
75
|
+
?? genericHostProfile(normalized, normalized);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function defaultHostForLanguage(language, hostProfiles, runtime) {
|
|
79
|
+
const normalizedLanguage = normalizeNativeLanguageId(language);
|
|
80
|
+
const normalizedRuntime = normalizeRuntimeId(runtime);
|
|
81
|
+
return hostProfiles.find((profile) => profile.language === normalizedLanguage && (!normalizedRuntime || profile.runtime === normalizedRuntime || profile.id === normalizedRuntime))
|
|
82
|
+
?? hostProfiles.find((profile) => profile.languageIds.includes(normalizedLanguage))
|
|
83
|
+
?? genericHostProfile(`${normalizedLanguage}:host`, normalizedLanguage);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function defaultHostForTarget(target, hostProfiles, runtime) {
|
|
87
|
+
const normalizedTarget = normalizeProjectionMatrixTargets([target])[0] ?? normalizeNativeLanguageId(target);
|
|
88
|
+
const normalizedRuntime = normalizeRuntimeId(runtime);
|
|
89
|
+
return hostProfiles.find((profile) => profile.target === normalizedTarget && (!normalizedRuntime || profile.runtime === normalizedRuntime || profile.id === normalizedRuntime))
|
|
90
|
+
?? hostProfiles.find((profile) => profile.language === normalizedTarget)
|
|
91
|
+
?? genericHostProfile(`${normalizedTarget}:host`, normalizedTarget);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function genericHostProfile(id, language) {
|
|
95
|
+
const normalizedLanguage = normalizeNativeLanguageId(language);
|
|
96
|
+
const normalizedId = String(id || `${normalizedLanguage}:host`);
|
|
97
|
+
return {
|
|
98
|
+
id: normalizedId,
|
|
99
|
+
language: normalizedLanguage,
|
|
100
|
+
aliases: [],
|
|
101
|
+
languageIds: [normalizedLanguage],
|
|
102
|
+
runtime: normalizedId.includes(':') ? normalizedId.split(':').at(-1) : 'host',
|
|
103
|
+
host: 'host',
|
|
104
|
+
target: normalizedLanguage,
|
|
105
|
+
capabilities: {},
|
|
106
|
+
notes: ['No built-in runtime host profile was available; callers may provide hostProfiles for stronger adapter planning.']
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function normalizeRuntimeRequirements(input, hostProfiles) {
|
|
111
|
+
const records = [
|
|
112
|
+
...runtimeRequirementRecords(input),
|
|
113
|
+
...runtimeRequirementRecordsFromImports(input.imports)
|
|
114
|
+
];
|
|
115
|
+
return records.flatMap((record) => normalizeRuntimeRequirementRecord(record, hostProfiles));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function runtimeRequirementRecords(input) {
|
|
119
|
+
if (!input) return [];
|
|
120
|
+
const value = input.runtimeRequirements ?? input.requiredRuntimeCapabilities ?? input.effects ?? [];
|
|
121
|
+
if (Array.isArray(value)) return value;
|
|
122
|
+
if (typeof value === 'object') {
|
|
123
|
+
return Object.entries(value).map(([key, capabilities]) => ({
|
|
124
|
+
sourceLanguage: key,
|
|
125
|
+
capabilities
|
|
126
|
+
}));
|
|
127
|
+
}
|
|
128
|
+
return [value];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function runtimeRequirementRecordsFromImports(imports) {
|
|
132
|
+
return (imports ?? []).flatMap((imported) => {
|
|
133
|
+
const value = imported?.runtimeRequirements
|
|
134
|
+
?? imported?.metadata?.runtimeRequirements
|
|
135
|
+
?? imported?.metadata?.runtimeCapabilities
|
|
136
|
+
?? imported?.metadata?.effects;
|
|
137
|
+
const records = Array.isArray(value) ? value : value ? [value] : [];
|
|
138
|
+
return records.map((record) => typeof record === 'string'
|
|
139
|
+
? { sourceLanguage: imported?.language ?? imported?.nativeAst?.language, capabilities: [record] }
|
|
140
|
+
: { sourceLanguage: imported?.language ?? imported?.nativeAst?.language, ...record });
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function normalizeRuntimeRequirementRecord(record, hostProfiles) {
|
|
145
|
+
if (!record) return [];
|
|
146
|
+
if (typeof record === 'string') return [{ capability: normalizeRuntimeCapabilityKind(record) }].filter((entry) => entry.capability);
|
|
147
|
+
const capabilities = uniqueStrings([
|
|
148
|
+
...(Array.isArray(record.capabilities) ? record.capabilities : []),
|
|
149
|
+
...(Array.isArray(record.requiredCapabilities) ? record.requiredCapabilities : []),
|
|
150
|
+
record.capability,
|
|
151
|
+
record.kind
|
|
152
|
+
].map(normalizeRuntimeCapabilityKind).filter(Boolean));
|
|
153
|
+
const sourceHost = resolveHostSelector(record.sourceHost ?? record.sourceRuntimeHost, hostProfiles);
|
|
154
|
+
const targetHost = resolveHostSelector(record.targetHost ?? record.targetRuntimeHost, hostProfiles);
|
|
155
|
+
return capabilities.map((capability) => ({
|
|
156
|
+
capability,
|
|
157
|
+
sourceLanguage: normalizeNativeLanguageId(record.sourceLanguage ?? record.language ?? sourceHost?.language),
|
|
158
|
+
sourceRuntime: normalizeRuntimeId(record.sourceRuntime ?? record.runtime ?? sourceHost?.runtime),
|
|
159
|
+
sourceHostId: sourceHost?.id,
|
|
160
|
+
target: normalizeProjectionMatrixTargets(record.target ? [record.target] : [])[0],
|
|
161
|
+
targetRuntime: normalizeRuntimeId(record.targetRuntime ?? targetHost?.runtime),
|
|
162
|
+
targetHostId: targetHost?.id,
|
|
163
|
+
reason: record.reason,
|
|
164
|
+
evidenceIds: uniqueStrings(record.evidenceIds ?? [])
|
|
165
|
+
}));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function normalizeRuntimeCapabilityKind(value) {
|
|
169
|
+
if (!value) return '';
|
|
170
|
+
const text = String(value).trim().toLowerCase();
|
|
171
|
+
if (text === 'http' || text === 'network' || text === 'networking') return 'fetch';
|
|
172
|
+
if (text === 'timer' || text === 'clock' || text === 'scheduler') return 'timers';
|
|
173
|
+
if (text === 'localstorage' || text === 'local-storage' || text === 'persistence') return 'storage';
|
|
174
|
+
if (text === 'file' || text === 'files' || text === 'fs') return 'filesystem';
|
|
175
|
+
if (text === 'threads' || text === 'workers' || text === 'worker') return 'threading';
|
|
176
|
+
if (text === 'browser-dom' || text === 'document') return 'dom';
|
|
177
|
+
if (text === 'promise' || text === 'promises' || text === 'await') return 'async';
|
|
178
|
+
if (text === 'native-ffi' || text === 'abi') return 'ffi';
|
|
179
|
+
return text;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function normalizeRuntimeId(value) {
|
|
183
|
+
if (!value) return '';
|
|
184
|
+
return String(value).trim().toLowerCase();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function normalizeCapabilitySupport(value) {
|
|
188
|
+
const support = String(value ?? 'native').trim().toLowerCase();
|
|
189
|
+
if (support === 'native' || support === 'adapter' || support === 'unavailable') return support;
|
|
190
|
+
if (support === 'unsupported' || support === 'missing' || support === 'none') return 'unavailable';
|
|
191
|
+
return support;
|
|
192
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
export const UniversalRuntimeCapabilityKinds = Object.freeze([
|
|
2
|
+
'fetch',
|
|
3
|
+
'timers',
|
|
4
|
+
'storage',
|
|
5
|
+
'filesystem',
|
|
6
|
+
'threading',
|
|
7
|
+
'dom',
|
|
8
|
+
'async',
|
|
9
|
+
'ffi'
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
export const UniversalRuntimeHostProfiles = Object.freeze([
|
|
13
|
+
runtimeHostProfile('javascript:web', 'javascript', 'web', 'browser', 'javascript', {
|
|
14
|
+
fetch: runtimeCapability('fetch', 'native', 'web.fetch'),
|
|
15
|
+
timers: runtimeCapability('timers', 'native', 'web.timers'),
|
|
16
|
+
storage: runtimeCapability('storage', 'native', 'web.storage'),
|
|
17
|
+
filesystem: runtimeCapability('filesystem', 'unavailable', 'web.no-filesystem'),
|
|
18
|
+
threading: runtimeCapability('threading', 'adapter', 'web.workers'),
|
|
19
|
+
dom: runtimeCapability('dom', 'native', 'web.dom'),
|
|
20
|
+
async: runtimeCapability('async', 'native', 'web.promise-event-loop'),
|
|
21
|
+
ffi: runtimeCapability('ffi', 'unavailable', 'web.no-native-ffi')
|
|
22
|
+
}, ['js', 'jsx']),
|
|
23
|
+
runtimeHostProfile('typescript:web', 'typescript', 'web', 'browser', 'typescript', {
|
|
24
|
+
fetch: runtimeCapability('fetch', 'native', 'web.fetch'),
|
|
25
|
+
timers: runtimeCapability('timers', 'native', 'web.timers'),
|
|
26
|
+
storage: runtimeCapability('storage', 'native', 'web.storage'),
|
|
27
|
+
filesystem: runtimeCapability('filesystem', 'unavailable', 'web.no-filesystem'),
|
|
28
|
+
threading: runtimeCapability('threading', 'adapter', 'web.workers'),
|
|
29
|
+
dom: runtimeCapability('dom', 'native', 'web.dom'),
|
|
30
|
+
async: runtimeCapability('async', 'native', 'web.promise-event-loop'),
|
|
31
|
+
ffi: runtimeCapability('ffi', 'unavailable', 'web.no-native-ffi')
|
|
32
|
+
}, ['ts', 'tsx']),
|
|
33
|
+
runtimeHostProfile('javascript:node', 'javascript', 'node', 'node', 'javascript', {
|
|
34
|
+
fetch: runtimeCapability('fetch', 'native', 'node.fetch'),
|
|
35
|
+
timers: runtimeCapability('timers', 'native', 'node.timers'),
|
|
36
|
+
storage: runtimeCapability('storage', 'adapter', 'node.storage-adapter'),
|
|
37
|
+
filesystem: runtimeCapability('filesystem', 'native', 'node.fs'),
|
|
38
|
+
threading: runtimeCapability('threading', 'adapter', 'node.worker-threads'),
|
|
39
|
+
dom: runtimeCapability('dom', 'unavailable', 'node.no-dom'),
|
|
40
|
+
async: runtimeCapability('async', 'native', 'node.promise-event-loop'),
|
|
41
|
+
ffi: runtimeCapability('ffi', 'adapter', 'node.native-addon')
|
|
42
|
+
}, ['nodejs']),
|
|
43
|
+
runtimeHostProfile('rust:cli', 'rust', 'cli', 'native-cli', 'rust', {
|
|
44
|
+
fetch: runtimeCapability('fetch', 'adapter', 'rust.http-client'),
|
|
45
|
+
timers: runtimeCapability('timers', 'native', 'rust.timer'),
|
|
46
|
+
storage: runtimeCapability('storage', 'adapter', 'rust.filesystem-storage'),
|
|
47
|
+
filesystem: runtimeCapability('filesystem', 'native', 'rust.std-fs'),
|
|
48
|
+
threading: runtimeCapability('threading', 'native', 'rust.std-thread'),
|
|
49
|
+
dom: runtimeCapability('dom', 'unavailable', 'rust.no-dom'),
|
|
50
|
+
async: runtimeCapability('async', 'adapter', 'rust.async-runtime'),
|
|
51
|
+
ffi: runtimeCapability('ffi', 'native', 'rust.ffi')
|
|
52
|
+
}, ['rs']),
|
|
53
|
+
runtimeHostProfile('python:cli', 'python', 'cli', 'native-cli', 'python', {
|
|
54
|
+
fetch: runtimeCapability('fetch', 'adapter', 'python.http-client'),
|
|
55
|
+
timers: runtimeCapability('timers', 'native', 'python.timers'),
|
|
56
|
+
storage: runtimeCapability('storage', 'adapter', 'python.persistence'),
|
|
57
|
+
filesystem: runtimeCapability('filesystem', 'native', 'python.filesystem'),
|
|
58
|
+
threading: runtimeCapability('threading', 'native', 'python.threading'),
|
|
59
|
+
dom: runtimeCapability('dom', 'unavailable', 'python.no-dom'),
|
|
60
|
+
async: runtimeCapability('async', 'native', 'python.asyncio'),
|
|
61
|
+
ffi: runtimeCapability('ffi', 'native', 'python.ctypes')
|
|
62
|
+
}, ['py']),
|
|
63
|
+
runtimeHostProfile('c:cli', 'c', 'cli', 'native-cli', 'c', {
|
|
64
|
+
fetch: runtimeCapability('fetch', 'adapter', 'c.http-client'),
|
|
65
|
+
timers: runtimeCapability('timers', 'native', 'c.timers'),
|
|
66
|
+
storage: runtimeCapability('storage', 'adapter', 'c.persistence'),
|
|
67
|
+
filesystem: runtimeCapability('filesystem', 'native', 'c.filesystem'),
|
|
68
|
+
threading: runtimeCapability('threading', 'native', 'c.threads'),
|
|
69
|
+
dom: runtimeCapability('dom', 'unavailable', 'c.no-dom'),
|
|
70
|
+
async: runtimeCapability('async', 'adapter', 'c.event-loop'),
|
|
71
|
+
ffi: runtimeCapability('ffi', 'native', 'c.abi')
|
|
72
|
+
}, ['h']),
|
|
73
|
+
runtimeHostProfile('cpp:cli', 'cpp', 'cli', 'native-cli', 'cpp', {
|
|
74
|
+
fetch: runtimeCapability('fetch', 'adapter', 'cpp.http-client'),
|
|
75
|
+
timers: runtimeCapability('timers', 'native', 'cpp.timers'),
|
|
76
|
+
storage: runtimeCapability('storage', 'adapter', 'cpp.persistence'),
|
|
77
|
+
filesystem: runtimeCapability('filesystem', 'native', 'cpp.filesystem'),
|
|
78
|
+
threading: runtimeCapability('threading', 'native', 'cpp.thread'),
|
|
79
|
+
dom: runtimeCapability('dom', 'unavailable', 'cpp.no-dom'),
|
|
80
|
+
async: runtimeCapability('async', 'adapter', 'cpp.async-runtime'),
|
|
81
|
+
ffi: runtimeCapability('ffi', 'native', 'cpp.abi')
|
|
82
|
+
}, ['cc', 'cxx', 'hpp'])
|
|
83
|
+
]);
|
|
84
|
+
|
|
85
|
+
function runtimeHostProfile(id, language, runtime, host, target, capabilities, aliases = []) {
|
|
86
|
+
return Object.freeze({
|
|
87
|
+
id,
|
|
88
|
+
language,
|
|
89
|
+
aliases,
|
|
90
|
+
runtime,
|
|
91
|
+
host,
|
|
92
|
+
target,
|
|
93
|
+
capabilities: freezeCapabilityMap(capabilities),
|
|
94
|
+
notes: []
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function runtimeCapability(kind, support, binding, notes = []) {
|
|
99
|
+
return Object.freeze({
|
|
100
|
+
kind,
|
|
101
|
+
support,
|
|
102
|
+
binding,
|
|
103
|
+
notes
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function freezeCapabilityMap(capabilities) {
|
|
108
|
+
return Object.freeze(Object.fromEntries(Object.entries(capabilities).map(([key, value]) => [key, Object.freeze(value)])));
|
|
109
|
+
}
|