rooklang 0.4.2 → 0.5.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 (100) hide show
  1. package/CHANGELOG.md +235 -0
  2. package/CHANGELOG.ru.md +235 -0
  3. package/dist/aliases.d.ts +2 -0
  4. package/dist/aliases.js +83 -0
  5. package/dist/ast/declarations.d.ts +18 -0
  6. package/dist/ast/expressions.d.ts +14 -1
  7. package/dist/ast/markup.d.ts +2 -0
  8. package/dist/ast/statements.d.ts +2 -2
  9. package/dist/checker/assignments.js +2 -1
  10. package/dist/checker/base.d.ts +3 -0
  11. package/dist/checker/base.js +1 -1
  12. package/dist/checker/builtins.js +5 -1
  13. package/dist/checker/calls.d.ts +2 -0
  14. package/dist/checker/calls.js +18 -3
  15. package/dist/checker/classes.js +8 -0
  16. package/dist/checker/component-bindings.d.ts +16 -0
  17. package/dist/checker/component-bindings.js +65 -2
  18. package/dist/checker/context.d.ts +12 -0
  19. package/dist/checker/declarations.d.ts +2 -0
  20. package/dist/checker/declarations.js +38 -3
  21. package/dist/checker/expressions.d.ts +1 -0
  22. package/dist/checker/expressions.js +17 -1
  23. package/dist/checker/flow.d.ts +1 -1
  24. package/dist/checker/flow.js +10 -0
  25. package/dist/checker/functions.d.ts +2 -0
  26. package/dist/checker/functions.js +33 -7
  27. package/dist/checker/goroutines.d.ts +2 -2
  28. package/dist/checker/goroutines.js +2 -2
  29. package/dist/checker/imports.d.ts +10 -0
  30. package/dist/checker/imports.js +73 -6
  31. package/dist/checker/initializers.d.ts +12 -0
  32. package/dist/checker/initializers.js +80 -0
  33. package/dist/checker/loops.js +3 -1
  34. package/dist/checker/members.js +1 -0
  35. package/dist/checker/resolution.d.ts +2 -0
  36. package/dist/checker/resolution.js +13 -2
  37. package/dist/checker/statements.d.ts +5 -0
  38. package/dist/checker/statements.js +26 -3
  39. package/dist/checker/tagged-unions.d.ts +6 -0
  40. package/dist/checker/tagged-unions.js +31 -1
  41. package/dist/checker/tags.d.ts +6 -0
  42. package/dist/checker/tags.js +44 -0
  43. package/dist/checker/types/constructors.js +10 -1
  44. package/dist/checker/types/params.js +33 -7
  45. package/dist/checker/types/printing.js +5 -1
  46. package/dist/checker/types/relations.js +2 -1
  47. package/dist/codegen/calls.d.ts +2 -0
  48. package/dist/codegen/calls.js +23 -1
  49. package/dist/codegen/component-props.js +8 -1
  50. package/dist/codegen/control-flow.d.ts +3 -0
  51. package/dist/codegen/control-flow.js +17 -0
  52. package/dist/codegen/expressions.d.ts +4 -1
  53. package/dist/codegen/expressions.js +4 -15
  54. package/dist/codegen/functions.d.ts +2 -0
  55. package/dist/codegen/functions.js +13 -0
  56. package/dist/codegen/mutations.d.ts +6 -0
  57. package/dist/codegen/mutations.js +36 -0
  58. package/dist/codegen/options.d.ts +2 -0
  59. package/dist/codegen/reactive.js +9 -5
  60. package/dist/codegen/simple-statements.js +3 -1
  61. package/dist/codegen/statements.d.ts +4 -0
  62. package/dist/codegen/statements.js +37 -1
  63. package/dist/compile.js +2 -0
  64. package/dist/completion.js +2 -1
  65. package/dist/declarations.js +18 -0
  66. package/dist/lexer/base.d.ts +3 -2
  67. package/dist/lexer/base.js +14 -5
  68. package/dist/lexer/lexer.js +3 -0
  69. package/dist/lexer/token.d.ts +6 -1
  70. package/dist/lexer/token.js +0 -1
  71. package/dist/modules.js +4 -3
  72. package/dist/parser/base.d.ts +5 -0
  73. package/dist/parser/base.js +9 -1
  74. package/dist/parser/classes.js +4 -3
  75. package/dist/parser/declarations.d.ts +2 -0
  76. package/dist/parser/declarations.js +25 -2
  77. package/dist/parser/decorators.js +1 -1
  78. package/dist/parser/expressions.js +6 -0
  79. package/dist/parser/literals.d.ts +2 -4
  80. package/dist/parser/literals.js +12 -24
  81. package/dist/parser/objects.d.ts +8 -0
  82. package/dist/parser/objects.js +51 -0
  83. package/dist/parser/params.d.ts +37 -4
  84. package/dist/parser/params.js +143 -9
  85. package/dist/parser/postfix.d.ts +5 -0
  86. package/dist/parser/postfix.js +36 -0
  87. package/dist/parser/simple-statements.d.ts +2 -0
  88. package/dist/parser/simple-statements.js +50 -0
  89. package/dist/parser/statements.js +8 -6
  90. package/dist/parser/syntax.js +0 -1
  91. package/dist/parser/types.d.ts +0 -4
  92. package/dist/parser/types.js +17 -32
  93. package/dist/project-modules.js +21 -0
  94. package/dist/reexports.d.ts +4 -0
  95. package/dist/reexports.js +56 -0
  96. package/dist/typescript/importer.d.ts +4 -0
  97. package/dist/typescript/importer.js +27 -3
  98. package/dist/typescript/library.js +5 -2
  99. package/dist/walk.js +12 -0
  100. package/package.json +4 -2
package/CHANGELOG.md ADDED
@@ -0,0 +1,235 @@
1
+ # Changelog
2
+
3
+ **English** · [Русский](CHANGELOG.ru.md)
4
+
5
+ What changed in each version of `rooklang`: the language, the compiler, the runtime and the VS Code
6
+ extension. The road to 1.0 is in [docs/roadmap.md](docs/roadmap.md).
7
+
8
+ **Versions before 1.0.** A minor version (0.4.0) may break code that compiled before, and says how
9
+ to change it under **Breaking**. A patch version (0.3.5) never does: it adds and fixes only.
10
+
11
+ ## 0.5.0 — 2026-10-31
12
+
13
+ What a team that builds a browser game in Rook, with Bun and Vite, found missing or broken.
14
+
15
+ ### Breaking
16
+
17
+ - A component changes a property that is not bound neither by assigning it nor in place:
18
+ `todo.done = true`, `bind:value={todo.title}` and `items.push(x)` on a property are errors, since
19
+ the object is the parent's and its markup did not know of the change. Declare the property bound,
20
+ `comp TodoItem(bind todo Todo)`, and pass it with `bind:todo={todo}`; the item of a `{for}` loop
21
+ can now be bound so.
22
+ - `export const Rows = Inner` of a component without a type is an error: its `.d.ts` lost the
23
+ properties. Write `export { Rows } from "./rows.rk"`, or give the constant a component type.
24
+
25
+ ### Added
26
+
27
+ - Default values of the parameters of functions, methods, constructors, `func` literals and arrow
28
+ functions, as properties of components have them: `func greet(name string = "you", times = 1)`.
29
+ - Rest parameters, `func log(level string, ...parts []any)`, and in function types,
30
+ `func(string, ...[]any)`.
31
+ - Tagged templates, `` sql`select * from users where id = ${id}` ``, checked against the parameters
32
+ of the tag.
33
+ - `export { Row, Rows } from "./rows.rk"` and `export * from "./rows.rk"`, with components,
34
+ decorators and state.
35
+ - Object destructuring in `const` and `let`: `const { name, size: bytes, ...rest } = file`.
36
+ - Methods in object literals: `{ fetch(req Request) Response { ... } }`.
37
+ - `x!` takes a value not to be `null`, as in TypeScript.
38
+ - `void`, for `Promise<void>` in interfaces and generics, and `never`, the result of a function
39
+ that never returns; a call of one narrows types as `throw` does, `process.exit(1)` included.
40
+ - `bind:item={item}` for the item of a `{for}` loop: changes in place update the list, and a new
41
+ value replaces the item in it.
42
+ - Imports of `.rk` and `.ts` modules by the aliases of `package.json` (`"imports"`, `#ui/button.rk`)
43
+ and of `tsconfig.json` (`"paths"`, `@/ui/button.rk`) are typed, and built with `.js`.
44
+ - A conditional expression can be split with `?` and `:` at the start of the lines.
45
+ - `func(a, b number) number` groups the parameters of a function type, as in Go.
46
+ - An object type is the result of a function when its body follows, `func names() { [string]: string } { ... }`.
47
+ - `type` is a keyword only before the name of a type at the start of a statement: variables,
48
+ parameters and fields can be named `type`.
49
+ - The npm package has the changelog.
50
+
51
+ ### Fixed
52
+
53
+ - A function of a component that changes state and that markup gives to a child, `act={copy}`,
54
+ or that an arrow given to it calls, `act={() => show("x")}`, updates the markup: it was taken for
55
+ code that renders, which updates nothing.
56
+ - Importing `describe` and `it` from Vitest overflowed the stack, then took two minutes: the types of
57
+ `.d.ts` files that refer to themselves are substituted when they are used. Messages print a long
58
+ type inside another one as `{ ... }`.
59
+ - The types of `@types/bun`: the global `Bun` and the module `bun` were untyped, and the options of
60
+ `Bun.serve({ fetch: req => ... })` give `req` its type.
61
+ - A callback whose result in a `.d.ts` is `any` or `void | T`, `ws.onopen = () => { ... }`, and a
62
+ function whose result is `any` may end without `return`.
63
+ - A line that ends with `>` of type arguments, `votes Map<string, number>`, ends the declaration.
64
+ - A field of a class sees a constant of its module with a written type or a literal value,
65
+ `limit = LIMIT`.
66
+ - Clearer errors for `` `${x++}` ``, type arguments in a call, `load<number>(1)`, and several
67
+ results of a conditional expression, `a ? two() : one()`.
68
+
69
+ ### The site
70
+
71
+ - The site is deployed with each release of npm, not with each push to `main`, so it describes the
72
+ version that `npm install` gets.
73
+
74
+ ## 0.4.2 — 2026-10-31
75
+
76
+ ### Fixed
77
+
78
+ - A function literal given to a child component, `<Plus add={() => { items++ }} />`, updates the
79
+ markup each time it is called. When the state it read changed, the parent gave the child the
80
+ function again, written without its updates: from the second call on, the state changed but the
81
+ page did not. A function declared with `func` in the body was not affected.
82
+
83
+ ## 0.4.1 — 2026-10-30
84
+
85
+ ### Added
86
+
87
+ - Bun: the plugin `rooklang/bun`, preloaded with `preload = ["rooklang/bun/register"]` in
88
+ `bunfig.toml`, compiles `.rk` modules when they load, for `bun app.rk`, imports from TypeScript,
89
+ `bun --hot` and `bun test`, goroutines included. `rook run` under the runtime of Bun,
90
+ `bun --bun rook run app.rk`, runs the program in Bun, `--watch` too; it used to fail on
91
+ `registerHooks`, which Bun does not have.
92
+ - The VS Code extension has the version of the package it carries, 0.4.1, and the stores get each
93
+ release: it was 0.1.0 there, with the compiler of 17 October. When the `rooklang` installed in a
94
+ project is older than its copy, which then checks the files with errors for newer syntax, the
95
+ status bar marks it and the extension offers to install the new version with the package
96
+ manager of the project.
97
+
98
+ ### Fixed
99
+
100
+ - A worker of `go` that fails before it starts, as when its module does not load, fails the calls
101
+ that wait for it: they used to wait forever while the pool started worker after worker.
102
+
103
+ ## 0.4.0 — 2026-10-29
104
+
105
+ ### Breaking
106
+
107
+ - `mount` is written without parentheses, like `effect`: `mount { ... }`. `mount() { ... }` is an
108
+ error that shows the new form.
109
+ - `mount` cleans up with `defer`, as an effect does, and returns nothing: write
110
+ `defer clearInterval(timer)` instead of `return () => clearInterval(timer)`. `defer f(x)` takes
111
+ `x` at once; for a value that comes later, `defer { editor?.dispose() }` reads it when it runs.
112
+
113
+ - A public member of a decorator is read as `@visible.shown`, without `get`: `get(@visible.shown)`
114
+ is now an error that shows the new form. Decorators are experimental, so the old form is not kept.
115
+ Write `@visible.shown` everywhere, in markup too: `{if @visible.shown { ... }}`.
116
+
117
+ ### Added
118
+
119
+ - State of a module (experimental): `state items []Item = []` or `export state` at the top level
120
+ of a module is shared by its components. The components that read it are updated when it changes
121
+ anywhere in the module, through names that refer into it too (`for item in items`); they listen
122
+ while they are on the page. Other modules read it and change it only with the functions of its
123
+ module: `items.push(x)` there is an error that says so.
124
+ - Bound properties (experimental): `comp Drawer(bind open bool = false)` changes `open` as its
125
+ state, and `<Drawer bind:open={menu} />` writes the changes, in place ones too, into the parent's
126
+ `menu`. Without `bind:` the property is the component's own state.
127
+ - `class` takes a list of classes, `class={[styles.tab, active ? styles.active : null]}`: `null`s
128
+ and empty strings are left out.
129
+ - A `bool` in `aria-*` and other attributes without a DOM property is written as `"true"` or
130
+ `"false"`, as ARIA expects; this is now documented and tested.
131
+
132
+ - A decorator can include others: `dec card(title string) includes framed(title), likes { ... }`
133
+ applies them with it, above its own body, and their arguments see its parameters. The component
134
+ reads their public members through it, `@card.count`; `@card` counts as `@likes` applied, for
135
+ `needs` and for applying twice. An exported decorator cannot include others yet.
136
+ - `public ref` in a decorator: the component reads the element of the wrapper as `@framed.box`.
137
+ The ref is read-only, its element is not: `@framed.box.title = "Card"`.
138
+ - A `derived` of several statements is a block that returns the value:
139
+ `derived summary string { ...; return text }`. The type may be left out, and is then inferred
140
+ from the `return`s. In JS the block becomes a function, called first and by the updates of what
141
+ it reads; assigning state in it is an error. A `{` after the name of a `derived` now starts the
142
+ block, so an object type goes in parentheses there: `derived p ({ x number }) = ...`.
143
+ - Tagged unions (experimental): comparing a tag, a field with a literal type in every member of a
144
+ union, narrows the union. After `if d.kind == "courier"` the fields of `Courier` can be read, and
145
+ so in `else`, after a branch that returns, in `switch d.kind` and in `{if}` and `{switch}` of
146
+ markup. An object literal where such a union is expected is checked as the member its tag
147
+ chooses: `{ kind: "pickup", shop: "Main st." }` fits `Pickup | Courier`, and a kind of no member
148
+ is an error that lists the kinds.
149
+ - Paths of data fields from a variable, a parameter, `state`, `derived` or a module `const` narrow
150
+ like the variable: `if user.boss != null` gives `user.boss.name`, without an intermediate
151
+ `const`; `typeof` and `instanceof` narrow them too. An assignment to the path, its start or its
152
+ tag ends the narrowing, one to another field does not; getters, `a[i]` and `?.` are not paths.
153
+ The hint for a nullable
154
+ `<page.other />` now shows `{if page.other != null { <page.other /> }}`.
155
+ - Keys of lists in markup: `{for todo in todos with key todo.id { ... }}` finds the blocks again
156
+ by the key, so a list loaded again from a server keeps its blocks and the state of the
157
+ components in them.
158
+ - The browser compiler, which the playground uses, knows `AbortController`, `AbortSignal` and
159
+ `ImageData` as types too: `signal AbortSignal` compiles there.
160
+ - The VS Code extension checks a file with the `rooklang` installed next to it, so the editor shows
161
+ the errors of the version that `rook build` runs; in an untrusted workspace, and without an
162
+ installed one, it uses its own copy. The status bar shows which compiler checked the file.
163
+ - [docs/roadmap.md](docs/roadmap.md): where Rook stands and the road to 1.0, with what the
164
+ language is to have by then.
165
+
166
+ ### Fixed
167
+
168
+ - The error of `decode` for a union names the member whose tag fits: `{ "kind": "square" }` of
169
+ `Circle | Square` gives `side: missing`, not `kind: expected "circle", got "square"`. A tag that
170
+ fits no member lists all of them: `kind: expected "circle" | "square", got "oval"`.
171
+ - A literal type or a union of them, `type Status "shown" | "aborted"`, goes into an attribute
172
+ without a DOM property, `data-status={status}`.
173
+ - With `runtime: "inline"`, as in the playground, a function of the program named like one of the
174
+ runtime, such as `check`, no longer replaces it.
175
+
176
+ ## 0.3.4 — 2026-10-26
177
+
178
+ ### Added
179
+
180
+ - `decode<T>(json)`: checks JSON from outside against a type when the program runs.
181
+ - `try` as an expression: what JS throws becomes the error value.
182
+ - `error(msg, err)` wraps an error, as `%w` of Go.
183
+ - `signal(...)`, `done(abortSignal)` and `abortSignal(ch)`: signals of the process and cancellation
184
+ as channels.
185
+ - Topics, `topic<T>(name)`: values between the tabs of a site.
186
+ - `for` over async iterables: streams of Node, `readline`, cursors.
187
+ - `data class`: instances that go to goroutines with their class and methods.
188
+ - Getters and setters, `readonly`, `abstract` classes, `if` with an initializer, labels, regular
189
+ expression literals.
190
+ - Source maps: stack traces, in goroutines too, show the lines of the `.rk` file.
191
+ - `rook run --watch`: runs the program again when a file of it changes.
192
+ - Goroutines run under Vitest, which tests `.rk` modules with the Vite plugin.
193
+ - The VS Code extension completes names that other `.rk` files of the package export and adds
194
+ their imports, and offers a quick fix that imports an undefined name.
195
+
196
+ ### Fixed
197
+
198
+ - An array, a string or a `Set` goes where a `.d.ts` expects `Iterable<T>`.
199
+ - The type parameters of a tuple `[K, V]` of a `.d.ts` are inferred by position:
200
+ `new Map([["a", 1]])` is a `Map<string, number>`.
201
+
202
+ ## 0.3.3 — 2026-10-18
203
+
204
+ ### Breaking
205
+
206
+ - In `const user, err = load(id)` of a function of `(User, error)`, `user` is a `?User` until
207
+ `err` is checked: such a function may now `return null, err`. Check the error before the value,
208
+ `if err != null { return }`.
209
+
210
+ ### Changed
211
+
212
+ - `go for` splits the array into four parts per processor, each to the first free worker.
213
+ - `for i, x in items` over an array goes over its indexes instead of the pairs of `entries()`,
214
+ which is faster.
215
+
216
+ ### Fixed
217
+
218
+ - `for i, c in s` over a string numbers its characters instead of throwing a `TypeError`.
219
+ - The workers of `rook run` no longer load the compiler.
220
+
221
+ ## 0.3.2 — 2026-10-17
222
+
223
+ ### Breaking
224
+
225
+ - The compiled code imports its runtime from `rooklang/runtime` instead of having it in every
226
+ module, so `rooklang` is a dependency of the project, not only of the build:
227
+ `npm install rooklang`.
228
+
229
+ ### Added
230
+
231
+ - Queues: `queue T`, made by `queue<T>()` and `queue<T>(items)`.
232
+ - Streams and channels: `chan(stream)` and `stream(ch)`.
233
+ - The VS Code extension, published from CI.
234
+
235
+ Earlier versions are in the history of the repository.
@@ -0,0 +1,235 @@
1
+ # Список изменений
2
+
3
+ [English](CHANGELOG.md) · **Русский**
4
+
5
+ Что изменилось в каждой версии `rooklang`: язык, компилятор, рантайм и расширение VS Code. Путь к
6
+ 1.0 описан в [docs/roadmap.ru.md](docs/roadmap.ru.md).
7
+
8
+ **Версии до 1.0.** Минорная версия (0.4.0) может сломать код, который раньше компилировался, и
9
+ говорит, как его поменять, в разделе **Ломающие изменения**. Патч (0.3.5) никогда не ломает: он
10
+ только добавляет и исправляет.
11
+
12
+ ## 0.5.0 — 2026-10-31
13
+
14
+ Что нашла команда, которая пишет на Rook браузерную игру с Bun и Vite: чего не хватало и что не
15
+ работало.
16
+
17
+ ### Ломающие изменения
18
+
19
+ - Компонент не меняет несвязанное свойство ни присваиванием, ни на месте: `todo.done = true`,
20
+ `bind:value={todo.title}` и `items.push(x)` для свойства — ошибки, потому что объект принадлежит
21
+ родителю, а его разметка об изменении не знала. Объявите свойство связанным,
22
+ `comp TodoItem(bind todo Todo)`, и передайте его через `bind:todo={todo}`; теперь так можно
23
+ связать и элемент цикла `{for}`.
24
+ - `export const Rows = Inner` для компонента без типа — ошибка: его `.d.ts` терял свойства.
25
+ Пишите `export { Rows } from "./rows.rk"` или дайте константе тип компонента.
26
+
27
+ ### Добавлено
28
+
29
+ - Значения по умолчанию у параметров функций, методов, конструкторов, литералов `func` и стрелочных
30
+ функций, как у свойств компонентов: `func greet(name string = "you", times = 1)`.
31
+ - Остаток аргументов, `func log(level string, ...parts []any)`, и в типах функций,
32
+ `func(string, ...[]any)`.
33
+ - Теговые шаблоны, `` sql`select * from users where id = ${id}` ``, которые проверяются по
34
+ параметрам тега.
35
+ - `export { Row, Rows } from "./rows.rk"` и `export * from "./rows.rk"` — с компонентами,
36
+ декораторами и состоянием.
37
+ - Деструктуризация объектов в `const` и `let`: `const { name, size: bytes, ...rest } = file`.
38
+ - Методы в объектных литералах: `{ fetch(req Request) Response { ... } }`.
39
+ - `x!` считает значение не `null`, как в TypeScript.
40
+ - `void` — для `Promise<void>` в интерфейсах и обобщённых типах, и `never` — результат функции,
41
+ которая не возвращается; её вызов сужает типы, как `throw`, в том числе `process.exit(1)`.
42
+ - `bind:item={item}` для элемента цикла `{for}`: изменения на месте обновляют список, а новое
43
+ значение заменяет в нём элемент.
44
+ - Импорты `.rk`- и `.ts`-модулей по алиасам из `package.json` (`"imports"`, `#ui/button.rk`) и
45
+ `tsconfig.json` (`"paths"`, `@/ui/button.rk`) типизированы и собираются с `.js`.
46
+ - Условное выражение можно переносить, начиная строки с `?` и `:`.
47
+ - `func(a, b number) number` группирует параметры типа функции, как в Go.
48
+ - Объектный тип — результат функции, если за ним идёт тело: `func names() { [string]: string } { ... }`.
49
+ - `type` — ключевое слово только перед именем типа в начале оператора: переменные, параметры и
50
+ поля можно называть `type`.
51
+ - В npm-пакете есть список изменений.
52
+
53
+ ### Исправлено
54
+
55
+ - Функция компонента, которая меняет состояние и которую разметка передаёт дочернему компоненту,
56
+ `act={copy}`, или которую вызывает переданная ему стрелка, `act={() => show("x")}`, обновляет
57
+ разметку: её принимали за код отрисовки, который ничего не обновляет.
58
+ - Импорт `describe` и `it` из Vitest переполнял стек, а затем проверялся две минуты: типы
59
+ `.d.ts`, которые ссылаются сами на себя, подставляются, когда используются. Длинный тип внутри
60
+ другого сообщения печатают как `{ ... }`.
61
+ - Типы `@types/bun`: глобальный `Bun` и модуль `bun` были без типов, а в
62
+ `Bun.serve({ fetch: req => ... })` у `req` теперь есть тип.
63
+ - Колбэк, у которого в `.d.ts` результат `any` или `void | T`, `ws.onopen = () => { ... }`, и
64
+ функция с результатом `any` могут закончиться без `return`.
65
+ - Строка, которая кончается на `>` аргументов типа, `votes Map<string, number>`, завершает
66
+ объявление.
67
+ - Поле класса видит константу своего модуля с записанным типом или литеральным значением,
68
+ `limit = LIMIT`.
69
+ - Понятные ошибки для `` `${x++}` ``, аргументов типа в вызове, `load<number>(1)`, и нескольких
70
+ результатов условного выражения, `a ? two() : one()`.
71
+
72
+ ### Сайт
73
+
74
+ - Сайт выкладывается с каждым выпуском в npm, а не с каждым пушем в `main`, поэтому описывает ту
75
+ версию, которую ставит `npm install`.
76
+
77
+ ## 0.4.2 — 2026-10-31
78
+
79
+ ### Исправлено
80
+
81
+ - Функция-литерал, переданная дочернему компоненту, `<Plus add={() => { items++ }} />`, обновляет
82
+ разметку при каждом вызове. Когда менялось состояние, которое она читала, родитель передавал
83
+ ребёнку функцию заново — уже без обновлений: начиная со второго вызова состояние менялось, а
84
+ страница нет. Функции, объявленной в теле через `func`, это не касалось.
85
+
86
+ ## 0.4.1 — 2026-10-30
87
+
88
+ ### Добавлено
89
+
90
+ - Bun: плагин `rooklang/bun`, который подключают заранее строкой
91
+ `preload = ["rooklang/bun/register"]` в `bunfig.toml`, компилирует `.rk`-модули при загрузке —
92
+ для `bun app.rk`, импортов из TypeScript, `bun --hot` и `bun test`, с горутинами. `rook run` под
93
+ рантаймом Bun, `bun --bun rook run app.rk`, выполняет программу в Bun, и с `--watch` тоже; раньше
94
+ он падал на `registerHooks`, которого в Bun нет.
95
+ - У расширения VS Code та же версия, что у пакета, который оно несёт, — 0.4.1, и в магазины
96
+ попадает каждый выпуск: там была 0.1.0 с компилятором от 17 октября. Если `rooklang`,
97
+ установленный в проекте, старше его копии — и тогда новый синтаксис подчёркивается как ошибка, —
98
+ строка состояния отмечает это, а расширение предлагает поставить новую версию менеджером пакетов
99
+ проекта.
100
+
101
+ ### Исправлено
102
+
103
+ - Воркер `go`, который упал до старта — например, потому что его модуль не загрузился, — отклоняет
104
+ вызовы, которые его ждут: раньше они ждали вечно, а пул запускал воркер за воркером.
105
+
106
+ ## 0.4.0 — 2026-10-29
107
+
108
+ ### Ломающие изменения
109
+
110
+ - `mount` пишется без скобок, как `effect`: `mount { ... }`. `mount() { ... }` — ошибка, которая
111
+ показывает новую запись.
112
+ - `mount` убирает за собой через `defer`, как эффект, и ничего не возвращает: пишите
113
+ `defer clearInterval(timer)` вместо `return () => clearInterval(timer)`. `defer f(x)` берёт `x`
114
+ сразу; для значения, которое появится позже, `defer { editor?.dispose() }` читает его при
115
+ выполнении.
116
+
117
+ - Публичный член декоратора читают как `@visible.shown`, без `get`: `get(@visible.shown)` теперь
118
+ ошибка, которая показывает новую запись. Декораторы экспериментальные, поэтому старая запись не
119
+ сохраняется. Пишите `@visible.shown` везде, и в разметке тоже: `{if @visible.shown { ... }}`.
120
+
121
+ ### Добавлено
122
+
123
+ - Состояние модуля (экспериментально): `state items []Item = []` или `export state` на верхнем
124
+ уровне модуля делят его компоненты. Компоненты, которые его читают, обновляются, когда оно
125
+ меняется где угодно в модуле, в том числе через имена, которые указывают внутрь него
126
+ (`for item in items`); они слушают, пока они на странице. Другие модули его читают и меняют только
127
+ функциями его модуля: `items.push(x)` там — ошибка, которая это подсказывает.
128
+ - Связанные свойства (экспериментально): `comp Drawer(bind open bool = false)` меняет `open` как
129
+ своё состояние, а `<Drawer bind:open={menu} />` записывает изменения, в том числе на месте, в
130
+ `menu` родителя. Без `bind:` свойство — собственное состояние компонента.
131
+ - `class` принимает список классов, `class={[styles.tab, active ? styles.active : null]}`: `null` и
132
+ пустые строки выпадают.
133
+ - `bool` в `aria-*` и других атрибутах без DOM-свойства записывается как `"true"` или `"false"`,
134
+ как ждёт ARIA; теперь это описано и проверено тестом.
135
+
136
+ - Декоратор может включать другие: `dec card(title string) includes framed(title), likes { ... }`
137
+ применяет их вместе с собой, выше своего тела, а их аргументы видят его параметры. Компонент
138
+ читает их публичные члены через него, `@card.count`; `@card` считается применённым `@likes` — для
139
+ `needs` и для повторного применения. Экспортированный декоратор пока не может включать другие.
140
+ - `public ref` в декораторе: компонент читает элемент обёртки как `@framed.box`. Сам ref только для
141
+ чтения, его элемент — нет: `@framed.box.title = "Card"`.
142
+ - `derived` из нескольких операторов — блок, который возвращает значение:
143
+ `derived summary string { ...; return text }`. Тип можно не писать, тогда он выводится из
144
+ `return`. В JS блок становится функцией, которую вызывают сначала и в обновлениях того, что он
145
+ читает; присвоить в нём состояние — ошибка. `{` после имени `derived` теперь начинает блок,
146
+ поэтому объектный тип там пишут в скобках: `derived p ({ x number }) = ...`.
147
+ - Tagged unions (экспериментально): сравнение метки, поля с литеральным типом у каждого члена
148
+ union, сужает union. После `if d.kind == "courier"` можно читать поля `Courier`, и так же в
149
+ `else`, после ветки с `return`, в `switch d.kind` и в `{if}` и `{switch}` разметки. Объектный
150
+ литерал там, где ожидается такой union, проверяется как член, который выбирает его метка:
151
+ `{ kind: "pickup", shop: "Main st." }` подходит к `Pickup | Courier`, а вид, которого нет ни у
152
+ одного члена, — ошибка со списком видов.
153
+ - Пути полей с данными от переменной, параметра, `state`, `derived` или `const` модуля сужаются
154
+ так же, как переменная: `if user.boss != null` даёт `user.boss.name` без промежуточной `const`;
155
+ `typeof` и `instanceof` их тоже сужают. Присваивание пути, его начала или его метки сбрасывает
156
+ сужение, присваивание другого поля — нет; геттеры, `a[i]` и `?.` путями не считаются. Подсказка для `<page.other />`, который
157
+ может быть null, теперь показывает `{if page.other != null { <page.other /> }}`.
158
+ - Ключи списков в разметке: `{for todo in todos with key todo.id { ... }}` находит блоки заново по
159
+ ключу, так что список, заново загруженный с сервера, сохраняет свои блоки и состояние компонентов
160
+ в них.
161
+ - Браузерный компилятор, которым пользуется песочница, знает `AbortController`, `AbortSignal` и
162
+ `ImageData` и как типы: `signal AbortSignal` там компилируется.
163
+ - Расширение VS Code проверяет файл тем `rooklang`, который установлен рядом с ним, так что редактор
164
+ показывает ошибки той версии, которую запускает `rook build`; в недоверенной рабочей области и без
165
+ установленного пакета — своей копией. Строка состояния показывает, какой компилятор проверил файл.
166
+ - [docs/roadmap.ru.md](docs/roadmap.ru.md): где Rook сейчас и путь к 1.0, и что к тому времени
167
+ должно быть в языке.
168
+
169
+ ### Исправлено
170
+
171
+ - Ошибка `decode` для union называет член, чья метка подошла: `{ "kind": "square" }` для
172
+ `Circle | Square` даёт `side: missing`, а не `kind: expected "circle", got "square"`. Метка, которая
173
+ не подошла ни к одному члену, перечисляет их все: `kind: expected "circle" | "square", got "oval"`.
174
+ - Литеральный тип или их объединение, `type Status "shown" | "aborted"`, можно передать в атрибут
175
+ без DOM-свойства, `data-status={status}`.
176
+ - С `runtime: "inline"`, как в песочнице, функция программы с тем же именем, что у функции
177
+ рантайма, например `check`, больше её не подменяет.
178
+
179
+ ## 0.3.4 — 2026-10-26
180
+
181
+ ### Добавлено
182
+
183
+ - `decode<T>(json)`: проверяет JSON снаружи по типу, когда программа работает.
184
+ - `try` как выражение: то, что бросает JS, становится значением ошибки.
185
+ - `error(msg, err)` оборачивает ошибку, как `%w` в Go.
186
+ - `signal(...)`, `done(abortSignal)` и `abortSignal(ch)`: сигналы процесса и отмена как каналы.
187
+ - Топики, `topic<T>(name)`: значения между вкладками сайта.
188
+ - `for` по асинхронным итерируемым: потоки Node, `readline`, курсоры.
189
+ - `data class`: экземпляры, которые уходят в горутины вместе со своим классом и методами.
190
+ - Геттеры и сеттеры, `readonly`, абстрактные классы, `if` с инициализатором, метки, литералы
191
+ регулярных выражений.
192
+ - Source maps: стектрейсы, в горутинах тоже, показывают строки `.rk`-файла.
193
+ - `rook run --watch`: запускает программу заново, когда меняется её файл.
194
+ - Горутины работают под Vitest, который тестирует `.rk`-модули с плагином Vite.
195
+ - Расширение VS Code дополняет имена, которые экспортируют другие `.rk`-файлы пакета, и добавляет
196
+ их импорты, а для неопределённого имени предлагает исправление, которое его импортирует.
197
+
198
+ ### Исправлено
199
+
200
+ - Массив, строку или `Set` можно передать туда, где `.d.ts` ждёт `Iterable<T>`.
201
+ - Параметры типа кортежа `[K, V]` из `.d.ts` выводятся по позиции: `new Map([["a", 1]])` — это
202
+ `Map<string, number>`.
203
+
204
+ ## 0.3.3 — 2026-10-18
205
+
206
+ ### Ломающие изменения
207
+
208
+ - В `const user, err = load(id)` функции с `(User, error)` значение `user` имеет тип `?User`, пока
209
+ не проверен `err`: такая функция теперь может вернуть `return null, err`. Проверяйте ошибку раньше
210
+ значения: `if err != null { return }`.
211
+
212
+ ### Изменено
213
+
214
+ - `go for` делит массив на четыре части на процессор, каждую — первому свободному воркеру.
215
+ - `for i, x in items` по массиву идёт по индексам, а не по парам `entries()`: так быстрее.
216
+
217
+ ### Исправлено
218
+
219
+ - `for i, c in s` по строке нумерует её символы, а не бросает `TypeError`.
220
+ - Воркеры `rook run` больше не загружают компилятор.
221
+
222
+ ## 0.3.2 — 2026-10-17
223
+
224
+ ### Ломающие изменения
225
+
226
+ - Скомпилированный код импортирует рантайм из `rooklang/runtime`, а не держит его в каждом модуле,
227
+ так что `rooklang` — зависимость проекта, а не только сборки: `npm install rooklang`.
228
+
229
+ ### Добавлено
230
+
231
+ - Очереди: `queue T`, создаются через `queue<T>()` и `queue<T>(items)`.
232
+ - Потоки и каналы: `chan(stream)` и `stream(ch)`.
233
+ - Расширение VS Code, которое публикуется из CI.
234
+
235
+ Более ранние версии — в истории репозитория.
@@ -0,0 +1,2 @@
1
+ /** The absolute path of the `.rk` module `specifier` imported from `fromFile`, or null. */
2
+ export declare function resolveRookModule(fromFile: string, specifier: string): string | null;
@@ -0,0 +1,83 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { dirname, join, resolve } from 'node:path';
3
+ // Where a `.rk` module that an import names is: a relative path, a subpath import of package.json,
4
+ // `#ui/button.rk` with "imports": { "#ui/*": "./src/ui/*" }, or a path of tsconfig.json,
5
+ // `@/ui/button.rk` with "paths": { "@/*": ["./src/*"] }, which Vite and TypeScript resolve too.
6
+ /** The absolute path of the `.rk` module `specifier` imported from `fromFile`, or null. */
7
+ export function resolveRookModule(fromFile, specifier) {
8
+ if (specifier.startsWith('./') || specifier.startsWith('../')) {
9
+ return resolve(dirname(fromFile), specifier);
10
+ }
11
+ if (specifier.startsWith('#')) {
12
+ const found = nearest(fromFile, 'package.json');
13
+ const imports = found?.json.imports;
14
+ const target = imports && match(imports, specifier);
15
+ return found && typeof target === 'string' ? resolve(found.dir, target) : null;
16
+ }
17
+ const found = nearest(fromFile, 'tsconfig.json');
18
+ const options = found?.json.compilerOptions;
19
+ const target = options?.paths && match(options.paths, specifier);
20
+ return found && typeof target === 'string'
21
+ ? resolve(found.dir, options?.baseUrl ?? '.', target)
22
+ : null;
23
+ }
24
+ /** The target of the first pattern that fits, with its `*` filled in. */
25
+ function match(patterns, specifier) {
26
+ for (const [pattern, value] of Object.entries(patterns)) {
27
+ const target = firstTarget(value);
28
+ const star = pattern.indexOf('*');
29
+ if (target === null)
30
+ continue;
31
+ if (star === -1) {
32
+ if (pattern === specifier)
33
+ return target;
34
+ continue;
35
+ }
36
+ const prefix = pattern.slice(0, star);
37
+ const suffix = pattern.slice(star + 1);
38
+ if (specifier.startsWith(prefix) && specifier.endsWith(suffix)) {
39
+ return target.replace('*', specifier.slice(prefix.length, specifier.length - suffix.length));
40
+ }
41
+ }
42
+ return null;
43
+ }
44
+ /** A path, the first of a list, or that of the conditions `import` or `default`. */
45
+ function firstTarget(value) {
46
+ if (typeof value === 'string')
47
+ return value;
48
+ if (Array.isArray(value))
49
+ return firstTarget(value[0]);
50
+ if (value && typeof value === 'object') {
51
+ const conditions = value;
52
+ return firstTarget(conditions.import ?? conditions.default ?? null);
53
+ }
54
+ return null;
55
+ }
56
+ /** The nearest file of this name above `fromFile`, read as JSON with comments, as tsconfig.json is. */
57
+ function nearest(fromFile, name) {
58
+ for (let dir = dirname(fromFile);; dir = dirname(dir)) {
59
+ let text = null;
60
+ try {
61
+ text = readFileSync(join(dir, name), 'utf8');
62
+ }
63
+ catch {
64
+ // Not in this directory.
65
+ }
66
+ if (text !== null) {
67
+ try {
68
+ return { dir, json: JSON.parse(withoutComments(text)) };
69
+ }
70
+ catch {
71
+ return null;
72
+ }
73
+ }
74
+ if (dirname(dir) === dir)
75
+ return null;
76
+ }
77
+ }
78
+ /** JSON without the comments and trailing commas that tsconfig.json may have. */
79
+ function withoutComments(text) {
80
+ return text
81
+ .replace(/"(?:\\.|[^"\\])*"|\/\/[^\n]*|\/\*[\s\S]*?\*\//g, (part) => part.startsWith('"') ? part : '')
82
+ .replace(/,(\s*[}\]])/g, '$1');
83
+ }
@@ -26,6 +26,16 @@ export interface ImportSpecifier extends NodeBase {
26
26
  imported: Identifier;
27
27
  local: Identifier;
28
28
  }
29
+ /**
30
+ * `export { Row, Rows } from "./rows.rk"` or `export * from "./rows.rk"`: names of another module,
31
+ * which this one exports but does not see itself, as in JS.
32
+ */
33
+ export interface ExportFromDeclaration extends NodeBase {
34
+ kind: 'ExportFromDeclaration';
35
+ /** `null` for `export *`; `imported` is the name there, `local` the one it is exported under. */
36
+ specifiers: ImportSpecifier[] | null;
37
+ source: StringLiteral;
38
+ }
29
39
  /** `func divide(a, b number) (number, error) { ... }` */
30
40
  export interface FuncDeclaration extends NodeBase {
31
41
  kind: 'FuncDeclaration';
@@ -142,6 +152,14 @@ export interface VariableDeclaration extends NodeBase {
142
152
  * component stops at it, as at other functions. Its result type is `type`; `values` is empty.
143
153
  */
144
154
  body: FuncExpression | null;
155
+ /**
156
+ * `const { name, size: bytes, ...rest } = file`: the key of the field that each name takes, in
157
+ * the order of `names`; with `rest`, the last name gets the other fields.
158
+ */
159
+ pattern?: {
160
+ keys: (Identifier | StringLiteral)[];
161
+ rest: boolean;
162
+ };
145
163
  }
146
164
  /** `class Admin extends User implements Shape { ... }` */
147
165
  export interface ClassDeclaration extends NodeBase {
@@ -1,7 +1,18 @@
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 | 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;
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 | NonNullExpression | TaggedTemplateExpression;
5
+ /** `user!`: the value is taken not to be null, as in TypeScript; nothing is checked at runtime. */
6
+ export interface NonNullExpression extends NodeBase {
7
+ kind: 'NonNullExpression';
8
+ expression: Expression;
9
+ }
10
+ /** sql`select ... ${id}`: the function gets the strings and the values, as in JS. */
11
+ export interface TaggedTemplateExpression extends NodeBase {
12
+ kind: 'TaggedTemplateExpression';
13
+ tag: Expression;
14
+ quasi: TemplateLiteral;
15
+ }
5
16
  /**
6
17
  * `[]byte("rook")`: the UTF-8 bytes of a string. `string(data)`, the way back, is a call, since
7
18
  * `string` may be the name of a value.
@@ -156,6 +167,8 @@ export interface Property extends NodeBase {
156
167
  key: Identifier | StringLiteral;
157
168
  value: Expression;
158
169
  shorthand: boolean;
170
+ /** `fetch(req Request) Response { ... }`: a method, whose value is a FuncExpression. */
171
+ method?: true;
159
172
  }
160
173
  /** `...xs` in array literals, object literals and call arguments. */
161
174
  export interface SpreadElement extends NodeBase {
@@ -101,6 +101,8 @@ export interface NullableType extends NodeBase {
101
101
  export interface FuncType extends NodeBase {
102
102
  kind: 'FuncType';
103
103
  params: TypeNode[];
104
+ /** `func(string, ...[]any)`: the array of the arguments after the others. */
105
+ rest?: TypeNode;
104
106
  results: TypeNode[];
105
107
  /** `func(yield func(T) bool)`: its one parameter is named `yield`, so it is an iterator. */
106
108
  iterator?: boolean;
@@ -1,7 +1,7 @@
1
- import type { ClassDeclaration, ComponentDeclaration, DecoratorDeclaration, FuncDeclaration, ImportDeclaration, InterfaceDeclaration, NodeBase, TypeAliasDeclaration, VariableDeclaration } from './declarations.ts';
1
+ import type { ClassDeclaration, ComponentDeclaration, DecoratorDeclaration, ExportFromDeclaration, FuncDeclaration, ImportDeclaration, InterfaceDeclaration, NodeBase, TypeAliasDeclaration, VariableDeclaration } from './declarations.ts';
2
2
  import type { CallExpression, Expression, Identifier, UnaryExpression } from './expressions.ts';
3
3
  import type { JsxElementStatement } from './markup.ts';
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;
4
+ export type Statement = ImportDeclaration | ExportFromDeclaration | 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
  /**