future-lang 0.3.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/ARCHITECTURE.md +424 -0
- package/MIGRATION.md +365 -0
- package/README.md +370 -0
- package/ROADMAP.md +263 -0
- package/examples/adult.future +8 -0
- package/examples/api.future +11 -0
- package/examples/assistant.future +8 -0
- package/examples/browser-demo.html +164 -0
- package/examples/greet.future +7 -0
- package/examples/hello.future +1 -0
- package/examples/math.future +8 -0
- package/examples/mini-app.html +301 -0
- package/examples/smarthome.future +10 -0
- package/future-browser.js +102 -0
- package/future-playground.html +650 -0
- package/package.json +27 -0
- package/runtime/ai.js +92 -0
- package/runtime/browser.js +458 -0
- package/runtime/device.js +36 -0
- package/runtime/home.js +19 -0
- package/runtime/http.js +32 -0
- package/runtime/index.js +403 -0
- package/runtime/lsp-metadata.js +104 -0
- package/runtime/math.js +16 -0
- package/runtime/memory.js +61 -0
- package/runtime/mqtt.js +49 -0
- package/runtime/providers/anthropic.js +59 -0
- package/runtime/providers/index.js +93 -0
- package/runtime/providers/openai-compat.js +85 -0
- package/runtime/providers/util.js +70 -0
- package/runtime/rag/chunker.js +65 -0
- package/runtime/rag/pipeline.js +86 -0
- package/runtime/rag/vector-store.js +119 -0
- package/runtime/rag.js +94 -0
- package/runtime/schedule.js +77 -0
- package/runtime/system.js +101 -0
- package/runtime/tts.js +38 -0
- package/runtime/vision.js +85 -0
- package/server.js +42 -0
- package/src/ast.js +202 -0
- package/src/cli.js +391 -0
- package/src/errors.js +21 -0
- package/src/formatter.js +48 -0
- package/src/generator.js +457 -0
- package/src/index.js +48 -0
- package/src/lexer.js +248 -0
- package/src/parser.js +469 -0
package/ARCHITECTURE.md
ADDED
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
# Future — Architecture & Folder Structure
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Future is an AI-first, IoT-first programming language that transpiles to JavaScript and runs on Node.js (and in the browser). The compiler is a classic three-phase pipeline: **Lex → Parse → Generate**. Capabilities (AI, HTTP, MQTT, math, …) are runtime modules — adding a new capability never requires a grammar change.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Folder Structure
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
future-lang/
|
|
13
|
+
│
|
|
14
|
+
├── src/ # Compiler frontend
|
|
15
|
+
│ ├── index.js # Public API — compile(source, options)
|
|
16
|
+
│ ├── lexer.js # Phase 1: source text → token list
|
|
17
|
+
│ ├── parser.js # Phase 2: token list → AST
|
|
18
|
+
│ ├── ast.js # AST node types and factory functions (23 types)
|
|
19
|
+
│ ├── generator.js # Phase 3: AST → JavaScript source
|
|
20
|
+
│ ├── errors.js # FutureError with line/column tracking
|
|
21
|
+
│ └── cli.js # CLI binary: future run / future compile
|
|
22
|
+
│
|
|
23
|
+
├── runtime/ # Capability modules (imported by generated JS)
|
|
24
|
+
│ ├── index.js # Aggregator: runtime object + manifest + introspection
|
|
25
|
+
│ │
|
|
26
|
+
│ ├── ai.js # Text generation — pluggable provider architecture
|
|
27
|
+
│ ├── http.js # REST API consumption (fetch-based)
|
|
28
|
+
│ ├── mqtt.js # Pub/sub messaging (real broker or in-process loopback)
|
|
29
|
+
│ ├── tts.js # Text-to-speech (system engine)
|
|
30
|
+
│ ├── rag.js # RAG — chunk → embed → store → retrieve → answer
|
|
31
|
+
│ ├── vision.js # Vision AI — describe, detect, ocr, classify, compare
|
|
32
|
+
│ ├── home.js # Home automation (composes over MQTT)
|
|
33
|
+
│ │
|
|
34
|
+
│ ├── memory.js # In-process key-value store (set/get/search/delete/forget)
|
|
35
|
+
│ ├── schedule.js # Recurring / one-shot / cron scheduling
|
|
36
|
+
│ ├── system.js # OS utilities: exec, open, notify, read, write
|
|
37
|
+
│ ├── device.js # IoT device registry
|
|
38
|
+
│ ├── math.js # Math module: round/floor/ceil/abs/sqrt/pow/log/random/min/max/pi/e
|
|
39
|
+
│ ├── browser.js # Browser-compatible runtime (no Node.js deps)
|
|
40
|
+
│ ├── lsp-metadata.js # VSCode / LSP metadata generated from the manifest
|
|
41
|
+
│ │
|
|
42
|
+
│ ├── providers/ # AI provider implementations
|
|
43
|
+
│ │ ├── index.js # Provider factory + env-var resolution
|
|
44
|
+
│ │ ├── anthropic.js # Anthropic Messages API (native format)
|
|
45
|
+
│ │ ├── openai-compat.js # OpenAI-compatible (OpenAI, Ollama, Gemini, OpenRouter, …)
|
|
46
|
+
│ │ └── util.js # SSE parser, keyword vector, cosine similarity
|
|
47
|
+
│ │
|
|
48
|
+
│ └── rag/ # RAG pipeline internals
|
|
49
|
+
│ ├── chunker.js # Document → overlapping text chunks
|
|
50
|
+
│ ├── vector-store.js # Vector store adapters (memory, file, cloud stubs)
|
|
51
|
+
│ └── pipeline.js # Full pipeline: index() and query()
|
|
52
|
+
│
|
|
53
|
+
├── test/ # Node built-in test runner suites
|
|
54
|
+
│ ├── lexer.test.js
|
|
55
|
+
│ ├── parser.test.js
|
|
56
|
+
│ ├── generator.test.js
|
|
57
|
+
│ ├── runtime.test.js
|
|
58
|
+
│ ├── capabilities.test.js
|
|
59
|
+
│ └── e2e.test.js
|
|
60
|
+
│
|
|
61
|
+
├── examples/ # Demo Future programs
|
|
62
|
+
│ ├── hello.future
|
|
63
|
+
│ ├── greet.future
|
|
64
|
+
│ ├── adult.future
|
|
65
|
+
│ ├── math.future
|
|
66
|
+
│ ├── api.future
|
|
67
|
+
│ ├── assistant.future
|
|
68
|
+
│ └── smarthome.future
|
|
69
|
+
│
|
|
70
|
+
├── future-browser.js # Browser entry point: window.Future + <script type="future">
|
|
71
|
+
├── future-playground.html # In-browser editor (11 examples, live compile)
|
|
72
|
+
├── package.json
|
|
73
|
+
├── ARCHITECTURE.md # This file
|
|
74
|
+
├── ROADMAP.md # Feature roadmap
|
|
75
|
+
└── MIGRATION.md # Changelog and migration notes
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Compiler Pipeline
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
Source text (.future)
|
|
84
|
+
│
|
|
85
|
+
▼
|
|
86
|
+
[ Lexer ] src/lexer.js
|
|
87
|
+
Token list 24 keywords, operators, strings, numbers
|
|
88
|
+
│
|
|
89
|
+
▼
|
|
90
|
+
[ Parser ] src/parser.js
|
|
91
|
+
AST (Program node) Recursive-descent, 23 node types
|
|
92
|
+
│
|
|
93
|
+
▼
|
|
94
|
+
[ Generator ] src/generator.js
|
|
95
|
+
JavaScript source SIMPLE or ASYNC mode
|
|
96
|
+
│
|
|
97
|
+
▼
|
|
98
|
+
Node.js / Browser runtime
|
|
99
|
+
(imports future-lang/runtime as __rt)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Two output modes
|
|
103
|
+
|
|
104
|
+
| Mode | Trigger | Output |
|
|
105
|
+
|------|---------|--------|
|
|
106
|
+
| **SIMPLE** | No capability calls, no `on`/`every`, no `input()`, no `math.*` | Plain synchronous JS, no imports |
|
|
107
|
+
| **ASYNC** | Any capability call, `on`, `every`, `input()`, `math.*`, `agent`, `stream` | ES module with `import { runtime as __rt }`, all functions `async`, all method calls `await`ed |
|
|
108
|
+
|
|
109
|
+
The user never writes `async` or `await` — the compiler injects them automatically.
|
|
110
|
+
|
|
111
|
+
In **browser mode** (`browserMode: true` option), the `import` statement is omitted and `print` is routed through `__rt.print` so it can be redirected to the DOM.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Lexer
|
|
116
|
+
|
|
117
|
+
### Keywords (24)
|
|
118
|
+
|
|
119
|
+
| Keyword | Token | Purpose |
|
|
120
|
+
|---------|-------|---------|
|
|
121
|
+
| `print` | PRINT | Output statement |
|
|
122
|
+
| `if` | IF | Conditional |
|
|
123
|
+
| `else` | ELSE | Else branch |
|
|
124
|
+
| `end` | END | Block terminator |
|
|
125
|
+
| `function` | FUNCTION | Function declaration |
|
|
126
|
+
| `return` | RETURN | Return statement |
|
|
127
|
+
| `true` / `false` | TRUE / FALSE | Boolean literals |
|
|
128
|
+
| `and` / `or` / `not` | AND / OR / NOT | Logical operators |
|
|
129
|
+
| `on` | ON | Event subscription |
|
|
130
|
+
| `every` | EVERY | Recurring task |
|
|
131
|
+
| `for` | FOR | List iteration |
|
|
132
|
+
| `in` | IN | Used with `for` |
|
|
133
|
+
| `try` | TRY | Error handling |
|
|
134
|
+
| `catch` | CATCH | Error handler branch |
|
|
135
|
+
| `while` | WHILE | Condition-based loop |
|
|
136
|
+
| `null` / `none` | NULL | Null literal (two spellings) |
|
|
137
|
+
| `stream` | STREAM | Streaming statement |
|
|
138
|
+
| `agent` | AGENT | Agent declaration |
|
|
139
|
+
| `use` | USE | Capability declaration inside `agent` |
|
|
140
|
+
|
|
141
|
+
### String escape
|
|
142
|
+
|
|
143
|
+
`\{` in source text is stored as the placeholder `\x01` during lexing. The generator converts it back to a literal `{` when building template literals, preventing accidental interpolation.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## AST Node Types (23)
|
|
148
|
+
|
|
149
|
+
| Category | Nodes |
|
|
150
|
+
|----------|-------|
|
|
151
|
+
| Program | `Program` |
|
|
152
|
+
| Statements | `PrintStatement`, `Assignment`, `IfStatement`, `FunctionDeclaration`, `ReturnStatement`, `ExpressionStatement` |
|
|
153
|
+
| Control flow | `ForStatement`, `WhileStatement`, `TryStatement` |
|
|
154
|
+
| Event statements | `OnStatement`, `EveryStatement` |
|
|
155
|
+
| AI/IoT statements | `AgentDeclaration`, `StreamStatement` |
|
|
156
|
+
| Expressions | `BinaryExpression`, `UnaryExpression`, `CallExpression`, `MemberExpression` |
|
|
157
|
+
| Literals | `Identifier`, `NumberLiteral`, `StringLiteral`, `BooleanLiteral`, `NullLiteral`, `ArrayLiteral`, `ObjectLiteral` |
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Generator
|
|
162
|
+
|
|
163
|
+
### SIMPLE vs ASYNC detection (`usesRuntime`)
|
|
164
|
+
|
|
165
|
+
The generator walks the full AST before emitting any code. ASYNC mode is triggered by any of:
|
|
166
|
+
|
|
167
|
+
- A `CallExpression` whose callee is `<namespace>.<method>` (namespace call)
|
|
168
|
+
- A `CallExpression` to the built-in `input()` function
|
|
169
|
+
- A `MemberExpression` where the object is a known namespace (e.g. `math.pi`)
|
|
170
|
+
- A `StringLiteral` whose value contains `{namespace.prop}` interpolation
|
|
171
|
+
- An `OnStatement`, `EveryStatement`, `StreamStatement`, or `AgentDeclaration`
|
|
172
|
+
|
|
173
|
+
### Built-in functions
|
|
174
|
+
|
|
175
|
+
Two built-in identifiers are special-cased in the generator — they do not go through the namespace routing:
|
|
176
|
+
|
|
177
|
+
| Built-in | Trigger ASYNC? | Emitted JS |
|
|
178
|
+
|----------|---------------|------------|
|
|
179
|
+
| `len(x)` | No | `__len(x)` — helper emitted once at top of program |
|
|
180
|
+
| `input(prompt)` | Yes | `await __rt.input(prompt)` |
|
|
181
|
+
|
|
182
|
+
The `__len` helper is only emitted when `len` is actually used:
|
|
183
|
+
```js
|
|
184
|
+
function __len(x) { return x == null ? 0 : (x.length ?? Object.keys(x).length); }
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Namespace set
|
|
188
|
+
|
|
189
|
+
```js
|
|
190
|
+
export const NAMESPACES = new Set([
|
|
191
|
+
'ai', 'http', 'mqtt', 'tts',
|
|
192
|
+
'rag', 'vision', 'home',
|
|
193
|
+
'memory', 'schedule', 'system', 'device',
|
|
194
|
+
'math',
|
|
195
|
+
]);
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Any identifier in this set, when used as the object of a `MemberExpression` or `CallExpression`, is routed through `__rt` in ASYNC mode. Adding a new capability is just a name in this set plus a matching runtime module — no grammar change.
|
|
199
|
+
|
|
200
|
+
### String interpolation
|
|
201
|
+
|
|
202
|
+
String literals containing `{identifier}` or `{identifier.prop}` are emitted as JS template literals. Namespace references inside strings are correctly prefixed with `__rt.` in ASYNC mode:
|
|
203
|
+
|
|
204
|
+
```future
|
|
205
|
+
print "π ≈ {math.pi}"
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Emits (async/browser mode):
|
|
209
|
+
```js
|
|
210
|
+
__rt.print(`π ≈ ${__rt.math.pi}`);
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
The interpolation logic lives in `Generator.genStringLiteral()` — an instance method so it has access to `this.asyncMode` and `NAMESPACES`.
|
|
214
|
+
|
|
215
|
+
### Variable hoisting
|
|
216
|
+
|
|
217
|
+
All variables assigned at a scope level are collected by `collectAssignedNames` and declared as `let` at the top of that scope. The collector recurses into `if`, `for`, `while`, and `try/catch` bodies. Loop variables (`const item of …`) and catch variables (`catch (err)`) are **not** hoisted — they are block-scoped by JS design.
|
|
218
|
+
|
|
219
|
+
### Method call awaiting
|
|
220
|
+
|
|
221
|
+
In ASYNC mode, ALL call expressions where the callee is a `MemberExpression` are `await`ed — including calls on runtime-returned objects like `kb.query()`. `await` on a synchronous return value is harmless in JS, and this rule is required for the Knowledge Base API to work correctly.
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Runtime Architecture
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
runtime/index.js
|
|
229
|
+
│
|
|
230
|
+
├── Imports 12 capability modules (+ readline for input())
|
|
231
|
+
├── Exports `runtime` object → used as `__rt` in generated JS
|
|
232
|
+
├── Exports `manifest` → structured metadata for every function
|
|
233
|
+
└── Attaches introspection:
|
|
234
|
+
runtime.listModules() → string[]
|
|
235
|
+
runtime.listFunctions(mod) → string[]
|
|
236
|
+
runtime.describe() → { version, modules, manifest }
|
|
237
|
+
runtime.input(prompt) → Promise<string> (stdin)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Manifest shape (per function)
|
|
241
|
+
|
|
242
|
+
```js
|
|
243
|
+
{
|
|
244
|
+
description: string,
|
|
245
|
+
params: [{ name: string, type: string, optional?: boolean }],
|
|
246
|
+
returns: string,
|
|
247
|
+
async: boolean,
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Browser Runtime
|
|
254
|
+
|
|
255
|
+
`runtime/browser.js` is a self-contained browser-compatible runtime with no Node.js dependencies. It is bundled into `future-browser.js` along with the compiler.
|
|
256
|
+
|
|
257
|
+
```
|
|
258
|
+
future-browser.js
|
|
259
|
+
│
|
|
260
|
+
├── Imports compiler (lexer + parser + generator)
|
|
261
|
+
├── Imports browserRuntime from runtime/browser.js
|
|
262
|
+
└── Exposes window.Future:
|
|
263
|
+
Future.configure({ proxy, provider, apiKey, model })
|
|
264
|
+
Future.run(source) → Promise (compile + execute)
|
|
265
|
+
Future.compile(source) → string (JS output only)
|
|
266
|
+
Future.runtime → browserRuntime object
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### `<script type="future">` interceptor
|
|
270
|
+
|
|
271
|
+
`future-browser.js` intercepts all `<script type="future">` tags on the page and executes them via `Future.run()`. Execution is deferred with `setTimeout(runScripts, 0)` so all `<script type="module">` configuration blocks (which set proxy, API key, or `print` override) finish initialising before any Future script runs.
|
|
272
|
+
|
|
273
|
+
### API key security (browser)
|
|
274
|
+
|
|
275
|
+
| Mode | Setup | Security |
|
|
276
|
+
|------|-------|----------|
|
|
277
|
+
| **Proxy** | `Future.configure({ proxy: '/api/ai' })` | Key stays on your server — recommended for production |
|
|
278
|
+
| **Demo** | `Future.configure({ provider: 'openai', apiKey: 'sk-...' })` | Key visible in source — dev/demos only |
|
|
279
|
+
|
|
280
|
+
Proxy contract:
|
|
281
|
+
```
|
|
282
|
+
POST {proxy}/ask { prompt } → { text }
|
|
283
|
+
POST {proxy}/chat { messages } → { text }
|
|
284
|
+
POST {proxy}/stream { prompt } → SSE stream
|
|
285
|
+
POST {proxy}/embed { text } → { embedding: number[] }
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## AI Provider Architecture
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
runtime/providers/index.js ← resolveProvider()
|
|
294
|
+
│
|
|
295
|
+
├── runtime/providers/anthropic.js ask / chat / stream / embed (keyword fallback)
|
|
296
|
+
└── runtime/providers/openai-compat.js ask / chat / stream / embed (real embeddings)
|
|
297
|
+
│
|
|
298
|
+
└── Preset base URLs for:
|
|
299
|
+
openai | ollama | openrouter | gemini | venice | groq | together
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Provider resolution order
|
|
303
|
+
|
|
304
|
+
```
|
|
305
|
+
1. ai.configure(provider, key, model) ← called from Future code (highest priority)
|
|
306
|
+
2. FUTURE_AI_PROVIDER + FUTURE_AI_API_KEY ← named preset (anthropic/openai/gemini/…)
|
|
307
|
+
3. FUTURE_AI_BASE_URL + FUTURE_AI_API_KEY ← custom OpenAI-compat endpoint
|
|
308
|
+
4. ANTHROPIC_API_KEY ← legacy default
|
|
309
|
+
5. (nothing) ← offline stub — program keeps running
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## RAG Pipeline Architecture
|
|
315
|
+
|
|
316
|
+
```
|
|
317
|
+
Documents (strings, objects, or local files)
|
|
318
|
+
│
|
|
319
|
+
▼
|
|
320
|
+
[ Chunker ] runtime/rag/chunker.js
|
|
321
|
+
Overlapping chunks sentence-aware splitting (512 chars, 64 overlap)
|
|
322
|
+
│
|
|
323
|
+
▼
|
|
324
|
+
[ Embedder ] runtime/ai.js → provider.embed()
|
|
325
|
+
Float vectors real (OpenAI/Ollama) or keyword-based fallback
|
|
326
|
+
│
|
|
327
|
+
▼
|
|
328
|
+
[ Vector Store ] runtime/rag/vector-store.js
|
|
329
|
+
Indexed chunks memory | file | qdrant* | pinecone* | weaviate*
|
|
330
|
+
│ (* stubs — implement adapter to activate)
|
|
331
|
+
▼
|
|
332
|
+
[ Retriever ] cosine similarity search (top-k)
|
|
333
|
+
│
|
|
334
|
+
▼
|
|
335
|
+
[ Context Builder ] runtime/rag/pipeline.js
|
|
336
|
+
Ranked passages
|
|
337
|
+
│
|
|
338
|
+
▼
|
|
339
|
+
[ LLM Answer ] ai.ask() with injected context
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## Event-Oriented Statements
|
|
345
|
+
|
|
346
|
+
```future
|
|
347
|
+
on mqtt "house/temp" → await __rt.mqtt.subscribe(ch, async (message) => { … })
|
|
348
|
+
print message
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
every "30m" → await __rt.schedule.every(interval, async () => { … })
|
|
352
|
+
print "tick"
|
|
353
|
+
end
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
## Agent Architecture
|
|
359
|
+
|
|
360
|
+
```future
|
|
361
|
+
agent support
|
|
362
|
+
use rag
|
|
363
|
+
use memory
|
|
364
|
+
docs = rag.query(goal)
|
|
365
|
+
return docs
|
|
366
|
+
end
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
Compiles to:
|
|
370
|
+
|
|
371
|
+
```js
|
|
372
|
+
async function support(goal) {
|
|
373
|
+
let docs;
|
|
374
|
+
docs = await __rt.rag.query(goal);
|
|
375
|
+
return docs;
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
- `goal` is the implicit parameter — automatically available inside the body.
|
|
380
|
+
- `use <capability>` lines are documentation only — no generated code.
|
|
381
|
+
- An `agent` declaration always forces ASYNC mode — callers `await` the result.
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## Streaming Architecture
|
|
386
|
+
|
|
387
|
+
```future
|
|
388
|
+
stream ai.ask("Tell me a story")
|
|
389
|
+
print chunk
|
|
390
|
+
end
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
Compiles to:
|
|
394
|
+
|
|
395
|
+
```js
|
|
396
|
+
await __rt.ai.stream("Tell me a story", async (chunk) => {
|
|
397
|
+
__rt.print(chunk);
|
|
398
|
+
});
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
`chunk` is an implicit variable provided by the streaming callback. The call must be a namespace capability call.
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## Adding a New Capability (4 steps)
|
|
406
|
+
|
|
407
|
+
1. Create `runtime/mymodule.js` with named exports.
|
|
408
|
+
2. Import it in `runtime/index.js`, add to `runtime` object, `MODULE_NAMES`, and `manifest`.
|
|
409
|
+
3. Add the namespace name to `NAMESPACES` in `src/generator.js`.
|
|
410
|
+
4. Add the module to `browserRuntime` in `runtime/browser.js` if browser support is wanted.
|
|
411
|
+
|
|
412
|
+
No grammar, lexer, parser, or AST changes needed.
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
## Package Exports
|
|
417
|
+
|
|
418
|
+
```json
|
|
419
|
+
{
|
|
420
|
+
".": "./src/index.js",
|
|
421
|
+
"./runtime": "./runtime/index.js",
|
|
422
|
+
"./runtime/lsp-metadata": "./runtime/lsp-metadata.js"
|
|
423
|
+
}
|
|
424
|
+
```
|