naidejs 1.2.0 → 1.4.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 +382 -229
- package/SPEC-X.nx +23 -1
- package/SPEC.naide +56 -0
- package/bin/naide.js +99 -2
- package/package.json +1 -1
- package/src/generator.js +199 -0
- package/src/index.js +26 -8
- package/src/lexer.js +17 -4
- package/src/parser.js +216 -24
- package/src/preprocess.js +3 -0
- package/src/runtime.js +258 -0
- package/src/tokens.js +24 -0
package/README.md
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
# NAIDE
|
|
2
2
|
|
|
3
|
-
**Node AI Development Environment** — A language designed for AI-speed code generation that transpiles to Node.js.
|
|
3
|
+
**Node AI Development Environment** — A programming language designed for AI-speed code generation that transpiles to Node.js.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
NAIDE is built on three principles: one way to write everything (zero ambiguity), keyword-driven intent (the first token decides meaning), and minimal token count (fewer tokens = faster AI generation). It includes built-in declarations for servers, databases, authentication, file uploads, WebSockets, job queues, testing, and more — all with zero external dependencies.
|
|
6
|
+
|
|
7
|
+
Two syntax modes:
|
|
8
|
+
|
|
9
|
+
- **NAIDE** (`.naide`) — Human-readable, ~40% fewer tokens than JavaScript
|
|
10
|
+
- **NAIDE-X** (`.nx`) — AI-only readability, ~80% fewer tokens than JavaScript
|
|
8
11
|
|
|
9
12
|
## Install
|
|
10
13
|
|
|
@@ -12,124 +15,310 @@ Two modes:
|
|
|
12
15
|
npm install -g naidejs
|
|
13
16
|
```
|
|
14
17
|
|
|
15
|
-
##
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Create a new project
|
|
22
|
+
naide init my-app
|
|
23
|
+
cd my-app
|
|
24
|
+
npm install
|
|
25
|
+
npm run dev
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or write a file directly:
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
# app.naide
|
|
32
|
+
server app port 3000:
|
|
33
|
+
get "/":
|
|
34
|
+
ret {message: "Hello from NAIDE"}
|
|
35
|
+
```
|
|
16
36
|
|
|
17
37
|
```bash
|
|
18
|
-
# Run a file
|
|
19
38
|
naide app.naide
|
|
20
|
-
|
|
39
|
+
```
|
|
21
40
|
|
|
22
|
-
|
|
23
|
-
naide -w app.naide
|
|
41
|
+
## CLI
|
|
24
42
|
|
|
25
|
-
|
|
26
|
-
naide
|
|
43
|
+
```bash
|
|
44
|
+
naide <file> # Run a .naide or .nx file
|
|
45
|
+
naide init [dir] # Scaffold a new project
|
|
46
|
+
naide build [dir] [outdir] # Transpile all files to JavaScript
|
|
47
|
+
naide -w <file> # Watch mode (auto-restart on changes)
|
|
48
|
+
naide --emit <file> # Print generated JavaScript
|
|
49
|
+
naide -o <out.js> <file> # Write JavaScript to file
|
|
50
|
+
naide --mid <file.nx> # Show intermediate NAIDE v1 (debug X mode)
|
|
51
|
+
naide --ast <file> # Print AST
|
|
52
|
+
naide --tokens <file> # Print token stream
|
|
53
|
+
```
|
|
27
54
|
|
|
28
|
-
|
|
29
|
-
naide -o app.js app.nx
|
|
55
|
+
## Language Reference
|
|
30
56
|
|
|
31
|
-
|
|
32
|
-
|
|
57
|
+
### Variables
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
str name = "hello" # immutable (const)
|
|
61
|
+
int count = 42
|
|
62
|
+
num price = 9.99
|
|
63
|
+
bool active = true
|
|
64
|
+
list items = [1, 2, 3]
|
|
65
|
+
map config = {host: "localhost"}
|
|
66
|
+
any data = null
|
|
67
|
+
|
|
68
|
+
mut int counter = 0 # mutable (let)
|
|
69
|
+
mut str label = "init"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Types: `str`, `int`, `num`, `bool`, `list`, `map`, `any`, `json`, `void`
|
|
73
|
+
|
|
74
|
+
### String Interpolation
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
str greeting = "Hello {name}, you have {count} items"
|
|
33
78
|
```
|
|
34
79
|
|
|
35
|
-
|
|
80
|
+
Double-quoted strings with `{expr}` are auto-interpolated.
|
|
36
81
|
|
|
37
|
-
|
|
82
|
+
### Functions
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
fn add(int a, int b) -> int:
|
|
86
|
+
ret a + b
|
|
87
|
+
|
|
88
|
+
fn greet(str name, str prefix = "Hello"):
|
|
89
|
+
log "{prefix}, {name}!"
|
|
90
|
+
|
|
91
|
+
fn sum(...int nums) -> int:
|
|
92
|
+
mut int total = 0
|
|
93
|
+
each n in nums:
|
|
94
|
+
total += n
|
|
95
|
+
ret total
|
|
96
|
+
|
|
97
|
+
fn.async fetchUser(str id) -> map:
|
|
98
|
+
any res = await fetch("/api/users/{id}")
|
|
99
|
+
ret await res.json()
|
|
100
|
+
```
|
|
38
101
|
|
|
39
|
-
###
|
|
102
|
+
### Control Flow
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
if count > 10:
|
|
106
|
+
log "many"
|
|
107
|
+
elif count > 5:
|
|
108
|
+
log "some"
|
|
109
|
+
else:
|
|
110
|
+
log "few"
|
|
111
|
+
|
|
112
|
+
str size = if count > 10 then "big" else "small"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Loops
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
each item in items:
|
|
119
|
+
log item
|
|
120
|
+
|
|
121
|
+
each key, val in config:
|
|
122
|
+
log "{key}: {val}"
|
|
123
|
+
|
|
124
|
+
for i in 0..10:
|
|
125
|
+
log i
|
|
126
|
+
|
|
127
|
+
while active:
|
|
128
|
+
log "running"
|
|
129
|
+
active = false
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Pattern Matching
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
match status:
|
|
136
|
+
"ok": log "success"
|
|
137
|
+
"error": log "failed"
|
|
138
|
+
_: log "unknown"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Error Handling
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
try:
|
|
145
|
+
data = await fetchData(url)
|
|
146
|
+
fail e:
|
|
147
|
+
log.error e.message
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Classes
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
model User:
|
|
154
|
+
str name
|
|
155
|
+
str email
|
|
156
|
+
int age = 0
|
|
157
|
+
|
|
158
|
+
fn greet() -> str:
|
|
159
|
+
ret "Hi, I'm {self.name}"
|
|
160
|
+
|
|
161
|
+
model Admin extends User:
|
|
162
|
+
str role = "admin"
|
|
163
|
+
fn permissions() -> list:
|
|
164
|
+
ret ["read", "write", "delete"]
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Pipe Operator
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
list result = data
|
|
171
|
+
|> filter((x) => x.active)
|
|
172
|
+
|> map((x) => x.name)
|
|
173
|
+
|> sort()
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Imports / Exports
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
use express
|
|
180
|
+
use {readFile, writeFile} from "fs/promises"
|
|
181
|
+
use axios from "axios"
|
|
182
|
+
|
|
183
|
+
pub fn helper() -> str:
|
|
184
|
+
ret "exported"
|
|
185
|
+
pub str VERSION = "1.0.0"
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Server & API Features
|
|
189
|
+
|
|
190
|
+
All features below are zero-dependency — the runtime is bundled with the package.
|
|
191
|
+
|
|
192
|
+
### server — Express App
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
server app port 3000:
|
|
196
|
+
get "/":
|
|
197
|
+
ret {message: "hello"}
|
|
198
|
+
post "/api/data" (req, res):
|
|
199
|
+
ret req.body
|
|
200
|
+
put "/api/data/:id" (req, res):
|
|
201
|
+
ret {updated: true}
|
|
202
|
+
del "/api/data/:id":
|
|
203
|
+
ret {deleted: true}
|
|
204
|
+
patch "/api/data/:id" (req, res):
|
|
205
|
+
ret {patched: true}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### schema — Data Models
|
|
40
209
|
|
|
41
210
|
```python
|
|
42
211
|
schema User:
|
|
43
|
-
id
|
|
44
|
-
name
|
|
45
|
-
email
|
|
46
|
-
age
|
|
47
|
-
role
|
|
48
|
-
joined
|
|
212
|
+
id auto
|
|
213
|
+
name str required min(2) max(50)
|
|
214
|
+
email str required email unique
|
|
215
|
+
age int optional min(0) max(150)
|
|
216
|
+
role enum("admin", "user") default("user")
|
|
217
|
+
joined timestamp auto
|
|
49
218
|
```
|
|
50
219
|
|
|
51
220
|
Types: `str`, `int`, `num`, `bool`, `auto` (UUID), `timestamp`, `enum(...)`
|
|
52
221
|
Modifiers: `required`, `optional`, `min(n)`, `max(n)`, `email`, `url`, `unique`, `auto`, `default(val)`
|
|
53
222
|
|
|
54
|
-
### db — Persistent
|
|
223
|
+
### db — Persistent Storage
|
|
55
224
|
|
|
56
225
|
```python
|
|
57
226
|
db "data/"
|
|
58
227
|
```
|
|
59
228
|
|
|
60
|
-
|
|
229
|
+
Schemas auto-persist to JSON files (`data/User.json`, etc.). Without `db`, data is in-memory only.
|
|
61
230
|
|
|
62
|
-
### crud — Auto-
|
|
231
|
+
### crud — Auto-generated REST Endpoints
|
|
63
232
|
|
|
64
233
|
```python
|
|
65
234
|
server app port 3000:
|
|
66
235
|
crud "/api/users" User
|
|
67
236
|
```
|
|
68
237
|
|
|
69
|
-
Generates GET (list + by
|
|
238
|
+
Generates GET (list + by-ID), POST, PUT, DELETE with validation. Built-in pagination, search, and sort:
|
|
70
239
|
|
|
71
|
-
**Built-in pagination, search, and sort:**
|
|
72
240
|
```
|
|
73
|
-
GET /api/users
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
241
|
+
GET /api/users?page=2&limit=10&q=john&sort=name&order=asc
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Response: `{ data: [...], total, page, limit, pages }`
|
|
245
|
+
|
|
246
|
+
### validate — Request Validation
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
server app port 3000:
|
|
250
|
+
validate "/api/users" User
|
|
251
|
+
post "/api/users" (req, res):
|
|
252
|
+
user = UserStore.create(req.body) # body is pre-validated
|
|
253
|
+
ret user
|
|
77
254
|
```
|
|
78
255
|
|
|
79
|
-
|
|
256
|
+
Auto-validates POST/PUT/PATCH bodies against the schema. Returns `400` with error details if invalid. Validated data replaces `req.body`.
|
|
80
257
|
|
|
81
|
-
### auth — JWT
|
|
258
|
+
### auth — JWT Authentication
|
|
82
259
|
|
|
83
260
|
```python
|
|
84
261
|
server app port 3000:
|
|
85
262
|
auth JWT_SECRET:
|
|
86
263
|
protect "/api/*"
|
|
87
264
|
public "/api/auth/*"
|
|
265
|
+
|
|
266
|
+
post "/api/auth/login" (req, res):
|
|
267
|
+
token = auth.sign({id: user.id})
|
|
268
|
+
ret {token}
|
|
88
269
|
```
|
|
89
270
|
|
|
90
|
-
|
|
271
|
+
### cors / limit / cookie / session
|
|
91
272
|
|
|
92
|
-
**Signing tokens in routes:**
|
|
93
273
|
```python
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
274
|
+
server app port 3000:
|
|
275
|
+
cors "*" # CORS middleware
|
|
276
|
+
limit "/api/*" 100 "1m" # rate limiting (100 req/min)
|
|
277
|
+
cookie # cookie parser → req.cookies
|
|
278
|
+
session "my-secret" # cookie sessions → req.session
|
|
97
279
|
```
|
|
98
280
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
### Password hashing
|
|
281
|
+
### upload — File Uploads
|
|
102
282
|
|
|
103
283
|
```python
|
|
104
|
-
|
|
105
|
-
|
|
284
|
+
server app port 3000:
|
|
285
|
+
upload "/api/upload" "avatar" (req, res):
|
|
286
|
+
ret {filename: req.file.filename, size: req.file.size}
|
|
106
287
|
```
|
|
107
288
|
|
|
108
|
-
Zero-dependency
|
|
289
|
+
Zero-dependency multipart parser. `req.file` = `{filename, contentType, data, size}`.
|
|
109
290
|
|
|
110
|
-
###
|
|
291
|
+
### view — Template Rendering
|
|
111
292
|
|
|
112
293
|
```python
|
|
113
294
|
server app port 3000:
|
|
114
|
-
|
|
115
|
-
|
|
295
|
+
view "./views"
|
|
296
|
+
get "/":
|
|
297
|
+
ret.render "home" {title: "Welcome", items: ["a", "b"]}
|
|
116
298
|
```
|
|
117
299
|
|
|
118
|
-
|
|
300
|
+
Reads `.html` files with `{{variable}}`, `{{if key}}...{{/if}}`, `{{each item in list}}...{{/each}}`.
|
|
301
|
+
|
|
302
|
+
### sse — Server-Sent Events
|
|
119
303
|
|
|
120
304
|
```python
|
|
121
305
|
server app port 3000:
|
|
122
|
-
|
|
306
|
+
sse "/events"
|
|
307
|
+
post "/api/notify" (req, res):
|
|
308
|
+
sse.broadcast req.body
|
|
309
|
+
ret {ok: true}
|
|
123
310
|
```
|
|
124
311
|
|
|
125
|
-
|
|
312
|
+
`sse.send(data)`, `sse.broadcast(data)`, `sse.count`.
|
|
313
|
+
|
|
314
|
+
### cache — Response Caching
|
|
126
315
|
|
|
127
316
|
```python
|
|
128
317
|
server app port 3000:
|
|
129
|
-
|
|
318
|
+
cache "/api/*" "5m"
|
|
130
319
|
```
|
|
131
320
|
|
|
132
|
-
|
|
321
|
+
Caches GET responses in memory with TTL. Sets `X-Cache: HIT/MISS`.
|
|
133
322
|
|
|
134
323
|
### ws — WebSocket
|
|
135
324
|
|
|
@@ -144,9 +333,9 @@ server app port 3000:
|
|
|
144
333
|
log "client left"
|
|
145
334
|
```
|
|
146
335
|
|
|
147
|
-
Built-in `send(data)` and `broadcast(data)
|
|
336
|
+
Built-in `send(data)` and `broadcast(data)`. Requires `npm install ws`.
|
|
148
337
|
|
|
149
|
-
### group — Route
|
|
338
|
+
### group — Route Groups
|
|
150
339
|
|
|
151
340
|
```python
|
|
152
341
|
server app port 3000:
|
|
@@ -157,101 +346,140 @@ server app port 3000:
|
|
|
157
346
|
ret req.body
|
|
158
347
|
```
|
|
159
348
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
### cookie — Cookie parsing
|
|
349
|
+
### mid — Named Middleware
|
|
163
350
|
|
|
164
351
|
```python
|
|
352
|
+
fn logger(req, res, next):
|
|
353
|
+
log req.method, req.url
|
|
354
|
+
next()
|
|
355
|
+
|
|
165
356
|
server app port 3000:
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
str theme = req.cookies.theme
|
|
169
|
-
ret {theme}
|
|
357
|
+
mid logger # apply globally
|
|
358
|
+
mid logger "/api" # apply to path only
|
|
170
359
|
```
|
|
171
360
|
|
|
172
|
-
|
|
361
|
+
### static — Serve Files
|
|
173
362
|
|
|
174
|
-
|
|
363
|
+
```python
|
|
364
|
+
server app port 3000:
|
|
365
|
+
static "/public"
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### error — Error Handler
|
|
175
369
|
|
|
176
370
|
```python
|
|
177
371
|
server app port 3000:
|
|
178
|
-
get "/":
|
|
179
|
-
ret {ok: true}
|
|
180
372
|
error (err, req, res):
|
|
181
373
|
log.error err.message
|
|
182
374
|
ret.status 500 {error: "Internal error"}
|
|
183
375
|
```
|
|
184
376
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
### api — HTTP client
|
|
377
|
+
### openapi — Auto-Generated API Docs
|
|
188
378
|
|
|
189
379
|
```python
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
380
|
+
server app port 3000:
|
|
381
|
+
openapi "/docs"
|
|
382
|
+
```
|
|
193
383
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
384
|
+
Generates an OpenAPI 3.1 JSON spec from your schemas, served at the specified path.
|
|
385
|
+
|
|
386
|
+
### Response Helpers
|
|
387
|
+
|
|
388
|
+
```python
|
|
389
|
+
ret {data: items} # JSON (default)
|
|
390
|
+
ret.status 404 {error: "nope"} # status code
|
|
391
|
+
ret.redirect "/login" # redirect
|
|
392
|
+
ret.html "<h1>Hello</h1>" # HTML
|
|
393
|
+
ret.text "pong" # plain text
|
|
394
|
+
ret.file "/path/to/file" # send file
|
|
395
|
+
ret.render "template" {data} # render template (requires view)
|
|
197
396
|
```
|
|
198
397
|
|
|
199
|
-
|
|
200
|
-
Zero-dependency — uses Node.js 18+ built-in `fetch`. Auto-imported when used.
|
|
398
|
+
## Testing
|
|
201
399
|
|
|
202
|
-
|
|
400
|
+
Built-in test syntax using Node.js test runner:
|
|
203
401
|
|
|
204
402
|
```python
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
403
|
+
test "user creation":
|
|
404
|
+
user = UserStore.create({name: "Alice", email: "alice@test.com"})
|
|
405
|
+
assert user.name == "Alice"
|
|
406
|
+
assert user.email == "alice@test.com"
|
|
407
|
+
|
|
408
|
+
test "math":
|
|
409
|
+
assert 1 + 1 == 2
|
|
410
|
+
assert 10 > 5
|
|
209
411
|
```
|
|
210
412
|
|
|
211
|
-
|
|
413
|
+
`assert a == b` generates `assert.strictEqual` for better error messages. Run with `node --test`.
|
|
212
414
|
|
|
213
|
-
|
|
415
|
+
## Job Queue
|
|
416
|
+
|
|
417
|
+
In-memory async job queue for background processing:
|
|
418
|
+
|
|
419
|
+
```python
|
|
420
|
+
queue jobs:
|
|
421
|
+
job "sendEmail" (data):
|
|
422
|
+
log "sending to {data.to}"
|
|
423
|
+
job "resize" (data):
|
|
424
|
+
log "resizing {data.path}"
|
|
425
|
+
|
|
426
|
+
server app port 3000:
|
|
427
|
+
post "/api/notify" (req, res):
|
|
428
|
+
jobs.add("sendEmail", {to: req.body.email})
|
|
429
|
+
ret {queued: true}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## Scheduled Tasks & Events
|
|
214
433
|
|
|
215
434
|
```python
|
|
216
435
|
every "5m":
|
|
217
436
|
log "cleanup running"
|
|
437
|
+
|
|
438
|
+
watch User.create (event):
|
|
439
|
+
log "new user: {event.data.name}"
|
|
218
440
|
```
|
|
219
441
|
|
|
220
|
-
Intervals: `"30s"`, `"5m"`, `"1h"`, `"1d"
|
|
442
|
+
Intervals: `"30s"`, `"5m"`, `"1h"`, `"1d"`.
|
|
443
|
+
`watch` connects to `crud` events automatically.
|
|
221
444
|
|
|
222
|
-
|
|
445
|
+
## Environment Variables
|
|
223
446
|
|
|
224
447
|
```python
|
|
225
|
-
|
|
226
|
-
|
|
448
|
+
env:
|
|
449
|
+
PORT int default(3000)
|
|
450
|
+
JWT_SECRET str required
|
|
451
|
+
DB_URL str default("data/")
|
|
227
452
|
```
|
|
228
453
|
|
|
229
|
-
|
|
454
|
+
Variables become constants. Missing `required` vars exit with an error.
|
|
230
455
|
|
|
231
|
-
|
|
456
|
+
## Built-in Functions
|
|
232
457
|
|
|
233
458
|
```python
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
ret.file "/path/to/file" # send file
|
|
459
|
+
str id = uuid() # UUID
|
|
460
|
+
str hashed = hash("password") # scrypt hash
|
|
461
|
+
bool ok = verify("password", hashed) # timing-safe verify
|
|
462
|
+
str token = sign({id: 1}) # JWT (uses auth secret)
|
|
463
|
+
str token = sign({id: 1}, "my-secret") # JWT (explicit secret)
|
|
240
464
|
```
|
|
241
465
|
|
|
242
|
-
|
|
466
|
+
Auto-imported from the runtime when used.
|
|
467
|
+
|
|
468
|
+
## HTTP Client
|
|
243
469
|
|
|
244
470
|
```python
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
471
|
+
fn.async getUsers() -> any:
|
|
472
|
+
any users = await api.get("https://api.example.com/users")
|
|
473
|
+
ret users
|
|
474
|
+
|
|
475
|
+
fn.async createUser(map data) -> any:
|
|
476
|
+
any result = await api.post("https://api.example.com/users", data)
|
|
477
|
+
ret result
|
|
250
478
|
```
|
|
251
479
|
|
|
252
|
-
|
|
480
|
+
Methods: `api.get(url)`, `api.post(url, body)`, `api.put(url, body)`, `api.del(url)`, `api.raw(url, opts)`.
|
|
253
481
|
|
|
254
|
-
|
|
482
|
+
## Full Example
|
|
255
483
|
|
|
256
484
|
```python
|
|
257
485
|
db "data/"
|
|
@@ -266,24 +494,29 @@ schema User:
|
|
|
266
494
|
email str required email
|
|
267
495
|
password str required
|
|
268
496
|
|
|
497
|
+
queue jobs:
|
|
498
|
+
job "welcome" (data):
|
|
499
|
+
log "Welcome email to {data.email}"
|
|
500
|
+
|
|
269
501
|
server app port PORT:
|
|
270
502
|
cors "*"
|
|
271
503
|
cookie
|
|
504
|
+
session JWT_SECRET
|
|
272
505
|
auth JWT_SECRET:
|
|
273
506
|
protect "/api/*"
|
|
274
507
|
public "/api/auth/*"
|
|
275
508
|
limit "/api/*" 100 "1m"
|
|
276
509
|
static "/public"
|
|
510
|
+
cache "/api/users" "1m"
|
|
511
|
+
validate "/api/users" User
|
|
277
512
|
crud "/api/users" User
|
|
278
|
-
|
|
279
|
-
group "/api/v1":
|
|
280
|
-
get "/status":
|
|
281
|
-
ret {version: "1.0"}
|
|
513
|
+
openapi "/docs"
|
|
282
514
|
|
|
283
515
|
post "/api/auth/register" (req, res):
|
|
284
516
|
str hashed = hash(req.body.password)
|
|
285
517
|
user = UserStore.create({...req.body, password: hashed})
|
|
286
518
|
token = auth.sign({id: user.id})
|
|
519
|
+
jobs.add("welcome", {email: user.email})
|
|
287
520
|
ret {token, user}
|
|
288
521
|
|
|
289
522
|
post "/api/auth/login" (req, res):
|
|
@@ -299,6 +532,8 @@ server app port PORT:
|
|
|
299
532
|
on "message" (data):
|
|
300
533
|
broadcast(data)
|
|
301
534
|
|
|
535
|
+
sse "/events"
|
|
536
|
+
|
|
302
537
|
get "/":
|
|
303
538
|
ret.html "<h1>Welcome</h1>"
|
|
304
539
|
|
|
@@ -308,130 +543,47 @@ server app port PORT:
|
|
|
308
543
|
|
|
309
544
|
watch User.create (event):
|
|
310
545
|
log "new user: {event.data.name}"
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
This generates a complete production API with persistent storage, auth, password hashing, CORS, cookies, rate limiting, CRUD with pagination/search, WebSocket, route groups, error handling, and static files — from ~45 lines.
|
|
314
|
-
|
|
315
|
-
## NAIDE syntax (.naide)
|
|
316
|
-
|
|
317
|
-
```python
|
|
318
|
-
# Variables with types
|
|
319
|
-
str name = "World"
|
|
320
|
-
int count = 3
|
|
321
|
-
mut int counter = 0
|
|
322
|
-
|
|
323
|
-
# Functions
|
|
324
|
-
fn greet(str who) -> str:
|
|
325
|
-
ret "Hello, {who}!"
|
|
326
|
-
|
|
327
|
-
# Async
|
|
328
|
-
fn.async fetchData(str url) -> any:
|
|
329
|
-
ret await fetch(url)
|
|
330
|
-
|
|
331
|
-
# Control flow
|
|
332
|
-
if count > 5:
|
|
333
|
-
log "many"
|
|
334
|
-
elif count > 2:
|
|
335
|
-
log "some"
|
|
336
|
-
else:
|
|
337
|
-
log "few"
|
|
338
|
-
|
|
339
|
-
# Loops
|
|
340
|
-
each item in items:
|
|
341
|
-
log item
|
|
342
|
-
|
|
343
|
-
for i in 0..10:
|
|
344
|
-
log i
|
|
345
|
-
|
|
346
|
-
# Server (Express built-in)
|
|
347
|
-
server app port 3000:
|
|
348
|
-
get "/users":
|
|
349
|
-
ret users
|
|
350
|
-
post "/users" (req, res):
|
|
351
|
-
ret req.body
|
|
352
546
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
data = await fetchData(url)
|
|
356
|
-
fail e:
|
|
357
|
-
log.error e.message
|
|
358
|
-
|
|
359
|
-
# Classes
|
|
360
|
-
model User:
|
|
361
|
-
str name
|
|
362
|
-
int age = 0
|
|
363
|
-
fn greet() -> str:
|
|
364
|
-
ret "Hi {self.name}"
|
|
365
|
-
|
|
366
|
-
# Pipe operator
|
|
367
|
-
list result = data
|
|
368
|
-
|> filter((x) => x.active)
|
|
369
|
-
|> map((x) => x.name)
|
|
547
|
+
every "30m":
|
|
548
|
+
log "cleanup"
|
|
370
549
|
```
|
|
371
550
|
|
|
372
|
-
|
|
551
|
+
This generates a complete production API — auth, password hashing, CORS, sessions, rate limiting, CRUD with pagination/search, WebSocket, SSE, file caching, request validation, background jobs, auto-generated API docs, and event-driven hooks — from ~55 lines.
|
|
552
|
+
|
|
553
|
+
## NAIDE-X Syntax (.nx)
|
|
373
554
|
|
|
374
555
|
Every keyword is a single character. Line-start symbol = intent.
|
|
375
556
|
|
|
376
557
|
```
|
|
377
|
-
--
|
|
378
|
-
|
|
379
|
-
i:
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
--
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
--
|
|
391
|
-
|
|
392
|
-
log"
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
:
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
--
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
558
|
+
s:name="World" -- str name = "World"
|
|
559
|
+
i:count=42 -- int count = 42
|
|
560
|
+
~i:counter=0 -- mut int counter = 0
|
|
561
|
+
|
|
562
|
+
f greet(s:who)s -- fn greet(str who) -> str:
|
|
563
|
+
>"Hello, {who}!" -- ret "Hello, {who}!"
|
|
564
|
+
|
|
565
|
+
~f fetchData(s:url)a -- fn.async fetchData(str url) -> any:
|
|
566
|
+
>~fetch(url) -- ret await fetch(url)
|
|
567
|
+
|
|
568
|
+
?count>5 -- if count > 5:
|
|
569
|
+
log"many" -- log "many"
|
|
570
|
+
|count>2 -- elif count > 2:
|
|
571
|
+
log"some" -- log "some"
|
|
572
|
+
: -- else:
|
|
573
|
+
log"few" -- log "few"
|
|
574
|
+
|
|
575
|
+
@item<items -- each item in items:
|
|
576
|
+
@i<0..10 -- for i in 0..10:
|
|
577
|
+
*active -- while active:
|
|
578
|
+
|
|
579
|
+
$app:3000 -- server app port 3000:
|
|
580
|
+
G"/users" -- get "/users":
|
|
581
|
+
>users -- ret users
|
|
582
|
+
P"/users"(req,res) -- post "/users" (req, res):
|
|
583
|
+
>req.body -- ret req.body
|
|
584
|
+
```
|
|
403
585
|
|
|
404
|
-
|
|
405
|
-
$app:3000
|
|
406
|
-
cors "*"
|
|
407
|
-
auth SECRET:
|
|
408
|
-
protect "/api/*"
|
|
409
|
-
static "/public"
|
|
410
|
-
crud "/api/users" User
|
|
411
|
-
G"/users"
|
|
412
|
-
>users
|
|
413
|
-
P"/users"(req,res)
|
|
414
|
-
>req.body
|
|
415
|
-
G"/old"
|
|
416
|
-
>.r "/new"
|
|
417
|
-
G"/"
|
|
418
|
-
>.h "<h1>Hello</h1>"
|
|
419
|
-
|
|
420
|
-
-- Error handling
|
|
421
|
-
!
|
|
422
|
-
data=~fetchData(url)
|
|
423
|
-
!!e
|
|
424
|
-
log.e e.message
|
|
425
|
-
|
|
426
|
-
-- Model
|
|
427
|
-
^User
|
|
428
|
-
s:name
|
|
429
|
-
i:age=0
|
|
430
|
-
f greet()s
|
|
431
|
-
>"Hi {self.name}"
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
### NAIDE-X cheat sheet
|
|
586
|
+
### NAIDE-X Cheat Sheet
|
|
435
587
|
|
|
436
588
|
| Symbol | Meaning | Symbol | Meaning |
|
|
437
589
|
|--------|---------|--------|---------|
|
|
@@ -445,14 +597,15 @@ $app:3000
|
|
|
445
597
|
| `+` | export | `~` | await |
|
|
446
598
|
| `G` | GET | `P` | POST |
|
|
447
599
|
| `U` | PUT | `D` | DELETE |
|
|
448
|
-
|
|
|
449
|
-
| `>.
|
|
600
|
+
| `X` | PATCH | `>.s` | ret.status |
|
|
601
|
+
| `>.r` | ret.redirect | `>.h` | ret.html |
|
|
602
|
+
| `>.t` | ret.text | `>.v` | ret.render |
|
|
450
603
|
|
|
451
604
|
Types: `s`=str `i`=int `n`=num `b`=bool `l`=list `m`=map `a`=any
|
|
452
605
|
|
|
453
|
-
High-level: `schema`, `crud`, `auth`, `cors`, `limit`, `env`, `every`, `watch`, `static`, `ws`, `db`, `group`, `cookie`, `error`
|
|
606
|
+
High-level keywords work in both modes: `schema`, `crud`, `auth`, `cors`, `limit`, `env`, `every`, `watch`, `static`, `ws`, `db`, `group`, `cookie`, `error`, `session`, `upload`, `view`, `sse`, `cache`, `patch`, `validate`, `test`, `assert`, `queue`, `openapi`.
|
|
454
607
|
|
|
455
|
-
## Why?
|
|
608
|
+
## Why NAIDE?
|
|
456
609
|
|
|
457
610
|
AI code generation speed depends on:
|
|
458
611
|
|