rooklang 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -7
- package/README.ru.md +34 -7
- package/dist/ast/declarations.d.ts +39 -4
- package/dist/ast/expressions.d.ts +34 -8
- package/dist/ast/markup.d.ts +6 -1
- package/dist/ast/statements.d.ts +28 -2
- package/dist/auto-import.d.ts +11 -0
- package/dist/auto-import.js +81 -0
- package/dist/breaks.d.ts +6 -0
- package/dist/breaks.js +36 -0
- package/dist/build.d.ts +7 -0
- package/dist/build.js +23 -2
- package/dist/checker/array-literals.d.ts +6 -0
- package/dist/checker/array-literals.js +59 -0
- package/dist/checker/assignments.d.ts +4 -0
- package/dist/checker/assignments.js +23 -3
- package/dist/checker/base.d.ts +8 -2
- package/dist/checker/base.js +7 -7
- package/dist/checker/builtins.js +22 -8
- package/dist/checker/bytes.d.ts +2 -2
- package/dist/checker/bytes.js +2 -2
- package/dist/checker/calls.js +3 -0
- package/dist/checker/channel-objects.d.ts +3 -0
- package/dist/checker/channel-objects.js +40 -0
- package/dist/checker/channels.d.ts +1 -0
- package/dist/checker/channels.js +17 -4
- package/dist/checker/checker.d.ts +1 -1
- package/dist/checker/checker.js +19 -0
- package/dist/checker/class-members.d.ts +22 -0
- package/dist/checker/class-members.js +105 -0
- package/dist/checker/classes.d.ts +5 -4
- package/dist/checker/classes.js +48 -13
- package/dist/checker/closing.d.ts +21 -0
- package/dist/checker/closing.js +164 -0
- package/dist/checker/completion.d.ts +3 -3
- package/dist/checker/completion.js +4 -3
- package/dist/checker/component-bindings.d.ts +7 -0
- package/dist/checker/component-bindings.js +45 -0
- package/dist/checker/component-values.js +10 -7
- package/dist/checker/components.d.ts +2 -2
- package/dist/checker/components.js +8 -3
- package/dist/checker/context.d.ts +41 -5
- package/dist/checker/context.js +23 -0
- package/dist/checker/control-flow.d.ts +11 -5
- package/dist/checker/control-flow.js +65 -40
- package/dist/checker/declarations.d.ts +2 -2
- package/dist/checker/declarations.js +4 -2
- package/dist/checker/decode.d.ts +8 -0
- package/dist/checker/decode.js +32 -0
- package/dist/checker/decorator-exports.js +4 -0
- package/dist/checker/decorator-includes.d.ts +9 -0
- package/dist/checker/decorator-includes.js +71 -0
- package/dist/checker/decorator-members.d.ts +8 -10
- package/dist/checker/decorator-members.js +28 -31
- package/dist/checker/decorator-wrappers.d.ts +1 -1
- package/dist/checker/decorator-wrappers.js +3 -2
- package/dist/checker/decorators.d.ts +14 -5
- package/dist/checker/decorators.js +52 -25
- package/dist/checker/expressions.d.ts +6 -2
- package/dist/checker/expressions.js +20 -40
- package/dist/checker/flow.d.ts +25 -3
- package/dist/checker/flow.js +56 -12
- package/dist/checker/functions.d.ts +2 -2
- package/dist/checker/functions.js +9 -5
- package/dist/checker/helpers.d.ts +5 -2
- package/dist/checker/helpers.js +16 -4
- package/dist/checker/imports.js +5 -2
- package/dist/checker/iterables.d.ts +3 -1
- package/dist/checker/iterables.js +13 -0
- package/dist/checker/iterators.d.ts +4 -1
- package/dist/checker/iterators.js +12 -4
- package/dist/checker/json.d.ts +5 -0
- package/dist/checker/json.js +92 -0
- package/dist/checker/loops.d.ts +2 -0
- package/dist/checker/loops.js +50 -5
- package/dist/checker/markup.js +14 -2
- package/dist/checker/members.js +10 -1
- package/dist/checker/operators.d.ts +2 -2
- package/dist/checker/operators.js +7 -5
- package/dist/checker/queues.d.ts +2 -2
- package/dist/checker/queues.js +2 -2
- package/dist/checker/resolution.js +5 -3
- package/dist/checker/shared-state.d.ts +11 -0
- package/dist/checker/shared-state.js +37 -0
- package/dist/checker/signals.d.ts +8 -0
- package/dist/checker/signals.js +48 -0
- package/dist/checker/statements.d.ts +5 -2
- package/dist/checker/statements.js +51 -22
- package/dist/checker/tagged-unions.d.ts +37 -0
- package/dist/checker/tagged-unions.js +132 -0
- package/dist/checker/topics.d.ts +6 -0
- package/dist/checker/topics.js +17 -0
- package/dist/checker/transfer.d.ts +3 -1
- package/dist/checker/transfer.js +25 -5
- package/dist/checker/try.d.ts +6 -0
- package/dist/checker/try.js +19 -0
- package/dist/checker/types/constructors.d.ts +1 -1
- package/dist/checker/types/constructors.js +2 -2
- package/dist/checker/types/generics.js +1 -1
- package/dist/checker/types/iterables.d.ts +13 -0
- package/dist/checker/types/iterables.js +52 -0
- package/dist/checker/types/model.d.ts +25 -0
- package/dist/checker/types/params.js +22 -3
- package/dist/checker/types/printing.js +4 -3
- package/dist/checker/types/relations.js +19 -25
- package/dist/checker/types/topic.d.ts +6 -0
- package/dist/checker/types/topic.js +23 -0
- package/dist/checker/types.d.ts +2 -0
- package/dist/checker/types.js +2 -0
- package/dist/checker/untyped-globals.d.ts +1 -0
- package/dist/checker/untyped-globals.js +3 -1
- package/dist/cli.js +18 -36
- package/dist/codegen/attributes.d.ts +4 -0
- package/dist/codegen/attributes.js +24 -2
- package/dist/codegen/calls.d.ts +23 -0
- package/dist/codegen/calls.js +88 -7
- package/dist/codegen/component-helpers.d.ts +6 -1
- package/dist/codegen/component-helpers.js +6 -1
- package/dist/codegen/component-props.d.ts +11 -2
- package/dist/codegen/component-props.js +50 -5
- package/dist/codegen/components.d.ts +6 -5
- package/dist/codegen/components.js +44 -21
- package/dist/codegen/control-flow.d.ts +2 -0
- package/dist/codegen/control-flow.js +23 -9
- package/dist/codegen/control-statements.d.ts +10 -2
- package/dist/codegen/control-statements.js +56 -19
- package/dist/codegen/creation.js +5 -2
- package/dist/codegen/decode.d.ts +14 -0
- package/dist/codegen/decode.js +93 -0
- package/dist/codegen/early-returns.d.ts +4 -3
- package/dist/codegen/early-returns.js +17 -5
- package/dist/codegen/emitter.d.ts +13 -41
- package/dist/codegen/emitter.js +27 -8
- package/dist/codegen/expressions.d.ts +9 -0
- package/dist/codegen/expressions.js +15 -26
- package/dist/codegen/functions.d.ts +11 -1
- package/dist/codegen/functions.js +31 -3
- package/dist/codegen/js.d.ts +2 -2
- package/dist/codegen/js.js +5 -2
- package/dist/codegen/live.d.ts +60 -0
- package/dist/codegen/live.js +29 -0
- package/dist/codegen/mutations.d.ts +7 -0
- package/dist/codegen/mutations.js +43 -2
- package/dist/codegen/options.d.ts +42 -0
- package/dist/codegen/options.js +1 -0
- package/dist/codegen/reactive.d.ts +4 -59
- package/dist/codegen/reactive.js +34 -72
- package/dist/codegen/runtime.d.ts +7 -3
- package/dist/codegen/runtime.js +33 -14
- package/dist/codegen/shared.d.ts +22 -0
- package/dist/codegen/shared.js +93 -0
- package/dist/codegen/simple-statements.d.ts +11 -5
- package/dist/codegen/simple-statements.js +40 -15
- package/dist/codegen/statements.d.ts +5 -0
- package/dist/codegen/statements.js +99 -4
- package/dist/codegen/try.d.ts +5 -0
- package/dist/codegen/try.js +40 -0
- package/dist/codegen/updates.d.ts +11 -3
- package/dist/codegen/updates.js +52 -4
- package/dist/codegen/web-components.d.ts +2 -2
- package/dist/codegen/web-components.js +2 -2
- package/dist/compile.d.ts +9 -0
- package/dist/compile.js +25 -8
- package/dist/completion.d.ts +4 -2
- package/dist/completion.js +10 -5
- package/dist/declarations.js +32 -6
- package/dist/decorator-copy.d.ts +1 -1
- package/dist/decorator-copy.js +6 -2
- package/dist/decorator-names.d.ts +14 -0
- package/dist/decorator-names.js +56 -0
- package/dist/decorators.d.ts +2 -3
- package/dist/decorators.js +36 -14
- package/dist/goroutines.d.ts +1 -1
- package/dist/goroutines.js +5 -4
- package/dist/index.d.ts +6 -2
- package/dist/index.js +14 -5
- package/dist/inline-packages.d.ts +2 -1
- package/dist/inline-packages.js +9 -4
- package/dist/lexer/base.d.ts +2 -0
- package/dist/lexer/base.js +6 -1
- package/dist/lexer/lexer.js +3 -0
- package/dist/lexer/literals.d.ts +5 -0
- package/dist/lexer/literals.js +51 -1
- package/dist/lexer/markup.js +3 -4
- package/dist/lexer/tables.js +2 -0
- package/dist/lexer/token.d.ts +4 -3
- package/dist/lexer/token.js +0 -2
- package/dist/loader.js +30 -8
- package/dist/names.d.ts +4 -0
- package/dist/names.js +29 -0
- package/dist/parser/base.d.ts +5 -0
- package/dist/parser/base.js +2 -1
- package/dist/parser/classes.d.ts +2 -0
- package/dist/parser/classes.js +88 -23
- package/dist/parser/control-flow.d.ts +8 -1
- package/dist/parser/control-flow.js +49 -26
- package/dist/parser/declarations.d.ts +5 -12
- package/dist/parser/declarations.js +14 -79
- package/dist/parser/decorators.d.ts +6 -2
- package/dist/parser/decorators.js +43 -19
- package/dist/parser/expressions.js +27 -3
- package/dist/parser/jumps.d.ts +11 -0
- package/dist/parser/jumps.js +77 -0
- package/dist/parser/literals.d.ts +9 -0
- package/dist/parser/literals.js +45 -6
- package/dist/parser/markup.js +1 -1
- package/dist/parser/params.d.ts +21 -0
- package/dist/parser/params.js +143 -0
- package/dist/parser/simple-statements.d.ts +2 -1
- package/dist/parser/simple-statements.js +38 -15
- package/dist/parser/statements.d.ts +5 -5
- package/dist/parser/statements.js +39 -35
- package/dist/parser/syntax.d.ts +11 -1
- package/dist/parser/syntax.js +16 -2
- package/dist/parser/types.js +8 -3
- package/dist/project-modules.d.ts +12 -0
- package/dist/project-modules.js +106 -0
- package/dist/run-file.d.ts +6 -0
- package/dist/run-file.js +111 -0
- package/dist/runtime/sources.js +13 -6
- package/dist/source-map.d.ts +17 -0
- package/dist/source-map.js +75 -0
- package/dist/ts-types.js +4 -1
- package/dist/typescript/convert-objects.d.ts +2 -1
- package/dist/typescript/convert-objects.js +18 -9
- package/dist/vite.js +12 -4
- package/dist/walk-types.js +1 -0
- package/dist/walk.d.ts +0 -2
- package/dist/walk.js +14 -31
- package/package.json +2 -2
- package/src/runtime/chan.js +15 -5
- package/src/runtime/channel.js +28 -0
- package/src/runtime/classes.js +32 -0
- package/src/runtime/core.js +10 -1
- package/src/runtime/decode.js +221 -0
- package/src/runtime/go.js +3 -0
- package/src/runtime/index.js +7 -0
- package/src/runtime/markup.js +27 -17
- package/src/runtime/select.js +14 -9
- package/src/runtime/shared.js +17 -0
- package/src/runtime/signals.js +59 -0
- package/src/runtime/threads.js +32 -5
- package/src/runtime/topic.js +118 -0
- package/src/runtime/try.js +45 -0
package/README.md
CHANGED
|
@@ -25,14 +25,21 @@ close(jobs)
|
|
|
25
25
|
for let i = 0; i < 4; i++ {
|
|
26
26
|
console.log(<-results)
|
|
27
27
|
}
|
|
28
|
+
close(results)
|
|
28
29
|
```
|
|
29
30
|
|
|
30
31
|
- **Goroutines and channels.** `go f(x)` runs a function as a goroutine, on another processor, and
|
|
31
|
-
channels, `select`, `after`, `tick` and `cancel` work as in Go
|
|
32
|
+
channels, `select`, `after`, `tick` and `cancel` work as in Go, and signals and `AbortSignal`
|
|
33
|
+
are channels too, `signal("SIGTERM")` and `done(request.signal)`; `go for i, v in pixels { ... }`
|
|
32
34
|
splits an array among the processors. The compiler checks that what goes to another thread can be
|
|
33
|
-
copied there
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
copied there, and warns of a channel that is never closed; an instance of a `data class` goes
|
|
36
|
+
with its class and methods.
|
|
37
|
+
- **Topics between tabs.** `topic<CartEvent>("cart")` passes values between the tabs of a site
|
|
38
|
+
over a `BroadcastChannel`: `cart <- e` sends and waits for nobody, `for e in cart` receives what
|
|
39
|
+
the other tabs send. `Channel` and `Topic` have what channels and topics compile to, by name, and
|
|
40
|
+
their closed zero values, `Channel.EMPTY` and `Topic.EMPTY`.
|
|
41
|
+
- **Go syntax.** `func`, the type after the name, several results, errors as a second value
|
|
42
|
+
(`try JSON.parse(text)` makes what JS throws one), `defer`, a single `for` loop:
|
|
36
43
|
|
|
37
44
|
```go
|
|
38
45
|
func divide(a, b number) (number, error) {
|
|
@@ -43,13 +50,16 @@ for let i = 0; i < 4; i++ {
|
|
|
43
50
|
}
|
|
44
51
|
```
|
|
45
52
|
|
|
46
|
-
- **Static types with null safety.** A `?User` cannot be used without a check
|
|
53
|
+
- **Static types with null safety.** A `?User` cannot be used without a check, and
|
|
54
|
+
`decode<User>(body)` checks JSON from outside against the type when the program runs.
|
|
47
55
|
- **JavaScript inside.** The same values, classes and modules, any JS library; markup creates real
|
|
48
56
|
DOM elements, and components are compiled away.
|
|
49
57
|
|
|
50
58
|
The guide with examples and a playground: <https://qwern-9876r.github.io/RookLang/>.
|
|
51
59
|
Specification: [docs/spec.md](docs/spec.md), design of components:
|
|
52
60
|
[docs/components.md](docs/components.md), an example: [examples/hello.rk](examples/hello.rk).
|
|
61
|
+
Where Rook stands and the road to 1.0: [docs/roadmap.md](docs/roadmap.md); what changed in each
|
|
62
|
+
version: [CHANGELOG.md](CHANGELOG.md).
|
|
53
63
|
|
|
54
64
|
## Installation
|
|
55
65
|
|
|
@@ -60,6 +70,7 @@ npm install rooklang
|
|
|
60
70
|
npx rook build app.rk # app.js next to the source
|
|
61
71
|
npx rook build src --out-dir dist # every module of a folder
|
|
62
72
|
npx rook run app.rk # compile and run
|
|
73
|
+
npx rook run --watch app.rk # and again when a file of it changes
|
|
63
74
|
```
|
|
64
75
|
|
|
65
76
|
The compiled code imports what channels, goroutines and markup need from `rooklang/runtime`, so
|
|
@@ -97,9 +108,11 @@ staged version is formatted, so edits that are not staged stay out of the commit
|
|
|
97
108
|
| `npm run vscode:package` | Pack the VS Code extension into `rooklang.vsix` |
|
|
98
109
|
|
|
99
110
|
Options of `build`: `--out-dir dir` writes the `.js` files to a separate folder, `--stdout` prints
|
|
100
|
-
the JS of one file, `--no-check` skips type checking
|
|
111
|
+
the JS of one file, `--no-check` skips type checking, `--no-source-map` writes no source maps
|
|
112
|
+
(`app.js.map`, by default next to each `.js`). `--markup` and `--no-markup` turn markup and
|
|
101
113
|
components on or off for all files (with `run` too); by default they are off, and a package turns
|
|
102
|
-
them on in its `package.json`: `"rook": { "markup": true }`.
|
|
114
|
+
them on in its `package.json`: `"rook": { "markup": true }`. `run --watch` runs the program again
|
|
115
|
+
when a `.rk` file or a CSS module of it changes, after stopping it with `SIGTERM`.
|
|
103
116
|
|
|
104
117
|
## Releases
|
|
105
118
|
|
|
@@ -183,6 +196,20 @@ build, and in development they show up over the page. Markup and components are
|
|
|
183
196
|
so `.rk` modules fit a React, Svelte or Vue app as they are; turn them on with
|
|
184
197
|
`"rook": { "markup": true }` in `package.json`, or `rook({ markup: true })`.
|
|
185
198
|
|
|
199
|
+
### Tests
|
|
200
|
+
|
|
201
|
+
Rook has no test runner of its own: Vitest, with the same plugin in `vitest.config.ts`, runs tests
|
|
202
|
+
of `.rk` modules, written in JS or TS. Goroutines work there too: a worker thread of Vitest loads
|
|
203
|
+
the `.rk` modules with the loader of `rook run`.
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
// math.test.ts
|
|
207
|
+
import { expect, it } from 'vitest';
|
|
208
|
+
import { add } from './math.rk';
|
|
209
|
+
|
|
210
|
+
it('adds', () => expect(add(1, 2)).toBe(3));
|
|
211
|
+
```
|
|
212
|
+
|
|
186
213
|
## Conventions
|
|
187
214
|
|
|
188
215
|
- Imports are written with the `.ts` extension (`import { x } from './lexer.ts'`).
|
package/README.ru.md
CHANGED
|
@@ -25,14 +25,21 @@ close(jobs)
|
|
|
25
25
|
for let i = 0; i < 4; i++ {
|
|
26
26
|
console.log(<-results)
|
|
27
27
|
}
|
|
28
|
+
close(results)
|
|
28
29
|
```
|
|
29
30
|
|
|
30
31
|
- **Горутины и каналы.** `go f(x)` запускает функцию горутиной, на другом процессоре, а каналы,
|
|
31
|
-
`select`, `after`, `tick` и `cancel` работают как в Go
|
|
32
|
+
`select`, `after`, `tick` и `cancel` работают как в Go, а сигналы и `AbortSignal` тоже становятся
|
|
33
|
+
каналами, `signal("SIGTERM")` и `done(request.signal)`; `go for i, v in pixels { ... }` делит
|
|
32
34
|
массив между процессорами. Компилятор проверяет, что уходящее в другой поток можно туда
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
скопировать, и предупреждает о канале, который никогда не закрывают; экземпляр `data class`
|
|
36
|
+
уходит вместе с классом и методами.
|
|
37
|
+
- **Топики между вкладками.** `topic<CartEvent>("cart")` передаёт значения между вкладками сайта
|
|
38
|
+
поверх `BroadcastChannel`: `cart <- e` отправляет и никого не ждёт, `for e in cart` принимает то,
|
|
39
|
+
что шлют другие вкладки. В `Channel` и `Topic` лежит то, во что компилируются каналы и топики, по
|
|
40
|
+
именам, и их закрытые нулевые значения `Channel.EMPTY` и `Topic.EMPTY`.
|
|
41
|
+
- **Синтаксис Go.** `func`, тип после имени, несколько результатов, ошибки вторым значением
|
|
42
|
+
(`try JSON.parse(text)` делает им то, что бросил JS), `defer`, один цикл `for`:
|
|
36
43
|
|
|
37
44
|
```go
|
|
38
45
|
func divide(a, b number) (number, error) {
|
|
@@ -43,13 +50,16 @@ for let i = 0; i < 4; i++ {
|
|
|
43
50
|
}
|
|
44
51
|
```
|
|
45
52
|
|
|
46
|
-
- **Статическая типизация с null-safety.** Значение типа `?User` нельзя использовать без
|
|
53
|
+
- **Статическая типизация с null-safety.** Значение типа `?User` нельзя использовать без проверки,
|
|
54
|
+
а `decode<User>(body)` во время работы сверяет с типом JSON, пришедший извне.
|
|
47
55
|
- **Внутри — JavaScript.** Те же значения, классы и модули, любые JS-библиотеки; разметка создаёт
|
|
48
56
|
настоящие DOM-элементы, а компоненты исчезают при компиляции.
|
|
49
57
|
|
|
50
58
|
Руководство с примерами и песочницей: <https://qwern-9876r.github.io/RookLang/ru/>.
|
|
51
59
|
Спецификация: [docs/spec.ru.md](docs/spec.ru.md), концепция компонентов:
|
|
52
60
|
[docs/components.ru.md](docs/components.ru.md), пример: [examples/hello.rk](examples/hello.rk).
|
|
61
|
+
Где Rook сейчас и путь к 1.0: [docs/roadmap.ru.md](docs/roadmap.ru.md); что изменилось в каждой
|
|
62
|
+
версии: [CHANGELOG.ru.md](CHANGELOG.ru.md).
|
|
53
63
|
|
|
54
64
|
## Установка
|
|
55
65
|
|
|
@@ -60,6 +70,7 @@ npm install rooklang
|
|
|
60
70
|
npx rook build app.rk # app.js рядом с исходником
|
|
61
71
|
npx rook build src --out-dir dist # все модули папки
|
|
62
72
|
npx rook run app.rk # скомпилировать и запустить
|
|
73
|
+
npx rook run --watch app.rk # и запускать снова, когда меняется его файл
|
|
63
74
|
```
|
|
64
75
|
|
|
65
76
|
Скомпилированный код импортирует то, что нужно каналам, горутинам и разметке, из
|
|
@@ -98,9 +109,11 @@ Node.js ≥ 24 (`nvm use`). Компилятор написан на TypeScript,
|
|
|
98
109
|
| `npm run vscode:package` | Упаковать расширение для VS Code в `rooklang.vsix` |
|
|
99
110
|
|
|
100
111
|
Опции `build`: `--out-dir dir` — писать `.js` в отдельную папку, `--stdout` — вывести JS одного
|
|
101
|
-
файла в консоль, `--no-check` — без проверки
|
|
112
|
+
файла в консоль, `--no-check` — без проверки типов, `--no-source-map` — без source maps
|
|
113
|
+
(`app.js.map`, по умолчанию рядом с каждым `.js`). `--markup` и `--no-markup` включают или
|
|
102
114
|
выключают разметку и компоненты для всех файлов (и в `run`); по умолчанию они выключены, а пакет
|
|
103
|
-
включает их в своём `package.json`: `"rook": { "markup": true }`.
|
|
115
|
+
включает их в своём `package.json`: `"rook": { "markup": true }`. `run --watch` запускает программу
|
|
116
|
+
заново, когда меняется её `.rk`-файл или CSS-модуль, сначала остановив её через `SIGTERM`.
|
|
104
117
|
|
|
105
118
|
## Релизы
|
|
106
119
|
|
|
@@ -183,6 +196,20 @@ export default defineConfig({ plugins: [rook()] });
|
|
|
183
196
|
есть; включить их можно через `"rook": { "markup": true }` в `package.json` или
|
|
184
197
|
`rook({ markup: true })`.
|
|
185
198
|
|
|
199
|
+
### Тесты
|
|
200
|
+
|
|
201
|
+
Своего запускателя тестов у Rook нет: Vitest с тем же плагином в `vitest.config.ts` запускает тесты
|
|
202
|
+
`.rk`-модулей, написанные на JS или TS. Горутины там тоже работают: поток воркера Vitest загружает
|
|
203
|
+
`.rk`-модули загрузчиком `rook run`.
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
// math.test.ts
|
|
207
|
+
import { expect, it } from 'vitest';
|
|
208
|
+
import { add } from './math.rk';
|
|
209
|
+
|
|
210
|
+
it('adds', () => expect(add(1, 2)).toBe(3));
|
|
211
|
+
```
|
|
212
|
+
|
|
186
213
|
## Соглашения
|
|
187
214
|
|
|
188
215
|
- Импорты пишутся с расширением `.ts` (`import { x } from './lexer.ts'`).
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Expression, Identifier, StringLiteral } from './expressions.ts';
|
|
1
|
+
import type { Expression, FuncExpression, Identifier, StringLiteral } from './expressions.ts';
|
|
2
2
|
import type { TypeMember, TypeNode, TypeReference } from './markup.ts';
|
|
3
3
|
import type { BlockStatement, Statement } from './statements.ts';
|
|
4
4
|
export interface NodeBase {
|
|
@@ -57,6 +57,19 @@ export interface Parameter extends NodeBase {
|
|
|
57
57
|
* properties, which `{...attrs}` puts on one of its elements.
|
|
58
58
|
*/
|
|
59
59
|
rest?: true;
|
|
60
|
+
/**
|
|
61
|
+
* `bind active string`: a property of a component that it may change. `bind:active={tab}`
|
|
62
|
+
* writes the changes into the parent's `tab`; without it the property is the component's state.
|
|
63
|
+
*/
|
|
64
|
+
bind?: true;
|
|
65
|
+
/**
|
|
66
|
+
* `constructor(private name string)`: the parameter is a property too, which the constructor
|
|
67
|
+
* assigns, as in TypeScript.
|
|
68
|
+
*/
|
|
69
|
+
property?: {
|
|
70
|
+
visibility: Visibility;
|
|
71
|
+
readonly?: true;
|
|
72
|
+
};
|
|
60
73
|
}
|
|
61
74
|
/**
|
|
62
75
|
* `comp Card(title string, children Content) { ...; return <section>...</section> }`. Components
|
|
@@ -89,6 +102,11 @@ export interface DecoratorDeclaration extends NodeBase {
|
|
|
89
102
|
params: Parameter[];
|
|
90
103
|
/** `needs cart, auth`: the decorators whose public members it uses; they are applied above it. */
|
|
91
104
|
needs: Identifier[];
|
|
105
|
+
/**
|
|
106
|
+
* `includes visible(margin), cart`: decorators applied with it, above its own body, whose
|
|
107
|
+
* arguments see its parameters. Their public members are its own for the component, `@shop.count`.
|
|
108
|
+
*/
|
|
109
|
+
includes: DecoratorUse[];
|
|
92
110
|
body: BlockStatement;
|
|
93
111
|
}
|
|
94
112
|
/** `@visible("300px")` or `@visible` before `comp`; the arguments are positional. */
|
|
@@ -110,19 +128,29 @@ export interface VariableDeclaration extends NodeBase {
|
|
|
110
128
|
exported: boolean;
|
|
111
129
|
keyword: 'let' | 'const' | 'state' | 'derived' | 'ref';
|
|
112
130
|
/**
|
|
113
|
-
* `public state`, `public derived` or `public const` in a decorator: the component reads it
|
|
114
|
-
*
|
|
131
|
+
* `public state`, `public derived` or `public const` in a decorator: the component reads it as
|
|
132
|
+
* `@name.x`.
|
|
115
133
|
*/
|
|
116
134
|
isPublic: boolean;
|
|
117
135
|
/** `_` is an ordinary identifier here; the checker treats it as "skip this value". */
|
|
118
136
|
names: Identifier[];
|
|
119
137
|
type: TypeNode | null;
|
|
120
138
|
values: Expression[];
|
|
139
|
+
/**
|
|
140
|
+
* `derived summary string { ...; return text }`: the block that computes a derived value, a
|
|
141
|
+
* function without parameters, so that what looks for the `return`s, `defer`s and `break`s of a
|
|
142
|
+
* component stops at it, as at other functions. Its result type is `type`; `values` is empty.
|
|
143
|
+
*/
|
|
144
|
+
body: FuncExpression | null;
|
|
121
145
|
}
|
|
122
146
|
/** `class Admin extends User implements Shape { ... }` */
|
|
123
147
|
export interface ClassDeclaration extends NodeBase {
|
|
124
148
|
kind: 'ClassDeclaration';
|
|
125
149
|
exported: boolean;
|
|
150
|
+
/** `data class Point`: its fields are data, and its instances go to goroutines with the class. */
|
|
151
|
+
data: boolean;
|
|
152
|
+
/** `abstract class Shape`: it has no instances of its own, only those of its subclasses. */
|
|
153
|
+
abstract?: true;
|
|
126
154
|
name: Identifier;
|
|
127
155
|
typeParams: TypeParameter[];
|
|
128
156
|
/** An expression, as in JS, so that classes from JS modules can be extended. */
|
|
@@ -138,6 +166,8 @@ export interface FieldDeclaration extends NodeBase {
|
|
|
138
166
|
/** `public` when no modifier is written. */
|
|
139
167
|
visibility: Visibility;
|
|
140
168
|
isStatic: boolean;
|
|
169
|
+
/** `readonly id string`: assigned only by its value or in the constructor of its class. */
|
|
170
|
+
readonly?: true;
|
|
141
171
|
name: Identifier;
|
|
142
172
|
type: TypeNode | null;
|
|
143
173
|
value: Expression | null;
|
|
@@ -156,10 +186,15 @@ export interface MethodDeclaration extends NodeBase {
|
|
|
156
186
|
isStatic: boolean;
|
|
157
187
|
/** `async load() User`, like `async func`. */
|
|
158
188
|
async?: true;
|
|
189
|
+
/** `get area() number { ... }` and `set area(v number) { ... }`, as in JS. */
|
|
190
|
+
accessor?: 'get' | 'set';
|
|
191
|
+
/** `abstract area() number`: no body, each subclass that is not abstract implements it. */
|
|
192
|
+
abstract?: true;
|
|
159
193
|
name: Identifier;
|
|
160
194
|
params: Parameter[];
|
|
161
195
|
results: TypeNode[];
|
|
162
|
-
|
|
196
|
+
/** `null` for an abstract method. */
|
|
197
|
+
body: BlockStatement | null;
|
|
163
198
|
}
|
|
164
199
|
/** `interface Shape { name string; area() number }` */
|
|
165
200
|
export interface InterfaceDeclaration extends NodeBase {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { NodeBase, Parameter } from './declarations.ts';
|
|
2
2
|
import type { ElementExpression, TypeNode } from './markup.ts';
|
|
3
3
|
import type { BlockStatement } from './statements.ts';
|
|
4
|
-
export type Expression = Identifier | NumberLiteral | BigIntLiteral | StringLiteral | TemplateLiteral | BooleanLiteral | NullLiteral | ThisExpression | SuperExpression | ArrayLiteral | ObjectLiteral | FuncExpression | ArrowFunction | UnaryExpression | BinaryExpression | ConditionalExpression | CallExpression | NewExpression | MemberExpression | IndexExpression | ElementExpression | DecoratorMember |
|
|
4
|
+
export type Expression = Identifier | NumberLiteral | BigIntLiteral | StringLiteral | RegExpLiteral | TemplateLiteral | BooleanLiteral | NullLiteral | ThisExpression | SuperExpression | ArrayLiteral | ObjectLiteral | FuncExpression | ArrowFunction | UnaryExpression | BinaryExpression | ConditionalExpression | CallExpression | NewExpression | MemberExpression | IndexExpression | ElementExpression | DecoratorMember | AsExpression | GoExpression | ChanExpression | StreamChanExpression | QueueExpression | TopicExpression | DecodeExpression | TryExpression | ConversionExpression | MakeExpression;
|
|
5
5
|
/**
|
|
6
6
|
* `[]byte("rook")`: the UTF-8 bytes of a string. `string(data)`, the way back, is a call, since
|
|
7
7
|
* `string` may be the name of a value.
|
|
@@ -33,6 +33,29 @@ export interface QueueExpression extends NodeBase {
|
|
|
33
33
|
element: TypeNode;
|
|
34
34
|
items: Expression | null;
|
|
35
35
|
}
|
|
36
|
+
/** `topic<CartEvent>("cart")`: values of the tabs of a site, over a BroadcastChannel of that name. */
|
|
37
|
+
export interface TopicExpression extends NodeBase {
|
|
38
|
+
kind: 'TopicExpression';
|
|
39
|
+
element: TypeNode;
|
|
40
|
+
name: Expression;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* `decode<User>(body)`: JSON text, or a value from JS, checked against a type when the program
|
|
44
|
+
* runs; it gives `(User, error)`.
|
|
45
|
+
*/
|
|
46
|
+
export interface DecodeExpression extends NodeBase {
|
|
47
|
+
kind: 'DecodeExpression';
|
|
48
|
+
type: TypeNode;
|
|
49
|
+
argument: Expression;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* `try JSON.parse(text)`: an exception in the expression, or a rejected Promise that an `await` in
|
|
53
|
+
* it waits for, becomes the error of `(T, error)`.
|
|
54
|
+
*/
|
|
55
|
+
export interface TryExpression extends NodeBase {
|
|
56
|
+
kind: 'TryExpression';
|
|
57
|
+
argument: Expression;
|
|
58
|
+
}
|
|
36
59
|
/**
|
|
37
60
|
* `chan(res.body, 4)`: a channel that receives the chunks of a ReadableStream, with room for 4,
|
|
38
61
|
* and a channel that gets the error of the stream, or null at its end.
|
|
@@ -82,6 +105,13 @@ export interface StringLiteral extends NodeBase {
|
|
|
82
105
|
/** Source text including quotes. */
|
|
83
106
|
raw: string;
|
|
84
107
|
}
|
|
108
|
+
/** `/ab+c/gi`, which JS writes the same way. */
|
|
109
|
+
export interface RegExpLiteral extends NodeBase {
|
|
110
|
+
kind: 'RegExpLiteral';
|
|
111
|
+
/** As it is written, between the slashes. */
|
|
112
|
+
pattern: string;
|
|
113
|
+
flags: string;
|
|
114
|
+
}
|
|
85
115
|
/** `` `Hello, ${name}!` ``: `quasis` always has one element more than `expressions`. */
|
|
86
116
|
export interface TemplateLiteral extends NodeBase {
|
|
87
117
|
kind: 'TemplateLiteral';
|
|
@@ -201,16 +231,12 @@ export interface IndexExpression extends NodeBase {
|
|
|
201
231
|
optional: boolean;
|
|
202
232
|
}
|
|
203
233
|
/**
|
|
204
|
-
* `@visible.shown`: a public member of a decorator applied to the component
|
|
205
|
-
* the decorator, not to any scope, so walkers do not visit them
|
|
234
|
+
* `@visible.shown` or `@visible.show()`: a public member of a decorator applied to the component,
|
|
235
|
+
* read or called. The names belong to the decorator, not to any scope, so walkers do not visit them
|
|
236
|
+
* as identifiers.
|
|
206
237
|
*/
|
|
207
238
|
export interface DecoratorMember extends NodeBase {
|
|
208
239
|
kind: 'DecoratorMember';
|
|
209
240
|
decorator: Identifier;
|
|
210
241
|
member: Identifier;
|
|
211
242
|
}
|
|
212
|
-
/** `get(@visible.shown)`: reads public state or a constant of a decorator. */
|
|
213
|
-
export interface DecoratorGet extends NodeBase {
|
|
214
|
-
kind: 'DecoratorGet';
|
|
215
|
-
target: DecoratorMember;
|
|
216
|
-
}
|
package/dist/ast/markup.d.ts
CHANGED
|
@@ -60,7 +60,7 @@ export interface EventHandler extends NodeBase {
|
|
|
60
60
|
kind: 'EventHandler';
|
|
61
61
|
body: SimpleStatement[];
|
|
62
62
|
}
|
|
63
|
-
export type TypeNode = TypeReference | ArrayType | NullableType | FuncType | ComponentType | ObjectType | UnionType | LiteralType | ChanType | QueueType;
|
|
63
|
+
export type TypeNode = TypeReference | ArrayType | NullableType | FuncType | ComponentType | ObjectType | UnionType | LiteralType | ChanType | QueueType | TopicType;
|
|
64
64
|
/**
|
|
65
65
|
* `chan number`: a channel of numbers, made by `chan<number>(size)`; `chan<- number` only sends
|
|
66
66
|
* and `<-chan number` only receives.
|
|
@@ -75,6 +75,11 @@ export interface QueueType extends NodeBase {
|
|
|
75
75
|
kind: 'QueueType';
|
|
76
76
|
element: TypeNode;
|
|
77
77
|
}
|
|
78
|
+
/** `topic CartEvent`: values that go to the other tabs of a site, made by `topic<T>(name)`. */
|
|
79
|
+
export interface TopicType extends NodeBase {
|
|
80
|
+
kind: 'TopicType';
|
|
81
|
+
element: TypeNode;
|
|
82
|
+
}
|
|
78
83
|
/** A named type: `number`, `User`, `Point`, `Box<number>`. */
|
|
79
84
|
export interface TypeReference extends NodeBase {
|
|
80
85
|
kind: 'TypeReference';
|
package/dist/ast/statements.d.ts
CHANGED
|
@@ -4,11 +4,20 @@ import type { JsxElementStatement } from './markup.ts';
|
|
|
4
4
|
export type Statement = ImportDeclaration | FuncDeclaration | ComponentDeclaration | DecoratorDeclaration | VariableDeclaration | ClassDeclaration | InterfaceDeclaration | TypeAliasDeclaration | BlockStatement | ExpressionStatement | AssignmentStatement | IncDecStatement | ReturnStatement | IfStatement | ForStatement | ForInStatement | SwitchStatement | BreakStatement | ContinueStatement | ThrowStatement | TryStatement | DeferStatement | MountStatement | EffectStatement | StyleStatement | DeleteStatement | JsxElementStatement | SendStatement | SelectStatement;
|
|
5
5
|
/** Statements allowed in the `init` and `update` parts of a `for` header. */
|
|
6
6
|
export type SimpleStatement = VariableDeclaration | ExpressionStatement | AssignmentStatement | IncDecStatement | DeleteStatement | SendStatement;
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* `ch <- value`: waits until the channel takes the value, so only in async functions. A send to a
|
|
9
|
+
* topic waits for nobody, so the parser, which does not know the type, leaves the error to the
|
|
10
|
+
* checker: `cannotWait` is the `<-` of a send where waiting is not allowed, and why.
|
|
11
|
+
*/
|
|
8
12
|
export interface SendStatement extends NodeBase {
|
|
9
13
|
kind: 'SendStatement';
|
|
10
14
|
channel: Expression;
|
|
11
15
|
value: Expression;
|
|
16
|
+
cannotWait?: {
|
|
17
|
+
inDefer: boolean;
|
|
18
|
+
start: number;
|
|
19
|
+
end: number;
|
|
20
|
+
};
|
|
12
21
|
}
|
|
13
22
|
export interface BlockStatement extends NodeBase {
|
|
14
23
|
kind: 'BlockStatement';
|
|
@@ -44,6 +53,8 @@ export interface ReturnStatement extends NodeBase {
|
|
|
44
53
|
}
|
|
45
54
|
export interface IfStatement extends NodeBase {
|
|
46
55
|
kind: 'IfStatement';
|
|
56
|
+
/** `if const v, err = f(); err != null { }`: its variables are seen in every branch, as in Go. */
|
|
57
|
+
init: VariableDeclaration | null;
|
|
47
58
|
condition: Expression;
|
|
48
59
|
consequent: BlockStatement;
|
|
49
60
|
/** `else { ... }` or `else if ...`. */
|
|
@@ -58,6 +69,8 @@ export interface IfStatement extends NodeBase {
|
|
|
58
69
|
*/
|
|
59
70
|
export interface ForStatement extends NodeBase {
|
|
60
71
|
kind: 'ForStatement';
|
|
72
|
+
/** `outer: for { ... }`, for `break outer` and `continue outer` in a nested loop. */
|
|
73
|
+
label?: Identifier;
|
|
61
74
|
init: SimpleStatement | null;
|
|
62
75
|
condition: Expression | null;
|
|
63
76
|
update: SimpleStatement | null;
|
|
@@ -69,15 +82,21 @@ export interface ForStatement extends NodeBase {
|
|
|
69
82
|
*/
|
|
70
83
|
export interface ForInStatement extends NodeBase {
|
|
71
84
|
kind: 'ForInStatement';
|
|
85
|
+
label?: Identifier;
|
|
72
86
|
key: Identifier | null;
|
|
73
87
|
value: Identifier;
|
|
74
88
|
iterable: Expression;
|
|
89
|
+
/** `with key todo.id` of a `{for}` in markup: what its blocks are found again by. */
|
|
90
|
+
withKey?: Expression;
|
|
75
91
|
body: BlockStatement;
|
|
76
92
|
go?: boolean;
|
|
77
93
|
}
|
|
78
94
|
/** `switch cmd { ... }`, or `switch { ... }` without a discriminant as an if/else chain. */
|
|
79
95
|
export interface SwitchStatement extends NodeBase {
|
|
80
96
|
kind: 'SwitchStatement';
|
|
97
|
+
label?: Identifier;
|
|
98
|
+
/** `switch const kind = node.kind; kind { }`, as the initializer of `if`. */
|
|
99
|
+
init: VariableDeclaration | null;
|
|
81
100
|
discriminant: Expression | null;
|
|
82
101
|
cases: SwitchCase[];
|
|
83
102
|
}
|
|
@@ -94,6 +113,7 @@ export interface SwitchCase extends NodeBase {
|
|
|
94
113
|
*/
|
|
95
114
|
export interface SelectStatement extends NodeBase {
|
|
96
115
|
kind: 'SelectStatement';
|
|
116
|
+
label?: Identifier;
|
|
97
117
|
cases: SelectCase[];
|
|
98
118
|
}
|
|
99
119
|
/** A case of `select`: a receive, `<-ch`, a send, `ch <- v`, or `default` when it is null. */
|
|
@@ -104,12 +124,18 @@ export interface SelectCase extends NodeBase {
|
|
|
104
124
|
operation: UnaryExpression | SendStatement | null;
|
|
105
125
|
body: Statement[];
|
|
106
126
|
}
|
|
127
|
+
/** `break`, or `break outer`: the label of an enclosing loop, switch or select. */
|
|
107
128
|
export interface BreakStatement extends NodeBase {
|
|
108
129
|
kind: 'BreakStatement';
|
|
130
|
+
label?: Identifier;
|
|
109
131
|
}
|
|
132
|
+
/** `continue`, or `continue outer`: the label of an enclosing loop. */
|
|
110
133
|
export interface ContinueStatement extends NodeBase {
|
|
111
134
|
kind: 'ContinueStatement';
|
|
135
|
+
label?: Identifier;
|
|
112
136
|
}
|
|
137
|
+
/** The statements that can have a label. */
|
|
138
|
+
export type LabeledStatement = ForStatement | ForInStatement | SwitchStatement | SelectStatement;
|
|
113
139
|
export interface ThrowStatement extends NodeBase {
|
|
114
140
|
kind: 'ThrowStatement';
|
|
115
141
|
argument: Expression;
|
|
@@ -132,7 +158,7 @@ export interface DeferStatement extends NodeBase {
|
|
|
132
158
|
body: CallExpression | BlockStatement;
|
|
133
159
|
}
|
|
134
160
|
/**
|
|
135
|
-
* `mount
|
|
161
|
+
* `mount { ... }` at the top level of a component: runs once the component's markup is in the
|
|
136
162
|
* document. It may return a function, which runs when `{if}`, `{switch}` or `{for}` removes the
|
|
137
163
|
* markup.
|
|
138
164
|
*/
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Completion, TextEdit } from './checker/checker.ts';
|
|
2
|
+
import type { CompletionList } from './completion.ts';
|
|
3
|
+
/** A fix of a diagnostic: the import of the name from one module. */
|
|
4
|
+
export interface ImportFix {
|
|
5
|
+
title: string;
|
|
6
|
+
edit: TextEdit;
|
|
7
|
+
}
|
|
8
|
+
/** The names of other modules that fit where the cursor is and that are not in scope there. */
|
|
9
|
+
export declare function importCompletions(source: string, filename: string, list: CompletionList): Completion[];
|
|
10
|
+
/** For an error about a name that is not defined, the imports of the modules that export it. */
|
|
11
|
+
export declare function importFixes(source: string, filename: string, message: string): ImportFix[];
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { dirname, relative, resolve, sep } from 'node:path';
|
|
2
|
+
import { markupFor } from "./config.js";
|
|
3
|
+
import { parse } from "./parser/parser.js";
|
|
4
|
+
import { projectExports } from "./project-modules.js";
|
|
5
|
+
const SPACES = {
|
|
6
|
+
value: 'value',
|
|
7
|
+
type: 'type',
|
|
8
|
+
tag: 'tag',
|
|
9
|
+
};
|
|
10
|
+
/** The names of other modules that fit where the cursor is and that are not in scope there. */
|
|
11
|
+
export function importCompletions(source, filename, list) {
|
|
12
|
+
const space = list.context && SPACES[list.context];
|
|
13
|
+
if (!space)
|
|
14
|
+
return [];
|
|
15
|
+
const known = new Set(list.items.map((item) => item.name));
|
|
16
|
+
const candidates = projectExports(filename).filter((each) => each.spaces.includes(space) && !known.has(each.name));
|
|
17
|
+
if (candidates.length === 0)
|
|
18
|
+
return [];
|
|
19
|
+
const imports = importsOf(source, filename);
|
|
20
|
+
return candidates.map((each) => {
|
|
21
|
+
const specifier = specifierOf(filename, each.path);
|
|
22
|
+
return {
|
|
23
|
+
name: each.name,
|
|
24
|
+
kind: each.kind,
|
|
25
|
+
import: { specifier, edit: importEdit(source, imports, each.name, specifier, each.path) },
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
const UNDEFINED = [
|
|
30
|
+
[/^"(.+)" is not defined$/, 'value'],
|
|
31
|
+
[/^unknown type "(.+)"$/, 'type'],
|
|
32
|
+
[/^unknown component <(.+)>$/, 'tag'],
|
|
33
|
+
[/^unknown decorator @(.+)$/, 'decorator'],
|
|
34
|
+
];
|
|
35
|
+
/** For an error about a name that is not defined, the imports of the modules that export it. */
|
|
36
|
+
export function importFixes(source, filename, message) {
|
|
37
|
+
for (const [pattern, space] of UNDEFINED) {
|
|
38
|
+
const name = pattern.exec(message)?.[1];
|
|
39
|
+
if (name === undefined)
|
|
40
|
+
continue;
|
|
41
|
+
const imports = importsOf(source, filename);
|
|
42
|
+
return projectExports(filename)
|
|
43
|
+
.filter((each) => each.name === name && each.spaces.includes(space))
|
|
44
|
+
.map((each) => {
|
|
45
|
+
const specifier = specifierOf(filename, each.path);
|
|
46
|
+
return {
|
|
47
|
+
title: `Add import { ${name} } from "${specifier}"`,
|
|
48
|
+
edit: importEdit(source, imports, name, specifier, each.path),
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
/** The imports of the module, with the absolute paths of the modules they import. */
|
|
55
|
+
function importsOf(source, filename) {
|
|
56
|
+
const { program } = parse(source, { markup: markupFor(filename) });
|
|
57
|
+
return program.body.flatMap((statement) => statement.kind === 'ImportDeclaration'
|
|
58
|
+
? [[statement, resolve(dirname(filename), statement.source.value)]]
|
|
59
|
+
: []);
|
|
60
|
+
}
|
|
61
|
+
/** The path of a module as an import of the file `filename` writes it: "./card.rk". */
|
|
62
|
+
function specifierOf(filename, path) {
|
|
63
|
+
const specifier = relative(dirname(resolve(filename)), path)
|
|
64
|
+
.split(sep)
|
|
65
|
+
.join('/');
|
|
66
|
+
return specifier.startsWith('../') ? specifier : `./${specifier}`;
|
|
67
|
+
}
|
|
68
|
+
function importEdit(source, imports, name, specifier, path) {
|
|
69
|
+
const same = imports.find(([node, from]) => from === path && node.namedImports.length > 0);
|
|
70
|
+
const last = same?.[0].namedImports.at(-1);
|
|
71
|
+
if (last)
|
|
72
|
+
return { start: last.end, end: last.end, text: `, ${name}` };
|
|
73
|
+
const line = `import { ${name} } from "${specifier}"`;
|
|
74
|
+
const after = imports.at(-1)?.[0];
|
|
75
|
+
if (!after)
|
|
76
|
+
return { start: 0, end: 0, text: `${line}\n\n` };
|
|
77
|
+
const end = source.indexOf('\n', after.end);
|
|
78
|
+
return end === -1
|
|
79
|
+
? { start: source.length, end: source.length, text: `\n${line}` }
|
|
80
|
+
: { start: end + 1, end: end + 1, text: `${line}\n` };
|
|
81
|
+
}
|
package/dist/breaks.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type * as ast from './ast.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Whether a `break` in these statements leaves the enclosing loop or switch: an unlabeled one
|
|
4
|
+
* outside of nested loops and switches, or `break label` anywhere when `label` is the statement's.
|
|
5
|
+
*/
|
|
6
|
+
export declare function containsBreak(statements: readonly ast.Statement[], label?: ast.Identifier | null): boolean;
|
package/dist/breaks.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { forEachChild } from "./walk.js";
|
|
2
|
+
/**
|
|
3
|
+
* Whether a `break` in these statements leaves the enclosing loop or switch: an unlabeled one
|
|
4
|
+
* outside of nested loops and switches, or `break label` anywhere when `label` is the statement's.
|
|
5
|
+
*/
|
|
6
|
+
export function containsBreak(statements, label = null) {
|
|
7
|
+
let found = false;
|
|
8
|
+
const visit = (node, nested) => {
|
|
9
|
+
switch (node.kind) {
|
|
10
|
+
case 'BreakStatement':
|
|
11
|
+
if (node.label ? node.label.name === label?.name : !nested)
|
|
12
|
+
found = true;
|
|
13
|
+
return;
|
|
14
|
+
// An unlabeled `break` inside these belongs to them.
|
|
15
|
+
case 'ForStatement':
|
|
16
|
+
case 'ForInStatement':
|
|
17
|
+
case 'SwitchStatement':
|
|
18
|
+
case 'SelectStatement':
|
|
19
|
+
if (label !== null)
|
|
20
|
+
forEachChild(node, (child) => visit(child, true));
|
|
21
|
+
return;
|
|
22
|
+
case 'FuncDeclaration':
|
|
23
|
+
case 'FuncExpression':
|
|
24
|
+
case 'ArrowFunction':
|
|
25
|
+
case 'ClassDeclaration':
|
|
26
|
+
case 'MountStatement':
|
|
27
|
+
case 'EffectStatement':
|
|
28
|
+
return;
|
|
29
|
+
default:
|
|
30
|
+
forEachChild(node, (child) => visit(child, nested));
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
for (const statement of statements)
|
|
34
|
+
visit(statement, false);
|
|
35
|
+
return found;
|
|
36
|
+
}
|
package/dist/build.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export interface BuildOptions {
|
|
|
9
9
|
declarations?: boolean;
|
|
10
10
|
/** Markup and components for every file; by default as its package.json says (config.ts). */
|
|
11
11
|
markup?: boolean;
|
|
12
|
+
/** Write a source map next to each `.js`, `app.js.map`. Defaults to `true`. */
|
|
13
|
+
sourceMap?: boolean;
|
|
12
14
|
}
|
|
13
15
|
export interface BuildOutput {
|
|
14
16
|
/** Absolute path of the `.rk` file. */
|
|
@@ -26,6 +28,11 @@ export interface BuildOutput {
|
|
|
26
28
|
output: string;
|
|
27
29
|
code: string;
|
|
28
30
|
};
|
|
31
|
+
/** The source maps of the module and of its worker module, `.js.map`, unless turned off. */
|
|
32
|
+
maps?: {
|
|
33
|
+
output: string;
|
|
34
|
+
code: string;
|
|
35
|
+
}[];
|
|
29
36
|
}
|
|
30
37
|
/** The errors or the warnings of a file. */
|
|
31
38
|
export interface BuildError {
|