novac 2.0.1 → 2.2.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.
Files changed (161) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +1574 -597
  3. package/bin/novac +468 -171
  4. package/bin/nvc +522 -0
  5. package/bin/nvml +78 -17
  6. package/demo.nv +0 -0
  7. package/demo_builtins.nv +0 -0
  8. package/demo_http.nv +0 -0
  9. package/examples/bf.nv +69 -0
  10. package/examples/math.nv +21 -0
  11. package/kits/birdAPI/kitdef.js +954 -0
  12. package/kits/kitRNG/kitdef.js +740 -0
  13. package/kits/kitSSH/kitdef.js +1272 -0
  14. package/kits/kitadb/kitdef.js +606 -0
  15. package/kits/kitai/kitdef.js +2185 -0
  16. package/kits/kitansi/kitdef.js +1402 -0
  17. package/kits/kitcanvas/kitdef.js +914 -0
  18. package/kits/kitclippy/kitdef.js +925 -0
  19. package/kits/kitformat/kitdef.js +1485 -0
  20. package/kits/kitgps/kitdef.js +1862 -0
  21. package/kits/kitlibproc/kitdef.js +3 -2
  22. package/kits/kitmatrix/ex.js +19 -0
  23. package/kits/kitmatrix/kitdef.js +960 -0
  24. package/kits/kitmorse/kitdef.js +229 -0
  25. package/kits/kitmpatch/kitdef.js +906 -0
  26. package/kits/kitnet/kitdef.js +1401 -0
  27. package/kits/kitnovacweb/README.md +1416 -143
  28. package/kits/kitnovacweb/kitdef.js +92 -2
  29. package/kits/kitnovacweb/nvml/executor.js +578 -176
  30. package/kits/kitnovacweb/nvml/index.js +2 -2
  31. package/kits/kitnovacweb/nvml/lexer.js +72 -69
  32. package/kits/kitnovacweb/nvml/parser.js +328 -159
  33. package/kits/kitnovacweb/nvml/renderer.js +770 -270
  34. package/kits/kitparse/kitdef.js +1688 -0
  35. package/kits/kitproto/kitdef.js +613 -0
  36. package/kits/kitqr/kitdef.js +637 -0
  37. package/kits/kitregex++/kitdef.js +1353 -0
  38. package/kits/kitrequire/kitdef.js +1599 -0
  39. package/kits/kitx11/kitdef.js +1 -0
  40. package/kits/kitx11/kitx11.js +2472 -0
  41. package/kits/kitx11/kitx11_conn.js +948 -0
  42. package/kits/kitx11/kitx11_worker.js +121 -0
  43. package/kits/libtea/kitdef.js +2691 -0
  44. package/kits/libterm/ex.js +285 -0
  45. package/kits/libterm/kitdef.js +1927 -0
  46. package/novac/LICENSE +21 -0
  47. package/novac/README.md +1823 -0
  48. package/novac/bin/novac +950 -0
  49. package/novac/bin/nvc +522 -0
  50. package/novac/bin/nvml +542 -0
  51. package/novac/demo.nv +245 -0
  52. package/novac/demo_builtins.nv +209 -0
  53. package/novac/demo_http.nv +62 -0
  54. package/novac/examples/bf.nv +69 -0
  55. package/novac/examples/math.nv +21 -0
  56. package/novac/kits/kitai/kitdef.js +2185 -0
  57. package/novac/kits/kitansi/kitdef.js +1402 -0
  58. package/novac/kits/kitformat/kitdef.js +1485 -0
  59. package/novac/kits/kitgps/kitdef.js +1862 -0
  60. package/novac/kits/kitlibfs/kitdef.js +231 -0
  61. package/{examples/example-project/nova_modules → novac/kits}/kitlibproc/kitdef.js +3 -2
  62. package/novac/kits/kitmatrix/ex.js +19 -0
  63. package/novac/kits/kitmatrix/kitdef.js +960 -0
  64. package/novac/kits/kitmpatch/kitdef.js +906 -0
  65. package/novac/kits/kitnovacweb/README.md +1572 -0
  66. package/novac/kits/kitnovacweb/demo.nv +12 -0
  67. package/novac/kits/kitnovacweb/demo.nvml +71 -0
  68. package/novac/kits/kitnovacweb/index.nova +12 -0
  69. package/novac/kits/kitnovacweb/kitdef.js +692 -0
  70. package/novac/kits/kitnovacweb/nova.kit.json +8 -0
  71. package/novac/kits/kitnovacweb/nvml/executor.js +739 -0
  72. package/novac/kits/kitnovacweb/nvml/index.js +67 -0
  73. package/novac/kits/kitnovacweb/nvml/lexer.js +263 -0
  74. package/novac/kits/kitnovacweb/nvml/parser.js +508 -0
  75. package/novac/kits/kitnovacweb/nvml/renderer.js +924 -0
  76. package/novac/kits/kitparse/kitdef.js +1688 -0
  77. package/novac/kits/kitregex++/kitdef.js +1353 -0
  78. package/novac/kits/kitrequire/kitdef.js +1599 -0
  79. package/novac/kits/kitx11/kitdef.js +1 -0
  80. package/novac/kits/kitx11/kitx11.js +2472 -0
  81. package/novac/kits/kitx11/kitx11_conn.js +948 -0
  82. package/novac/kits/kitx11/kitx11_worker.js +121 -0
  83. package/novac/kits/libtea/tf.js +2691 -0
  84. package/novac/kits/libterm/ex.js +285 -0
  85. package/novac/kits/libterm/kitdef.js +1927 -0
  86. package/novac/node_modules/chalk/license +9 -0
  87. package/novac/node_modules/chalk/package.json +83 -0
  88. package/novac/node_modules/chalk/readme.md +297 -0
  89. package/novac/node_modules/chalk/source/index.d.ts +325 -0
  90. package/novac/node_modules/chalk/source/index.js +225 -0
  91. package/novac/node_modules/chalk/source/utilities.js +33 -0
  92. package/novac/node_modules/chalk/source/vendor/ansi-styles/index.d.ts +236 -0
  93. package/novac/node_modules/chalk/source/vendor/ansi-styles/index.js +223 -0
  94. package/novac/node_modules/chalk/source/vendor/supports-color/browser.d.ts +1 -0
  95. package/novac/node_modules/chalk/source/vendor/supports-color/browser.js +34 -0
  96. package/novac/node_modules/chalk/source/vendor/supports-color/index.d.ts +55 -0
  97. package/novac/node_modules/chalk/source/vendor/supports-color/index.js +190 -0
  98. package/novac/node_modules/commander/LICENSE +22 -0
  99. package/novac/node_modules/commander/Readme.md +1176 -0
  100. package/novac/node_modules/commander/esm.mjs +16 -0
  101. package/novac/node_modules/commander/index.js +24 -0
  102. package/novac/node_modules/commander/lib/argument.js +150 -0
  103. package/novac/node_modules/commander/lib/command.js +2777 -0
  104. package/novac/node_modules/commander/lib/error.js +39 -0
  105. package/novac/node_modules/commander/lib/help.js +747 -0
  106. package/novac/node_modules/commander/lib/option.js +380 -0
  107. package/novac/node_modules/commander/lib/suggestSimilar.js +101 -0
  108. package/novac/node_modules/commander/package-support.json +19 -0
  109. package/novac/node_modules/commander/package.json +82 -0
  110. package/novac/node_modules/commander/typings/esm.d.mts +3 -0
  111. package/novac/node_modules/commander/typings/index.d.ts +1113 -0
  112. package/novac/node_modules/node-addon-api/LICENSE.md +9 -0
  113. package/novac/node_modules/node-addon-api/README.md +95 -0
  114. package/novac/node_modules/node-addon-api/common.gypi +21 -0
  115. package/novac/node_modules/node-addon-api/except.gypi +25 -0
  116. package/novac/node_modules/node-addon-api/index.js +14 -0
  117. package/novac/node_modules/node-addon-api/napi-inl.deprecated.h +186 -0
  118. package/novac/node_modules/node-addon-api/napi-inl.h +7165 -0
  119. package/novac/node_modules/node-addon-api/napi.h +3364 -0
  120. package/novac/node_modules/node-addon-api/node_addon_api.gyp +42 -0
  121. package/novac/node_modules/node-addon-api/node_api.gyp +9 -0
  122. package/novac/node_modules/node-addon-api/noexcept.gypi +26 -0
  123. package/novac/node_modules/node-addon-api/package-support.json +21 -0
  124. package/novac/node_modules/node-addon-api/package.json +480 -0
  125. package/novac/node_modules/node-addon-api/tools/README.md +73 -0
  126. package/novac/node_modules/node-addon-api/tools/check-napi.js +99 -0
  127. package/novac/node_modules/node-addon-api/tools/clang-format.js +71 -0
  128. package/novac/node_modules/node-addon-api/tools/conversion.js +301 -0
  129. package/novac/node_modules/serialize-javascript/LICENSE +27 -0
  130. package/novac/node_modules/serialize-javascript/README.md +149 -0
  131. package/novac/node_modules/serialize-javascript/index.js +297 -0
  132. package/novac/node_modules/serialize-javascript/package.json +33 -0
  133. package/novac/package.json +27 -0
  134. package/novac/scripts/update-bin.js +24 -0
  135. package/novac/src/core/bstd.js +1035 -0
  136. package/novac/src/core/config.js +155 -0
  137. package/novac/src/core/describe.js +187 -0
  138. package/novac/src/core/emitter.js +499 -0
  139. package/novac/src/core/error.js +86 -0
  140. package/novac/src/core/executor.js +5606 -0
  141. package/novac/src/core/formatter.js +686 -0
  142. package/novac/src/core/lexer.js +1026 -0
  143. package/novac/src/core/nova_builtins.js +717 -0
  144. package/novac/src/core/nova_thread_worker.js +166 -0
  145. package/novac/src/core/parser.js +2181 -0
  146. package/novac/src/core/types.js +112 -0
  147. package/novac/src/index.js +28 -0
  148. package/novac/src/runtime/stdlib.js +244 -0
  149. package/package.json +6 -3
  150. package/scripts/update-bin.js +0 -0
  151. package/src/core/bstd.js +838 -362
  152. package/src/core/executor.js +2578 -170
  153. package/src/core/lexer.js +502 -54
  154. package/src/core/nova_builtins.js +21 -3
  155. package/src/core/parser.js +413 -72
  156. package/src/core/types.js +30 -2
  157. package/src/index.js +0 -0
  158. package/examples/example-project/README.md +0 -3
  159. package/examples/example-project/src/main.nova +0 -3
  160. package/src/core/environment.js +0 -0
  161. /package/{examples/example-project/bin/example-project.nv → novac/node_modules/node-addon-api/nothing.c} +0 -0
@@ -0,0 +1,1823 @@
1
+ # novac Language Reference
2
+
3
+ novac is a dynamic, expressive scripting language with a JavaScript-style syntax, a rich infix operator set, built-in event system, HTTP primitives, a Nova Classic layer, and a comprehensive standard library. Files use the `.nv` or `.nova` extension and are run with the `novac` CLI.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [Comments](#comments)
10
+ 2. [Preprocessor Directives](#preprocessor-directives)
11
+ 3. [Literals & Values](#literals--values)
12
+ 4. [Variables & Smart Modifiers](#variables--smart-modifiers)
13
+ 5. [Types](#types)
14
+ 6. [Operators](#operators)
15
+ 7. [Strings & F-Strings](#strings--f-strings)
16
+ 8. [Control Flow](#control-flow)
17
+ 9. [Functions](#functions)
18
+ 10. [Classes](#classes)
19
+ 11. [Pattern Matching](#pattern-matching)
20
+ 12. [Events](#events)
21
+ 13. [Error Handling](#error-handling)
22
+ 14. [Modules & Namespaces](#modules--namespaces)
23
+ 15. [HTTP & Networking](#http--networking)
24
+ 16. [Nova Classic Features](#nova-classic-features)
25
+ 17. [Built-in Global Objects](#built-in-global-objects)
26
+ 18. [Built-in Class Objects](#built-in-class-objects)
27
+ 19. [Standard Library (std)](#standard-library-std)
28
+ 20. [Standard Built-ins (bstd / import_builtin)](#standard-builtins-bstd--import_builtin)
29
+ 21. [Array Methods](#array-methods)
30
+ 22. [Object Methods](#object-methods)
31
+ 23. [String Methods](#string-methods)
32
+ 24. [Type System & Casting](#type-system--casting)
33
+ 25. [Threads](#threads)
34
+
35
+ ---
36
+
37
+ ## Comments
38
+
39
+ ```nova
40
+ // single-line comment
41
+ /! also a single-line comment
42
+ /* multi-line block comment */
43
+
44
+ /?/ core.print("executed at lex time") // executable comment — runs during lexing
45
+ ```
46
+
47
+ ---
48
+
49
+ ## Preprocessor Directives
50
+
51
+ ```nova
52
+ #define NAME value // substitution macro (NAME replaced everywhere in source)
53
+ #define FLAG // valueless flag (for ifdef/ifndef)
54
+ #undef NAME // remove a macro
55
+ #ifdef FLAG // include following block only if FLAG is defined
56
+ #ifndef FLAG // include following block only if FLAG is NOT defined
57
+ #endif // close an ifdef/ifndef block
58
+ #register operator NAME {"precedence":N, "isUnary":bool}
59
+ #inject <json-token> // inject a raw token into the token stream
60
+ ```
61
+
62
+ ---
63
+
64
+ ## Literals & Values
65
+
66
+ ### Numbers
67
+
68
+ | Form | Example | Notes |
69
+ |------|---------|-------|
70
+ | Decimal | `42`, `3.14` | Standard |
71
+ | Separator | `1_000_000` | Underscores ignored |
72
+ | Hex | `0xFF` | Case insensitive |
73
+ | Binary | `0b1010` | Case insensitive |
74
+ | Custom base | `0r16FF` | `0r<base><digits>`, base 2–36 |
75
+ | Holland/scale | `0hbillion`, `0hmega` | Named SI / large-number literals |
76
+ | BigInt | `42n` | Suffix `n` |
77
+ | Scientific | `1e6`, `2.5E-3` | Standard scientific |
78
+ | Short suffix | `10k`, `2m`, `1b`, `4t` | k=1e3, m=1e6, b=1e9, t=1e12 |
79
+
80
+ **Holland scale literals** — `0h` prefix:
81
+
82
+ | Name | Value | Name | Value |
83
+ |------|-------|------|-------|
84
+ | `kilo` | 1e3 | `milli` | 1e-3 |
85
+ | `mega` | 1e6 | `micro` | 1e-6 |
86
+ | `giga` | 1e9 | `nano` | 1e-9 |
87
+ | `tera` | 1e12 | `pico` | 1e-12 |
88
+ | `million` | 1e6 | `femto` | 1e-15 |
89
+ | `billion` | 1e9 | `atto` | 1e-18 |
90
+ | `trillion` | 1e12 | `googol` | 1e100 |
91
+ | `quadrillion` | 1e15 | | |
92
+ | `quintillion` | 1e18 | | |
93
+
94
+ ### Special Literals
95
+
96
+ | Token | Value |
97
+ |-------|-------|
98
+ | `true` | boolean true |
99
+ | `false` | boolean false |
100
+ | `null` | null |
101
+ | `nstr` | `""` (empty string) |
102
+ | `nfunc` | A function that returns null |
103
+
104
+ ### URL Literals
105
+
106
+ Tokens beginning with a recognized scheme are URL literals:
107
+
108
+ ```nova
109
+ let url = https://api.example.com/users
110
+ let local = localhost:3000
111
+ // Recognized: http, https, ftp, ws, wss, content, localhost:<port>
112
+ ```
113
+
114
+ ### Arrays
115
+
116
+ ```nova
117
+ let arr = [1, 2, 3]
118
+ let spread = [...arr, 4, 5]
119
+ ```
120
+
121
+ ### Objects
122
+
123
+ ```nova
124
+ let obj = { x: 1, 'y': 2 }
125
+ let method = { greet() { give "hi"; } }
126
+ let overload = {
127
+ [op]: {
128
+ unary: { '~': () => 17 }
129
+ binary: { '+': (a) => a*10 }
130
+ }
131
+ }
132
+ core.print(~obj + obj); // ~obj becomes 17, now 17 + obj becomes 17*10 which is 170.
133
+ let computed = { ["key" + idx]: value }
134
+ let withSpread = { ...obj, z: 3 }
135
+ let getset = {
136
+ get prop() { give this._val; },
137
+ set prop(v) { this._val = v; }
138
+ }
139
+ let presence = { active? true } // boolean-constrained property: must be true or false
140
+ ```
141
+
142
+ ---
143
+
144
+ ## Variables & Smart Modifiers
145
+
146
+ ```nova
147
+ var x = 10 // mutable, function-scoped
148
+ let y = 20 // mutable, block-scoped
149
+ const Z = 30 // immutable binding/
150
+ // special __...__ identifiers:
151
+ let __my cool variable++-__ = 19; // when novac sees __, it collects everything until __ as the var name and gives an identifier token type, so you can even name a variable __26__ and the token with be { type: 'IDENTIFIER', value: '26' }
152
+ ```
153
+
154
+ ### Destructuring
155
+
156
+ ```nova
157
+ let { a, b } = obj
158
+ let { a: renamed, b: other = "default" } = obj
159
+ let [first, second] = arr
160
+ let [head, ...tail] = arr
161
+ ```
162
+
163
+ ### Smart Variable Modifiers
164
+
165
+ Placed between the variable name and `=`:
166
+
167
+ | Modifier | Effect |
168
+ |----------|--------|
169
+ | `frozen` | Throws on any reassignment after first set |
170
+ | `lazy` | Expression evaluated only on first read |
171
+ | `tracked` | `console.log`s every assignment change |
172
+ | `nonull` | Throws if assigned `null` or `undefined` |
173
+ | `once` | Can only be set once; further assigns silently ignored |
174
+ | `setter <fn>` | Calls `fn(newVal, oldVal)` on every assignment; if fn returns non-undefined, that becomes the stored value |
175
+ | `getter <fn>` | Calls `fn()` on every read |
176
+ | `as fnum [min, max]` | Clamps to float range on every assign |
177
+ | `as fint [min, max]` | Clamps to integer range (`Math.trunc`) on every assign |
178
+
179
+ ```nova
180
+ let x frozen = 5
181
+ let y lazy = computeHeavy()
182
+ let z tracked = 0
183
+ let n nonull = getValue()
184
+ let once_val once = initialize()
185
+ let watched setter mySetFn = 0
186
+ let computed getter myGetFn = 0
187
+ let clamped as fnum [0.0, 1.0] = 0.5
188
+ let bounded as fint [0, 255] = 128
189
+ ```
190
+
191
+ ### Links and $-notations
192
+ ```nova
193
+ let obj = { test: { example: 29 } };
194
+ let link2example = link(obj.test.example); // link is not a function, its a special keyword function
195
+ link2example = 3; // example is also set
196
+ obj.test.example; // 3
197
+ obj.test.example = 2;
198
+ link2example; // 2
199
+ // you can also directly set a link call:
200
+ link(obj.test.example) = 1; // works
201
+ // nest links:
202
+ link(link2example) = 3; // now obj.test.example is also 3
203
+ ```
204
+
205
+ ```nova
206
+ // $ notation:
207
+ // when used as a normal call:
208
+ $29; // noop, just 29
209
+ ${a: 6 + 3}; // noop again, just the object
210
+ // real magic in $ assingments:
211
+ $"hi" = 29; // sets variable hi
212
+ $26 = 1; // set variable 26, even tho you can't just read from a var directly called 26, you can still use __26__ to read (novac trims __...__ and just leaves an ident with value ...)
213
+ ```
214
+
215
+ ### Type Annotation
216
+
217
+ ```nova
218
+ let count: int = 0
219
+ let name: string = "Nova"
220
+ func add(a: int, b: int): int => { give a + b }
221
+ ```
222
+
223
+ ### Pointer Declaration & Dereference
224
+
225
+ ```nova
226
+ var *ptr = someValue
227
+ let result = *ptr // dereference
228
+ *ptr = newValue // assign through pointer
229
+ ```
230
+
231
+ ---
232
+
233
+ ## Types
234
+
235
+ ### Type Alias
236
+
237
+ ```nova
238
+ type ID = string
239
+ type Status = "active" | "inactive" | "pending"
240
+ type Point = { x: int, y: int }
241
+ type Result<T> = T | null
242
+ ```
243
+
244
+ ### Struct
245
+
246
+ ```nova
247
+ struct Vec2 {
248
+ x: int = 0,
249
+ y: int = 0
250
+ }
251
+ let v = Vec2({ x: 3, y: 4 })
252
+ v.x // 3
253
+ ```
254
+
255
+ ### Interface
256
+
257
+ ```nova
258
+ interface Serializable {
259
+ serialize(): string
260
+ deserialize(data: string): bool
261
+ name?: string // optional member
262
+ }
263
+ interface Extended extends Serializable, Printable { }
264
+ ```
265
+
266
+ ### Enum
267
+
268
+ ```nova
269
+ enum Status { Active, Inactive, Pending }
270
+ enum Shape {
271
+ Circle(int),
272
+ Rect(int, int),
273
+ Point = 0
274
+ }
275
+ let s = Status.Active
276
+ s.__variant__ // "Active"
277
+ s.__enum_type__ // "Status"
278
+ ```
279
+
280
+ ### Trait & Impl
281
+
282
+ ```nova
283
+ trait Drawable {
284
+ draw(ctx) { }
285
+ }
286
+ impl Drawable of Circle {
287
+ draw(ctx) { ctx.circle(this.x, this.y, this.r); }
288
+ }
289
+ // Also: impl Drawable for Circle { }
290
+ ```
291
+
292
+ ### Type Expressions
293
+
294
+ ```nova
295
+ string | null // union
296
+ int & Serializable // intersection
297
+ string[] // array type
298
+ { name: string, age?: int } // inline shape type
299
+ Map<string, int> // generic
300
+ ```
301
+
302
+ ---
303
+
304
+ ## Operators
305
+
306
+ ### Arithmetic
307
+
308
+ | Op | Meaning |
309
+ |----|---------|
310
+ | `+` `-` `*` `/` `%` | Standard arithmetic |
311
+ | `**` | Exponentiation (right-associative) |
312
+ | `++` `--` | Increment / decrement (prefix or postfix) |
313
+
314
+ ### Assignment
315
+
316
+ | Op | Meaning |
317
+ |----|---------|
318
+ | `=` | Assign |
319
+ | `+=` `-=` `*=` `/=` `%=` `**=` | Compound assign |
320
+ | `&&=` | Logical-AND assign |
321
+ | `\|\|=` | Assign if current is null/undefined |
322
+ | `??=` | Nullish-coalesce assign |
323
+
324
+ ### Comparison
325
+
326
+ | Op | Meaning |
327
+ |----|---------|
328
+ | `==` `!=` | Loose equality |
329
+ | `===` `!==` | Strict equality |
330
+ | `<` `>` `<=` `>=` | Relational |
331
+ | `is` | Strict equality alias |
332
+ | `isnt` | Non-identity alias |
333
+ | `equals` | `===` alias |
334
+ | `equals_ignore` | Case-insensitive string equality |
335
+ | `cmp` | `localeCompare` — returns -1/0/1 |
336
+
337
+ ### Logical
338
+
339
+ | Op | Meaning |
340
+ |----|---------|
341
+ | `&&` / `and` | Logical AND |
342
+ | `\|\|` / `or` | Logical OR |
343
+ | `!` / `not` | Logical NOT (unary) |
344
+ | `??` | Nullish coalesce |
345
+ | `xor` | Exclusive OR |
346
+ | `nand` | NOT AND |
347
+ | `nor` | NOT OR |
348
+ | `xnor` | Exclusive NOR |
349
+
350
+ ### Bitwise
351
+
352
+ | Op | Meaning |
353
+ |----|---------|
354
+ | `&` `\|` `^` `~` | Bitwise AND / OR / XOR / NOT |
355
+ | `<<` `>>` `>>>` | Left / right / unsigned right shift |
356
+
357
+ ### Type & Predicate
358
+
359
+ | Op | Meaning |
360
+ |----|---------|
361
+ | `typeof` | Returns type string (unary) |
362
+ | `instanceof` | Instance check |
363
+ | `in` | Membership / range containment |
364
+ | `istypeof` | `typeOf(left) === right` |
365
+ | `matches` | Regex test of left string against right |
366
+ | `between` | `left > arr[0] && left < arr[1]` |
367
+
368
+ ### Special / Flow
369
+
370
+ | Op | Meaning |
371
+ |----|---------|
372
+ | `\|>` | Pipe: `x \|> f` → `f(x)` |
373
+ | `=>` | Arrow function body |
374
+ | `..` | Inclusive range: `1..10` → `NovaRange(1,10)` |
375
+ | `...` (unary) | Spread / rest |
376
+ | `...` (binary) | Exclusive range: `1...10` → array `[1..9]` |
377
+ | `?.` | Optional chain — null if left is null |
378
+ | `?` | Ternary start |
379
+ | `::` | Namespace / property access |
380
+ | `>>` | Pipe-right: `val >> fn` → `fn(val)`; also used in `compose` / `engage` |
381
+ | `delete` | Delete variable, property, or subscript |
382
+ | `void` | Evaluate and return undefined |
383
+ | `#` | Size of right operand (array/object/string length) |
384
+
385
+ ### Array / Collection Infix
386
+
387
+ | Op | Meaning |
388
+ |----|---------|
389
+ | `intersect` | Elements in both arrays |
390
+ | `union` | Deduplicated merge |
391
+ | `diff_arr` | Elements in left not in right |
392
+ | `zip` | `[[a0,b0],[a1,b1],...]` |
393
+ | `extend` | Merge objects / concatenate arrays |
394
+ | `concat` | Concatenate |
395
+ | `index` | `arr index 2` → element at 2 |
396
+ | `step` | `0..10 step 2` → `[0,2,4,6,8,10]` |
397
+
398
+ ### Numeric Infix
399
+
400
+ | Op | Meaning |
401
+ |----|---------|
402
+ | `avg` | `(a + b) / 2` |
403
+ | `diff` | `Math.abs(a - b)` |
404
+ | `ratio` | `a / b` |
405
+ | `mult_of` | `a % b === 0` |
406
+ | `gcd` | Greatest common divisor |
407
+ | `lcm` | Least common multiple |
408
+ | `pow` | Alias for `**` |
409
+ | `bigger` / `smaller` | `a > b` / `a < b` aliases |
410
+
411
+ ### String Infix
412
+
413
+ | Op | Meaning |
414
+ |----|---------|
415
+ | `pad_start` | `.padStart(right, ' ')` |
416
+ | `pad_end` | `.padEnd(right, ' ')` |
417
+
418
+ ### Operator Precedence (highest → lowest)
419
+
420
+ | Prec | Operators |
421
+ |------|-----------|
422
+ | 15 | `++` `--` (postfix), `?.`, `::`, `#:`, `$:`, `index` |
423
+ | 14 | Unary: `!` `~` `-` `+` `*` `...` `not` `typeof` `void` `delete` |
424
+ | 13 | `**` `pow` (right-assoc) |
425
+ | 12 | `*` `/` `%` `ratio` `mult_of` `gcd` `lcm` |
426
+ | 11 | `+` `-` `avg` `diff` `pad_start` `pad_end` `concat` |
427
+ | 10 | `>>` `<<` `>>>` `..` `step` `zip` |
428
+ | 9 | `<` `>` `<=` `>=` `bigger` `smaller` |
429
+ | 8 | `==` `!=` `===` `!==` `is` `isnt` `equals` `equals_ignore` `cmp` `istypeof` `matches` `instanceof` `in` |
430
+ | 7 | `&` `intersect` `diff_arr` |
431
+ | 6 | `^` |
432
+ | 5 | `\|` `union` `extend` |
433
+ | 4 | `&&` `and` `nand` |
434
+ | 3 | `??` `xor` `xnor` |
435
+ | 2 | `\|\|` `or` `nor` |
436
+ | 0 | `=` `+=` `-=` `*=` `/=` `%=` `**=` `&&=` `\|\|=` `??=` `=>` `\|>` |
437
+
438
+ ---
439
+
440
+ ## Strings & F-Strings
441
+
442
+ ```nova
443
+ let a = "hello"
444
+ let b = 'world'
445
+ // Escape sequences: \n \t \r \\ \' \"...etc
446
+
447
+ // F-strings: f"..." with {} interpolation — any expression allowed
448
+ let msg = f"\color{blue}Hello {name}!\reset"
449
+ let math = f"2^10 = {2 ** 10}"
450
+ let complex = f"items: {arr.map(x => x * 2).join(', ')}"
451
+ ```
452
+
453
+ ---
454
+
455
+ ## Control Flow
456
+
457
+ ### If / Else
458
+
459
+ ```nova
460
+ if (cond) { } else if (other) { } else { }
461
+
462
+ let x = a > b ? a : b // ternary
463
+ let y = value if condition else alt // postfix if-expression
464
+ ```
465
+
466
+ ### Unless / Until / Repeat
467
+
468
+ ```nova
469
+ unless (cond) { } // runs when cond is false
470
+ until (cond) { } // runs while cond is false
471
+ repeat (n) { } // runs exactly n times
472
+ ```
473
+
474
+ ### While / Do-While
475
+
476
+ ```nova
477
+ while (cond) { }
478
+ do { } while (cond)
479
+ ```
480
+
481
+ ### For
482
+
483
+ ```nova
484
+ for (let i = 0; i < 10; i++) { }
485
+ for (let item of array) { }
486
+ for (let key in object) { }
487
+ ```
488
+
489
+ ### Each
490
+
491
+ ```nova
492
+ each item of array { }
493
+ each item, index of array { }
494
+ ```
495
+
496
+ ### Switch / Case
497
+
498
+ ```nova
499
+ switch (value) {
500
+ case 1: core.print("one"); break;
501
+ default: core.print("other"); break;
502
+ }
503
+ ```
504
+
505
+ ### Match
506
+
507
+ ```nova
508
+ match (value) {
509
+ when 1 { }
510
+ when 2, 3 { } // comma = multi-pattern
511
+ when 1..10 { } // range
512
+ when "ok" where cond { } // with guard
513
+ default { }
514
+ }
515
+ ```
516
+
517
+ ### Loop Control
518
+
519
+ | Keyword | Effect |
520
+ |---------|--------|
521
+ | `break` | Exit loop |
522
+ | `continue` | Next iteration |
523
+ | `skip` | Alias for `continue` (parsed as `skip`, no-op in execute) |
524
+ | `goback` | Throw `{ __return: scope.__return }` — return from function |
525
+ | `end` | Throw `{ __return: undefined }` — terminate scope |
526
+
527
+ ### Guard
528
+
529
+ ```nova
530
+ guard (cond) {
531
+ // body runs only when cond is TRUE (passes through)
532
+ } else {
533
+ // runs when cond is FALSE
534
+ }
535
+ ```
536
+
537
+ ### When
538
+
539
+ ```nova
540
+ when cond do { } // runs body once if cond is truthy
541
+ when cond then { } // same
542
+ ```
543
+
544
+ ### Where (scoped bindings)
545
+
546
+ ```nova
547
+ where (base = 100, rate = 0.15) {
548
+ let tax = base * rate
549
+ }
550
+ ```
551
+
552
+ ### With
553
+
554
+ ```nova
555
+ with (object) {
556
+ // object properties brought into scope
557
+ }
558
+ with option featureFlag {
559
+ // body runs with flag set; removed after block
560
+ }
561
+ ```
562
+
563
+ ### Loop (Classic iteration)
564
+
565
+ ```nova
566
+ loop item in iterable { }
567
+ ```
568
+
569
+ ### Foreach (Classic key-value)
570
+
571
+ ```nova
572
+ foreach(collection)(key, value) { }
573
+ foreach(collection)(key, value, length) { } // third var = total length
574
+ ```
575
+
576
+ ### Wait (sync sleep)
577
+
578
+ ```nova
579
+ wait(1000) // blocks for 1000ms (Atomics.wait, fallback: child process)
580
+ ```
581
+
582
+ ### Time Block
583
+
584
+ ```nova
585
+ time {
586
+ // times this block; prints elapsed ms on completion
587
+ }
588
+ ```
589
+
590
+ ---
591
+
592
+ ## Functions
593
+
594
+ ### Named Functions
595
+
596
+ ```nova
597
+ func add(a, b) => {
598
+ give a + b
599
+ }
600
+ function greet(name) {
601
+ return f"Hello {name}"
602
+ }
603
+ ```
604
+
605
+ ### Function Modifiers
606
+
607
+ Modifiers come **after** `func`/`function` and **before** the function name. Multiple modifiers can be chained in any order.
608
+
609
+ | Modifier | Effect |
610
+ |----------|--------|
611
+ | `async` | Marks async; `await` blocks synchronously via `SharedArrayBuffer` |
612
+ | `Strict` | Throws if argument count doesn't match exactly |
613
+ | `once` | Body only runs once; later calls return the first result |
614
+ | `memo` | Results memoized by `JSON.stringify(args)` key |
615
+ | `generator` | Returns an iterator; `yield` inside collects values |
616
+ | `timeout <expr>` | Throws if function exceeds `expr` ms |
617
+ | `defer <stmt>` | Executes `stmt` when function returns (in `finally`) |
618
+
619
+ ```nova
620
+ func async load(url) => { }
621
+ func Strict strict(a, b) => { }
622
+ func once init() => { }
623
+ func memo fib(n) => { }
624
+ func generator counter() => { }
625
+ func async memo cachedFetch(url) => { }
626
+ func timeout 5000 riskyOp() => { }
627
+ func defer cleanup() riskyOp() => { }
628
+
629
+ // function keyword works identically
630
+ function async load(url) { }
631
+ function Strict strict(a, b) { }
632
+ ```
633
+
634
+ in objects, you can have a [expr] quick access method that runs on
635
+ obj.(...args)
636
+ example:
637
+ ```nova
638
+ let obj = { [expr]: (a, b) => return a + b }
639
+ core.print(obj.(1,5)); // 6
640
+ ```
641
+
642
+ ### Generator Iterator API
643
+
644
+ | Method | Description |
645
+ |--------|-------------|
646
+ | `.next()` | `{ value, done }` |
647
+ | `.last()` | Step back one |
648
+ | `.current()` | Peek without advancing |
649
+ | `.seek(n)` | Jump to index n |
650
+ | `.setIndex(n)` | Set position |
651
+ | `.currentIndex()` | Current index |
652
+ | `.length()` | Total collected values |
653
+ | `.at(n)` | Value at index n |
654
+ | `[Symbol.iterator]` | Makes it iterable in `for-of` |
655
+
656
+ ### Return / Give / Goback
657
+
658
+ ```nova
659
+ return value // sets __return, does NOT terminate
660
+ give value // alias — same as return, but terminates the function by throwing
661
+ goback // throws { __return: scope.__return }
662
+ yield value // collects into generator's output array
663
+ ```
664
+
665
+ ### Arrow Functions
666
+
667
+ ```nova
668
+ let double = x => x * 2
669
+ let add = (a, b) => a + b
670
+ ```
671
+
672
+ ### Rest & Default Parameters
673
+
674
+ ```nova
675
+ func sum(...nums) => { give nums.reduce((a, b) => a + b, 0) }
676
+ func greet(name = "World") => { }
677
+ ```
678
+
679
+ ### Block functions:
680
+ these auto call on reference, and use the returned value
681
+ ```nova
682
+ block coolBlock { core.print(8); return 8; }
683
+ core.print(coolBlock); /* result:
684
+ 8 //from inside coolBlock
685
+ 8 //from core.print(coolBlock);
686
+ */
687
+ // you can also just run the block using nova.runBlock('coolBlock')
688
+ ```
689
+
690
+ ### Run bounder:
691
+ ```nova
692
+ // run CODE
693
+ // or
694
+ // run { ... }
695
+ // example:
696
+ core.print(run let x = 10); //10 because run uses last result if no return/give
697
+ core.print(x); // 10
698
+ core.print(run { let c = 8; return c; }); // 8
699
+ core.print(c); // 8
700
+
701
+ ```
702
+
703
+ ### Pipe Operator
704
+
705
+ ```nova
706
+ let result = 5 |> double |> addOne
707
+ ```
708
+
709
+ ---
710
+
711
+ ## Classes
712
+
713
+ ```nova
714
+ class Animal {
715
+ name: "unknown"
716
+ speak() { core.print(f"{this.name} speaks") }
717
+ }
718
+ class Dog extends Animal {
719
+ breed: "mixed"
720
+ speak() { core.print(f"{this.name} barks") }
721
+ }
722
+ class Doc implements Serializable {
723
+ // must satisfy all non-optional interface members
724
+ }
725
+ ```
726
+
727
+ ### Getter / Setter
728
+
729
+ ```nova
730
+ class Box {
731
+ _val: 0
732
+ get value() { give this._val; }
733
+ set value(v) { this._val = v; }
734
+ }
735
+ ```
736
+
737
+ ### Decorators
738
+
739
+ ```nova
740
+ @logged
741
+ @deprecated("use newFn")
742
+ class OldClass {
743
+ @readonly
744
+ name: "old"
745
+ }
746
+ ```
747
+
748
+ ---
749
+
750
+ ## Pattern Matching
751
+
752
+ ```nova
753
+ match (value) {
754
+ when 90..100 { } // range — uses NovaRange.includes()
755
+ when "ok" { } // scalar — uses ==
756
+ when 1, 2, 3 { } // any of these — comma-separated
757
+ when x where x > 0 { } // with guard expression
758
+ default { }
759
+ }
760
+ ```
761
+
762
+ ---
763
+
764
+ ## Events
765
+
766
+ ```nova
767
+ emit "eventName"
768
+ emit "eventName", payload
769
+
770
+ on "eventName" (data) {
771
+ core.print(data)
772
+ }
773
+
774
+ // Internal: fires on every statement execution step
775
+ on "nv:tick" () { }
776
+ ```
777
+
778
+ ---
779
+
780
+ ## Error Handling
781
+
782
+ ```nova
783
+ try {
784
+ riskyOp()
785
+ } catch (err) {
786
+ core.print(f"caught: {err}")
787
+ } finally {
788
+ cleanup()
789
+ }
790
+
791
+ try { riskyOp() } catch { } // no binding — catch without name
792
+
793
+ throw "plain string"
794
+ throw new Error("typed")
795
+
796
+ assert condition
797
+ assert condition, "failure message"
798
+
799
+ expt "expectedOutput" from {
800
+ core.print("expectedOutput")
801
+ }
802
+ ```
803
+
804
+ ---
805
+
806
+ ## Modules & Namespaces
807
+
808
+ ### Import
809
+
810
+ ```nova
811
+ import "path/to/module"
812
+ import "path/to/module" as alias
813
+ import "path/to/module" as name1, name2
814
+ from "module" import func1, func2
815
+ import_builtin Air, Chalk, Input, Shema
816
+ ```
817
+
818
+ ### Export
819
+
820
+ ```nova
821
+ export myValue
822
+ export { name = value, other = value2 }
823
+ default myMainExport
824
+ ```
825
+
826
+ ### Namespace
827
+
828
+ ```nova
829
+ namespace Math {
830
+ func add(a, b) => { give a + b }
831
+ }
832
+ Math::add(1, 2)
833
+ using namespace Math // bring all members into scope
834
+ ```
835
+
836
+ ### Using / Unuse
837
+
838
+ ```nova
839
+ using featureFlag
840
+ using namespace MyNS
841
+ unuse featureFlag
842
+ ```
843
+
844
+ ### Environment Variable
845
+
846
+ ```nova
847
+ env VAR_NAME // reads process.env.VAR_NAME; throws if undefined
848
+ ```
849
+
850
+ ---
851
+
852
+ ## HTTP & Networking
853
+
854
+ ### First-Class HTTP Verbs
855
+
856
+ ```nova
857
+ get https://api.example.com/users
858
+ post https://api.example.com/users({ name: "novac" })
859
+ put https://api.example.com/users/1({ name: "Updated" })
860
+ delete https://api.example.com/users/1()
861
+ patch https://api.example.com/users/1({ active: false })
862
+ head https://api.example.com/health
863
+ options https://api.example.com/
864
+ // Returns: { ok: bool, status: int, body: object|string, text: string }
865
+ ```
866
+
867
+ **Sync fetch strategies (tried in order):** in-process local Nova server dispatch → curl → PowerShell (Windows) → Node child process.
868
+
869
+ ### Fetch
870
+
871
+ ```nova
872
+ fetch(url)
873
+ fetch(url, { method: "POST", headers: { Authorization: "Bearer x" }, body: payload })
874
+ fetch(url, opts) => resultVar // statement form — assigns result
875
+ ```
876
+
877
+ ### Server Declaration
878
+
879
+ ```nova
880
+ server(3000) {
881
+ get "/api/users" (req, res) {
882
+ res.json([])
883
+ }
884
+ post "/api/users" (req, res) {
885
+ res.json({ created: true, body: req.body })
886
+ }
887
+ delete "/api/users/:id" (req, res) {
888
+ res.json({ deleted: req.params.id })
889
+ }
890
+ }
891
+ // req: { method, url, path, headers, body, params, query }
892
+ // res: .status(code) .header(k,v) .json(data) .send(data)
893
+ // :param values also bound directly into route scope
894
+ // If res.json/send never called, route handler's return value is auto-sent
895
+ ```
896
+
897
+ ---
898
+
899
+ ## @classic — Classic Compatibility Block
900
+
901
+ Classic novac keywords are **only valid inside an `@classic { }` block**. Outside of one they are plain identifiers and cause a parse error if used as statements. This keeps the core language surface area clean while preserving full backward compatibility for legacy code.
902
+
903
+ ```nova
904
+ @classic {
905
+ // any classic keyword works in here
906
+ echo "hello"
907
+ keep port = 8080
908
+ gear(500) poll {
909
+ let data = fetch(https://api.example.com/data)
910
+ echo data.body
911
+ }
912
+ engage poll
913
+ }
914
+ ```
915
+
916
+ If you use a Classic keyword outside `@classic`, the parser throws:
917
+
918
+ ```
919
+ ClassicError: 'echo' is a Classic novac keyword and must be used inside an @classic { } block.
920
+ Wrap your legacy code: @classic { echo ... }
921
+ ```
922
+
923
+ `@classic` blocks can appear anywhere a statement is valid — top-level, inside functions, inside `if` bodies, etc. They share the same scope as their surroundings.
924
+
925
+ ```nova
926
+ func migrate() => {
927
+ @classic {
928
+ backup session = currentSession
929
+ temp session = "migration" => {
930
+ runMigration()
931
+ }
932
+ retrieve session
933
+ }
934
+ }
935
+ ```
936
+
937
+ ### Classic Keywords (only valid inside `@classic { }`)
938
+
939
+ **Output:**
940
+
941
+ | Keyword | Behavior |
942
+ |---------|----------|
943
+ | `echo value` | `process.stdout.write(String(value))` — no newline |
944
+ | `print(val, ...)` | Space-joined args + newline |
945
+ | `println(value)` | `process.stdout.write(value)` — no newline |
946
+ | `log(val, ...)` | `console.log(...args)` |
947
+ | `logln(value)` | `process.stdout.write(value)` |
948
+ | `warn "msg"` | `"Warning: msg\n"` |
949
+ | `info "msg"` | `"INFO: msg\n"` |
950
+ | `hello` | Prints `"Hello, !"` |
951
+ | `hello "a", "b"` | Prints `"Hello, a, and b!"` |
952
+ | `banner "text"` | Box-drawn ASCII banner |
953
+
954
+ **Scoped Binding:**
955
+
956
+ | Keyword | Behavior |
957
+ |---------|----------|
958
+ | `temp x = val => { }` | Override x for the block duration, then restore |
959
+ | `keep x = val` | Set x only if currently null/undefined; silent otherwise |
960
+
961
+ **Macros & Named Code:**
962
+
963
+ | Keyword | Behavior |
964
+ |---------|----------|
965
+ | `macro NAME = val` | Store value in `nova.macros` and scope |
966
+ | `snippet name { }` | Register named snippet; run with `nova.runSnippet("name")` |
967
+ | `defunc name(args) => { }` | Declare function (arrow-body style) |
968
+ | `lambda name = x => expr` | Declare arrow function |
969
+ | `compose name = f >> g` | Compose functions left-to-right: `g(f(x))` |
970
+ | `partial name = fn(arg)` | Partial application |
971
+
972
+ **Iteration:**
973
+
974
+ | Keyword | Behavior |
975
+ |---------|----------|
976
+ | `loop item in iterable { }` | For-of style |
977
+ | `foreach(col)(key, val) { }` | Key-value iteration |
978
+ | `foreach(col)(key, val, len) { }` | With length variable |
979
+
980
+ **State:**
981
+
982
+ | Keyword | Behavior |
983
+ |---------|----------|
984
+ | `backup x = x` | Save value to executor backup store |
985
+ | `retrieve x` | Restore from backup store |
986
+ | `addto arr val` | Push value to array |
987
+ | `addto map val : key` | Set `map[key] = val` |
988
+
989
+ **Async Tasks:**
990
+
991
+ | Keyword | Behavior |
992
+ |---------|----------|
993
+ | `gear(ms) name { }` | Named loop task; waits `ms` between iterations |
994
+ | `gear name { }` | Named loop task; no wait |
995
+ | `engage a >> b` | Run gears left-to-right in continuous loop until `break` |
996
+
997
+ **Isolation:**
998
+
999
+ | Keyword | Behavior |
1000
+ |---------|----------|
1001
+ | `sandbox { }` | Run in isolated Node.js vm context; scope vars snapshotted in/out |
1002
+ | `infer ("model") => var: "prompt"` | Run local AI model via `ollama` |
1003
+
1004
+ **Data:**
1005
+
1006
+ | Keyword | Behavior |
1007
+ |---------|----------|
1008
+ | `sstream name => { put val }` | Named sync stream with `put` accumulator |
1009
+ | `lend fn src to dst` | Merge `src` function body into `dst` |
1010
+ | `lend m map with fn` | Attach `fn` as method on `map` object |
1011
+
1012
+ **Session / Resumable:**
1013
+
1014
+ | Keyword | Behavior |
1015
+ |---------|----------|
1016
+ | `session("name") { }` | Store named session body |
1017
+ | `enter key type` | Log `[enter] key type` — interactive entry point marker |
1018
+ | `resu name(args) => { },` | Resumable: re-parsed and run fresh on each call |
1019
+ | `keyfunc name(x) { } { }` | Pattern-matched function dispatch |
1020
+
1021
+ **Annotation / Registry:**
1022
+
1023
+ | Keyword | Behavior |
1024
+ |---------|----------|
1025
+ | `describe "text"` | Append to `nova.descriptions` |
1026
+ | `using flagName` | Set `this.options[flag] = true` |
1027
+ | `unuse flagName` | Delete `this.options[flag]` |
1028
+ | `using namespace MyNS` | Bring all namespace members into scope |
1029
+
1030
+ **Type Ops:**
1031
+
1032
+ | Keyword | Behavior |
1033
+ |---------|----------|
1034
+ | `classify value` | Print/return type string |
1035
+ | `classify value as Type` | Return bool |
1036
+ | `rate(v) type` | Type-cast (see full table in Type System section) |
1037
+
1038
+ **Control:**
1039
+
1040
+ | Keyword | Behavior |
1041
+ |---------|----------|
1042
+ | `skip` | No-op (parsed, returns undefined) |
1043
+ | `end` | Terminate current scope: throws `{ __return: undefined }` |
1044
+ | `clear` | Reset `nova.descriptions` to `[]` |
1045
+ | `time { }` | Time a block; print elapsed ms |
1046
+ | `wait(ms)` | Sync sleep via Atomics.wait |
1047
+
1048
+ **Misc:**
1049
+
1050
+ | Keyword | Behavior |
1051
+ |---------|----------|
1052
+ | `expt "val" from { }` | Capture stdout; error if `actual.trim() !== "val"` |
1053
+ | `option name = fn` | Set runtime option/hook |
1054
+ | `env VAR` | Read `process.env.VAR` into scope; throws if undefined |
1055
+ | `eval expr` | Re-evaluate an already-parsed AST node |
1056
+ | `declare (expr) as x` | Assign to `x` |
1057
+ | `declare (expr) into x` | Append string to `x` |
1058
+ | `declare (expr) as x log` | Assign and print |
1059
+ | `declare (expr) as x throw` | Assign and throw |
1060
+ | `declare (expr) as x finalize` | Assign and `return` |
1061
+
1062
+
1063
+ ## Built-in Global Objects
1064
+
1065
+ Always in scope — no import needed.
1066
+
1067
+ ### `core`
1068
+
1069
+ | Member | Description |
1070
+ |--------|-------------|
1071
+ | `core.print(v)` | `process.stdout.write(stringify(v) + '\n')` |
1072
+ | `core.json` | Reference to `JSON` |
1073
+ | `core.getAst()` | Returns current program AST |
1074
+ | `core.vars` | Reference to global scope variables |
1075
+ | `core.types` | Reference to the TypeRegistry |
1076
+ | `core.register(fn)` | Wraps a novac function as a native callable |
1077
+ | `core.import` | Module import function |
1078
+ | `core.ndb()` | Dev bridge: `{ exe, scopes, types, eventBus, gears, backups, macros, blocks, snippets, keyfuncs, sessions, resus, namespaces }` |
1079
+
1080
+ ### `nova` (Unified Registry)
1081
+
1082
+ Live proxy over all internal registries:
1083
+
1084
+ | Member | Description |
1085
+ |--------|-------------|
1086
+ | `nova.version` | `"2.0"` |
1087
+ | `nova.macros` | All defined macros |
1088
+ | `nova.blocks` | All defined blocks |
1089
+ | `nova.snippets` | All defined snippets |
1090
+ | `nova.gears` | All defined gears |
1091
+ | `nova.sessions` | All defined sessions |
1092
+ | `nova.resus` | All defined resus |
1093
+ | `nova.keyfuncs` | All defined keyfuncs |
1094
+ | `nova.backups` | All backed-up values |
1095
+ | `nova.options` | Current option flags |
1096
+ | `nova.descriptions` | Array of all `describe` annotations |
1097
+ | `nova.scope` | Reference to global scope |
1098
+ | `nova.types.structs` | Registered struct names |
1099
+ | `nova.types.interfaces` | Registered interface names |
1100
+ | `nova.types.enums` | Registered enum names |
1101
+ | `nova.types.traits` | Registered trait names |
1102
+ | `nova.types.check(val, typeName)` | Runtime type check → bool |
1103
+ | `nova.types.list()` | All registered type names |
1104
+ | `nova.events.events()` | Active event names |
1105
+ | `nova.events.count(ev)` | Number of listeners |
1106
+ | `nova.events.has(ev)` | Has listeners? |
1107
+ | `nova.events.clear(ev)` | Remove all listeners for event |
1108
+ | `nova.events.clearAll()` | Remove all events |
1109
+ | `nova.setMacro(name, val)` | Define/update a macro |
1110
+ | `nova.getMacro(name)` | Get macro value |
1111
+ | `nova.hasMacro(name)` | Check if macro exists |
1112
+ | `nova.setBlock(name, fn)` | Register a native block |
1113
+ | `nova.runBlock(name)` | Execute a named block |
1114
+ | `nova.runSnippet(name, ...args)` | Execute a named snippet |
1115
+ | `nova.emit(event, val)` | Emit event |
1116
+ | `nova.on(event, fn)` | Listen for event |
1117
+ | `nova.eval(code)` | Parse and run a novac code string |
1118
+ | `nova.inspect(name)` | `{ inScope, isMacro, isBlock, isSnippet, isGear, isSession, isResu, value }` |
1119
+ | `nova.clearAll()` | Clear macros, blocks, snippets, gears, sessions, descriptions |
1120
+
1121
+ ### `nvk` (Platform / System Namespace)
1122
+
1123
+ `nvk` exposes all system and I/O operations. These replaced the previous statement-based system keywords.
1124
+
1125
+ | Member | Description |
1126
+ |--------|-------------|
1127
+ | `nvk.notify(title, content)` | Termux notification (fallback: stdout) |
1128
+ | `nvk.toast(msg)` | Termux toast |
1129
+ | `nvk.vibrate(ms)` | Termux vibrate |
1130
+ | `nvk.clipboard(text)` | Set clipboard via Termux |
1131
+ | `nvk.camera(path)` | Take photo via Termux |
1132
+ | `nvk.share(path)` | Share file via Termux |
1133
+ | `nvk.open(path)` | Open file via Termux |
1134
+ | `nvk.cpu` | Array of CPU model strings |
1135
+ | `nvk.mem` | Total memory e.g. `"8.00GB"` |
1136
+ | `nvk.hostname` | `os.hostname()` |
1137
+ | `nvk.uptime` | `os.uptime()` in seconds |
1138
+ | `nvk.pid` | `process.pid` |
1139
+ | `nvk.arch` | `os.arch()` |
1140
+ | `nvk.platform` | `process.platform` |
1141
+ | `nvk.osPlatform` | `os.platform()` |
1142
+ | `nvk.userInfo` | `os.userInfo()` as NovaObject |
1143
+ | `nvk.network` | `os.networkInterfaces()` as NovaObject |
1144
+ | `nvk.load` | `os.loadavg()` as NovaArray |
1145
+ | `nvk.tmpDir` | `os.tmpdir()` |
1146
+ | `nvk.cwd` | `process.cwd()` |
1147
+ | `nvk.pathDir(p)` | `path.dirname(p)` |
1148
+ | `nvk.pathBase(p)` | `path.basename(p)` |
1149
+ | `nvk.pathExt(p)` | `path.extname(p)` |
1150
+ | `nvk.pathJoin(...parts)` | `path.join(...parts)` |
1151
+ | `nvk.sha256(s)` | SHA-256 hex digest |
1152
+ | `nvk.randomBytes(n)` | N random bytes as hex string |
1153
+ | `nvk.uuid()` | Random UUID v4 |
1154
+ | `nvk.parseURL(raw)` | `{ hostname, pathname, search, protocol, port }` |
1155
+ | `nvk.readFile(path)` | `fs.readFileSync(path, 'utf8')` |
1156
+ | `nvk.writeFile(path, content)` | `fs.writeFileSync` |
1157
+ | `nvk.createFile(path, content)` | Create/overwrite file |
1158
+ | `nvk.deleteFile(path)` | `fs.unlinkSync` |
1159
+ | `nvk.listFiles(dir)` | `fs.readdirSync(dir)` as NovaArray |
1160
+ | `nvk.exists(path)` | `fs.existsSync(path)` |
1161
+ | `nvk.execFile(path)` | Parse and run a `.nova` file |
1162
+ | `nvk.sh(cmd)` | `execSync(cmd)` — prints and returns stdout |
1163
+ | `nvk.exec(code)` | Parse and run a novac code string |
1164
+ | `nvk.term(cmd, shell)` | Run cmd in specified shell (`bash` default) |
1165
+ | `nvk.banner(text)` | Print box-drawn banner |
1166
+ | `nvk.warn(msg)` | `"Warning: msg"` |
1167
+ | `nvk.info(msg)` | `"INFO: msg"` |
1168
+
1169
+ ### `qae` (Query Assertion Engine)
1170
+
1171
+ All members are functions `(a) => bool` or `(a) => value`:
1172
+
1173
+ | Member | Description |
1174
+ |--------|-------------|
1175
+ | `qae.even(a)` / `qae.odd(a)` | Parity check |
1176
+ | `qae.integer(a)` | `Number.isInteger(a)` |
1177
+ | `qae.positive(a)` / `qae.negative(a)` / `qae.zero(a)` | Sign check |
1178
+ | `qae.finite_(a)` / `qae.infinite(a)` / `qae.nan_(a)` | Numeric state |
1179
+ | `qae.isnull(a)` / `qae.defined(a)` | Nullability |
1180
+ | `qae.trimable(a)` / `qae.trimmed(a)` | Whitespace |
1181
+ | `qae.uppercase(a)` / `qae.lowercase(a)` | Case transform |
1182
+ | `qae.numeric(a)` / `qae.alpha(a)` / `qae.alnum(a)` / `qae.blank(a)` | String class |
1183
+ | `qae.palindrome(a)` | Is palindrome (case-insensitive, strips spaces) |
1184
+ | `qae.empty(a)` / `qae.nonempty(a)` | Emptiness |
1185
+ | `qae.unique(a)` | Array has no duplicates |
1186
+ | `qae.first(a)` / `qae.last(a)` / `qae.length(a)` | Array/string access |
1187
+ | `qae.truthy(a)` / `qae.falsy(a)` | Boolean coercion |
1188
+ | `qae.type_(a)` | `typeof a` |
1189
+ | `qae.string_(a)` / `qae.number_(a)` / `qae.boolean_(a)` / `qae.object_(a)` / `qae.array_(a)` / `qae.function_(a)` | Type checks |
1190
+ | `qae.prime(a)` / `qae.composite(a)` / `qae.oddprime(a)` | Number theory |
1191
+ | `qae.vowel(a)` / `qae.consonant(a)` | Character class |
1192
+ | `qae.sorted(a)` / `qae.ascending(a)` / `qae.descending(a)` | Order checks |
1193
+ | `qae.contains(a, b)` / `qae.startsWith_(a, b)` / `qae.endsWith_(a, b)` / `qae.matches_(a, b)` | Containment |
1194
+ | `qae.divisible(a, b)` / `qae.between_(a, lo, hi)` | Numeric predicates |
1195
+ | `qae.check(a, pred)` | Apply function or named qae predicate to a |
1196
+
1197
+ ### `novaRegex(pattern, flags)`
1198
+
1199
+ Semantic regex with `<name>` placeholders. Returns a JS `RegExp`.
1200
+
1201
+ ```nova
1202
+ let emailRe = novaRegex("<email>")
1203
+ emailRe.test("a@b.com") // true
1204
+ novaRegex("<email|url>") // combined with |
1205
+ ```
1206
+
1207
+ Semantic names: `keyword` `symbol` `digit` `nondigit` `whitespace` `tab` `newline` `start` `end` `any` `wordboundary` `word` `variable` `integer` `float` `hex` `binary` `space` `title` `email` `url` `uuid` `date` `time` `color`
1208
+
1209
+ ### Global Functions
1210
+
1211
+ | Function | Description |
1212
+ |----------|-------------|
1213
+ | `typeOf(v)` | `"number"` `"string"` `"bool"` `"null"` `"array"` `"object"` `"range"` `"pointer"` `"function"` `"struct:Name"` `"enum:Name"` |
1214
+ | `typecheck(v, typeName)` | Runtime type check → bool |
1215
+ | `satisfies(v, ifaceName)` | Does value satisfy all required interface members? |
1216
+ | `fetch(url, options?)` | Sync HTTP → `{ ok, status, body, text }` |
1217
+ | `setTimeout(fn, delay)` | Schedule function after delay |
1218
+
1219
+ ---
1220
+
1221
+ ## Built-in Class Objects
1222
+
1223
+ All available globally:
1224
+
1225
+ ### `ForLoop(opts)`
1226
+
1227
+ ```nova
1228
+ ForLoop({ from: 1, to: 10 }).map(i => i * i).collect()
1229
+ ForLoop({ from: 0, to: 20, step: 2 }).toArray()
1230
+ ForLoop({ from: 1, to: 100 }).do(i => { sum += i }).run()
1231
+ ```
1232
+
1233
+ | Method | Description |
1234
+ |--------|-------------|
1235
+ | `.from(n)` `.to(n)` `.step(n)` | Configure range |
1236
+ | `.do(fn)` / `.each(fn)` / `.map(fn)` | Set body |
1237
+ | `.run()` | Execute without collecting |
1238
+ | `.collect()` | Execute and collect results |
1239
+ | `.toArray()` | Collect index values |
1240
+ | `.filter(fn)` | Convert to Pipeline then filter |
1241
+ | `.pipe()` | Convert to Pipeline |
1242
+ | `.toStream()` | Convert to DataStream |
1243
+
1244
+ ### `WhileLoop(opts)`
1245
+
1246
+ ```nova
1247
+ WhileLoop({}).cond(() => n < 32).do(() => { n *= 2 }).maxIter(100).run()
1248
+ ```
1249
+
1250
+ ### `IfBlock(opts)`
1251
+
1252
+ ```nova
1253
+ IfBlock({ cond: score >= 90, then: () => "A" })
1254
+ .elseIf(score >= 80, () => "B").else(() => "F").run()
1255
+ ```
1256
+
1257
+ ### `MatchBlock(subject)`
1258
+
1259
+ ```nova
1260
+ MatchBlock(404)
1261
+ .when(200, () => "OK")
1262
+ .when(404, () => "Not Found")
1263
+ .when(90..100, x => "A")
1264
+ .when(x => x > 500, x => "server err")
1265
+ .default(() => "Unknown")
1266
+ .run()
1267
+ ```
1268
+
1269
+ ### `TryCatch()`
1270
+
1271
+ ```nova
1272
+ TryCatch().try(() => { throw "oops" }).catch(e => core.print(e)).finally(() => {}).run()
1273
+ ```
1274
+
1275
+ ### `Pipeline(initial)`
1276
+
1277
+ ```nova
1278
+ Pipeline([1,2,3,4,5]).filter(x => x % 2 == 0).map(x => x*x).take(2).collect()
1279
+ ```
1280
+
1281
+ | Method | Description |
1282
+ |--------|-------------|
1283
+ | `.pipe(fn)` / `.map(fn)` | Transform |
1284
+ | `.filter(fn)` | Filter |
1285
+ | `.tap(fn)` | Side-effect passthrough |
1286
+ | `.flatMap(fn)` | Map + flatten |
1287
+ | `.reduce(fn, init)` | Immediate reduce |
1288
+ | `.take(n)` / `.skip(n)` | Slice |
1289
+ | `.run()` / `.collect()` | Execute |
1290
+
1291
+ ### `FuncDef(opts)`
1292
+
1293
+ ```nova
1294
+ FuncDef({ args: ["a", "b"], body: (a, b) => a + b }).named("add").call(10, 32)
1295
+ ```
1296
+
1297
+ ### `Timer()`
1298
+
1299
+ ```nova
1300
+ let t = Timer(); t.start(); t.lap(); let ms = t.stop()
1301
+ t.elapsed // ms since start
1302
+ t.laps // NovaArray of lap times
1303
+ ```
1304
+
1305
+ ### `Counter(initial, step)`
1306
+
1307
+ ```nova
1308
+ let c = Counter(0); c.increment(5); c.decrement(2); c.clamp(0, 100); c.value
1309
+ ```
1310
+
1311
+ ### `Stack()` / `Queue()` / `LinkedList()`
1312
+
1313
+ ```nova
1314
+ let s = Stack(); s.push(10); s.pop(); s.peek(); s.size; s.empty
1315
+ let q = Queue(); q.enqueue("a"); q.dequeue(); q.peek(); q.size
1316
+ let ll = LinkedList(); ll.push("a"); ll.shift(); ll.pop(); ll.unshift("z"); ll.size
1317
+ ```
1318
+
1319
+ ### `State(initial)`
1320
+
1321
+ ```nova
1322
+ let sm = State("idle")
1323
+ sm.add("idle", "start", "running").add("running", "done", "idle")
1324
+ sm.onEnter("running", s => {}).onExit("idle", s => {})
1325
+ sm.dispatch("start") // true = success
1326
+ sm.current; sm.history; sm.is("running")
1327
+ ```
1328
+
1329
+ ### `Observable(initial)` / `Signal(initial)`
1330
+
1331
+ ```nova
1332
+ let obs = Observable(0)
1333
+ obs.subscribe((newVal, oldVal) => {})
1334
+ obs.value = 42
1335
+ let derived = obs.pipe(x => x * 2)
1336
+
1337
+ let sig = Signal(1)
1338
+ let doubled = sig.derive(x => x * 2)
1339
+ sig.value = 5 // doubled.value = 10 (automatic propagation)
1340
+ sig.effect(v => {}) // runs immediately and on every change
1341
+ ```
1342
+
1343
+ ### `Validator()`
1344
+
1345
+ ```nova
1346
+ Validator().required().type("number").min(0).max(100).validate(50)
1347
+ // { valid: true, errors: [], value: 50 }
1348
+ ```
1349
+
1350
+ | Method | Description |
1351
+ |--------|-------------|
1352
+ | `.required()` `.type(t)` `.min(n)` `.max(n)` | Core validators |
1353
+ | `.minLen(n)` `.maxLen(n)` `.pattern(re)` `.email()` | String validators |
1354
+ | `.custom(fn, msg)` | Custom validator |
1355
+ | `.validate(v)` | Returns `{ valid, errors: NovaArray, value }` |
1356
+
1357
+ ### `DataStream(source)`
1358
+
1359
+ ```nova
1360
+ DataStream([5,3,8,1,9]).filter(x => x > 3).sort().reverse().take(3).collect()
1361
+ ```
1362
+
1363
+ | Method | Description |
1364
+ |--------|-------------|
1365
+ | `.map` `.filter` `.take` `.skip` `.flatMap` | Transform |
1366
+ | `.distinct()` | Deduplicate via Set |
1367
+ | `.sort(fn?)` `.reverse()` `.zip(other)` | Reorder |
1368
+ | `.collect()` `.reduce(fn, init)` `.forEach(fn)` | Materialize |
1369
+ | `.first()` `.last()` `.count()` | Inspect |
1370
+
1371
+ ### `Transformer()` / `TransformerJSON()` / `TransformerBase64()`
1372
+
1373
+ ```nova
1374
+ let jt = TransformerJSON(); jt.to({ x: 1 }); jt.from('{"x":1}')
1375
+ let b64 = TransformerBase64(); b64.to("Hello!"); b64.from(encoded)
1376
+ // Static presets: Transformer.upper(), Transformer.trim_(), Transformer.number_()
1377
+ ```
1378
+
1379
+ ### `Router()`
1380
+
1381
+ ```nova
1382
+ let router = Router()
1383
+ router.on("/api/users/(.*)", id => f"user {id}").default(p => f"404: {p}")
1384
+ router.dispatch("/api/users/42") // "user 42"
1385
+ ```
1386
+
1387
+ ### `EventBus()`
1388
+
1389
+ ```nova
1390
+ let bus = EventBus()
1391
+ bus.on("data", v => {}).once("ready", () => {}).off("data", handler)
1392
+ bus.emit("data", 42); bus.events()
1393
+ ```
1394
+
1395
+ ### `Memo(fn, keyFn?)` / `Lazy(fn)`
1396
+
1397
+ ```nova
1398
+ let m = Memo(x => x * x * x)
1399
+ m.call(5); m.stats; m.clear(); m.invalidate(5)
1400
+
1401
+ let lazy = Lazy(() => expensiveOp())
1402
+ lazy.value; lazy.reset(); lazy.map(fn)
1403
+ ```
1404
+
1405
+ ---
1406
+
1407
+ ## Standard Library (`std`)
1408
+
1409
+ Always available as `std.X`.
1410
+
1411
+ ### `std.Math`
1412
+
1413
+ `abs` `ceil` `floor` `round` `sqrt` `pow` `max` `min` `log` `log2` `log10` `sin` `cos` `tan` `PI` `E` `trunc` `sign` `random` plus:
1414
+
1415
+ | Member | Description |
1416
+ |--------|-------------|
1417
+ | `clamp(v, lo, hi)` | `Math.min(Math.max(v,lo),hi)` |
1418
+ | `floorTo(a, b)` | Floor to nearest multiple of b |
1419
+ | `ceilTo(a, b)` | Ceil to nearest multiple of b |
1420
+ | `factorial(n)` | Memoized factorial |
1421
+ | `fibonacci(n)` | Memoized fibonacci |
1422
+ | `divmod(a, b)` | `[quotient, remainder]` |
1423
+
1424
+ ### `std.Array`
1425
+
1426
+ `from(it)` `of(...items)` `range(start, end, step)` `isArray(v)` `fill(n, val)` `zip(...arrs)`
1427
+
1428
+ ### `std.Object`
1429
+
1430
+ `keys(o)` `values(o)` `entries(o)` `assign(target, ...srcs)` `freeze(o)` `has(o, k)` `create(proto)`
1431
+
1432
+ ### `std.String`
1433
+
1434
+ `from(v)` `padStart` `padEnd` `repeat` `includes` `startsWith` `endsWith` `trim` `split` `replace` `replaceAll` `toUpper` `toLower` `charAt` `charCodeAt` `fromCharCode` `slice` `indexOf`
1435
+
1436
+ ### `std.is`
1437
+
1438
+ ```nova
1439
+ std.is.number(v) std.is.string(v) std.is.bool(v) std.is.array(v)
1440
+ std.is.object(v) std.is.null(v) std.is.func(v) std.is.range(v)
1441
+ std.is.integer(v) std.is.finite(v) std.is.NaN(v)
1442
+ ```
1443
+
1444
+ ### `std.fn`
1445
+
1446
+ `identity` `compose` `pipe` `memoize` `once` `partial` `curry` `noop` `always` `flip` `not`
1447
+
1448
+ ### Other `std` Members
1449
+
1450
+ | Member | Description |
1451
+ |--------|-------------|
1452
+ | `std.num(v)` / `std.str(v)` / `std.bool(v)` / `std.int(v)` | Coercions |
1453
+ | `std.print(...)` | `console.log(...)` |
1454
+ | `std.error(msg)` | Throw an Error |
1455
+ | `std.range(start, end, step)` | Create NovaRange |
1456
+ | `std.fnum(min, max, initial)` | Clamped float with `.value` get/set |
1457
+ | `std.fint(min, max, initial)` | Clamped integer with `.value` get/set |
1458
+ | `std.convertCase(str, target)` | `"snake"` `"camel"` `"pascal"` `"kebab"` `"upper"` `"lower"` |
1459
+ | `std.randomWord()` | Random pronounceable word |
1460
+ | `std.randomName(format?, minLen?, maxLen?)` | Capitalized random name |
1461
+ | `std.console.*` | `log warn error info time timeEnd` |
1462
+ | `std.Date.now()` / `std.Date.create(...)` | Date utilities |
1463
+ | `std.json.parse(s)` / `std.json.stringify(v, sp?)` | JSON with NovaObject unwrapping |
1464
+ | `std.Promise.*` | `resolve reject all race allSettled any` |
1465
+
1466
+ ---
1467
+
1468
+ ## Standard Built-ins (`bstd` / `import_builtin`)
1469
+
1470
+ ### `Air`
1471
+
1472
+ Object of references to all novac core modules keyed by filename.
1473
+
1474
+ ### `Chalk`
1475
+
1476
+ ANSI terminal colors (same API as `chalk` npm package):
1477
+
1478
+ ```nova
1479
+ import_builtin Chalk
1480
+ core.print(Chalk.red("error"))
1481
+ core.print(Chalk.bold.green("success"))
1482
+ ```
1483
+
1484
+ ### `History`
1485
+
1486
+ File-backed input history stored as `.184.<name>`:
1487
+
1488
+ `getKey(name)` `exists(key)` `createHistory(key)` `appendHistory(key, item, mode?, index?)` `readHistory(key)` `rawSetHistory(key, array)` `rawGetHistory(key)` `clearHistory(key)`
1489
+
1490
+ ### `Input`
1491
+
1492
+ Synchronous terminal input with full line-editing:
1493
+
1494
+ ```nova
1495
+ import_builtin Input
1496
+ let r = Input.prompt("Name: ")
1497
+ // r: { result: "typed text", history: [] }
1498
+ Input.prompt("Pwd: ", { password: true, passwordHash: "*" })
1499
+ Input.prompt("Cmd: ", true) // enable history
1500
+ Input.prompt("Search: ", { completer: buf => "suggestion" })
1501
+ ```
1502
+
1503
+ Features: cursor, history `↑↓`, backspace, delete, tab completion, Ctrl+C, password masking.
1504
+
1505
+ ### `Shema` / `ShemaType`
1506
+
1507
+ ```nova
1508
+ import_builtin Shema, ShemaType
1509
+ let schema = new Shema({ name: ShemaTypes.String, age: ShemaTypes.Int })
1510
+ schema.validate({ name: "novac", age: 2 })
1511
+ schema.defaultObj()
1512
+ new ShemaType("PositiveInt", val => Number.isInteger(val) && val > 0)
1513
+ ```
1514
+
1515
+ Built-in `ShemaTypes`: `Int` `Float` `String` `Boolean` `Array` `Object` `Function` `Null` `Undefined` `Symbol` `BigInt` `Date` `RegExp` `Shema` `Any`
1516
+
1517
+ ### `ConfigFile`
1518
+
1519
+ ```nova
1520
+ import_builtin ConfigFile
1521
+ let cfg = new ConfigFile("app", "json", false, mySchema)
1522
+ cfg.writeFull({ host: "localhost", port: 8080 })
1523
+ cfg.write(["database", "host"], "db.example.com")
1524
+ cfg.readFull(); cfg.read(["database", "host"])
1525
+ cfg.interactiveSetup(defaultConfig)
1526
+ ```
1527
+
1528
+ ### `JsDB`
1529
+
1530
+ `JsDB.class(JsClass)` `JsDB.run(code)` `JsDB.require` `JsDB.gt` `JsDB.fetch(url, opts)` `JsDB.process` `JsDB.version` `JsDB.platform` `JsDB.env`
1531
+
1532
+ ### `Storage`
1533
+
1534
+ ```nova
1535
+ import_builtin Storage
1536
+ Storage.setItem("key", { data: 42 })
1537
+ Storage.getItem("key")
1538
+ Storage.removeItem("key")
1539
+ Storage.clear()
1540
+ ```
1541
+
1542
+ ### `Crypto`
1543
+
1544
+ ```nova
1545
+ import_builtin Crypto
1546
+ Crypto.hash("data") // SHA-256 hex
1547
+ Crypto.hash("data", "sha512") // any Node.js crypto algo
1548
+ ```
1549
+
1550
+ ### `PathUtils`
1551
+
1552
+ `join` `resolve` `basename` `dirname` `extname`
1553
+
1554
+ ### `Base64`
1555
+
1556
+ `Base64.encode(s)` `Base64.decode(s)`
1557
+
1558
+ ### `OsUtils`
1559
+
1560
+ `platform` `homedir()` `tmpdir()` `cpus()` `totalmem()` `freemem()` `uptime()` `openFile(path)` (Windows: `requestAdminPrivileges()`)
1561
+
1562
+ ### `Zip`
1563
+
1564
+ ```nova
1565
+ import_builtin Zip
1566
+ await Zip.zip(["a.txt"], "out.zip")
1567
+ await Zip.unzip("out.zip", "./output/")
1568
+ ```
1569
+
1570
+ ---
1571
+
1572
+ ## Array Methods
1573
+
1574
+ Auto-dispatched on any NovaArray:
1575
+
1576
+ `map` `filter` `reduce` `find` `findIndex` `some` `every` `flat` `flatMap` `sort` `reverse` `slice` `splice` `indexOf` `includes` `join` `push` `pop` `shift` `unshift` `concat` `fill` `forEach` `keys` `values` `entries` `at` `first` `last` `random` `unique` `count` `groupBy` `shuffle` `min` `max` `sum` `avg` `product` `toArray` `toObject` `toString` | `.length` (property)
1577
+
1578
+ ---
1579
+
1580
+ ## Object Methods
1581
+
1582
+ Auto-dispatched on any NovaObject:
1583
+
1584
+ `keys()` `values()` `entries()` `has(k)` `assign(...srcs)` | `.length` (property)
1585
+
1586
+ ---
1587
+
1588
+ ## String Methods
1589
+
1590
+ Auto-dispatched on any string:
1591
+
1592
+ `toUpperCase` `toLowerCase` `trim` `split` `includes` `startsWith` `endsWith` `slice` `indexOf` `lastIndexOf` `repeat` `replace` `match` | `.length` (property)
1593
+
1594
+ ---
1595
+
1596
+ ## Type System & Casting
1597
+
1598
+ ### `as` Cast
1599
+
1600
+ ```nova
1601
+ let n = value as int // Math.trunc(Number(v))
1602
+ let f = value as float // Number(v)
1603
+ let s = value as string // String(v)
1604
+ let b = value as bool // Boolean(v)
1605
+ let a = value as array // _toIterable(v) → NovaArray
1606
+ let st = value as MyStruct
1607
+ ```
1608
+
1609
+ ### `rate()` Cast — Full Type Table
1610
+
1611
+ | Type | Operation |
1612
+ |------|-----------|
1613
+ | `int` | `Math.trunc(Number(v))` |
1614
+ | `float` / `f64` | `Number(v)` |
1615
+ | `f32` | `Math.fround(Number(v))` |
1616
+ | `string` | `String(v)` |
1617
+ | `bool` | `Boolean(v)` |
1618
+ | `bigint` | `BigInt(Math.trunc(Number(v)))` |
1619
+ | `u8` | `parseInt(v) & 0xFF` |
1620
+ | `u16` | `parseInt(v) & 0xFFFF` |
1621
+ | `u32` | `parseInt(v) >>> 0` |
1622
+ | `i8` | `(parseInt(v) << 24) >> 24` |
1623
+ | `i16` | `(parseInt(v) << 16) >> 16` |
1624
+ | `i32` | `parseInt(v) \| 0` |
1625
+ | `char` | `String(v)[0]` |
1626
+ | `array` | `_toIterable(v)` → NovaArray |
1627
+ | `StructName` | `createStruct("StructName", v)` |
1628
+
1629
+ ### Type Check
1630
+
1631
+ ```nova
1632
+ typecheck(42, "number") // true
1633
+ satisfies(doc, "Serializable") // true if all required interface members present
1634
+ classify value // returns type string
1635
+ classify value as TypeName // returns bool
1636
+ ```
1637
+
1638
+ ---
1639
+
1640
+ ## CLI — novac
1641
+
1642
+ ```sh
1643
+ novac <file> [args...] Run a .nova / .nv file
1644
+ novac test <file> Check syntax (exit 0 = OK, prints "Syntax OK")
1645
+ novac format [file] Format a file (or stdin if no file given)
1646
+ novac eval <code> Evaluate a novac code string inline
1647
+ novac tokens <file> Print token stream as JSON
1648
+ novac ast <file> Print AST as JSON
1649
+ novac repl Start interactive REPL
1650
+ novac new <project> Scaffold a new project directory
1651
+ novac new-kit <dirname> Scaffold a new kit in current directory
1652
+ novac init PATH Add npm bin to system PATH (writes to shell rc)
1653
+ novac init build Bundle project into a .novamod file
1654
+ novac config get [key] Read global/project config (all keys if no key given)
1655
+ novac config set <key> <value> Write a config key
1656
+ novac config init Interactive config setup wizard
1657
+ novac etc notices Show runtime notices from stdlib
1658
+ novac etc describe <file> Print a human-readable description of a .nova file's AST
1659
+ novac etc kit <name> Install a built-in kit into ./nova_modules/<name>
1660
+ novac etc kit <name> --global Install a built-in kit into ~/.novac/nova_modules/<name>
1661
+ novac module install [path] Install a .novamod bundle (or all deps from nova.config.json)
1662
+ novac module install [path] -g Install globally into ~/.novac/nova_modules
1663
+ novac module list List all installed modules in nova_modules/
1664
+ novac module remove <name> Remove an installed module
1665
+ ```
1666
+
1667
+ ### Running a File
1668
+
1669
+ ```sh
1670
+ novac src/main.nova
1671
+ novac src/main.nova arg1 arg2
1672
+ novac src/main.nova --port 8080 --debug
1673
+ novac src/main.nova @addr1 +feature1
1674
+ ```
1675
+
1676
+ All arguments after the file are parsed and exposed as the `cli` object inside the script (see below).
1677
+
1678
+ ### Argument Parsing Rules
1679
+
1680
+ | Argument form | Goes into |
1681
+ |---------------|-----------|
1682
+ | `positional` (no prefix) | `cli.args` array |
1683
+ | `-flag` | `cli.options.flag = true` |
1684
+ | `--flag` | `cli.options.flag = true` |
1685
+ | `--flag value` | `cli.options.flag = "value"` |
1686
+ | `--flag=value` | `cli.options.flag = "value"` |
1687
+ | `@name` | `cli.addrs.name = true` |
1688
+ | `+feature` | `cli.additions.feature = true` |
1689
+
1690
+ Arguments that start with `-`, `@`, or `+` are **excluded** from `cli.args`.
1691
+
1692
+ ### REPL Commands
1693
+
1694
+ Inside `novac repl`:
1695
+
1696
+ | Command | Description |
1697
+ |---------|-------------|
1698
+ | `.exit` | Exit the REPL |
1699
+ | `.clear` | Clear the screen |
1700
+ | `.ast <code>` | Print AST of inline code |
1701
+ | `.tokens <code>` | Print token stream of inline code |
1702
+ | `.help` | Show REPL help |
1703
+
1704
+ History is persisted to `~/.nova_repl_history`.
1705
+
1706
+ ### `novac new <project>`
1707
+
1708
+ Scaffolds a project directory with:
1709
+
1710
+ ```
1711
+ <project>/
1712
+ src/main.nova // starter file with print("Hello, Nova!")
1713
+ bin/<project>.nv // entry script (empty, chmod 755)
1714
+ nova_modules/ // local module directory
1715
+ nova.config.json // project manifest
1716
+ README.md
1717
+ .gitignore
1718
+ ```
1719
+
1720
+ `nova.config.json` fields: `name`, `version`, `description`, `author`, `license`, `main`, `srcDir`, `scripts.run`, `dependencies`, `devDependencies`.
1721
+
1722
+ ### `novac init build`
1723
+
1724
+ Reads `nova.config.json` from `cwd`, collects all `.nova`/`.nv` files from `srcDir`, and bundles them into `<name>.novamod` — a JSON file with:
1725
+
1726
+ ```json
1727
+ {
1728
+ "manifest": { "name", "version", "main", ...config },
1729
+ "sources": { "relative/path.nova": "source code", ... },
1730
+ "buildTime": "ISO timestamp"
1731
+ }
1732
+ ```
1733
+
1734
+ Install in another project: `novac module install ./<name>.novamod`
1735
+
1736
+ ### `novac etc kit <name>`
1737
+
1738
+ Installs a built-in kit from `novac/kits/<name>/` into `nova_modules/`. Available built-in kits: `kitnovacweb`, `kitlibfs`, `kitlibproc`.
1739
+
1740
+ ---
1741
+
1742
+ ## Built-in `cli` Object
1743
+
1744
+ When a file is run via `novac <file> [args...]`, a `cli` object is automatically injected into the global scope:
1745
+
1746
+ ```nova
1747
+ // novac myapp.nova hello world --port 8080 --debug @prod +cache
1748
+
1749
+ cli.args // ["hello", "world"] — positional args (no flag prefix)
1750
+ cli.options // { port: "8080", debug: true }
1751
+ cli.addrs // { prod: true }
1752
+ cli.additions // { cache: true }
1753
+ cli.raw // process.argv — full raw argument array
1754
+ ```
1755
+
1756
+ ### Full `cli` Object Shape
1757
+
1758
+ | Property | Type | Description |
1759
+ |----------|------|-------------|
1760
+ | `cli.args` | Array | Positional arguments (no `-`, `@`, `+` prefix) |
1761
+ | `cli.options` | Object | All `-flag`, `--flag`, `--flag=val`, `--flag val` arguments |
1762
+ | `cli.addrs` | Object | All `@name` arguments, values are `true` |
1763
+ | `cli.additions` | Object | All `+name` arguments, values are `true` |
1764
+ | `cli.raw` | Array | `process.argv` — complete unprocessed argument list |
1765
+
1766
+ ### Usage Examples
1767
+
1768
+ ```nova
1769
+ // novac server.nova --port 3000 --host localhost
1770
+ let port = cli.options.port or "8080"
1771
+ let host = cli.options.host or "0.0.0.0"
1772
+ server(port) {
1773
+ get "/" (req, res) { res.json({ host, port }) }
1774
+ }
1775
+ ```
1776
+
1777
+ ```nova
1778
+ // novac build.nova src/main.nova --minify --output dist/app.js
1779
+ let inputFile = cli.args[0]
1780
+ let minify = cli.options.minify or false
1781
+ let output = cli.options.output or "out.js"
1782
+ ```
1783
+
1784
+ ```nova
1785
+ // novac deploy.nova @production +cache
1786
+ if (cli.addrs.production) {
1787
+ core.print("Deploying to production")
1788
+ }
1789
+ if (cli.additions.cache) {
1790
+ core.print("Cache warming enabled")
1791
+ }
1792
+ ```
1793
+
1794
+ ---
1795
+
1796
+ ## Threads
1797
+
1798
+ ```nova
1799
+ func worker() => {
1800
+ give heavyComputation()
1801
+ }
1802
+
1803
+ let t = Thread(worker)
1804
+ t.start()
1805
+ t.send("message")
1806
+ t.on_message(msg => { core.print(msg) })
1807
+ let result = t.join()
1808
+ ```
1809
+
1810
+ | Method / Property | Description |
1811
+ |-------------------|-------------|
1812
+ | `.start()` | Spawn the worker thread |
1813
+ | `.join()` | Block until done; applies scope mutations; returns result |
1814
+ | `.send(value)` | Post message to worker |
1815
+ | `.on_message(fn)` | Handler for messages from worker |
1816
+ | `.result` | Final return value |
1817
+ | `.error` | Error string if worker threw |
1818
+ | `.done` | Boolean: completed |
1819
+
1820
+ Scope snapshot: user-defined variables serialized and sent. Functions serialized via `toString()`. Worker can write back via `thread.set(name, val)` — applied atomically on `.join()`.
1821
+
1822
+
1823
+ Read also: NVML readme (./kits/kitnovacweb/README.md)