naider 1.24.5 → 2.0.1

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/examples/async.nx DELETED
@@ -1,40 +0,0 @@
1
- -- NAIDE-X async/await
2
-
3
- ~f fetchData(s:url)a
4
- a:res=~fetch(url)
5
- a:data=~res.json()
6
- >data
7
-
8
- ~f getTopUsers()l
9
- a:data=~fetchData("https://jsonplaceholder.typicode.com/users")
10
- l:result=data
11
- |>filter((u)=>u.name.length>5)
12
- |>map((u)=>({name:u.name,email:u.email}))
13
- >result
14
-
15
- ~f safeFetch(s:url)m
16
- !
17
- a:data=~fetchData(url)
18
- >{ok:true,data:data}
19
- !!e
20
- log.e"Fetch failed: {e.message}"
21
- >{ok:false,error:e.message}
22
-
23
- ~f loadDash()m
24
- l:urls=[
25
- "https://jsonplaceholder.typicode.com/users",
26
- "https://jsonplaceholder.typicode.com/posts",
27
- "https://jsonplaceholder.typicode.com/todos"
28
- ]
29
- l:results=~~urls.map((url)=>fetchData(url))
30
- >{users:results[0],posts:results[1],todos:results[2]}
31
-
32
- ~f main()
33
- log"Fetching data..."
34
- m:dash=~safeFetch("https://jsonplaceholder.typicode.com/users")
35
- ?dash.ok
36
- log"Got {dash.data.length} items"
37
- :
38
- log.e dash.error
39
-
40
- main()
package/examples/crud.nx DELETED
@@ -1,64 +0,0 @@
1
- -- NAIDE-X full CRUD
2
-
3
- ^Todo
4
- s:id
5
- s:title
6
- b:done=false
7
- s:createdAt
8
-
9
- f toggle()
10
- self.done=not self.done
11
-
12
- f toJSON()m
13
- >{id:self.id,title:self.title,done:self.done,createdAt:self.createdAt}
14
-
15
- ~l:todos=[]
16
- ~i:nextId=1
17
-
18
- f findTodo(s:id)a
19
- @todo<todos
20
- ?todo.id==id
21
- >todo
22
- >null
23
-
24
- f genId()s
25
- s:id="todo_{nextId}"
26
- nextId+=1
27
- >id
28
-
29
- $app:8080
30
-
31
- G"/api/todos"
32
- >{todos:todos,count:todos.length}
33
-
34
- G"/api/todos/:id"(req,res)
35
- a:todo=findTodo(req.params.id)
36
- ?todo==null
37
- >.s 404 {error:"Todo not found"}
38
- >todo
39
-
40
- P"/api/todos"(req,res)
41
- m:body=req.body
42
- ?not body.title
43
- >.s 400 {error:"Title is required"}
44
- m:todo={id:genId(),title:body.title,done:false,createdAt:new Date().toISOString()}
45
- todos.push(todo)
46
- >.s 201 todo
47
-
48
- U"/api/todos/:id"(req,res)
49
- a:todo=findTodo(req.params.id)
50
- ?todo==null
51
- >.s 404 {error:"Todo not found"}
52
- m:body=req.body
53
- ?body.title
54
- todo.title=body.title
55
- ?body.done!=null
56
- todo.done=body.done
57
- >todo
58
-
59
- D"/api/todos/:id"(req,res)
60
- i:idx=todos.findIndex((t)=>t.id==req.params.id)
61
- ?idx==-1
62
- >.s 404 {error:"Todo not found"}
63
- todos.splice(idx,1)
64
- >{status:"deleted"}
@@ -1,74 +0,0 @@
1
- -- Full NAIDE-X app with all features
2
-
3
- db "data/"
4
-
5
- env:
6
- PORT int default(3000)
7
- JWT_SECRET str required
8
-
9
- schema User:
10
- id auto
11
- name str required min(2) max(50)
12
- email str required email
13
- password str required
14
- role str default("user")
15
-
16
- schema Todo:
17
- id auto
18
- title str required min(1)
19
- done bool default(false)
20
- created timestamp auto
21
-
22
- $app:PORT
23
- cors "*"
24
- cookie
25
- auth JWT_SECRET:
26
- protect "/api/*"
27
- public "/api/auth/*"
28
- limit "/api/*" 100 "1m"
29
- static "/public"
30
- crud "/api/users" User
31
- crud "/api/todos" Todo
32
-
33
- group "/api/v1":
34
- G"/status"
35
- >{version:"1.0",status:"ok"}
36
-
37
- P"/api/auth/register"(req,res)
38
- s:hashed=hash(req.body.password)
39
- user=UserStore.create({name:req.body.name,email:req.body.email,password:hashed})
40
- ?user.error
41
- >.s 400 {errors:user.error}
42
- token=auth.sign({id:user.id,role:user.role})
43
- >{token,user:{id:user.id,name:user.name,email:user.email}}
44
-
45
- P"/api/auth/login"(req,res)
46
- user=UserStore.where({email:req.body.email})[0]
47
- ?not user
48
- >.s 401 {error:"Invalid credentials"}
49
- ?not verify(req.body.password,user.password)
50
- >.s 401 {error:"Invalid credentials"}
51
- token=auth.sign({id:user.id,role:user.role})
52
- >{token}
53
-
54
- G"/health"
55
- >{status:"ok"}
56
-
57
- G"/"
58
- >.h "<h1>Welcome to NAIDE</h1>"
59
-
60
- ws "/chat":
61
- on "connect":
62
- send({type:"welcome"})
63
- on "message" (data):
64
- broadcast(data)
65
-
66
- error (err, req, res):
67
- log.error err.message
68
- >.s 500 {error:"Internal server error"}
69
-
70
- every "30m":
71
- log"cleanup running"
72
-
73
- watch User.create (event):
74
- log"new user: {event.data.name}"
package/examples/hello.nx DELETED
@@ -1,29 +0,0 @@
1
- -- NAIDE-X hello world
2
-
3
- s:name="World"
4
- i:count=3
5
-
6
- f greet(s:who)s
7
- >"Hello, {who}!"
8
-
9
- @i<0..count
10
- s:msg=greet(name)
11
- log msg
12
-
13
- ?count>5
14
- log"many"
15
- |count>2
16
- log"a few"
17
- :
18
- log"few"
19
-
20
- l:items=["apple","banana","cherry"]
21
-
22
- @fruit<items
23
- log"I like {fruit}"
24
-
25
- s:status="ok"
26
- %status
27
- "ok": log "All good"
28
- "error": log "Something went wrong"
29
- _: log "Unknown"
@@ -1,27 +0,0 @@
1
- -- NAIDE-X REST API server
2
-
3
- $app:3000
4
-
5
- G"/"
6
- >{message:"Welcome to NAIDE-X API"}
7
-
8
- G"/users"
9
- l:users=[
10
- {id:1,name:"Alice",age:30},
11
- {id:2,name:"Bob",age:25}
12
- ]
13
- >users
14
-
15
- G"/users/:id"(req,res)
16
- s:id=req.params.id
17
- >{id:id,name:"User {id}"}
18
-
19
- P"/users"(req,res)
20
- m:body=req.body
21
- log"Creating user: {body.name}"
22
- >{status:"created",user:body}
23
-
24
- D"/users/:id"(req,res)
25
- s:id=req.params.id
26
- log"Deleting user {id}"
27
- >{status:"deleted",id:id}
@@ -1,23 +0,0 @@
1
- -- SQLite-backed API (NAIDE-X)
2
- -- npm install better-sqlite3
3
-
4
- db.sql "sqlite" "app.db"
5
-
6
- env:
7
- PORT int default(3000)
8
-
9
- schema Task:
10
- id auto
11
- title str required min(1) max(200)
12
- done bool default(false)
13
-
14
- $app:PORT
15
- cors "*"
16
- crud "/api/tasks" Task
17
-
18
- U"/api/tasks/:id/toggle"(req,res)
19
- task=TaskStore.getById(req.params.id)
20
- ?not task
21
- >.s 404 {error:"Not found"}
22
- updated=TaskStore.update(req.params.id,{done:!task.done})
23
- >updated
@@ -1,31 +0,0 @@
1
- -- Todo API in NAIDE-X (~80% fewer tokens)
2
- -- Run: naide examples/todo-api.nx
3
-
4
- db "data/"
5
-
6
- env:
7
- PORT int default(3000)
8
-
9
- schema Todo:
10
- id auto
11
- title str required min(1) max(200)
12
- done bool default(false)
13
- created timestamp auto
14
-
15
- $app:PORT
16
- cors "*"
17
- cookie
18
- cache "/api/todos" "30s"
19
- validate "/api/todos" Todo
20
- crud "/api/todos" Todo
21
- openapi "/docs"
22
- G"/"
23
- >.h "<h1>Todo API</h1><p>GET /api/todos | /docs</p>"
24
- G"/api/stats"(req,res)
25
- l:all=TodoStore.all()
26
- i:total=all.length
27
- i:done=all.filter((t)=>t.done).length
28
- >{total,done,pending:total-done}
29
- error (err,req,res):
30
- log.e err.message
31
- >.s 500 {error:err.message}
package/src/preprocess.js DELETED
@@ -1,308 +0,0 @@
1
- const TYPE_MAP = { s: 'str', i: 'int', n: 'num', b: 'bool', l: 'list', m: 'map', a: 'any', j: 'json', v: 'void' };
2
- const TYPE_CHARS = new Set(Object.keys(TYPE_MAP));
3
-
4
- function expandType(ch) { return TYPE_MAP[ch] || ch; }
5
-
6
- function expandParams(paramStr) {
7
- if (!paramStr) return '';
8
- return paramStr.split(',').map(p => {
9
- p = p.trim();
10
- if (!p) return p;
11
- const m = p.match(/^(\.\.\.)?([ sinblmaj]):(.+)$/);
12
- if (m) return `${m[1] || ''}${expandType(m[2])} ${m[3]}`;
13
- const m2 = p.match(/^(\.\.\.)?([ sinblmaj])(\w+)$/);
14
- if (m2) return `${m2[1] || ''}${expandType(m2[2])} ${m2[3]}`;
15
- return p;
16
- }).join(', ');
17
- }
18
-
19
- function transformFunc(rest, isAsync, isPublic) {
20
- const pub = isPublic ? 'pub ' : '';
21
- const fn = isAsync ? 'fn.async' : 'fn';
22
- const nameM = rest.match(/^(\w+)/);
23
- if (!nameM) return `${pub}${fn} ${rest}:`;
24
- const name = nameM[1];
25
- let rem = rest.slice(name.length);
26
-
27
- let params = '';
28
- if (rem.startsWith('(')) {
29
- let depth = 1, i = 1;
30
- while (i < rem.length && depth > 0) {
31
- if (rem[i] === '(') depth++;
32
- if (rem[i] === ')') depth--;
33
- i++;
34
- }
35
- params = expandParams(rem.slice(1, i - 1));
36
- rem = rem.slice(i).trim();
37
- }
38
-
39
- let retType = '';
40
- if (rem.length > 0 && TYPE_CHARS.has(rem[0]) && (rem.length === 1 || !rem[1].match(/\w/))) {
41
- retType = ` -> ${expandType(rem[0])}`;
42
- }
43
-
44
- return `${pub}${fn} ${name}(${params})${retType}:`;
45
- }
46
-
47
- function transformRoute(method, rest) {
48
- const m = rest.match(/^("[^"]*")\s*(\[[^\]]*\])?\s*(\([^)]*\))?\s*(.*)$/);
49
- if (!m) return `${method} ${rest}:`;
50
- const path = m[1];
51
- const middleware = m[2] ? ` ${m[2]}` : '';
52
- const routeParams = m[3] ? ` ${m[3]}` : '';
53
- const inline = m[4] ? m[4].trim() : '';
54
-
55
- if (inline) {
56
- const body = transformContent(inline);
57
- return `${method} ${path}${middleware}${routeParams}:\n ${body}`;
58
- }
59
- return `${method} ${path}${middleware}${routeParams}:`;
60
- }
61
-
62
- function transformAwait(text) {
63
- // ~~ → await.all
64
- text = text.replace(/~~/g, 'await.all ');
65
- // ~ before identifier or ( → await (but not ~f, ~TYPE: which are handled at line level)
66
- text = text.replace(/~(\w)/g, (_, ch) => `await ${ch}`);
67
- text = text.replace(/~\(/g, 'await (');
68
- return text;
69
- }
70
-
71
- function transformContent(line) {
72
- // Log shorthands
73
- line = line.replace(/\blog\.e\b/g, 'log.error');
74
- line = line.replace(/\blog\.w\b/g, 'log.warn');
75
- line = line.replace(/\blog\.i\b/g, 'log.info');
76
- line = line.replace(/\blog\.d\b/g, 'log.debug');
77
- // log"msg" → log "msg"
78
- line = line.replace(/\blog"/g, 'log "');
79
- line = line.replace(/\blog\.error"/g, 'log.error "');
80
- line = line.replace(/\blog\.warn"/g, 'log.warn "');
81
- line = line.replace(/\blog\.info"/g, 'log.info "');
82
- line = line.replace(/\blog\.debug"/g, 'log.debug "');
83
- // Await transforms
84
- line = transformAwait(line);
85
- return line;
86
- }
87
-
88
- export function preprocess(source) {
89
- const lines = source.split('\n');
90
- const result = [];
91
-
92
- for (let raw of lines) {
93
- const indentM = raw.match(/^(\s*)/);
94
- const indent = indentM ? indentM[1] : '';
95
- let line = raw.slice(indent.length);
96
-
97
- // Empty line
98
- if (!line.trim()) { result.push(''); continue; }
99
-
100
- // Comment: -- → #
101
- if (line.startsWith('--')) { result.push(indent + '#' + line.slice(2)); continue; }
102
-
103
- // Keep # comments as-is
104
- if (line.startsWith('#') && !line.startsWith('#=')) { result.push(raw); continue; }
105
-
106
- const first = line[0];
107
- const second = line[1] || '';
108
- let out = '';
109
-
110
- // > return
111
- if (first === '>' && second !== '=' && second !== '>') {
112
- const rest = line.slice(1).trim();
113
- if (rest.startsWith('.s ') || rest.startsWith('.s(')) {
114
- out = 'ret.status ' + transformContent(rest.slice(3));
115
- } else if (rest.startsWith('.r ')) {
116
- out = 'ret.redirect ' + transformContent(rest.slice(3));
117
- } else if (rest.startsWith('.h ')) {
118
- out = 'ret.html ' + transformContent(rest.slice(3));
119
- } else if (rest.startsWith('.t ')) {
120
- out = 'ret.text ' + transformContent(rest.slice(3));
121
- } else if (rest.startsWith('.f ')) {
122
- out = 'ret.file ' + transformContent(rest.slice(3));
123
- } else if (rest.startsWith('.v ')) {
124
- out = 'ret.render ' + transformContent(rest.slice(3));
125
- } else if (rest.startsWith('.d ')) {
126
- out = 'ret.download ' + transformContent(rest.slice(3));
127
- } else {
128
- out = rest ? 'ret ' + transformContent(rest) : 'ret';
129
- }
130
- }
131
- // ? if
132
- else if (first === '?' && second !== '.' && second !== '?') {
133
- out = 'if ' + transformContent(line.slice(1).trim()) + ':';
134
- }
135
- // | elif (but not |>)
136
- else if (first === '|' && second !== '>') {
137
- out = 'elif ' + transformContent(line.slice(1).trim()) + ':';
138
- }
139
- // : else (alone on line)
140
- else if (line.trim() === ':') {
141
- out = 'else:';
142
- }
143
- // @ loop
144
- else if (first === '@') {
145
- const rest = line.slice(1);
146
- const loopM = rest.match(/^(\w+(?:,\w+)?)<(.+)$/);
147
- if (loopM) {
148
- const vars = loopM[1];
149
- const col = transformContent(loopM[2]);
150
- if (col.includes('..')) {
151
- const [start, end] = col.split('..');
152
- out = `for ${vars} in ${start}..${end}:`;
153
- } else if (vars.includes(',')) {
154
- const [k, v] = vars.split(',');
155
- out = `each ${k}, ${v} in ${col}:`;
156
- } else {
157
- out = `each ${vars} in ${col}:`;
158
- }
159
- } else {
160
- out = transformContent(line);
161
- }
162
- }
163
- // * while
164
- else if (first === '*') {
165
- out = 'while ' + transformContent(line.slice(1).trim()) + ':';
166
- }
167
- // !!! ensure/finally (before !! and ! checks)
168
- else if (first === '!' && second === '!' && (line[2] || '') === '!') {
169
- out = 'ensure:';
170
- }
171
- // !! catch (before ! try check)
172
- else if (first === '!' && second === '!') {
173
- const rest = line.slice(2).trim();
174
- out = rest ? `fail ${rest}:` : 'fail:';
175
- }
176
- // ! try (alone)
177
- else if (line.trim() === '!') {
178
- out = 'try:';
179
- }
180
- // $ server
181
- else if (first === '$') {
182
- const rest = line.slice(1);
183
- const srvM = rest.match(/^(\w+):(.+)$/);
184
- if (srvM) {
185
- out = `server ${srvM[1]} port ${transformContent(srvM[2].trim())}:`;
186
- } else {
187
- out = `server ${rest.trim()}:`;
188
- }
189
- }
190
- // HTTP routes: G P U D
191
- else if (first === 'G' && second === '"') { out = transformRoute('get', line.slice(1)); }
192
- else if (first === 'P' && second === '"') { out = transformRoute('post', line.slice(1)); }
193
- else if (first === 'U' && second === '"') { out = transformRoute('put', line.slice(1)); }
194
- else if (first === 'D' && second === '"') { out = transformRoute('del', line.slice(1)); }
195
- else if (first === 'X' && second === '"') { out = transformRoute('patch', line.slice(1)); }
196
- // ^ model
197
- else if (first === '^') {
198
- const rest = line.slice(1).trim();
199
- const extM = rest.match(/^(\w+)<(\w+)$/);
200
- if (extM) {
201
- out = `model ${extM[1]} extends ${extM[2]}:`;
202
- } else {
203
- out = `model ${rest}:`;
204
- }
205
- }
206
- // < import
207
- else if (first === '<') {
208
- const rest = line.slice(1);
209
- if (rest.startsWith('{')) {
210
- const impM = rest.match(/^\{([^}]+)\}"(.+)"$/);
211
- if (impM) {
212
- out = `use {${impM[1]}} from "${impM[2]}"`;
213
- } else {
214
- out = transformContent(line);
215
- }
216
- } else {
217
- const fromM = rest.match(/^(\w+)"(.+)"$/);
218
- if (fromM) {
219
- out = `use ${fromM[1]} from "${fromM[2]}"`;
220
- } else {
221
- out = `use ${rest.trim()}`;
222
- }
223
- }
224
- }
225
- // % match
226
- else if (first === '%') {
227
- out = 'match ' + transformContent(line.slice(1).trim()) + ':';
228
- }
229
- // + export prefix
230
- else if (first === '+') {
231
- const inner = line.slice(1);
232
- if (inner.startsWith('~f ')) {
233
- out = transformFunc(inner.slice(3), true, true);
234
- } else if (inner.startsWith('f ')) {
235
- out = transformFunc(inner.slice(2), false, true);
236
- } else {
237
- const tvM = inner.match(/^([sinblmaj]):(\w+)=(.+)$/);
238
- if (tvM) {
239
- out = `pub ${expandType(tvM[1])} ${tvM[2]} = ${transformContent(tvM[3])}`;
240
- } else {
241
- out = 'pub ' + transformContent(inner);
242
- }
243
- }
244
- }
245
- // ~f async function
246
- else if (first === '~' && second === 'f' && line[2] === ' ') {
247
- out = transformFunc(line.slice(3), true, false);
248
- }
249
- // ~TYPE:name=value → mutable
250
- else if (first === '~' && TYPE_CHARS.has(second) && line[2] === ':') {
251
- const rest = line.slice(1);
252
- const tvM = rest.match(/^([sinblmaj]):(\w+)=(.+)$/);
253
- if (tvM) {
254
- out = `mut ${expandType(tvM[1])} ${tvM[2]} = ${transformContent(tvM[3])}`;
255
- } else {
256
- // Mutable field without assignment: ~s:name
257
- const fieldM = rest.match(/^([sinblmaj]):(\w+)$/);
258
- if (fieldM) {
259
- out = `mut ${expandType(fieldM[1])} ${fieldM[2]}`;
260
- } else {
261
- out = transformContent(line);
262
- }
263
- }
264
- }
265
- // f function
266
- else if (first === 'f' && second === ' ') {
267
- out = transformFunc(line.slice(2), false, false);
268
- }
269
- // TYPE:name=value → typed variable
270
- else if (TYPE_CHARS.has(first) && second === ':') {
271
- const rest = line;
272
- const tvM = rest.match(/^([sinblmaj]):(\w+)=(.+)$/);
273
- if (tvM) {
274
- out = `${expandType(tvM[1])} ${tvM[2]} = ${transformContent(tvM[3])}`;
275
- } else {
276
- // Could be a type field in model: s:name (no assignment)
277
- const fieldM = rest.match(/^([sinblmaj]):(\w+)$/);
278
- if (fieldM) {
279
- out = `${expandType(fieldM[1])} ${fieldM[2]}`;
280
- } else {
281
- // type:name=... with complex value
282
- const fieldDefM = rest.match(/^([sinblmaj]):(\w+)=(.+)$/);
283
- if (fieldDefM) {
284
- out = `${expandType(fieldDefM[1])} ${fieldDefM[2]} = ${transformContent(fieldDefM[3])}`;
285
- } else {
286
- out = transformContent(line);
287
- }
288
- }
289
- }
290
- }
291
- // Default: apply inline transforms
292
- else {
293
- out = transformContent(line);
294
- }
295
-
296
- // Handle multi-line output from route transform
297
- if (out.includes('\n')) {
298
- const subLines = out.split('\n');
299
- for (const sl of subLines) {
300
- result.push(indent + sl);
301
- }
302
- } else {
303
- result.push(indent + out);
304
- }
305
- }
306
-
307
- return result.join('\n');
308
- }
@@ -1,32 +0,0 @@
1
- {
2
- "comments": {
3
- "lineComment": "--"
4
- },
5
- "brackets": [
6
- ["{", "}"],
7
- ["[", "]"],
8
- ["(", ")"]
9
- ],
10
- "autoClosingPairs": [
11
- { "open": "{", "close": "}" },
12
- { "open": "[", "close": "]" },
13
- { "open": "(", "close": ")" },
14
- { "open": "\"", "close": "\"" },
15
- { "open": "'", "close": "'" }
16
- ],
17
- "surroundingPairs": [
18
- { "open": "{", "close": "}" },
19
- { "open": "[", "close": "]" },
20
- { "open": "(", "close": ")" },
21
- { "open": "\"", "close": "\"" },
22
- { "open": "'", "close": "'" }
23
- ],
24
- "indentationRules": {
25
- "increaseIndentPattern": "^\\s*(fn|fn\\.async|if|elif|else|each|for|while|match|try|fail|ensure|server|model|on|schema|crud|auth|env|every|watch|ws|group|upload|queue|job|test|get|post|put|del|patch|error|sse|view|cache|mid|validate|openapi|static|session|cookie|cors|limit)\\b.*:\\s*$",
26
- "decreaseIndentPattern": "^\\s*(elif|else|fail|ensure)\\b"
27
- },
28
- "folding": {
29
- "offSide": true
30
- },
31
- "wordPattern": "(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)"
32
- }
Binary file