@shapeshift-labs/frontier-lang-compiler 0.2.65 → 0.2.67
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 +37 -8
- package/bench/smoke.mjs +15 -1
- package/bench/universal-fixture-suite.mjs +183 -0
- package/dist/declarations/import-adapter-core.d.ts +3 -0
- package/dist/declarations/native-project-admission.d.ts +133 -0
- package/dist/declarations/roundtrip-audit.d.ts +177 -0
- package/dist/declarations/roundtrip.d.ts +2 -53
- package/dist/declarations/semantic-history-records.d.ts +277 -0
- package/dist/declarations/semantic-history.d.ts +45 -92
- package/dist/declarations/semantic-merge-candidates.d.ts +200 -0
- package/dist/declarations/semantic-merge-conflicts.d.ts +12 -0
- package/dist/declarations/semantic-sidecar.d.ts +8 -3
- 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 +2 -0
- package/dist/index.js +2 -0
- package/dist/internal/index-impl/attachExternalOwnership.js +18 -10
- package/dist/internal/index-impl/createNativeRoundtripEvidence.js +54 -49
- package/dist/internal/index-impl/createSemanticImportSidecar.js +6 -0
- package/dist/internal/index-impl/createSemanticSlice.js +4 -3
- package/dist/internal/index-impl/createSemanticSliceAdmissionRecord.js +10 -1
- package/dist/internal/index-impl/diffNativeSourceImports.js +3 -2
- package/dist/internal/index-impl/expandSemanticSliceSelection.js +0 -1
- package/dist/internal/index-impl/externalSemanticBase.js +1 -0
- package/dist/internal/index-impl/importExternalSemanticIndex.js +4 -0
- 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 +77 -117
- 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/semanticMergeCandidateRecordInternals.js +314 -0
- package/dist/internal/index-impl/semanticMergeCandidateRecords.js +241 -0
- 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/internal/index-impl/withExternalEmptyLoss.js +1 -0
- package/dist/language-adapter-package-contracts.js +12 -57
- package/dist/language-adapter-package-rows.js +116 -0
- package/dist/lightweight-dependency-language.js +8 -0
- package/dist/native-region-scanner-core.js +42 -10
- package/dist/native-region-scanner-js-helpers.js +2 -0
- package/dist/native-region-scanner-js-imports.js +111 -0
- package/dist/native-region-scanner-js.js +111 -28
- 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-adapters.mjs +89 -0
- package/examples/js-frontier-rust-workbench-bounds.mjs +4 -3
- package/examples/js-frontier-rust-workbench-client.mjs +135 -59
- package/examples/js-frontier-rust-workbench-convert.mjs +161 -0
- package/examples/js-frontier-rust-workbench-html.mjs +20 -13
- 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 +12 -54
- package/examples/js-frontier-rust-workbench.mjs +54 -214
- package/package.json +1 -1
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import {
|
|
2
|
+
idFragment,
|
|
3
|
+
uniqueStrings
|
|
4
|
+
} from './native-import-utils.js';
|
|
5
|
+
|
|
6
|
+
export function runtimeRoute(sourceHost, targetHost, input) {
|
|
7
|
+
const requiredCapabilities = requirementsForRoute(input.requirements, sourceHost, targetHost);
|
|
8
|
+
const requirementRows = requiredCapabilities.map((capability) => runtimeCapabilityRequirement(capability, sourceHost, targetHost, input));
|
|
9
|
+
const adapterRequirements = requirementRows.filter((row) => row.adapterRequired).map((row) => row.adapterRequirement);
|
|
10
|
+
const satisfiedCapabilities = requirementRows.filter((row) => !row.adapterRequired).map((row) => row.capability);
|
|
11
|
+
const missingCapabilities = requirementRows.filter((row) => row.targetSupport === 'unavailable').map((row) => row.capability);
|
|
12
|
+
const blockers = requirementRows.filter((row) => row.sourceSupport === 'unavailable')
|
|
13
|
+
.map((row) => `Source host ${sourceHost.id} does not declare required runtime capability ${row.capability}.`);
|
|
14
|
+
const review = adapterRequirements.map((requirement) => requirement.reason);
|
|
15
|
+
const id = `runtime_${idFragment(sourceHost.id)}_to_${idFragment(targetHost.id)}_${idFragment(targetHost.target)}`;
|
|
16
|
+
return {
|
|
17
|
+
id,
|
|
18
|
+
source: runtimeHostSummary(sourceHost),
|
|
19
|
+
target: runtimeHostSummary(targetHost),
|
|
20
|
+
requiredCapabilities,
|
|
21
|
+
satisfiedCapabilities,
|
|
22
|
+
adapterRequirements,
|
|
23
|
+
missingCapabilities,
|
|
24
|
+
readiness: blockers.length ? 'blocked' : adapterRequirements.length ? 'needs-review' : 'ready',
|
|
25
|
+
blockers,
|
|
26
|
+
review: uniqueStrings(review),
|
|
27
|
+
metadata: {
|
|
28
|
+
generatedAt: input.generatedAt,
|
|
29
|
+
note: 'Runtime adapter requirements describe host API obligations only; parser, syntax, and target-projection evidence remain separate.'
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function requirementsForRoute(requirements, sourceHost, targetHost) {
|
|
35
|
+
return uniqueStrings((requirements ?? []).filter((requirement) => requirementApplies(requirement, sourceHost, targetHost))
|
|
36
|
+
.map((requirement) => requirement.capability));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function requirementApplies(requirement, sourceHost, targetHost) {
|
|
40
|
+
if (requirement.sourceHostId && requirement.sourceHostId !== sourceHost.id) return false;
|
|
41
|
+
if (requirement.targetHostId && requirement.targetHostId !== targetHost.id) return false;
|
|
42
|
+
if (requirement.sourceLanguage && !sourceHost.languageIds.includes(requirement.sourceLanguage)) return false;
|
|
43
|
+
if (requirement.sourceRuntime && requirement.sourceRuntime !== sourceHost.runtime && requirement.sourceRuntime !== sourceHost.id) return false;
|
|
44
|
+
if (requirement.target && requirement.target !== targetHost.target) return false;
|
|
45
|
+
if (requirement.targetRuntime && requirement.targetRuntime !== targetHost.runtime && requirement.targetRuntime !== targetHost.id) return false;
|
|
46
|
+
return Boolean(requirement.capability);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function runtimeCapabilityRequirement(capability, sourceHost, targetHost, input) {
|
|
50
|
+
const sourceCapability = sourceHost.capabilities[capability] ?? unavailableCapability(capability, sourceHost.id);
|
|
51
|
+
const targetCapability = targetHost.capabilities[capability] ?? unavailableCapability(capability, targetHost.id);
|
|
52
|
+
const compatible = runtimeCapabilityCompatible(sourceHost, targetHost, sourceCapability, targetCapability);
|
|
53
|
+
const reason = runtimeAdapterReason(capability, sourceHost, targetHost, sourceCapability, targetCapability);
|
|
54
|
+
return {
|
|
55
|
+
capability,
|
|
56
|
+
sourceSupport: sourceCapability.support,
|
|
57
|
+
targetSupport: targetCapability.support,
|
|
58
|
+
sourceBinding: sourceCapability.binding,
|
|
59
|
+
targetBinding: targetCapability.binding,
|
|
60
|
+
adapterRequired: !compatible,
|
|
61
|
+
adapterRequirement: compatible ? undefined : {
|
|
62
|
+
id: `runtime_adapter_${idFragment(sourceHost.id)}_${idFragment(targetHost.id)}_${idFragment(capability)}`,
|
|
63
|
+
capability,
|
|
64
|
+
adapterKind: runtimeAdapterKind(capability, sourceHost, targetHost),
|
|
65
|
+
sourceHost: sourceHost.id,
|
|
66
|
+
targetHost: targetHost.id,
|
|
67
|
+
sourceBinding: sourceCapability.binding,
|
|
68
|
+
targetBinding: targetCapability.binding,
|
|
69
|
+
required: true,
|
|
70
|
+
reason,
|
|
71
|
+
evidenceIds: uniqueStrings(input.requirements
|
|
72
|
+
.filter((requirement) => requirement.capability === capability && requirementApplies(requirement, sourceHost, targetHost))
|
|
73
|
+
.flatMap((requirement) => requirement.evidenceIds ?? []))
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function runtimeCapabilityCompatible(sourceHost, targetHost, sourceCapability, targetCapability) {
|
|
79
|
+
if (sourceHost.id === targetHost.id) return true;
|
|
80
|
+
if (sourceCapability.support === 'unavailable' || targetCapability.support === 'unavailable') return false;
|
|
81
|
+
return sourceCapability.binding === targetCapability.binding;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function unavailableCapability(kind, hostId) {
|
|
85
|
+
return {
|
|
86
|
+
kind,
|
|
87
|
+
support: 'unavailable',
|
|
88
|
+
binding: `${hostId}.${kind}.unavailable`,
|
|
89
|
+
notes: []
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function runtimeHostSummary(host) {
|
|
94
|
+
return {
|
|
95
|
+
id: host.id,
|
|
96
|
+
language: host.language,
|
|
97
|
+
aliases: host.aliases,
|
|
98
|
+
languageIds: host.languageIds,
|
|
99
|
+
runtime: host.runtime,
|
|
100
|
+
host: host.host,
|
|
101
|
+
target: host.target,
|
|
102
|
+
capabilities: host.capabilities
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function runtimeAdapterKind(capability, sourceHost, targetHost) {
|
|
107
|
+
if (capability === 'fetch' && sourceHost.runtime === 'web' && targetHost.runtime === 'cli') return 'browser-fetch-to-cli-http-client';
|
|
108
|
+
if (capability === 'fetch' && sourceHost.runtime === 'cli' && targetHost.runtime === 'web') return 'cli-http-client-to-browser-fetch';
|
|
109
|
+
if (capability === 'timers') return `${sourceHost.runtime}-timers-to-${targetHost.runtime}-timers`;
|
|
110
|
+
if (capability === 'storage' && targetHost.runtime === 'cli') return 'browser-storage-to-cli-persistence';
|
|
111
|
+
if (capability === 'storage' && targetHost.runtime === 'web') return 'cli-storage-to-browser-storage';
|
|
112
|
+
if (capability === 'filesystem' && targetHost.runtime === 'web') return 'filesystem-to-browser-storage';
|
|
113
|
+
if (capability === 'filesystem') return `${sourceHost.runtime}-filesystem-to-${targetHost.runtime}-filesystem`;
|
|
114
|
+
if (capability === 'threading' && targetHost.runtime === 'web') return 'native-threading-to-web-workers';
|
|
115
|
+
if (capability === 'threading') return `${sourceHost.runtime}-threading-to-${targetHost.runtime}-threading`;
|
|
116
|
+
if (capability === 'dom' && targetHost.runtime === 'cli') return 'dom-to-headless-host';
|
|
117
|
+
if (capability === 'dom') return `${sourceHost.runtime}-dom-to-${targetHost.runtime}-dom`;
|
|
118
|
+
if (capability === 'async') return `${sourceHost.runtime}-async-to-${targetHost.runtime}-async`;
|
|
119
|
+
if (capability === 'ffi' && targetHost.runtime === 'web') return 'native-ffi-to-web-boundary';
|
|
120
|
+
if (capability === 'ffi') return `${sourceHost.runtime}-ffi-to-${targetHost.runtime}-ffi`;
|
|
121
|
+
return `${sourceHost.runtime}-${capability}-to-${targetHost.runtime}-${capability}`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function runtimeAdapterReason(capability, sourceHost, targetHost, sourceCapability, targetCapability) {
|
|
125
|
+
if (targetCapability.support === 'unavailable') {
|
|
126
|
+
return `${sourceHost.id} requires ${capability}, but ${targetHost.id} does not provide a compatible host capability.`;
|
|
127
|
+
}
|
|
128
|
+
if (sourceCapability.support === 'unavailable') {
|
|
129
|
+
return `${sourceHost.id} declared ${capability}, but the source host profile marks it unavailable.`;
|
|
130
|
+
}
|
|
131
|
+
return `${sourceHost.id} uses ${sourceCapability.binding} for ${capability}; ${targetHost.id} exposes ${targetCapability.binding}, so a host adapter must preserve the runtime effect boundary.`;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function runtimeCapabilityMatrixSummary(routes) {
|
|
135
|
+
const byReadiness = {};
|
|
136
|
+
const byCapability = {};
|
|
137
|
+
const byAdapterKind = {};
|
|
138
|
+
let adapterRequirements = 0;
|
|
139
|
+
let routesWithAdapters = 0;
|
|
140
|
+
let missingCapabilities = 0;
|
|
141
|
+
for (const route of routes) {
|
|
142
|
+
byReadiness[route.readiness] = (byReadiness[route.readiness] ?? 0) + 1;
|
|
143
|
+
if (route.adapterRequirements.length) routesWithAdapters += 1;
|
|
144
|
+
adapterRequirements += route.adapterRequirements.length;
|
|
145
|
+
missingCapabilities += route.missingCapabilities.length;
|
|
146
|
+
for (const capability of route.requiredCapabilities) {
|
|
147
|
+
byCapability[capability] = (byCapability[capability] ?? 0) + 1;
|
|
148
|
+
}
|
|
149
|
+
for (const requirement of route.adapterRequirements) {
|
|
150
|
+
byAdapterKind[requirement.adapterKind] = (byAdapterKind[requirement.adapterKind] ?? 0) + 1;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
routes: routes.length,
|
|
155
|
+
routesWithAdapters,
|
|
156
|
+
adapterRequirements,
|
|
157
|
+
missingCapabilities,
|
|
158
|
+
byReadiness,
|
|
159
|
+
byCapability,
|
|
160
|
+
byAdapterKind
|
|
161
|
+
};
|
|
162
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export function createTsToRustWorkbenchAdapter() {
|
|
2
|
+
return {
|
|
3
|
+
id: 'frontier-lang-workbench-ts-to-rust',
|
|
4
|
+
sourceLanguage: 'typescript',
|
|
5
|
+
target: 'rust',
|
|
6
|
+
version: '0.0.0-demo',
|
|
7
|
+
capabilities: ['semantic-symbol-scaffold'],
|
|
8
|
+
coverage: {
|
|
9
|
+
readiness: 'ready',
|
|
10
|
+
handledLossKinds: ['opaqueNative', 'declarationOnlyCoverage', 'partialSemanticIndex', 'sourceMapApproximation', 'sourcePreservation'],
|
|
11
|
+
notes: ['Workbench adapter lowers TypeScript semantic symbols to Rust scaffolding and leaves bodies explicit.']
|
|
12
|
+
},
|
|
13
|
+
project(input) {
|
|
14
|
+
return {
|
|
15
|
+
output: rustFromSymbols(input.importResult.semanticIndex?.symbols ?? []),
|
|
16
|
+
readiness: 'ready',
|
|
17
|
+
evidence: [{
|
|
18
|
+
id: 'evidence_workbench_js_to_rust',
|
|
19
|
+
kind: 'projection',
|
|
20
|
+
status: 'passed',
|
|
21
|
+
summary: 'Workbench adapter projected TypeScript semantic symbols to Rust scaffolding.'
|
|
22
|
+
}]
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function createTsToPythonWorkbenchAdapter() {
|
|
29
|
+
return {
|
|
30
|
+
id: 'frontier-lang-workbench-ts-to-python',
|
|
31
|
+
sourceLanguage: 'typescript',
|
|
32
|
+
target: 'python',
|
|
33
|
+
version: '0.0.0-demo',
|
|
34
|
+
capabilities: ['semantic-symbol-scaffold'],
|
|
35
|
+
coverage: {
|
|
36
|
+
readiness: 'ready',
|
|
37
|
+
handledLossKinds: ['opaqueNative', 'declarationOnlyCoverage', 'partialSemanticIndex', 'sourceMapApproximation', 'sourcePreservation'],
|
|
38
|
+
notes: ['Workbench adapter lowers TypeScript semantic symbols to Python scaffolding and leaves bodies explicit.']
|
|
39
|
+
},
|
|
40
|
+
project(input) {
|
|
41
|
+
return {
|
|
42
|
+
output: pythonFromSymbols(input.importResult.semanticIndex?.symbols ?? []),
|
|
43
|
+
readiness: 'ready',
|
|
44
|
+
evidence: [{
|
|
45
|
+
id: 'evidence_workbench_js_to_python',
|
|
46
|
+
kind: 'projection',
|
|
47
|
+
status: 'passed',
|
|
48
|
+
summary: 'Workbench adapter projected TypeScript semantic symbols to Python scaffolding.'
|
|
49
|
+
}]
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function rustFromSymbols(symbols) {
|
|
56
|
+
const lines = ['// Generated from Frontier semantic graph evidence.'];
|
|
57
|
+
for (const symbol of symbols) {
|
|
58
|
+
if (symbol.kind === 'class') lines.push('', `pub struct ${safeTypeName(symbol.name)};`);
|
|
59
|
+
if (symbol.kind === 'function' || symbol.kind === 'method') {
|
|
60
|
+
lines.push('', `pub fn ${safeRustName(symbol.name)}() {`, ' // port body from preserved TypeScript source', '}');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return `${lines.join('\n').trim()}\n`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function pythonFromSymbols(symbols) {
|
|
67
|
+
const lines = ['# Generated from Frontier semantic graph evidence.'];
|
|
68
|
+
for (const symbol of symbols) {
|
|
69
|
+
if (symbol.kind === 'type' || symbol.kind === 'class') lines.push('', `class ${safeTypeName(symbol.name)}:`, ' pass');
|
|
70
|
+
if (symbol.kind === 'function' || symbol.kind === 'method') {
|
|
71
|
+
lines.push('', `def ${safePythonName(symbol.name)}(*args):`, ' raise NotImplementedError("port body from preserved TypeScript source")');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return `${lines.join('\n').trim()}\n`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function safeTypeName(name) {
|
|
78
|
+
const clean = String(name).replace(/[^A-Za-z0-9_]/g, '');
|
|
79
|
+
return clean && /^[A-Z]/.test(clean) ? clean : `Frontier${clean || 'Type'}`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function safeRustName(name) {
|
|
83
|
+
return String(name).replace(/\./g, '_').replace(/([a-z0-9])([A-Z])/g, '$1_$2').replace(/[^A-Za-z0-9_]/g, '_').toLowerCase();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function safePythonName(name) {
|
|
87
|
+
const clean = String(name).replace(/\./g, '_').replace(/([a-z0-9])([A-Z])/g, '$1_$2').replace(/[^A-Za-z0-9_]/g, '_').toLowerCase();
|
|
88
|
+
return /^[A-Za-z_]/.test(clean) ? clean : `frontier_${clean}`;
|
|
89
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export function conversionBounds(sourceLanguage, targetLanguage) {
|
|
2
|
+
const targetDisplay = String(targetLanguage).replace('/', ' and ');
|
|
2
3
|
return {
|
|
3
4
|
sourceLanguage,
|
|
4
5
|
targetLanguage,
|
|
@@ -10,13 +11,13 @@ export function conversionBounds(sourceLanguage, targetLanguage) {
|
|
|
10
11
|
],
|
|
11
12
|
reviewRequired: [
|
|
12
13
|
'Function bodies are preserved as source evidence and emitted as TODO scaffolds.',
|
|
13
|
-
|
|
14
|
+
`Types are declaration evidence, not a full ${targetDisplay} runtime or ownership proof.`,
|
|
14
15
|
'Runtime APIs such as fetch, timers, storage, DOM, Node, and npm crates need adapters.',
|
|
15
16
|
'Round trips are useful for review, but not automatic semantic equivalence proofs.'
|
|
16
17
|
],
|
|
17
18
|
unsupportedToday: [
|
|
18
|
-
'Behavior-preserving transpilation of arbitrary TypeScript or
|
|
19
|
-
'Full generic constraints, overload resolution, conditional types, macros, and
|
|
19
|
+
'Behavior-preserving transpilation of arbitrary TypeScript into Rust or Python.',
|
|
20
|
+
'Full generic constraints, overload resolution, conditional types, macros, and ownership inference.',
|
|
20
21
|
'Async control-flow lowering, exception/error model conversion, and memory ownership synthesis.',
|
|
21
22
|
'Perfect comments/trivia formatting in projected target code without richer parser evidence.'
|
|
22
23
|
]
|