@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
|
@@ -9,7 +9,7 @@ function nativeDeclaration(input, lineNumber, languageKind, symbolKind, name, fi
|
|
|
9
9
|
name,
|
|
10
10
|
symbolKind,
|
|
11
11
|
symbolId: `symbol:${input.language}:${idFragment(name)}`,
|
|
12
|
-
span: spanForLine(input, lineNumber),
|
|
12
|
+
span: options.span ?? spanForLine(input, lineNumber),
|
|
13
13
|
fields,
|
|
14
14
|
metadata: { scan: 'lightweight-declaration', hasBody, ...options.metadata },
|
|
15
15
|
...(options.regionKind ? { regionKind: options.regionKind } : {}),
|
|
@@ -18,8 +18,8 @@ function nativeDeclaration(input, lineNumber, languageKind, symbolKind, name, fi
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
function nativeImportDeclaration(input, lineNumber, importPath, languageKind, symbolKind) {
|
|
22
|
-
const name = String(importPath);
|
|
21
|
+
function nativeImportDeclaration(input, lineNumber, importPath, languageKind, symbolKind, options = {}) {
|
|
22
|
+
const name = String(options.name ?? importPath);
|
|
23
23
|
const nodeId = `native_${idFragment(languageKind)}_${lineNumber}_${idFragment(name)}`;
|
|
24
24
|
return {
|
|
25
25
|
nodeId,
|
|
@@ -27,15 +27,44 @@ function nativeImportDeclaration(input, lineNumber, importPath, languageKind, sy
|
|
|
27
27
|
languageKind: `${input.language}.${languageKind}`,
|
|
28
28
|
name,
|
|
29
29
|
symbolKind,
|
|
30
|
-
symbolId: `symbol:${input.language}:import:${idFragment(name)}`,
|
|
31
|
-
role: 'import',
|
|
32
|
-
importPath:
|
|
33
|
-
span: spanForLine(input, lineNumber),
|
|
34
|
-
fields: { importPath:
|
|
35
|
-
metadata: { scan: 'lightweight-import' }
|
|
30
|
+
symbolId: options.symbolId ?? `symbol:${input.language}:import:${idFragment(name)}`,
|
|
31
|
+
role: options.role ?? 'import',
|
|
32
|
+
importPath: String(importPath),
|
|
33
|
+
span: options.span ?? spanForLine(input, lineNumber),
|
|
34
|
+
fields: { importPath: String(importPath), ...options.fields },
|
|
35
|
+
metadata: { scan: 'lightweight-import', ...options.metadata },
|
|
36
|
+
...(options.regionKind ? { regionKind: options.regionKind } : {})
|
|
36
37
|
};
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
function nativeImportBindingDeclaration(input, lineNumber, importPath, binding, options = {}) {
|
|
41
|
+
const localName = String(binding.localName ?? binding.name ?? importPath);
|
|
42
|
+
const importedName = binding.importedName ?? localName;
|
|
43
|
+
const importKind = binding.importKind ?? 'named';
|
|
44
|
+
return nativeImportDeclaration(input, lineNumber, importPath, options.languageKind ?? 'ImportBinding', binding.symbolKind ?? 'import', {
|
|
45
|
+
name: localName,
|
|
46
|
+
symbolId: options.symbolId ?? `symbol:${input.language}:import:${idFragment(`${importPath}:${localName}`)}`,
|
|
47
|
+
span: options.span,
|
|
48
|
+
fields: {
|
|
49
|
+
localName,
|
|
50
|
+
importedName,
|
|
51
|
+
importKind,
|
|
52
|
+
importPath: String(importPath),
|
|
53
|
+
...(binding.exportedName ? { exportedName: binding.exportedName } : {}),
|
|
54
|
+
...(binding.typeOnly ? { typeOnly: true } : {})
|
|
55
|
+
},
|
|
56
|
+
metadata: {
|
|
57
|
+
scan: 'lightweight-import-binding',
|
|
58
|
+
localName,
|
|
59
|
+
importedName,
|
|
60
|
+
importKind,
|
|
61
|
+
...(binding.exportedName ? { exportedName: binding.exportedName } : {}),
|
|
62
|
+
...(binding.typeOnly ? { typeOnly: true } : {}),
|
|
63
|
+
...options.metadata
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
39
68
|
function nativeMacroLoss(input, lineNumber, source, kind, name = idFragment(source).slice(0, 40)) {
|
|
40
69
|
const nodeId = `native_${kind}_${lineNumber}_${idFragment(name)}`;
|
|
41
70
|
return {
|
|
@@ -133,12 +162,14 @@ function sourceLines(sourceText) {
|
|
|
133
162
|
}
|
|
134
163
|
|
|
135
164
|
function spanForLine(input, lineNumber) {
|
|
165
|
+
const line = sourceLines(input.sourceText)[lineNumber - 1]?.line ?? '';
|
|
136
166
|
return {
|
|
137
167
|
sourceId: input.sourceHash,
|
|
138
168
|
path: input.sourcePath,
|
|
139
169
|
startLine: lineNumber,
|
|
140
170
|
endLine: lineNumber,
|
|
141
|
-
startColumn: 1
|
|
171
|
+
startColumn: 1,
|
|
172
|
+
endColumn: line.length + 1
|
|
142
173
|
};
|
|
143
174
|
}
|
|
144
175
|
|
|
@@ -172,6 +203,7 @@ export {
|
|
|
172
203
|
lightweightCoverageLosses,
|
|
173
204
|
nativeDeclaration,
|
|
174
205
|
nativeImportDeclaration,
|
|
206
|
+
nativeImportBindingDeclaration,
|
|
175
207
|
nativeMacroLoss,
|
|
176
208
|
sourceLines,
|
|
177
209
|
splitParameters,
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
nativeDeclaration,
|
|
4
4
|
splitParameters
|
|
5
5
|
} from './native-region-scanner-core.js';
|
|
6
|
+
import { jsImportDeclarations } from './native-region-scanner-js-imports.js';
|
|
6
7
|
|
|
7
8
|
function jsCommentOnlyLine(trimmed) {
|
|
8
9
|
return trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*');
|
|
@@ -247,6 +248,7 @@ export {
|
|
|
247
248
|
jsDeclarationScanLine,
|
|
248
249
|
jsExportedContainerDeclaration,
|
|
249
250
|
jsInitializerKind,
|
|
251
|
+
jsImportDeclarations,
|
|
250
252
|
jsObjectPropertyDeclaration,
|
|
251
253
|
jsObjectRegionContext,
|
|
252
254
|
jsRegionKindForDeclarationName,
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import {
|
|
2
|
+
nativeImportBindingDeclaration,
|
|
3
|
+
nativeImportDeclaration
|
|
4
|
+
} from './native-region-scanner-core.js';
|
|
5
|
+
|
|
6
|
+
export function jsImportDeclarations(input, lineNumber, trimmed) {
|
|
7
|
+
const importEquals = trimmed.match(/^import\s+(type\s+)?([A-Za-z_$][\w$]*)\s*=\s*require\s*\(\s*(['"])([^'"]+)\3\s*\)/);
|
|
8
|
+
if (importEquals) return jsImportModuleDeclarations(input, lineNumber, importEquals[4], 'ImportEqualsDeclaration', [{
|
|
9
|
+
localName: importEquals[2],
|
|
10
|
+
importedName: 'default',
|
|
11
|
+
importKind: 'commonjs-require',
|
|
12
|
+
typeOnly: Boolean(importEquals[1])
|
|
13
|
+
}]);
|
|
14
|
+
const importMatch = trimmed.match(/^import\s+(type\s+)?(?:(.+?)\s+from\s+)?(['"])([^'"]+)\3/);
|
|
15
|
+
if (importMatch) {
|
|
16
|
+
const typeOnly = Boolean(importMatch[1]);
|
|
17
|
+
const importPath = importMatch[4];
|
|
18
|
+
const clause = importMatch[2]?.trim();
|
|
19
|
+
const bindings = clause ? jsImportBindingsFromClause(clause, { typeOnly }) : [];
|
|
20
|
+
return jsImportModuleDeclarations(input, lineNumber, importPath, 'ImportDeclaration', bindings, { typeOnly, sideEffectOnly: bindings.length === 0 });
|
|
21
|
+
}
|
|
22
|
+
const exportMatch = trimmed.match(/^export\s+(type\s+)?(?:(\*)\s+from|\*\s+as\s+([A-Za-z_$][\w$]*)\s+from|\{([^}]+)\}\s+from)\s+(['"])([^'"]+)\5/);
|
|
23
|
+
if (exportMatch) {
|
|
24
|
+
const typeOnly = Boolean(exportMatch[1]);
|
|
25
|
+
const importPath = exportMatch[6];
|
|
26
|
+
const bindings = exportMatch[3]
|
|
27
|
+
? [{ localName: exportMatch[3], importedName: '*', exportedName: exportMatch[3], importKind: 'namespace-reexport', typeOnly }]
|
|
28
|
+
: exportMatch[4]
|
|
29
|
+
? jsNamedImportBindings(exportMatch[4], { typeOnly, reexport: true })
|
|
30
|
+
: [];
|
|
31
|
+
return jsImportModuleDeclarations(input, lineNumber, importPath, 'ExportFromDeclaration', bindings, { typeOnly, reexport: true, exportStar: Boolean(exportMatch[2]) });
|
|
32
|
+
}
|
|
33
|
+
const requireMatch = trimmed.match(/^(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:await\s+)?(?:require|import)\s*\(\s*(['"])([^'"]+)\2\s*\)/);
|
|
34
|
+
if (requireMatch) return jsImportModuleDeclarations(input, lineNumber, requireMatch[3], 'CommonJsRequireDeclaration', [{
|
|
35
|
+
localName: requireMatch[1],
|
|
36
|
+
importedName: 'default',
|
|
37
|
+
importKind: trimmed.includes('import') ? 'dynamic-import-binding' : 'commonjs-require'
|
|
38
|
+
}]);
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function jsImportModuleDeclarations(input, lineNumber, importPath, languageKind, bindings = [], metadata = {}) {
|
|
43
|
+
const bindingSummaries = bindings.map((binding) => ({
|
|
44
|
+
localName: binding.localName,
|
|
45
|
+
importedName: binding.importedName,
|
|
46
|
+
importKind: binding.importKind,
|
|
47
|
+
...(binding.exportedName ? { exportedName: binding.exportedName } : {}),
|
|
48
|
+
...(binding.typeOnly ? { typeOnly: true } : {})
|
|
49
|
+
}));
|
|
50
|
+
return [
|
|
51
|
+
nativeImportDeclaration(input, lineNumber, importPath, languageKind, 'module', {
|
|
52
|
+
fields: {
|
|
53
|
+
moduleOnly: true,
|
|
54
|
+
importBindings: bindingSummaries,
|
|
55
|
+
...(metadata.typeOnly ? { typeOnly: true } : {}),
|
|
56
|
+
...(metadata.sideEffectOnly ? { sideEffectOnly: true } : {}),
|
|
57
|
+
...(metadata.reexport ? { reexport: true } : {}),
|
|
58
|
+
...(metadata.exportStar ? { exportStar: true } : {})
|
|
59
|
+
},
|
|
60
|
+
metadata: {
|
|
61
|
+
moduleOnly: true,
|
|
62
|
+
bindingCount: bindings.length,
|
|
63
|
+
...metadata
|
|
64
|
+
}
|
|
65
|
+
}),
|
|
66
|
+
...bindings.map((binding) => nativeImportBindingDeclaration(input, lineNumber, importPath, binding))
|
|
67
|
+
];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function jsImportBindingsFromClause(clause, options = {}) {
|
|
71
|
+
const source = String(clause ?? '').trim();
|
|
72
|
+
if (!source) return [];
|
|
73
|
+
const namespace = source.match(/^\*\s+as\s+([A-Za-z_$][\w$]*)$/);
|
|
74
|
+
if (namespace) return [{ localName: namespace[1], importedName: '*', importKind: 'namespace', typeOnly: options.typeOnly }];
|
|
75
|
+
const bindings = [];
|
|
76
|
+
const named = source.match(/\{([^}]*)\}/);
|
|
77
|
+
const defaultPart = source.replace(/\{[^}]*\}/, '').split(',').map((part) => part.trim()).filter(Boolean)[0];
|
|
78
|
+
if (defaultPart && /^[A-Za-z_$][\w$]*$/.test(defaultPart)) {
|
|
79
|
+
bindings.push({ localName: defaultPart, importedName: 'default', importKind: 'default', typeOnly: options.typeOnly });
|
|
80
|
+
}
|
|
81
|
+
if (named) bindings.push(...jsNamedImportBindings(named[1], options));
|
|
82
|
+
return bindings;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function jsNamedImportBindings(raw, options = {}) {
|
|
86
|
+
return String(raw ?? '')
|
|
87
|
+
.split(',')
|
|
88
|
+
.map((part) => jsNamedImportBinding(part, options))
|
|
89
|
+
.filter(Boolean);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function jsNamedImportBinding(raw, options = {}) {
|
|
93
|
+
let text = String(raw ?? '').trim();
|
|
94
|
+
if (!text) return undefined;
|
|
95
|
+
let typeOnly = Boolean(options.typeOnly);
|
|
96
|
+
if (text.startsWith('type ')) {
|
|
97
|
+
typeOnly = true;
|
|
98
|
+
text = text.slice(5).trim();
|
|
99
|
+
}
|
|
100
|
+
const match = text.match(/^([A-Za-z_$][\w$]*|\*)\s*(?:as\s+([A-Za-z_$][\w$]*))?$/);
|
|
101
|
+
if (!match) return undefined;
|
|
102
|
+
const importedName = match[1];
|
|
103
|
+
const localName = match[2] ?? importedName;
|
|
104
|
+
return {
|
|
105
|
+
localName,
|
|
106
|
+
importedName,
|
|
107
|
+
exportedName: options.reexport ? localName : undefined,
|
|
108
|
+
importKind: options.reexport ? 'reexport' : typeOnly ? 'type-named' : 'named',
|
|
109
|
+
typeOnly
|
|
110
|
+
};
|
|
111
|
+
}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
jsDeclarationScanLine,
|
|
13
13
|
jsExportedContainerDeclaration,
|
|
14
14
|
jsInitializerKind,
|
|
15
|
+
jsImportDeclarations,
|
|
15
16
|
jsObjectPropertyDeclaration,
|
|
16
17
|
jsObjectRegionContext,
|
|
17
18
|
jsRegionKindForDeclarationName,
|
|
@@ -22,11 +23,18 @@ import {
|
|
|
22
23
|
|
|
23
24
|
function scanJavaScriptLike(input) {
|
|
24
25
|
const declarations = [];
|
|
26
|
+
const lines = sourceLines(input.sourceText);
|
|
27
|
+
const pushDeclaration = (declaration) => {
|
|
28
|
+
if (declaration) declarations.push(jsDeclarationWithSourceSpan(input, declaration, lines));
|
|
29
|
+
};
|
|
30
|
+
const pushDeclarations = (items) => {
|
|
31
|
+
for (const declaration of items ?? []) pushDeclaration(declaration);
|
|
32
|
+
};
|
|
25
33
|
let currentClass;
|
|
26
34
|
let classDepth = 0;
|
|
27
35
|
let currentObject;
|
|
28
36
|
const lexicalState = { inBlockComment: false, inTemplateString: false };
|
|
29
|
-
for (const { line, number } of
|
|
37
|
+
for (const { line, number } of lines) {
|
|
30
38
|
const scanLine = jsDeclarationScanLine(line, lexicalState);
|
|
31
39
|
const trimmed = scanLine.trim();
|
|
32
40
|
if (!trimmed || jsCommentOnlyLine(trimmed)) continue;
|
|
@@ -35,42 +43,42 @@ function scanJavaScriptLike(input) {
|
|
|
35
43
|
if (currentObject) {
|
|
36
44
|
const routeRecord = jsRouteRecordDeclaration(input, number, trimmed, currentObject);
|
|
37
45
|
if (routeRecord) {
|
|
38
|
-
|
|
46
|
+
pushDeclaration(routeRecord);
|
|
39
47
|
} else {
|
|
40
48
|
const property = jsObjectPropertyDeclaration(input, number, trimmed, currentObject);
|
|
41
|
-
if (property)
|
|
49
|
+
if (property) pushDeclaration(property);
|
|
42
50
|
}
|
|
43
51
|
}
|
|
44
|
-
|
|
45
|
-
|
|
52
|
+
const importDeclarations = jsImportDeclarations(input, number, trimmed);
|
|
53
|
+
if (importDeclarations.length) {
|
|
54
|
+
pushDeclarations(importDeclarations);
|
|
46
55
|
} else if ((match = trimmed.match(/^import\s*\(\s*['"]([^'"]+)['"]\s*\)/))) {
|
|
47
|
-
|
|
48
|
-
} else if ((match =
|
|
49
|
-
|
|
50
|
-
} else if ((match =
|
|
51
|
-
|
|
52
|
-
} else if ((match = trimmed.match(/^export\s+default\s+(?:async\s+)?function\*?\s*([A-Za-z_$][\w$]*)?\s*\(([^)]*)\)/))) {
|
|
53
|
-
declarations.push(nativeDeclaration(input, number, 'ExportDefaultFunctionDeclaration', 'function', match[1] ?? 'default', { parameters: splitParameters(match[2]), exportDefault: true }, trimmed.includes('{')));
|
|
56
|
+
pushDeclaration(nativeImportDeclaration(input, number, match[1], 'DynamicImportExpression', 'module'));
|
|
57
|
+
} else if ((match = declarationLine.match(/^(?:async\s+)?function\*?\s+([A-Za-z_$][\w$]*)\s*(?:<[^({;]+>)?\s*\(([^)]*)\)\s*(?::\s*[^={]+)?/))) {
|
|
58
|
+
pushDeclaration(nativeDeclaration(input, number, 'FunctionDeclaration', 'function', match[1], { parameters: splitParameters(match[2]) }, declarationLine.includes('{')));
|
|
59
|
+
} else if ((match = trimmed.match(/^export\s+default\s+(?:async\s+)?function\*?\s*([A-Za-z_$][\w$]*)?\s*(?:<[^({;]+>)?\s*\(([^)]*)\)\s*(?::\s*[^={]+)?/))) {
|
|
60
|
+
pushDeclaration(nativeDeclaration(input, number, 'ExportDefaultFunctionDeclaration', 'function', match[1] ?? 'default', { parameters: splitParameters(match[2]), exportDefault: true }, trimmed.includes('{')));
|
|
54
61
|
} else if ((match = declarationLine.match(/^(?:default\s+)?(?:abstract\s+)?class\s+([A-Za-z_$][\w$]*)/))) {
|
|
55
|
-
|
|
56
|
-
|
|
62
|
+
pushDeclaration(nativeDeclaration(input, number, declarationLine.startsWith('default ') ? 'ExportDefaultClassDeclaration' : 'ClassDeclaration', 'class', match[1], { exportDefault: declarationLine.startsWith('default ') || undefined }, declarationLine.includes('{')));
|
|
63
|
+
pushDeclarations(jsInlineClassMemberDeclarations(input, number, declarationLine, match[1]));
|
|
64
|
+
if (jsStructureDelta(declarationLine).value > 0) {
|
|
57
65
|
currentClass = match[1];
|
|
58
66
|
classDepth = 0;
|
|
59
67
|
}
|
|
60
68
|
} else if ((match = declarationLine.match(/^interface\s+([A-Za-z_$][\w$]*)/))) {
|
|
61
|
-
|
|
69
|
+
pushDeclaration(nativeDeclaration(input, number, 'InterfaceDeclaration', 'interface', match[1], {}, declarationLine.includes('{')));
|
|
62
70
|
} else if ((match = declarationLine.match(/^(?:const\s+)?enum\s+([A-Za-z_$][\w$]*)/))) {
|
|
63
|
-
|
|
71
|
+
pushDeclaration(nativeDeclaration(input, number, 'EnumDeclaration', 'type', match[1], {}, declarationLine.includes('{')));
|
|
64
72
|
} else if ((match = declarationLine.match(/^(?:namespace|module)\s+([A-Za-z_$][\w$.]*)/))) {
|
|
65
|
-
|
|
73
|
+
pushDeclaration(nativeDeclaration(input, number, 'ModuleDeclaration', 'module', match[1], {}, declarationLine.includes('{')));
|
|
66
74
|
} else if ((match = declarationLine.match(/^type\s+([A-Za-z_$][\w$]*)\s*=/))) {
|
|
67
|
-
|
|
68
|
-
} else if ((match = declarationLine.match(/^(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s
|
|
69
|
-
|
|
75
|
+
pushDeclaration(nativeDeclaration(input, number, 'TypeAliasDeclaration', 'type', match[1], {}, false));
|
|
76
|
+
} else if ((match = declarationLine.match(/^(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*(?::\s*[^=]+)?=\s*(?:async\s*)?(?:<[^=]+>\s*)?(?:\(([^)]*)\)|([A-Za-z_$][\w$]*))\s*(?::\s*[^=]+)?=>/))) {
|
|
77
|
+
pushDeclaration(nativeDeclaration(input, number, 'VariableFunctionDeclaration', 'function', match[1], { parameters: splitParameters(match[2] ?? match[3]) }, true));
|
|
70
78
|
} else if ((match = declarationLine.match(/^(?:const|let|var)\s+([A-Za-z_$][\w$]*)\b/))) {
|
|
71
79
|
const initializerKind = jsInitializerKind(declarationLine, match[1]);
|
|
72
80
|
const regionKind = jsRegionKindForDeclarationName(match[1], declarationLine);
|
|
73
|
-
|
|
81
|
+
pushDeclaration(nativeDeclaration(input, number, 'VariableDeclaration', jsVariableSymbolKind(regionKind, initializerKind), match[1], {
|
|
74
82
|
initializerKind
|
|
75
83
|
}, jsVariableHasBody(initializerKind, declarationLine), {
|
|
76
84
|
regionKind,
|
|
@@ -78,21 +86,21 @@ function scanJavaScriptLike(input) {
|
|
|
78
86
|
}));
|
|
79
87
|
currentObject = jsObjectRegionContext(match[1], declarationLine, number, regionKind);
|
|
80
88
|
} else if ((match = jsExportedContainerDeclaration(input, number, trimmed))) {
|
|
81
|
-
|
|
89
|
+
pushDeclaration(match.declaration);
|
|
82
90
|
currentObject = match.context;
|
|
83
91
|
} else if ((match = trimmed.match(/^(?:module\.)?exports\.([A-Za-z_$][\w$]*)\s*=\s*(?:async\s+)?function\*?\s*\(([^)]*)\)/))) {
|
|
84
|
-
|
|
92
|
+
pushDeclaration(nativeDeclaration(input, number, 'CommonJsFunctionExport', 'function', match[1], { parameters: splitParameters(match[2]) }, true));
|
|
85
93
|
} else if ((match = trimmed.match(/^(?:module\.)?exports\.([A-Za-z_$][\w$]*)\s*=/))) {
|
|
86
94
|
const regionKind = jsRegionKindForDeclarationName(match[1], trimmed);
|
|
87
|
-
|
|
88
|
-
} else if (currentClass && (match = declarationLine.match(/^(?:(?:public|private|protected|static|async|override|readonly|abstract|accessor|get|set)\s+)*(?:async\s+)?(?:get\s+|set\s+)?([A-Za-z_$][\w$]*)
|
|
89
|
-
|
|
95
|
+
pushDeclaration(nativeDeclaration(input, number, 'CommonJsExport', 'variable', match[1], { export: 'commonjs' }, false, { regionKind }));
|
|
96
|
+
} else if (currentClass && (match = declarationLine.match(/^(?:(?:public|private|protected|static|async|override|readonly|abstract|accessor|get|set)\s+)*(?:async\s+)?(?:get\s+|set\s+)?([A-Za-z_$][\w$]*)\??\s*(?:<[^({;]+>)?\s*\(([^)]*)\)\s*(?::\s*[^={]+)?(?:\{|=>|$)/)) && !jsControlKeyword(match[1])) {
|
|
97
|
+
pushDeclaration(nativeDeclaration(input, number, 'MethodDefinition', 'method', `${currentClass}.${match[1]}`, {
|
|
90
98
|
methodName: match[1],
|
|
91
99
|
owner: currentClass,
|
|
92
100
|
parameters: splitParameters(match[2])
|
|
93
101
|
}, declarationLine.includes('{') || declarationLine.includes('=>')));
|
|
94
|
-
} else if (currentClass && (match = declarationLine.match(/^(?:(?:public|private|protected|static|readonly|declare|accessor)\s+)*([A-Za-z_$][\w$]*)
|
|
95
|
-
|
|
102
|
+
} else if (currentClass && (match = declarationLine.match(/^(?:(?:public|private|protected|static|readonly|declare|accessor)\s+)*([A-Za-z_$][\w$]*)[?!]?\s*(?::\s*([^=;{]+))?(?:[=;]|$)/))) {
|
|
103
|
+
pushDeclaration(nativeDeclaration(input, number, 'PropertyDefinition', 'property', `${currentClass}.${match[1]}`, {
|
|
96
104
|
propertyName: match[1],
|
|
97
105
|
owner: currentClass,
|
|
98
106
|
valueType: match[2]?.trim()
|
|
@@ -113,4 +121,79 @@ function scanJavaScriptLike(input) {
|
|
|
113
121
|
return declarations;
|
|
114
122
|
}
|
|
115
123
|
|
|
124
|
+
function jsDeclarationWithSourceSpan(input, declaration, lines) {
|
|
125
|
+
const startLine = declaration.span?.startLine ?? 1;
|
|
126
|
+
const endLine = declaration.metadata?.hasBody ? jsBalancedDeclarationEndLine(input, lines, startLine) : startLine;
|
|
127
|
+
const endLineText = lines[Math.max(0, endLine - 1)]?.line ?? '';
|
|
128
|
+
return {
|
|
129
|
+
...declaration,
|
|
130
|
+
span: {
|
|
131
|
+
...declaration.span,
|
|
132
|
+
sourceId: declaration.span?.sourceId ?? input.sourceHash,
|
|
133
|
+
path: declaration.span?.path ?? input.sourcePath,
|
|
134
|
+
startLine,
|
|
135
|
+
endLine,
|
|
136
|
+
startColumn: declaration.span?.startColumn ?? 1,
|
|
137
|
+
endColumn: declaration.span?.endColumn ?? endLineText.length + 1
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function jsBalancedDeclarationEndLine(input, lines, startLine) {
|
|
143
|
+
const state = { inBlockComment: false, inTemplateString: false };
|
|
144
|
+
let depth = 0;
|
|
145
|
+
let opened = false;
|
|
146
|
+
for (let index = Math.max(0, startLine - 1); index < lines.length; index += 1) {
|
|
147
|
+
const scanLine = jsDeclarationScanLine(lines[index].line, state);
|
|
148
|
+
const delta = jsStructureDelta(scanLine);
|
|
149
|
+
if (delta.opened) opened = true;
|
|
150
|
+
depth += delta.value;
|
|
151
|
+
if (opened && depth <= 0) return lines[index].number;
|
|
152
|
+
}
|
|
153
|
+
return startLine;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function jsStructureDelta(source) {
|
|
157
|
+
let value = 0;
|
|
158
|
+
let opened = false;
|
|
159
|
+
let quote;
|
|
160
|
+
let escaped = false;
|
|
161
|
+
for (const char of String(source ?? '')) {
|
|
162
|
+
if (quote) {
|
|
163
|
+
if (escaped) escaped = false;
|
|
164
|
+
else if (char === '\\') escaped = true;
|
|
165
|
+
else if (char === quote) quote = undefined;
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (char === '\'' || char === '"' || char === '`') {
|
|
169
|
+
quote = char;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (char === '{' || char === '[' || char === '(') {
|
|
173
|
+
value += 1;
|
|
174
|
+
opened = true;
|
|
175
|
+
} else if (char === '}' || char === ']' || char === ')') {
|
|
176
|
+
value -= 1;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return { value, opened };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function jsInlineClassMemberDeclarations(input, lineNumber, declarationLine, className) {
|
|
183
|
+
const open = declarationLine.indexOf('{');
|
|
184
|
+
const close = declarationLine.lastIndexOf('}');
|
|
185
|
+
if (open < 0 || close <= open) return [];
|
|
186
|
+
const body = declarationLine.slice(open + 1, close);
|
|
187
|
+
const declarations = [];
|
|
188
|
+
for (const match of body.matchAll(/(?:(?:public|private|protected|static|async|override|readonly|abstract|accessor|get|set)\s+)*(?:async\s+)?(?:get\s+|set\s+)?([A-Za-z_$][\w$]*)\??\s*(?:<[^({;]+>)?\s*\(([^)]*)\)\s*(?::\s*[^={;]+)?\s*(?:\{|=>)/g)) {
|
|
189
|
+
if (jsControlKeyword(match[1])) continue;
|
|
190
|
+
declarations.push(nativeDeclaration(input, lineNumber, 'MethodDefinition', 'method', `${className}.${match[1]}`, {
|
|
191
|
+
methodName: match[1],
|
|
192
|
+
owner: className,
|
|
193
|
+
parameters: splitParameters(match[2])
|
|
194
|
+
}, true));
|
|
195
|
+
}
|
|
196
|
+
return declarations;
|
|
197
|
+
}
|
|
198
|
+
|
|
116
199
|
export { scanJavaScriptLike };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export function conversionPlanSummary(routes) {
|
|
2
|
+
const summary = {
|
|
3
|
+
routes: routes.length,
|
|
4
|
+
byMode: {},
|
|
5
|
+
byReadiness: {},
|
|
6
|
+
byAdmissionAction: {},
|
|
7
|
+
readyRoutes: 0,
|
|
8
|
+
reviewRoutes: 0,
|
|
9
|
+
blockedRoutes: 0,
|
|
10
|
+
preserveSourceRoutes: 0,
|
|
11
|
+
targetAdapterRoutes: 0,
|
|
12
|
+
stubOnlyRoutes: 0,
|
|
13
|
+
semanticIndexOnlyRoutes: 0,
|
|
14
|
+
missingEvidence: 0,
|
|
15
|
+
runtimeAdapterRequirements: 0,
|
|
16
|
+
runtimeRoutesWithAdapters: 0,
|
|
17
|
+
blockers: 0,
|
|
18
|
+
reviewReasons: 0,
|
|
19
|
+
autoMergeClaims: 0,
|
|
20
|
+
semanticEquivalenceClaims: 0
|
|
21
|
+
};
|
|
22
|
+
for (const route of routes) {
|
|
23
|
+
summary.byMode[route.mode] = (summary.byMode[route.mode] ?? 0) + 1;
|
|
24
|
+
summary.byReadiness[route.readiness] = (summary.byReadiness[route.readiness] ?? 0) + 1;
|
|
25
|
+
summary.byAdmissionAction[route.admissionAction] = (summary.byAdmissionAction[route.admissionAction] ?? 0) + 1;
|
|
26
|
+
if (route.readiness === 'ready') summary.readyRoutes += 1;
|
|
27
|
+
if (route.readiness === 'needs-review' || route.readiness === 'ready-with-losses') summary.reviewRoutes += 1;
|
|
28
|
+
if (route.readiness === 'blocked') summary.blockedRoutes += 1;
|
|
29
|
+
if (route.mode === 'preserve-source') summary.preserveSourceRoutes += 1;
|
|
30
|
+
if (route.mode === 'target-adapter') summary.targetAdapterRoutes += 1;
|
|
31
|
+
if (route.mode === 'stub-only') summary.stubOnlyRoutes += 1;
|
|
32
|
+
if (route.mode === 'semantic-index-only') summary.semanticIndexOnlyRoutes += 1;
|
|
33
|
+
summary.missingEvidence += route.missingEvidence.length;
|
|
34
|
+
summary.runtimeAdapterRequirements += route.runtimeAdapterRequirements.length;
|
|
35
|
+
if (route.runtimeAdapterRequirements.length) summary.runtimeRoutesWithAdapters += 1;
|
|
36
|
+
summary.blockers += route.blockers.length;
|
|
37
|
+
summary.reviewReasons += route.review.length;
|
|
38
|
+
if (route.autoMergeClaim) summary.autoMergeClaims += 1;
|
|
39
|
+
if (route.semanticEquivalenceClaim) summary.semanticEquivalenceClaims += 1;
|
|
40
|
+
}
|
|
41
|
+
return summary;
|
|
42
|
+
}
|
|
@@ -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
|
-
}
|