@shapeshift-labs/frontier-lang-compiler 0.2.65 → 0.2.66
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 +31 -6
- package/dist/declarations/import-adapter-core.d.ts +3 -0
- package/dist/declarations/native-project-admission.d.ts +18 -0
- 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/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/internal/index-impl/attachExternalOwnership.js +18 -10
- package/dist/internal/index-impl/createSemanticImportSidecar.js +6 -0
- package/dist/internal/index-impl/createSemanticSlice.js +3 -2
- package/dist/internal/index-impl/diffNativeSourceImports.js +3 -2
- package/dist/internal/index-impl/externalSemanticBase.js +1 -0
- package/dist/internal/index-impl/importExternalSemanticIndex.js +4 -0
- package/dist/internal/index-impl/projectImportAdmissionSummaries.js +31 -6
- package/dist/internal/index-impl/semanticMergeCandidateRecordInternals.js +314 -0
- package/dist/internal/index-impl/semanticMergeCandidateRecords.js +241 -0
- package/dist/internal/index-impl/withExternalEmptyLoss.js +1 -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/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 +78 -59
- package/examples/js-frontier-rust-workbench-html.mjs +20 -13
- package/examples/js-frontier-rust-workbench-styles.mjs +9 -16
- package/examples/js-frontier-rust-workbench.mjs +67 -121
- package/package.json +1 -1
|
@@ -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,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
|
]
|