typenative 0.0.10 → 0.0.11
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 +9 -3
- package/bin/index.js +5 -3
- package/bin/transpiler.js +94 -20
- package/package.json +6 -3
- package/types/typenative.d.ts +38 -1
package/README.md
CHANGED
|
@@ -33,18 +33,24 @@ TypeNative currently supports a subset of TypeScript syntax elements that are tr
|
|
|
33
33
|
| Increment/Decrement | ✅ | `++`, `--` |
|
|
34
34
|
| **Control Flow** | | |
|
|
35
35
|
| For loops | ✅ | Standard `for` loops |
|
|
36
|
+
| For...of loops | ✅ | Iteration over arrays |
|
|
37
|
+
| While loops | ✅ | Transpiled to Go's `for` loops |
|
|
38
|
+
| Do...while loops | ✅ | Implemented with conditional break |
|
|
39
|
+
| If/Else statements | ✅ | Fully supported |
|
|
40
|
+
| Switch statements | ✅ | Case and default statements |
|
|
36
41
|
| **Data Structures** | | |
|
|
37
42
|
| Arrays | ✅ | Basic array operations |
|
|
43
|
+
| Array methods | ✅ | `push` supported |
|
|
38
44
|
| **Functions** | | |
|
|
39
45
|
| console.log | ✅ | Mapped to `fmt.Println` |
|
|
46
|
+
| console.time/timeEnd | ✅ | Performance measurement |
|
|
47
|
+
| Math.random | ✅ | Mapped to Go's `rand.Float64()` |
|
|
48
|
+
| Math.floor | ✅ | Mapped to Go's `math.Floor()` |
|
|
40
49
|
| **Unsupported Features** | | |
|
|
41
50
|
| Classes | ❌ | Not implemented |
|
|
42
51
|
| Interfaces | ❌ | Not implemented |
|
|
43
52
|
| Functions | ❌ | Custom function definitions not supported |
|
|
44
53
|
| Arrow Functions | ❌ | Not implemented |
|
|
45
|
-
| If/Else statements | ❌ | Not implemented |
|
|
46
|
-
| While/Do loops | ❌ | Not implemented |
|
|
47
|
-
| Switch statements | ❌ | Not implemented |
|
|
48
54
|
| Async/Await | ❌ | Not implemented |
|
|
49
55
|
| Modules/Imports | ❌ | Not implemented |
|
|
50
56
|
| Generics | ❌ | Not implemented |
|
package/bin/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
|
-
import shell from 'shelljs';
|
|
4
3
|
import fs from 'fs-extra';
|
|
5
4
|
import path from 'path';
|
|
5
|
+
import { execa } from 'execa';
|
|
6
6
|
import { transpileToNative } from './transpiler.js';
|
|
7
7
|
import { fileURLToPath } from 'url';
|
|
8
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -37,14 +37,16 @@ const __dirname = path.dirname(__filename);
|
|
|
37
37
|
const nativeCode = transpileToNative(tsCode);
|
|
38
38
|
await fs.ensureDir('dist');
|
|
39
39
|
await fs.writeFile('dist/code.go', nativeCode, { encoding: 'utf-8' });
|
|
40
|
-
|
|
40
|
+
await execa('go build -o dist/native.exe dist/code.go');
|
|
41
41
|
// await fs.remove('dist/code.go');
|
|
42
42
|
if (answers.output) {
|
|
43
43
|
await fs.copy('dist/native.exe', answers.output, { overwrite: true });
|
|
44
44
|
await fs.remove('dist/native.exe');
|
|
45
45
|
}
|
|
46
46
|
if (scriptMode) {
|
|
47
|
-
|
|
47
|
+
await execa('dist/native.exe', {
|
|
48
|
+
stdio: 'inherit'
|
|
49
|
+
});
|
|
48
50
|
await fs.remove('dist/native.exe');
|
|
49
51
|
}
|
|
50
52
|
else {
|
package/bin/transpiler.js
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
2
|
let TypeCheker;
|
|
3
|
+
let importedPackages = new Set();
|
|
3
4
|
export function transpileToNative(code) {
|
|
4
5
|
const sourceFile = ts.createSourceFile('main.ts', code, ts.ScriptTarget.ES2020, true, ts.ScriptKind.TS);
|
|
5
6
|
TypeCheker = ts.createProgram(['main.ts'], {}).getTypeChecker();
|
|
7
|
+
importedPackages.clear();
|
|
8
|
+
const transpiledCode = visit(sourceFile);
|
|
6
9
|
return `package main
|
|
7
10
|
|
|
8
|
-
import "
|
|
11
|
+
${[...importedPackages].map((pkg) => `import "${pkg}"`).join('\n')}
|
|
9
12
|
|
|
10
13
|
func main() {
|
|
11
|
-
${
|
|
14
|
+
${transpiledCode.trim()}
|
|
12
15
|
}`;
|
|
13
16
|
}
|
|
14
|
-
export function visit(node, inline = false) {
|
|
17
|
+
export function visit(node, inline = false, extraBlockContent = '') {
|
|
15
18
|
let code = '';
|
|
16
19
|
if (ts.isIdentifier(node)) {
|
|
17
20
|
return node.text;
|
|
@@ -28,20 +31,30 @@ export function visit(node, inline = false) {
|
|
|
28
31
|
else if (ts.isToken(node) && node.kind === ts.SyntaxKind.FalseKeyword) {
|
|
29
32
|
return `false`;
|
|
30
33
|
}
|
|
34
|
+
else if (ts.isArrayLiteralExpression(node)) {
|
|
35
|
+
const type = ts.isVariableDeclaration(node.parent) ? getType(node.parent.type, true) : '';
|
|
36
|
+
return `[]${type} {${node.elements.map((e) => visit(e)).join(', ')}}`;
|
|
37
|
+
}
|
|
31
38
|
else if (ts.isBlock(node)) {
|
|
32
|
-
return `{\n\t\t${node.statements.map((n) => visit(n)).join('\t')}}\n\t`;
|
|
39
|
+
return `{\n\t\t${node.statements.map((n) => visit(n)).join('\t')}${extraBlockContent}}${inline ? '' : '\n\t'}`;
|
|
40
|
+
}
|
|
41
|
+
else if (ts.isElementAccessExpression(node)) {
|
|
42
|
+
return `${visit(node.expression)}[int(${visit(node.argumentExpression)})]`;
|
|
33
43
|
}
|
|
34
44
|
else if (ts.isPropertyAccessExpression(node)) {
|
|
35
|
-
|
|
45
|
+
const leftSide = visit(node.expression);
|
|
46
|
+
const rightSide = visit(node.name);
|
|
47
|
+
return getAcessString(leftSide, rightSide);
|
|
36
48
|
}
|
|
37
49
|
else if (ts.isVariableDeclaration(node)) {
|
|
38
50
|
const type = getType(node.type);
|
|
39
51
|
const initializer = node.initializer ? `= ${visit(node.initializer)}` : '';
|
|
40
|
-
return `${type === ':' ? '' : 'var'}
|
|
52
|
+
return `${type === ':' ? '' : 'var '}${visit(node.name)} ${type}${type === ':' ? '' : ' '}${initializer}`;
|
|
41
53
|
}
|
|
42
54
|
else if (ts.isCallExpression(node)) {
|
|
43
|
-
const
|
|
44
|
-
|
|
55
|
+
const caller = visit(node.expression);
|
|
56
|
+
const args = node.arguments.map((a) => visit(a));
|
|
57
|
+
return getCallString(caller, args);
|
|
45
58
|
}
|
|
46
59
|
else if (ts.isPrefixUnaryExpression(node)) {
|
|
47
60
|
return `${getOperatorText(node.operator)}${visit(node.operand)}`;
|
|
@@ -56,24 +69,53 @@ export function visit(node, inline = false) {
|
|
|
56
69
|
return `(${visit(node.expression)})`;
|
|
57
70
|
}
|
|
58
71
|
else if (ts.isVariableDeclarationList(node)) {
|
|
59
|
-
return (node.declarations.map((n) => visit(n)).join(inline ? ';' : ';\n\t') + (inline ? '
|
|
72
|
+
return (node.declarations.map((n) => visit(n)).join(inline ? ';' : ';\n\t') + (inline ? '' : ';\n\t'));
|
|
60
73
|
}
|
|
61
74
|
else if (ts.isExpressionStatement(node)) {
|
|
62
|
-
return visit(node.expression) + (inline ? '
|
|
75
|
+
return visit(node.expression) + (inline ? '' : ';\n\t');
|
|
63
76
|
}
|
|
64
77
|
else if (ts.isForStatement(node)) {
|
|
65
|
-
return `for${visit(node.initializer, true)} ${visit(node.condition, true)}; ${visit(node.incrementor, true)}${visit(node.statement)}`;
|
|
78
|
+
return `for ${visit(node.initializer, true)}; ${visit(node.condition, true)}; ${visit(node.incrementor, true)}${visit(node.statement)}`;
|
|
79
|
+
}
|
|
80
|
+
else if (ts.isForOfStatement(node)) {
|
|
81
|
+
return `for _,${visit(node.initializer, true)}= range ${visit(node.expression, true)}${visit(node.statement)}`;
|
|
82
|
+
}
|
|
83
|
+
else if (ts.isWhileStatement(node)) {
|
|
84
|
+
return `for ${visit(node.expression, true)}${visit(node.statement)}`;
|
|
85
|
+
}
|
|
86
|
+
else if (ts.isDoStatement(node)) {
|
|
87
|
+
const condition = `\tif !(${visit(node.expression, true)}) {\n\t\t\tbreak \n\t\t}\n\t`;
|
|
88
|
+
return `for ${visit(node.statement, false, condition)}`;
|
|
89
|
+
}
|
|
90
|
+
else if (ts.isIfStatement(node)) {
|
|
91
|
+
const condition = `if ${visit(node.expression, true)} ${visit(node.thenStatement, true)}`;
|
|
92
|
+
if (node.elseStatement) {
|
|
93
|
+
return `${condition} else ${visit(node.elseStatement)}`;
|
|
94
|
+
}
|
|
95
|
+
return condition;
|
|
96
|
+
}
|
|
97
|
+
const syntaxKind = ts.SyntaxKind[node.kind];
|
|
98
|
+
if (!['SourceFile', 'FirstStatement', 'EndOfFileToken'].includes(syntaxKind)) {
|
|
99
|
+
console.log(ts.SyntaxKind[node.kind], node.getText());
|
|
66
100
|
}
|
|
67
|
-
console.log(ts.SyntaxKind[node.kind], node.getText());
|
|
68
101
|
ts.forEachChild(node, (subNode) => {
|
|
69
102
|
code += visit(subNode);
|
|
70
103
|
return null;
|
|
71
104
|
});
|
|
72
105
|
return code;
|
|
73
106
|
}
|
|
74
|
-
function getType(typeNode) {
|
|
107
|
+
function getType(typeNode, getArrayType = false) {
|
|
75
108
|
const type = TypeCheker.getTypeFromTypeNode(typeNode);
|
|
76
|
-
|
|
109
|
+
let typeName = TypeCheker.typeToString(type);
|
|
110
|
+
const isArray = typeNode?.kind & ts.SyntaxKind.ArrayType;
|
|
111
|
+
if (isArray) {
|
|
112
|
+
if (getArrayType) {
|
|
113
|
+
typeName = typeName.replace('[]', '');
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
return ':';
|
|
117
|
+
}
|
|
118
|
+
}
|
|
77
119
|
switch (typeName) {
|
|
78
120
|
case 'number':
|
|
79
121
|
return 'float64';
|
|
@@ -85,13 +127,39 @@ function getType(typeNode) {
|
|
|
85
127
|
return typeName;
|
|
86
128
|
}
|
|
87
129
|
}
|
|
88
|
-
function
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
return 'fmt.Println';
|
|
92
|
-
default:
|
|
93
|
-
return expr;
|
|
130
|
+
function getAcessString(leftSide, rightSide) {
|
|
131
|
+
if (rightSide === 'length') {
|
|
132
|
+
return 'float64(len(arr))';
|
|
94
133
|
}
|
|
134
|
+
return `${leftSide}.${rightSide}`;
|
|
135
|
+
}
|
|
136
|
+
function getCallString(caller, args) {
|
|
137
|
+
if (caller === 'console.log') {
|
|
138
|
+
importedPackages.add('fmt');
|
|
139
|
+
return `fmt.Println(${args.join(', ')})`;
|
|
140
|
+
}
|
|
141
|
+
else if (caller === 'console.time') {
|
|
142
|
+
importedPackages.add('time');
|
|
143
|
+
return `${getTimerName(args[0])} := time.Now()`;
|
|
144
|
+
}
|
|
145
|
+
else if (caller === 'console.timeEnd') {
|
|
146
|
+
importedPackages.add('time');
|
|
147
|
+
importedPackages.add('fmt');
|
|
148
|
+
return `fmt.Println("Elapsed time:", time.Since(${getTimerName(args[0])}))`;
|
|
149
|
+
}
|
|
150
|
+
else if (caller === 'Math.random') {
|
|
151
|
+
importedPackages.add('math/rand');
|
|
152
|
+
return 'rand.Float64()';
|
|
153
|
+
}
|
|
154
|
+
else if (caller === 'Math.floor') {
|
|
155
|
+
importedPackages.add('math');
|
|
156
|
+
return `math.Floor(${args.join(', ')})`;
|
|
157
|
+
}
|
|
158
|
+
else if (caller.endsWith('.push')) {
|
|
159
|
+
const arrayName = caller.substring(0, caller.length - '.push'.length);
|
|
160
|
+
return `${arrayName} = append(${arrayName},${args.join(', ')})`;
|
|
161
|
+
}
|
|
162
|
+
return `${caller}(${args.join(', ')})`;
|
|
95
163
|
}
|
|
96
164
|
function getOperatorText(operator) {
|
|
97
165
|
switch (operator) {
|
|
@@ -107,5 +175,11 @@ function getOperatorText(operator) {
|
|
|
107
175
|
return '++';
|
|
108
176
|
case ts.SyntaxKind.MinusMinusToken:
|
|
109
177
|
return '--';
|
|
178
|
+
default:
|
|
179
|
+
console.error('Did not find operator', operator);
|
|
180
|
+
return '';
|
|
110
181
|
}
|
|
111
182
|
}
|
|
183
|
+
function getTimerName(name) {
|
|
184
|
+
return `__timer_${name.replaceAll(' ', '_').replaceAll('"', '')}__`;
|
|
185
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typenative",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"description": "Build native applications using Typescript.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -14,7 +14,10 @@
|
|
|
14
14
|
"test": "node ./bin/index --source test/test.ts --script",
|
|
15
15
|
"test2": "node ./bin/index --source test/test2.ts --script",
|
|
16
16
|
"test3": "node ./bin/index --source test/test3.ts --script",
|
|
17
|
+
"test3_node": "tsc test/test3.ts && node test/test3.js && rimraf test/test3.js",
|
|
17
18
|
"test4": "node ./bin/index --source test/test4.ts --script",
|
|
19
|
+
"test5": "node ./bin/index --source test/test5.ts --script",
|
|
20
|
+
"test6": "node ./bin/index --source test/test6.ts --script",
|
|
18
21
|
"release": "npm publish"
|
|
19
22
|
},
|
|
20
23
|
"repository": {
|
|
@@ -31,12 +34,12 @@
|
|
|
31
34
|
"@types/fs-extra": "^11.0.4",
|
|
32
35
|
"@types/inquirer": "^9.0.8",
|
|
33
36
|
"@types/node": "^22.15.21",
|
|
34
|
-
"
|
|
37
|
+
"rimraf": "^6.0.1"
|
|
35
38
|
},
|
|
36
39
|
"dependencies": {
|
|
40
|
+
"execa": "^9.5.3",
|
|
37
41
|
"fs-extra": "^11.3.0",
|
|
38
42
|
"inquirer": "^12.6.1",
|
|
39
|
-
"shelljs": "^0.10.0",
|
|
40
43
|
"typescript": "^5.8.3"
|
|
41
44
|
}
|
|
42
45
|
}
|
package/types/typenative.d.ts
CHANGED
|
@@ -1,4 +1,33 @@
|
|
|
1
|
-
interface
|
|
1
|
+
interface SymbolConstructor {
|
|
2
|
+
readonly iterator: unique symbol;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
declare var Symbol: SymbolConstructor;
|
|
6
|
+
|
|
7
|
+
interface IteratorYieldResult<TYield> {
|
|
8
|
+
done?: false;
|
|
9
|
+
value: TYield;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface IteratorReturnResult<TReturn> {
|
|
13
|
+
done: true;
|
|
14
|
+
value: TReturn;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;
|
|
18
|
+
|
|
19
|
+
interface Iterator<T, TReturn = any, TNext = any> {
|
|
20
|
+
// NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.
|
|
21
|
+
next(...[value]: [] | [TNext]): IteratorResult<T, TReturn>;
|
|
22
|
+
return?(value?: TReturn): IteratorResult<T, TReturn>;
|
|
23
|
+
throw?(e?: any): IteratorResult<T, TReturn>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface IterableIterator<T, TReturn = any, TNext = any> extends Iterator<T, TReturn, TNext> {
|
|
27
|
+
[Symbol.iterator](): IterableIterator<T, TReturn, TNext>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface Array<T> extends IterableIterator<T> {
|
|
2
31
|
/**
|
|
3
32
|
* Gets or sets the length of the array. This is a number one higher than the highest index in the array.
|
|
4
33
|
*/
|
|
@@ -13,5 +42,13 @@ interface Array<T> {
|
|
|
13
42
|
|
|
14
43
|
interface Console {
|
|
15
44
|
log(...data: any[]): void;
|
|
45
|
+
time(label?: string): void;
|
|
46
|
+
timeEnd(label?: string): void;
|
|
16
47
|
}
|
|
17
48
|
declare var console: Console;
|
|
49
|
+
|
|
50
|
+
interface Math {
|
|
51
|
+
random(): number;
|
|
52
|
+
floor(x: number): number;
|
|
53
|
+
}
|
|
54
|
+
declare var Math: Math;
|