@shapeshift-labs/frontier-lang-compiler 0.2.54 → 0.2.55
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 +13 -0
- package/dist/internal/index-impl/createSemanticImportSidecar.js +5 -1
- package/dist/internal/index-impl/treeSitterDeclaration.js +14 -6
- package/dist/internal/index-impl/treeSitterFieldText.js +1 -5
- package/dist/internal/index-impl/treeSitterNodeAccess.js +75 -0
- package/dist/internal/index-impl/visitTreeSitterNode.js +2 -28
- package/dist/semantic-import-sidecar-entry.js +13 -2
- package/examples/native-js-to-rust-demo.mjs +148 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,6 +19,19 @@ const result = compileFrontierSource(source, { target: 'typescript' });
|
|
|
19
19
|
if (result.ok) console.log(result.output);
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
+
Run a small end-to-end demo after installing or building the package:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
npm run build
|
|
26
|
+
node examples/native-js-to-rust-demo.mjs
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The demo prints JavaScript source, the Frontier universal AST/semantic-index summary,
|
|
30
|
+
Rust declaration stubs, a host-adapter Rust projection, and a direct Frontier-source
|
|
31
|
+
to Rust projection. Native JavaScript projection remains loss-aware: without a
|
|
32
|
+
target adapter the compiler emits review-required stubs rather than claiming a
|
|
33
|
+
lossless JS-to-Rust transpilation.
|
|
34
|
+
|
|
22
35
|
Emit code with declaration-level source-map sidecars for semantic review and merge admission:
|
|
23
36
|
|
|
24
37
|
```js
|
|
@@ -18,9 +18,13 @@ export function createSemanticImportSidecar(importResult, options = {}) {
|
|
|
18
18
|
const proofSpec = summarizeSemanticImportSidecarProofSpec(importEntries);
|
|
19
19
|
const paradigmSemantics = summarizeSemanticImportSidecarParadigmSemantics(importEntries);
|
|
20
20
|
const dependencies = summarizeSemanticImportDependencies(imports);
|
|
21
|
+
const entryReadiness = importEntries.reduce(
|
|
22
|
+
(current, entry) => maxSemanticMergeReadiness(current, entry.readiness),
|
|
23
|
+
lossSummary.semanticMergeReadiness
|
|
24
|
+
);
|
|
21
25
|
const readiness = mergeCandidates.reduce(
|
|
22
26
|
(current, candidate) => maxSemanticMergeReadiness(current, candidate.readiness),
|
|
23
|
-
|
|
27
|
+
entryReadiness
|
|
24
28
|
);
|
|
25
29
|
const patchHints = ownershipRegions.map((region) => semanticPatchHintForRegion(region, readiness, options));
|
|
26
30
|
const quality = createSemanticImportSidecarQuality({
|
|
@@ -1,24 +1,32 @@
|
|
|
1
|
-
import{declarationRecord}from'./declarationRecord.js';import{
|
|
1
|
+
import{declarationRecord}from'./declarationRecord.js';import{shortNodeText}from'./shortNodeText.js';import{treeSitterChildText,treeSitterFieldText}from'./treeSitterNodeAccess.js';
|
|
2
2
|
export function treeSitterDeclaration(node, kind, nativeNodeId, input) {
|
|
3
3
|
if (/import|include|use/.test(kind)) {
|
|
4
|
-
const name =
|
|
4
|
+
const name = treeSitterNamedText(node, ['string', 'string_fragment', 'identifier']) ?? shortNodeText(node);
|
|
5
5
|
if (name) return declarationRecord(input, nativeNodeId, name, 'module', 'import');
|
|
6
6
|
}
|
|
7
7
|
if (/function|method|fn_item|function_declaration/.test(kind)) {
|
|
8
|
-
const name =
|
|
8
|
+
const name = treeSitterNamedText(node, ['identifier', 'property_identifier']);
|
|
9
9
|
if (name) return declarationRecord(input, nativeNodeId, name, 'function', 'definition');
|
|
10
10
|
}
|
|
11
11
|
if (/class/.test(kind)) {
|
|
12
|
-
const name =
|
|
12
|
+
const name = treeSitterNamedText(node, ['type_identifier', 'identifier']);
|
|
13
13
|
if (name) return declarationRecord(input, nativeNodeId, name, 'class', 'definition');
|
|
14
14
|
}
|
|
15
15
|
if (/interface/.test(kind)) {
|
|
16
|
-
const name =
|
|
16
|
+
const name = treeSitterNamedText(node, ['type_identifier', 'identifier']);
|
|
17
17
|
if (name) return declarationRecord(input, nativeNodeId, name, 'interface', 'definition');
|
|
18
18
|
}
|
|
19
19
|
if (/struct|enum|type/.test(kind)) {
|
|
20
|
-
const name =
|
|
20
|
+
const name = treeSitterNamedText(node, ['type_identifier', 'identifier']);
|
|
21
21
|
if (name) return declarationRecord(input, nativeNodeId, name, 'type', 'definition');
|
|
22
22
|
}
|
|
23
|
+
if (/variable_declarator|property_declaration|field_declaration/.test(kind)) {
|
|
24
|
+
const name = treeSitterNamedText(node, ['identifier', 'property_identifier', 'field_identifier']);
|
|
25
|
+
if (name) return declarationRecord(input, nativeNodeId, name, 'variable', 'definition');
|
|
26
|
+
}
|
|
23
27
|
return undefined;
|
|
24
28
|
}
|
|
29
|
+
|
|
30
|
+
function treeSitterNamedText(node, childKinds) {
|
|
31
|
+
return treeSitterFieldText(node, 'name') ?? treeSitterFieldText(node, 'declarator') ?? treeSitterChildText(node, childKinds);
|
|
32
|
+
}
|
|
@@ -1,5 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export function treeSitterFieldText(node, field) {
|
|
3
|
-
if (typeof node.childForFieldName !== 'function') return undefined;
|
|
4
|
-
return shortNodeText(node.childForFieldName(field));
|
|
5
|
-
}
|
|
1
|
+
export{treeSitterFieldText}from'./treeSitterNodeAccess.js';
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import{shortNodeText}from'./shortNodeText.js';
|
|
2
|
+
export function treeSitterNodeKind(node) {
|
|
3
|
+
return String(node?.type ?? node?.kind ?? 'node');
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function treeSitterChildren(node) {
|
|
7
|
+
const children = treeSitterArrayChildren(node, 'children');
|
|
8
|
+
if (children.length) return children;
|
|
9
|
+
const childCountChildren = treeSitterIndexedChildren(node, 'childCount', 'child');
|
|
10
|
+
if (childCountChildren.length) return childCountChildren;
|
|
11
|
+
const namedChildren = treeSitterArrayChildren(node, 'namedChildren');
|
|
12
|
+
if (namedChildren.length) return namedChildren;
|
|
13
|
+
return treeSitterIndexedChildren(node, 'namedChildCount', 'namedChild');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function treeSitterChildText(node, kinds) {
|
|
17
|
+
const wanted = new Set(kinds);
|
|
18
|
+
const stack = [...treeSitterChildren(node)];
|
|
19
|
+
while (stack.length) {
|
|
20
|
+
const child = stack.shift();
|
|
21
|
+
if (!child || typeof child !== 'object') continue;
|
|
22
|
+
if (wanted.has(treeSitterNodeKind(child))) {
|
|
23
|
+
const text = shortNodeText(child);
|
|
24
|
+
if (text) return text;
|
|
25
|
+
}
|
|
26
|
+
stack.unshift(...treeSitterChildren(child));
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function treeSitterFieldText(node, field) {
|
|
32
|
+
const exact = treeSitterFieldNode(node, field);
|
|
33
|
+
if (exact) return shortNodeText(exact);
|
|
34
|
+
return treeSitterNamedFieldText(node, field);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function treeSitterFieldNode(node, field) {
|
|
38
|
+
if (typeof node?.childForFieldName === 'function') return node.childForFieldName(field);
|
|
39
|
+
if (typeof node?.child_by_field_name === 'function') return node.child_by_field_name(field);
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function treeSitterNamedFieldText(node, field) {
|
|
44
|
+
for (const child of treeSitterChildren(node)) {
|
|
45
|
+
if (treeSitterFieldName(child) === field) {
|
|
46
|
+
const text = shortNodeText(child);
|
|
47
|
+
if (text) return text;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function treeSitterFieldName(node) {
|
|
54
|
+
if (typeof node?.fieldName === 'string') return node.fieldName;
|
|
55
|
+
if (typeof node?.field_name === 'string') return node.field_name;
|
|
56
|
+
if (typeof node?.fieldName === 'function') return node.fieldName();
|
|
57
|
+
if (typeof node?.field_name === 'function') return node.field_name();
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function treeSitterArrayChildren(node, field) {
|
|
62
|
+
const value = node?.[field];
|
|
63
|
+
return Array.isArray(value) ? value.filter((child) => child && typeof child === 'object') : [];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function treeSitterIndexedChildren(node, countField, childMethod) {
|
|
67
|
+
const count = Number(node?.[countField]);
|
|
68
|
+
if (!Number.isFinite(count) || count <= 0 || typeof node?.[childMethod] !== 'function') return [];
|
|
69
|
+
const children = [];
|
|
70
|
+
for (let index = 0; index < count; index += 1) {
|
|
71
|
+
const child = node[childMethod](index);
|
|
72
|
+
if (child && typeof child === 'object') children.push(child);
|
|
73
|
+
}
|
|
74
|
+
return children;
|
|
75
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import{idFragment}from'../../native-import-utils.js';
|
|
2
|
-
import{nativeNodeId}from'./nativeNodeId.js';import{numberOrUndefined}from'./numberOrUndefined.js';import{shortNodeText}from'./shortNodeText.js';import{spanFromTreeSitterNode}from'./spanFromTreeSitterNode.js';import{treeSitterDeclaration}from'./treeSitterDeclaration.js';
|
|
2
|
+
import{nativeNodeId}from'./nativeNodeId.js';import{numberOrUndefined}from'./numberOrUndefined.js';import{shortNodeText}from'./shortNodeText.js';import{spanFromTreeSitterNode}from'./spanFromTreeSitterNode.js';import{treeSitterDeclaration}from'./treeSitterDeclaration.js';import{treeSitterChildren,treeSitterNodeKind}from'./treeSitterNodeAccess.js';
|
|
3
3
|
export function visitTreeSitterNode(node, context, propertyPath, depth = 0) {
|
|
4
4
|
if (!node || typeof node !== 'object' || context.truncated) return undefined;
|
|
5
5
|
if (context.objectIds.has(node)) return context.objectIds.get(node);
|
|
@@ -8,7 +8,7 @@ export function visitTreeSitterNode(node, context, propertyPath, depth = 0) {
|
|
|
8
8
|
return undefined;
|
|
9
9
|
}
|
|
10
10
|
context.counter += 1;
|
|
11
|
-
const kind =
|
|
11
|
+
const kind = treeSitterNodeKind(node);
|
|
12
12
|
const span = spanFromTreeSitterNode(node, context.input);
|
|
13
13
|
const id = nativeNodeId(context, kind, { start: { line: span?.startLine, column: span?.startColumn } }, propertyPath);
|
|
14
14
|
context.objectIds.set(node, id);
|
|
@@ -82,32 +82,6 @@ export function visitTreeSitterNode(node, context, propertyPath, depth = 0) {
|
|
|
82
82
|
return id;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
function treeSitterChildren(node) {
|
|
86
|
-
const children = treeSitterArrayChildren(node, 'children');
|
|
87
|
-
if (children.length) return children;
|
|
88
|
-
const childCountChildren = treeSitterIndexedChildren(node, 'childCount', 'child');
|
|
89
|
-
if (childCountChildren.length) return childCountChildren;
|
|
90
|
-
const namedChildren = treeSitterArrayChildren(node, 'namedChildren');
|
|
91
|
-
if (namedChildren.length) return namedChildren;
|
|
92
|
-
return treeSitterIndexedChildren(node, 'namedChildCount', 'namedChild');
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function treeSitterArrayChildren(node, field) {
|
|
96
|
-
const value = node[field];
|
|
97
|
-
return Array.isArray(value) ? value.filter((child) => child && typeof child === 'object') : [];
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function treeSitterIndexedChildren(node, countField, childMethod) {
|
|
101
|
-
const count = Number(node[countField]);
|
|
102
|
-
if (!Number.isFinite(count) || count <= 0 || typeof node[childMethod] !== 'function') return [];
|
|
103
|
-
const children = [];
|
|
104
|
-
for (let index = 0; index < count; index += 1) {
|
|
105
|
-
const child = node[childMethod](index);
|
|
106
|
-
if (child && typeof child === 'object') children.push(child);
|
|
107
|
-
}
|
|
108
|
-
return children;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
85
|
function treeSitterBoolean(node, ...fields) {
|
|
112
86
|
for (const field of fields) {
|
|
113
87
|
const value = node[field];
|
|
@@ -18,6 +18,7 @@ function semanticImportSidecarEntry(imported, index, options) {
|
|
|
18
18
|
const proofSpec = summarizeProofSpecLayer(imported?.universalAst?.proof ?? imported?.proof);
|
|
19
19
|
const paradigmSemantics = summarizeParadigmSemanticsLayer(imported?.universalAst?.paradigmSemantics ?? imported?.paradigmSemantics);
|
|
20
20
|
const dependencies = summarizeSemanticImportDependencyRelations(semanticIndex?.relations ?? []);
|
|
21
|
+
const readiness = semanticImportEntryReadiness(imported);
|
|
21
22
|
const mappingsBySymbolId = new Map();
|
|
22
23
|
for (const mapping of sourceMapMappings) {
|
|
23
24
|
if (mapping.semanticSymbolId && !mappingsBySymbolId.has(mapping.semanticSymbolId)) {
|
|
@@ -44,7 +45,7 @@ function semanticImportSidecarEntry(imported, index, options) {
|
|
|
44
45
|
ownershipRegionId: region.id,
|
|
45
46
|
ownershipKey: region.key,
|
|
46
47
|
ownershipRegionKind: region.regionKind,
|
|
47
|
-
readiness
|
|
48
|
+
readiness
|
|
48
49
|
});
|
|
49
50
|
}
|
|
50
51
|
const ownershipRegions = uniqueRecordsById(regions);
|
|
@@ -71,7 +72,7 @@ function semanticImportSidecarEntry(imported, index, options) {
|
|
|
71
72
|
paradigmSemantics,
|
|
72
73
|
dependencyRelationCount: dependencies.total,
|
|
73
74
|
dependencyPredicates: dependencies.predicates,
|
|
74
|
-
readiness
|
|
75
|
+
readiness,
|
|
75
76
|
emptySemanticIndex: symbols.length === 0,
|
|
76
77
|
regionTaxonomy,
|
|
77
78
|
symbols,
|
|
@@ -79,4 +80,14 @@ function semanticImportSidecarEntry(imported, index, options) {
|
|
|
79
80
|
};
|
|
80
81
|
}
|
|
81
82
|
|
|
83
|
+
function semanticImportEntryReadiness(imported) {
|
|
84
|
+
const readiness = imported?.metadata?.semanticMergeReadiness
|
|
85
|
+
?? imported?.metadata?.nativeImportLossSummary?.semanticMergeReadiness
|
|
86
|
+
?? imported?.readiness?.semanticMergeReadiness
|
|
87
|
+
?? imported?.readiness?.readiness
|
|
88
|
+
?? (typeof imported?.readiness === 'string' ? imported.readiness : undefined)
|
|
89
|
+
?? imported?.mergeCandidates?.[0]?.readiness;
|
|
90
|
+
return readiness ?? 'needs-review';
|
|
91
|
+
}
|
|
92
|
+
|
|
82
93
|
export { semanticImportSidecarEntry };
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import {
|
|
2
|
+
compileFrontierSource,
|
|
3
|
+
compileNativeSource,
|
|
4
|
+
importNativeSource,
|
|
5
|
+
writeUniversalAstJson
|
|
6
|
+
} from '../dist/index.js';
|
|
7
|
+
|
|
8
|
+
const javascriptSource = `import { nanoid } from "nanoid";
|
|
9
|
+
|
|
10
|
+
export function addTodo(title) {
|
|
11
|
+
return { id: nanoid(), title };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class TodoStore {
|
|
15
|
+
save(title) {
|
|
16
|
+
return addTodo(title);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
const imported = importNativeSource({
|
|
22
|
+
language: 'javascript',
|
|
23
|
+
sourcePath: 'src/todo.js',
|
|
24
|
+
sourceText: javascriptSource
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const graphSummary = {
|
|
28
|
+
universalAst: imported.universalAst.kind,
|
|
29
|
+
semanticIndexId: imported.semanticIndex.id,
|
|
30
|
+
symbols: imported.semanticIndex.symbols.map((symbol) => ({
|
|
31
|
+
name: symbol.name,
|
|
32
|
+
kind: symbol.kind,
|
|
33
|
+
region: symbol.metadata?.ownershipRegionKind
|
|
34
|
+
})),
|
|
35
|
+
sourceMapMappings: imported.sourceMaps[0]?.mappings.length ?? 0,
|
|
36
|
+
mergeReadiness: imported.metadata.nativeImportLossSummary.semanticMergeReadiness,
|
|
37
|
+
losses: imported.losses.map((loss) => loss.kind)
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
console.log('--- JavaScript source ---');
|
|
41
|
+
console.log(javascriptSource.trim());
|
|
42
|
+
console.log('\n--- Frontier graph summary ---');
|
|
43
|
+
console.log(JSON.stringify(graphSummary, null, 2));
|
|
44
|
+
console.log('\n--- Universal AST envelope excerpt ---');
|
|
45
|
+
console.log(JSON.stringify(universalAstExcerpt(imported), null, 2));
|
|
46
|
+
|
|
47
|
+
const stubProjection = compileNativeSource(imported, {
|
|
48
|
+
target: 'rust',
|
|
49
|
+
targetPath: 'src/todo.rs'
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
console.log('\n--- Rust declaration stubs without a target adapter ---');
|
|
53
|
+
console.log(`ok=${stubProjection.ok} readiness=${stubProjection.readiness.readiness} mode=${stubProjection.outputMode}`);
|
|
54
|
+
console.log(stubProjection.output.trim());
|
|
55
|
+
|
|
56
|
+
const adapterProjection = compileNativeSource(imported, {
|
|
57
|
+
target: 'rust',
|
|
58
|
+
targetPath: 'src/todo.rs',
|
|
59
|
+
targetAdapters: [createDemoJsToRustAdapter()]
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
console.log('\n--- Rust output with a host-owned target adapter ---');
|
|
63
|
+
console.log(`ok=${adapterProjection.ok} readiness=${adapterProjection.readiness.readiness} mode=${adapterProjection.outputMode}`);
|
|
64
|
+
console.log(adapterProjection.output.trim());
|
|
65
|
+
|
|
66
|
+
const frontierSource = `module TodoApp @id("mod_todo")
|
|
67
|
+
|
|
68
|
+
type TodoInput @id("type_todo_input") {
|
|
69
|
+
title: Text
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
entity Todo @id("ent_todo") {
|
|
73
|
+
title @id("field_title"): Text
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
action addTodo @id("action_add") {
|
|
77
|
+
input TodoInput
|
|
78
|
+
writes field_title
|
|
79
|
+
returns Patch
|
|
80
|
+
}
|
|
81
|
+
`;
|
|
82
|
+
|
|
83
|
+
const canonicalRust = compileFrontierSource(frontierSource, { target: 'rust' });
|
|
84
|
+
|
|
85
|
+
console.log('\n--- Frontier source projected directly to Rust ---');
|
|
86
|
+
console.log(`ok=${canonicalRust.ok} target=${canonicalRust.target}`);
|
|
87
|
+
console.log(canonicalRust.output.trim());
|
|
88
|
+
|
|
89
|
+
function universalAstExcerpt(importResult) {
|
|
90
|
+
const parsed = JSON.parse(writeUniversalAstJson(importResult.universalAst));
|
|
91
|
+
return {
|
|
92
|
+
kind: parsed.kind,
|
|
93
|
+
id: parsed.id,
|
|
94
|
+
documentCount: parsed.documents?.length ?? 0,
|
|
95
|
+
symbolCount: parsed.semanticIndex?.symbols?.length ?? 0,
|
|
96
|
+
sourceMapCount: parsed.sourceMaps?.length ?? 0
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function createDemoJsToRustAdapter() {
|
|
101
|
+
return {
|
|
102
|
+
id: 'demo-js-to-rust-target-adapter',
|
|
103
|
+
sourceLanguage: 'javascript',
|
|
104
|
+
target: 'rust',
|
|
105
|
+
version: '0.0.0-demo',
|
|
106
|
+
capabilities: ['declaration-stubs'],
|
|
107
|
+
coverage: {
|
|
108
|
+
readiness: 'ready',
|
|
109
|
+
handledLossKinds: ['opaqueNative', 'declarationOnlyCoverage', 'partialSemanticIndex', 'sourceMapApproximation', 'sourcePreservation'],
|
|
110
|
+
notes: ['Demo adapter turns Frontier semantic symbols into deterministic Rust scaffolding.']
|
|
111
|
+
},
|
|
112
|
+
project(input) {
|
|
113
|
+
const symbols = input.importResult.semanticIndex?.symbols ?? [];
|
|
114
|
+
return {
|
|
115
|
+
output: renderRustScaffold(symbols),
|
|
116
|
+
readiness: 'ready',
|
|
117
|
+
evidence: [{
|
|
118
|
+
id: 'evidence_demo_js_to_rust_adapter',
|
|
119
|
+
kind: 'projection',
|
|
120
|
+
status: 'passed',
|
|
121
|
+
summary: 'Demo adapter projected JavaScript semantic symbols to Rust scaffolding.'
|
|
122
|
+
}]
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function renderRustScaffold(symbols) {
|
|
129
|
+
const lines = ['// Generated from Frontier semantic graph evidence.'];
|
|
130
|
+
for (const symbol of symbols) {
|
|
131
|
+
if (symbol.kind === 'class') {
|
|
132
|
+
lines.push(`pub struct ${symbol.name};`, '');
|
|
133
|
+
} else if (symbol.kind === 'function' || symbol.kind === 'method') {
|
|
134
|
+
lines.push(`pub fn ${rustName(symbol.name)}() {`);
|
|
135
|
+
lines.push(' todo!("port body from native source evidence");');
|
|
136
|
+
lines.push('}', '');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return `${lines.join('\n').trim()}\n`;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function rustName(name) {
|
|
143
|
+
return String(name)
|
|
144
|
+
.replace(/\./g, '_')
|
|
145
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1_$2')
|
|
146
|
+
.replace(/[^A-Za-z0-9_]/g, '_')
|
|
147
|
+
.toLowerCase();
|
|
148
|
+
}
|
package/package.json
CHANGED