@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.
Files changed (30) hide show
  1. package/README.md +31 -6
  2. package/dist/declarations/import-adapter-core.d.ts +3 -0
  3. package/dist/declarations/native-project-admission.d.ts +18 -0
  4. package/dist/declarations/semantic-merge-candidates.d.ts +200 -0
  5. package/dist/declarations/semantic-merge-conflicts.d.ts +12 -0
  6. package/dist/declarations/semantic-sidecar.d.ts +8 -3
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.js +1 -0
  9. package/dist/internal/index-impl/attachExternalOwnership.js +18 -10
  10. package/dist/internal/index-impl/createSemanticImportSidecar.js +6 -0
  11. package/dist/internal/index-impl/createSemanticSlice.js +3 -2
  12. package/dist/internal/index-impl/diffNativeSourceImports.js +3 -2
  13. package/dist/internal/index-impl/externalSemanticBase.js +1 -0
  14. package/dist/internal/index-impl/importExternalSemanticIndex.js +4 -0
  15. package/dist/internal/index-impl/projectImportAdmissionSummaries.js +31 -6
  16. package/dist/internal/index-impl/semanticMergeCandidateRecordInternals.js +314 -0
  17. package/dist/internal/index-impl/semanticMergeCandidateRecords.js +241 -0
  18. package/dist/internal/index-impl/withExternalEmptyLoss.js +1 -0
  19. package/dist/lightweight-dependency-language.js +8 -0
  20. package/dist/native-region-scanner-core.js +42 -10
  21. package/dist/native-region-scanner-js-helpers.js +2 -0
  22. package/dist/native-region-scanner-js-imports.js +111 -0
  23. package/dist/native-region-scanner-js.js +111 -28
  24. package/examples/js-frontier-rust-workbench-adapters.mjs +89 -0
  25. package/examples/js-frontier-rust-workbench-bounds.mjs +4 -3
  26. package/examples/js-frontier-rust-workbench-client.mjs +78 -59
  27. package/examples/js-frontier-rust-workbench-html.mjs +20 -13
  28. package/examples/js-frontier-rust-workbench-styles.mjs +9 -16
  29. package/examples/js-frontier-rust-workbench.mjs +67 -121
  30. 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 sourceLines(input.sourceText)) {
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
- declarations.push(routeRecord);
46
+ pushDeclaration(routeRecord);
39
47
  } else {
40
48
  const property = jsObjectPropertyDeclaration(input, number, trimmed, currentObject);
41
- if (property) declarations.push(property);
49
+ if (property) pushDeclaration(property);
42
50
  }
43
51
  }
44
- if ((match = trimmed.match(/^import\s+(?:.+?\s+from\s+)?['"]([^'"]+)['"]/))) {
45
- declarations.push(nativeImportDeclaration(input, number, match[1], 'ImportDeclaration', 'module'));
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
- declarations.push(nativeImportDeclaration(input, number, match[1], 'DynamicImportExpression', 'module'));
48
- } else if ((match = trimmed.match(/^export\s+(?:\*\s+from|\{[^}]*\}\s+from)\s+['"]([^'"]+)['"]/))) {
49
- declarations.push(nativeImportDeclaration(input, number, match[1], 'ExportFromDeclaration', 'module'));
50
- } else if ((match = declarationLine.match(/^(?:async\s+)?function\*?\s+([A-Za-z_$][\w$]*)\s*\(([^)]*)\)/))) {
51
- declarations.push(nativeDeclaration(input, number, 'FunctionDeclaration', 'function', match[1], { parameters: splitParameters(match[2]) }, declarationLine.includes('{')));
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
- declarations.push(nativeDeclaration(input, number, declarationLine.startsWith('default ') ? 'ExportDefaultClassDeclaration' : 'ClassDeclaration', 'class', match[1], { exportDefault: declarationLine.startsWith('default ') || undefined }, declarationLine.includes('{')));
56
- if (declarationLine.includes('{') && !declarationLine.includes('}')) {
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
- declarations.push(nativeDeclaration(input, number, 'InterfaceDeclaration', 'interface', match[1], {}, declarationLine.includes('{')));
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
- declarations.push(nativeDeclaration(input, number, 'EnumDeclaration', 'type', match[1], {}, declarationLine.includes('{')));
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
- declarations.push(nativeDeclaration(input, number, 'ModuleDeclaration', 'module', match[1], {}, declarationLine.includes('{')));
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
- declarations.push(nativeDeclaration(input, number, 'TypeAliasDeclaration', 'type', match[1], {}, false));
68
- } else if ((match = declarationLine.match(/^(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:async\s*)?\(?([^=;]*)\)?\s*=>/))) {
69
- declarations.push(nativeDeclaration(input, number, 'VariableFunctionDeclaration', 'function', match[1], { parameters: splitParameters(match[2]) }, true));
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
- declarations.push(nativeDeclaration(input, number, 'VariableDeclaration', jsVariableSymbolKind(regionKind, initializerKind), match[1], {
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
- declarations.push(match.declaration);
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
- declarations.push(nativeDeclaration(input, number, 'CommonJsFunctionExport', 'function', match[1], { parameters: splitParameters(match[2]) }, true));
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
- declarations.push(nativeDeclaration(input, number, 'CommonJsExport', 'variable', match[1], { export: 'commonjs' }, false, { regionKind }));
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$]*)\s*\(([^)]*)\)\s*(?::\s*[^={]+)?(?:\{|=>|$)/)) && !jsControlKeyword(match[1])) {
89
- declarations.push(nativeDeclaration(input, number, 'MethodDefinition', 'method', `${currentClass}.${match[1]}`, {
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$]*)\s*(?::\s*([^=;{]+))?(?:[=;]|$)/))) {
95
- declarations.push(nativeDeclaration(input, number, 'PropertyDefinition', 'property', `${currentClass}.${match[1]}`, {
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
- 'Types are declaration evidence, not a full Rust trait/lifetime/ownership proof.',
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 Rust.',
19
- 'Full generic constraints, overload resolution, conditional types, macros, and borrow checking.',
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
  ]