naider 1.8.0 → 1.10.0
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 +1 -1
- package/bin/naide.js +39 -6
- package/lsp/server.js +140 -0
- package/package.json +1 -1
- package/src/generator-bun.js +513 -0
- package/src/generator-python.js +1449 -0
- package/src/index.js +55 -1
package/README.md
CHANGED
|
@@ -68,7 +68,7 @@ naide --tokens <file> # Print token stream
|
|
|
68
68
|
|
|
69
69
|
```
|
|
70
70
|
$ naide
|
|
71
|
-
NAIDE REPL v1.
|
|
71
|
+
NAIDE REPL v1.9.0 — type NAIDE code, see JavaScript output
|
|
72
72
|
Type .exit to quit, .eval to toggle eval mode
|
|
73
73
|
|
|
74
74
|
>>> str name = "hello"
|
package/bin/naide.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { readFileSync, writeFileSync, unlinkSync, watch as fsWatch, existsSync, mkdirSync, readdirSync, statSync } from 'fs';
|
|
4
4
|
import { resolve, basename, extname, join, relative } from 'path';
|
|
5
|
-
import { compile } from '../src/index.js';
|
|
5
|
+
import { compile, compileAsync } from '../src/index.js';
|
|
6
6
|
import { spawn } from 'child_process';
|
|
7
7
|
|
|
8
8
|
import { createRequire } from 'module';
|
|
@@ -76,6 +76,7 @@ const flags = {
|
|
|
76
76
|
watch: false,
|
|
77
77
|
debug: false,
|
|
78
78
|
check: false,
|
|
79
|
+
target: 'node',
|
|
79
80
|
};
|
|
80
81
|
|
|
81
82
|
const files = [];
|
|
@@ -93,6 +94,7 @@ for (let i = 0; i < args.length; i++) {
|
|
|
93
94
|
case '--watch': case '-w': flags.watch = true; break;
|
|
94
95
|
case '--debug': case '-d': flags.debug = true; break;
|
|
95
96
|
case '--check': flags.check = true; flags.run = false; break;
|
|
97
|
+
case '--target': case '-t': flags.target = args[++i]; break;
|
|
96
98
|
default: files.push(arg);
|
|
97
99
|
}
|
|
98
100
|
}
|
|
@@ -151,7 +153,7 @@ if (files[0] === 'repl' || (files.length === 0 && !flags.help)) {
|
|
|
151
153
|
const { createInterface } = await import('readline');
|
|
152
154
|
const { transpile } = await import('../src/index.js');
|
|
153
155
|
|
|
154
|
-
console.log(`\n NAIDE REPL v1.
|
|
156
|
+
console.log(`\n NAIDE REPL v1.10.0 — type NAIDE code, see JavaScript output`);
|
|
155
157
|
console.log(` Type .exit to quit, .eval to toggle eval mode\n`);
|
|
156
158
|
|
|
157
159
|
const rl = createInterface({
|
|
@@ -290,7 +292,7 @@ if (files[0] === 'init') {
|
|
|
290
292
|
writeFileSync(resolve(dir, 'package.json'), JSON.stringify({
|
|
291
293
|
name, version: '1.0.0', type: 'module',
|
|
292
294
|
scripts: { start: 'naide app.naide', dev: 'naide -w app.naide', build: 'naide --emit app.naide -o dist/app.mjs' },
|
|
293
|
-
dependencies: { naider: '^1.
|
|
295
|
+
dependencies: { naider: '^1.9.0' }
|
|
294
296
|
}, null, 2) + '\n');
|
|
295
297
|
}
|
|
296
298
|
|
|
@@ -681,6 +683,11 @@ if (flags.help) {
|
|
|
681
683
|
naide -w <file.naide> Watch mode (auto-restart on changes)
|
|
682
684
|
naide -d <file> Debug mode (Node.js inspector)
|
|
683
685
|
|
|
686
|
+
Targets:
|
|
687
|
+
node Node.js / JavaScript (default)
|
|
688
|
+
bun Bun-optimized JavaScript
|
|
689
|
+
python Python (Flask for servers)
|
|
690
|
+
|
|
684
691
|
Modes:
|
|
685
692
|
.naide Standard NAIDE (~40% fewer tokens than JS)
|
|
686
693
|
.nx NAIDE-X extreme (~80% fewer tokens than JS)
|
|
@@ -691,6 +698,7 @@ if (flags.help) {
|
|
|
691
698
|
-x Force NAIDE-X mode
|
|
692
699
|
-w, --watch Watch mode: restart on file changes
|
|
693
700
|
-d, --debug Start with Node.js debugger (--inspect-brk)
|
|
701
|
+
-t, --target Compile target: node (default), bun, python/py
|
|
694
702
|
--check Type-check files without running
|
|
695
703
|
--mid Show intermediate NAIDE v1 (X mode only)
|
|
696
704
|
--ast Print AST
|
|
@@ -772,7 +780,10 @@ for (const file of files) {
|
|
|
772
780
|
continue;
|
|
773
781
|
}
|
|
774
782
|
|
|
775
|
-
const
|
|
783
|
+
const useAsync = flags.target !== 'node';
|
|
784
|
+
const result = useAsync
|
|
785
|
+
? await compileAsync(source, { mode, runtimePath, sourceFile: file, typeCheck: flags.check, target: flags.target })
|
|
786
|
+
: compile(source, { mode, runtimePath, sourceFile: file, typeCheck: flags.check });
|
|
776
787
|
|
|
777
788
|
if (flags.check) {
|
|
778
789
|
const { typeErrors } = result;
|
|
@@ -794,17 +805,39 @@ for (const file of files) {
|
|
|
794
805
|
continue;
|
|
795
806
|
}
|
|
796
807
|
|
|
808
|
+
const outputCode = result.code || result.js;
|
|
809
|
+
const outputExt = flags.target === 'python' || flags.target === 'py' ? '.py' : '.mjs';
|
|
810
|
+
|
|
797
811
|
if (flags.output) {
|
|
798
|
-
writeFileSync(flags.output,
|
|
812
|
+
writeFileSync(flags.output, outputCode, 'utf-8');
|
|
799
813
|
console.log(`Written to ${flags.output}`);
|
|
800
814
|
continue;
|
|
801
815
|
}
|
|
802
816
|
|
|
803
817
|
if (flags.emit) {
|
|
804
|
-
console.log(
|
|
818
|
+
console.log(outputCode);
|
|
819
|
+
continue;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
if (flags.target === 'python' || flags.target === 'py') {
|
|
823
|
+
const outFile = flags.output || resolve(basename(file, ext) + '.py');
|
|
824
|
+
writeFileSync(outFile, outputCode, 'utf-8');
|
|
825
|
+
console.log(` ${file} → ${basename(outFile)} (Python)`);
|
|
805
826
|
continue;
|
|
806
827
|
}
|
|
807
828
|
|
|
829
|
+
if (flags.target === 'bun') {
|
|
830
|
+
const tempFile = resolve(`.naide_tmp_${basename(file, ext)}.mjs`);
|
|
831
|
+
writeFileSync(tempFile, outputCode, 'utf-8');
|
|
832
|
+
console.log(`[NAIDE] Running with Bun — ${file}`);
|
|
833
|
+
const bunChild = spawn('bun', ['run', tempFile], { stdio: 'inherit', shell: true });
|
|
834
|
+
bunChild.on('close', (code) => {
|
|
835
|
+
try { unlinkSync(tempFile); } catch {}
|
|
836
|
+
process.exit(code || 0);
|
|
837
|
+
});
|
|
838
|
+
await new Promise(() => {});
|
|
839
|
+
}
|
|
840
|
+
|
|
808
841
|
// Run mode
|
|
809
842
|
const tempFile = resolve(`.naide_tmp_${basename(file, ext)}.mjs`);
|
|
810
843
|
writeFileSync(tempFile, result.js, 'utf-8');
|
package/lsp/server.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { compile } from '../src/index.js';
|
|
2
2
|
|
|
3
3
|
const documents = new Map();
|
|
4
|
+
const symbolIndex = new Map();
|
|
4
5
|
let buffer = '';
|
|
5
6
|
|
|
6
7
|
process.stdin.setEncoding('utf-8');
|
|
@@ -37,6 +38,8 @@ function handleMessage(msg) {
|
|
|
37
38
|
textDocumentSync: 1,
|
|
38
39
|
completionProvider: { triggerCharacters: ['.', '"'] },
|
|
39
40
|
hoverProvider: true,
|
|
41
|
+
definitionProvider: true,
|
|
42
|
+
referencesProvider: true,
|
|
40
43
|
}
|
|
41
44
|
});
|
|
42
45
|
break;
|
|
@@ -68,6 +71,14 @@ function handleMessage(msg) {
|
|
|
68
71
|
respond(msg.id, getHover(msg.params));
|
|
69
72
|
break;
|
|
70
73
|
|
|
74
|
+
case 'textDocument/definition':
|
|
75
|
+
respond(msg.id, getDefinition(msg.params));
|
|
76
|
+
break;
|
|
77
|
+
|
|
78
|
+
case 'textDocument/references':
|
|
79
|
+
respond(msg.id, getReferences(msg.params));
|
|
80
|
+
break;
|
|
81
|
+
|
|
71
82
|
case 'shutdown':
|
|
72
83
|
respond(msg.id, null);
|
|
73
84
|
break;
|
|
@@ -133,9 +144,138 @@ function validateDocument(uri) {
|
|
|
133
144
|
});
|
|
134
145
|
}
|
|
135
146
|
|
|
147
|
+
indexSymbols(uri, text);
|
|
136
148
|
notify('textDocument/publishDiagnostics', { uri, diagnostics });
|
|
137
149
|
}
|
|
138
150
|
|
|
151
|
+
function indexSymbols(uri, text) {
|
|
152
|
+
const symbols = { definitions: new Map(), references: new Map() };
|
|
153
|
+
const lines = text.split('\n');
|
|
154
|
+
|
|
155
|
+
for (let i = 0; i < lines.length; i++) {
|
|
156
|
+
const line = lines[i];
|
|
157
|
+
const trimmed = line.trimStart();
|
|
158
|
+
|
|
159
|
+
const fnMatch = trimmed.match(/^(?:pub\s+)?(?:fn\.async|fn)\s+(\w+)\s*\(/);
|
|
160
|
+
if (fnMatch) {
|
|
161
|
+
const name = fnMatch[1];
|
|
162
|
+
const col = line.indexOf(name);
|
|
163
|
+
symbols.definitions.set(name, { line: i, col, kind: 'function' });
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const varMatch = trimmed.match(/^(?:pub\s+)?(?:mut\s+)?(?:str|int|num|bool|list|map|any|json|void)\s+(\w+)\s*=/);
|
|
167
|
+
if (varMatch) {
|
|
168
|
+
const name = varMatch[1];
|
|
169
|
+
const col = line.indexOf(name);
|
|
170
|
+
symbols.definitions.set(name, { line: i, col, kind: 'variable' });
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const modelMatch = trimmed.match(/^model\s+(\w+)/);
|
|
174
|
+
if (modelMatch) {
|
|
175
|
+
const name = modelMatch[1];
|
|
176
|
+
const col = line.indexOf(name);
|
|
177
|
+
symbols.definitions.set(name, { line: i, col, kind: 'class' });
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const schemaMatch = trimmed.match(/^schema\s+(\w+)/);
|
|
181
|
+
if (schemaMatch) {
|
|
182
|
+
const name = schemaMatch[1];
|
|
183
|
+
const col = line.indexOf(name);
|
|
184
|
+
symbols.definitions.set(name, { line: i, col, kind: 'schema' });
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const promptMatch = trimmed.match(/^prompt\s+(\w+)/);
|
|
188
|
+
if (promptMatch) {
|
|
189
|
+
const name = promptMatch[1];
|
|
190
|
+
const col = line.indexOf(name);
|
|
191
|
+
symbols.definitions.set(name, { line: i, col, kind: 'prompt' });
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
for (const def of symbols.definitions.keys()) {
|
|
195
|
+
const re = new RegExp(`\\b${def}\\b`, 'g');
|
|
196
|
+
let m;
|
|
197
|
+
while ((m = re.exec(line)) !== null) {
|
|
198
|
+
if (i === symbols.definitions.get(def)?.line && m.index === symbols.definitions.get(def)?.col) continue;
|
|
199
|
+
if (!symbols.references.has(def)) symbols.references.set(def, []);
|
|
200
|
+
symbols.references.get(def).push({ line: i, col: m.index });
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
symbolIndex.set(uri, symbols);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function getWordAtPosition(text, line, col) {
|
|
209
|
+
const lines = text.split('\n');
|
|
210
|
+
if (line >= lines.length) return null;
|
|
211
|
+
const lineText = lines[line];
|
|
212
|
+
let start = col, end = col;
|
|
213
|
+
while (start > 0 && /\w/.test(lineText[start - 1])) start--;
|
|
214
|
+
while (end < lineText.length && /\w/.test(lineText[end])) end++;
|
|
215
|
+
return lineText.slice(start, end) || null;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function getDefinition(params) {
|
|
219
|
+
const uri = params.textDocument.uri;
|
|
220
|
+
const text = documents.get(uri);
|
|
221
|
+
if (!text) return null;
|
|
222
|
+
|
|
223
|
+
const word = getWordAtPosition(text, params.position.line, params.position.character);
|
|
224
|
+
if (!word) return null;
|
|
225
|
+
|
|
226
|
+
const symbols = symbolIndex.get(uri);
|
|
227
|
+
if (!symbols) return null;
|
|
228
|
+
|
|
229
|
+
const def = symbols.definitions.get(word);
|
|
230
|
+
if (!def) return null;
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
uri,
|
|
234
|
+
range: {
|
|
235
|
+
start: { line: def.line, character: def.col },
|
|
236
|
+
end: { line: def.line, character: def.col + word.length },
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function getReferences(params) {
|
|
242
|
+
const uri = params.textDocument.uri;
|
|
243
|
+
const text = documents.get(uri);
|
|
244
|
+
if (!text) return [];
|
|
245
|
+
|
|
246
|
+
const word = getWordAtPosition(text, params.position.line, params.position.character);
|
|
247
|
+
if (!word) return [];
|
|
248
|
+
|
|
249
|
+
const symbols = symbolIndex.get(uri);
|
|
250
|
+
if (!symbols) return [];
|
|
251
|
+
|
|
252
|
+
const results = [];
|
|
253
|
+
|
|
254
|
+
const def = symbols.definitions.get(word);
|
|
255
|
+
if (def) {
|
|
256
|
+
results.push({
|
|
257
|
+
uri,
|
|
258
|
+
range: {
|
|
259
|
+
start: { line: def.line, character: def.col },
|
|
260
|
+
end: { line: def.line, character: def.col + word.length },
|
|
261
|
+
},
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const refs = symbols.references.get(word) || [];
|
|
266
|
+
for (const ref of refs) {
|
|
267
|
+
results.push({
|
|
268
|
+
uri,
|
|
269
|
+
range: {
|
|
270
|
+
start: { line: ref.line, character: ref.col },
|
|
271
|
+
end: { line: ref.line, character: ref.col + word.length },
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return results;
|
|
277
|
+
}
|
|
278
|
+
|
|
139
279
|
function getCompletions() {
|
|
140
280
|
const keywords = [
|
|
141
281
|
'fn', 'ret', 'if', 'elif', 'else', 'each', 'for', 'while', 'match',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "naider",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "NAIDE - Node AI Development Environment. AI-specialized language with built-in server, auth, DB, SQL, AI/LLM, WebSocket, and more — transpiles to Node.js.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"exports": {
|