rooklang 0.0.0-stage → 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.
Files changed (314) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +177 -2
  3. package/README.ru.md +178 -0
  4. package/dist/ast/declarations.d.ts +185 -0
  5. package/dist/ast/declarations.js +1 -0
  6. package/dist/ast/expressions.d.ts +201 -0
  7. package/dist/ast/expressions.js +1 -0
  8. package/dist/ast/markup.d.ts +141 -0
  9. package/dist/ast/markup.js +1 -0
  10. package/dist/ast/statements.d.ts +173 -0
  11. package/dist/ast/statements.js +1 -0
  12. package/dist/ast.d.ts +18 -0
  13. package/dist/ast.js +18 -0
  14. package/dist/attrs.d.ts +8 -0
  15. package/dist/attrs.js +23 -0
  16. package/dist/browser.d.ts +30 -0
  17. package/dist/browser.js +36 -0
  18. package/dist/build.d.ts +48 -0
  19. package/dist/build.js +112 -0
  20. package/dist/checker/assignments.d.ts +14 -0
  21. package/dist/checker/assignments.js +197 -0
  22. package/dist/checker/base.d.ts +124 -0
  23. package/dist/checker/base.js +180 -0
  24. package/dist/checker/bigint.d.ts +15 -0
  25. package/dist/checker/bigint.js +85 -0
  26. package/dist/checker/builtins.d.ts +9 -0
  27. package/dist/checker/builtins.js +307 -0
  28. package/dist/checker/bytes.d.ts +11 -0
  29. package/dist/checker/bytes.js +72 -0
  30. package/dist/checker/calls.d.ts +23 -0
  31. package/dist/checker/calls.js +210 -0
  32. package/dist/checker/channel.d.ts +14 -0
  33. package/dist/checker/channel.js +44 -0
  34. package/dist/checker/channels.d.ts +9 -0
  35. package/dist/checker/channels.js +95 -0
  36. package/dist/checker/checker.d.ts +4 -0
  37. package/dist/checker/checker.js +22 -0
  38. package/dist/checker/classes.d.ts +24 -0
  39. package/dist/checker/classes.js +223 -0
  40. package/dist/checker/completion-names.d.ts +11 -0
  41. package/dist/checker/completion-names.js +100 -0
  42. package/dist/checker/completion.d.ts +25 -0
  43. package/dist/checker/completion.js +222 -0
  44. package/dist/checker/component-values.d.ts +11 -0
  45. package/dist/checker/component-values.js +88 -0
  46. package/dist/checker/components.d.ts +37 -0
  47. package/dist/checker/components.js +287 -0
  48. package/dist/checker/context.d.ts +196 -0
  49. package/dist/checker/context.js +35 -0
  50. package/dist/checker/control-flow.d.ts +24 -0
  51. package/dist/checker/control-flow.js +237 -0
  52. package/dist/checker/declarations.d.ts +26 -0
  53. package/dist/checker/declarations.js +259 -0
  54. package/dist/checker/decorator-exports.d.ts +5 -0
  55. package/dist/checker/decorator-exports.js +40 -0
  56. package/dist/checker/decorator-members.d.ts +28 -0
  57. package/dist/checker/decorator-members.js +140 -0
  58. package/dist/checker/decorator-wrappers.d.ts +20 -0
  59. package/dist/checker/decorator-wrappers.js +132 -0
  60. package/dist/checker/decorators.d.ts +28 -0
  61. package/dist/checker/decorators.js +265 -0
  62. package/dist/checker/dom-svg.d.ts +7 -0
  63. package/dist/checker/dom-svg.js +19 -0
  64. package/dist/checker/dom.d.ts +22 -0
  65. package/dist/checker/dom.js +361 -0
  66. package/dist/checker/expressions.d.ts +32 -0
  67. package/dist/checker/expressions.js +244 -0
  68. package/dist/checker/flow.d.ts +18 -0
  69. package/dist/checker/flow.js +134 -0
  70. package/dist/checker/forwarding.d.ts +15 -0
  71. package/dist/checker/forwarding.js +78 -0
  72. package/dist/checker/functions.d.ts +24 -0
  73. package/dist/checker/functions.js +154 -0
  74. package/dist/checker/go-for.d.ts +12 -0
  75. package/dist/checker/go-for.js +93 -0
  76. package/dist/checker/goroutines.d.ts +19 -0
  77. package/dist/checker/goroutines.js +110 -0
  78. package/dist/checker/helpers.d.ts +35 -0
  79. package/dist/checker/helpers.js +162 -0
  80. package/dist/checker/imports.d.ts +7 -0
  81. package/dist/checker/imports.js +83 -0
  82. package/dist/checker/initializers.d.ts +22 -0
  83. package/dist/checker/initializers.js +104 -0
  84. package/dist/checker/iterables.d.ts +5 -0
  85. package/dist/checker/iterables.js +17 -0
  86. package/dist/checker/iterators.d.ts +13 -0
  87. package/dist/checker/iterators.js +95 -0
  88. package/dist/checker/loops.d.ts +10 -0
  89. package/dist/checker/loops.js +82 -0
  90. package/dist/checker/markup.d.ts +28 -0
  91. package/dist/checker/markup.js +220 -0
  92. package/dist/checker/members.d.ts +29 -0
  93. package/dist/checker/members.js +233 -0
  94. package/dist/checker/operators.d.ts +13 -0
  95. package/dist/checker/operators.js +177 -0
  96. package/dist/checker/promise.d.ts +17 -0
  97. package/dist/checker/promise.js +49 -0
  98. package/dist/checker/refs.d.ts +26 -0
  99. package/dist/checker/refs.js +136 -0
  100. package/dist/checker/resolution.d.ts +23 -0
  101. package/dist/checker/resolution.js +173 -0
  102. package/dist/checker/statements.d.ts +28 -0
  103. package/dist/checker/statements.js +212 -0
  104. package/dist/checker/styles.d.ts +14 -0
  105. package/dist/checker/styles.js +49 -0
  106. package/dist/checker/transfer.d.ts +5 -0
  107. package/dist/checker/transfer.js +83 -0
  108. package/dist/checker/types/bytes.d.ts +4 -0
  109. package/dist/checker/types/bytes.js +51 -0
  110. package/dist/checker/types/classes.d.ts +22 -0
  111. package/dist/checker/types/classes.js +93 -0
  112. package/dist/checker/types/constructors.d.ts +27 -0
  113. package/dist/checker/types/constructors.js +129 -0
  114. package/dist/checker/types/generics.d.ts +20 -0
  115. package/dist/checker/types/generics.js +75 -0
  116. package/dist/checker/types/lazy.d.ts +30 -0
  117. package/dist/checker/types/lazy.js +92 -0
  118. package/dist/checker/types/model.d.ts +149 -0
  119. package/dist/checker/types/model.js +15 -0
  120. package/dist/checker/types/params.d.ts +7 -0
  121. package/dist/checker/types/params.js +220 -0
  122. package/dist/checker/types/printing.d.ts +6 -0
  123. package/dist/checker/types/printing.js +109 -0
  124. package/dist/checker/types/relations.d.ts +16 -0
  125. package/dist/checker/types/relations.js +294 -0
  126. package/dist/checker/types.d.ts +9 -0
  127. package/dist/checker/types.js +10 -0
  128. package/dist/cli.d.ts +2 -0
  129. package/dist/cli.js +193 -0
  130. package/dist/codegen/analysis.d.ts +18 -0
  131. package/dist/codegen/analysis.js +144 -0
  132. package/dist/codegen/attributes.d.ts +40 -0
  133. package/dist/codegen/attributes.js +227 -0
  134. package/dist/codegen/calls.d.ts +22 -0
  135. package/dist/codegen/calls.js +106 -0
  136. package/dist/codegen/chan-helpers.d.ts +2 -0
  137. package/dist/codegen/chan-helpers.js +253 -0
  138. package/dist/codegen/component-helpers.d.ts +33 -0
  139. package/dist/codegen/component-helpers.js +18 -0
  140. package/dist/codegen/component-props.d.ts +42 -0
  141. package/dist/codegen/component-props.js +173 -0
  142. package/dist/codegen/component-values.d.ts +27 -0
  143. package/dist/codegen/component-values.js +146 -0
  144. package/dist/codegen/components.d.ts +53 -0
  145. package/dist/codegen/components.js +268 -0
  146. package/dist/codegen/control-flow.d.ts +25 -0
  147. package/dist/codegen/control-flow.js +152 -0
  148. package/dist/codegen/control-statements.d.ts +28 -0
  149. package/dist/codegen/control-statements.js +226 -0
  150. package/dist/codegen/creation.d.ts +31 -0
  151. package/dist/codegen/creation.js +113 -0
  152. package/dist/codegen/early-returns.d.ts +59 -0
  153. package/dist/codegen/early-returns.js +244 -0
  154. package/dist/codegen/element-helpers.d.ts +12 -0
  155. package/dist/codegen/element-helpers.js +54 -0
  156. package/dist/codegen/elements.d.ts +71 -0
  157. package/dist/codegen/elements.js +293 -0
  158. package/dist/codegen/emitter.d.ts +135 -0
  159. package/dist/codegen/emitter.js +296 -0
  160. package/dist/codegen/expressions.d.ts +49 -0
  161. package/dist/codegen/expressions.js +262 -0
  162. package/dist/codegen/functions.d.ts +28 -0
  163. package/dist/codegen/functions.js +170 -0
  164. package/dist/codegen/go-helpers.d.ts +9 -0
  165. package/dist/codegen/go-helpers.js +307 -0
  166. package/dist/codegen/helpers.d.ts +10 -0
  167. package/dist/codegen/helpers.js +356 -0
  168. package/dist/codegen/imported.d.ts +38 -0
  169. package/dist/codegen/imported.js +71 -0
  170. package/dist/codegen/js.d.ts +20 -0
  171. package/dist/codegen/js.js +113 -0
  172. package/dist/codegen/mutations.d.ts +10 -0
  173. package/dist/codegen/mutations.js +102 -0
  174. package/dist/codegen/parallel.d.ts +7 -0
  175. package/dist/codegen/parallel.js +63 -0
  176. package/dist/codegen/reactive.d.ts +95 -0
  177. package/dist/codegen/reactive.js +280 -0
  178. package/dist/codegen/refs.d.ts +62 -0
  179. package/dist/codegen/refs.js +160 -0
  180. package/dist/codegen/select-helpers.d.ts +2 -0
  181. package/dist/codegen/select-helpers.js +135 -0
  182. package/dist/codegen/simple-statements.d.ts +42 -0
  183. package/dist/codegen/simple-statements.js +253 -0
  184. package/dist/codegen/statements.d.ts +22 -0
  185. package/dist/codegen/statements.js +142 -0
  186. package/dist/codegen/styles.d.ts +54 -0
  187. package/dist/codegen/styles.js +157 -0
  188. package/dist/codegen/syntax.d.ts +18 -0
  189. package/dist/codegen/syntax.js +70 -0
  190. package/dist/codegen/thread-helpers.d.ts +2 -0
  191. package/dist/codegen/thread-helpers.js +198 -0
  192. package/dist/codegen/updates.d.ts +51 -0
  193. package/dist/codegen/updates.js +201 -0
  194. package/dist/codegen/web-components.d.ts +20 -0
  195. package/dist/codegen/web-components.js +149 -0
  196. package/dist/compile-file.d.ts +11 -0
  197. package/dist/compile-file.js +24 -0
  198. package/dist/compile.d.ts +53 -0
  199. package/dist/compile.js +187 -0
  200. package/dist/completion.d.ts +10 -0
  201. package/dist/completion.js +134 -0
  202. package/dist/config.d.ts +2 -0
  203. package/dist/config.js +44 -0
  204. package/dist/css/hash.d.ts +1 -0
  205. package/dist/css/hash.js +10 -0
  206. package/dist/css/parse.d.ts +42 -0
  207. package/dist/css/parse.js +138 -0
  208. package/dist/css/print.d.ts +9 -0
  209. package/dist/css/print.js +35 -0
  210. package/dist/css/selectors.d.ts +29 -0
  211. package/dist/css/selectors.js +168 -0
  212. package/dist/declarations.d.ts +3 -0
  213. package/dist/declarations.js +207 -0
  214. package/dist/decorator-copy.d.ts +18 -0
  215. package/dist/decorator-copy.js +158 -0
  216. package/dist/decorators.d.ts +61 -0
  217. package/dist/decorators.js +241 -0
  218. package/dist/diagnostics.d.ts +17 -0
  219. package/dist/diagnostics.js +22 -0
  220. package/dist/go-for.d.ts +26 -0
  221. package/dist/go-for.js +155 -0
  222. package/dist/goroutines.d.ts +37 -0
  223. package/dist/goroutines.js +253 -0
  224. package/dist/html-tag.d.ts +21 -0
  225. package/dist/html-tag.js +103 -0
  226. package/dist/index.d.ts +33 -0
  227. package/dist/index.js +55 -0
  228. package/dist/inline-packages.d.ts +32 -0
  229. package/dist/inline-packages.js +129 -0
  230. package/dist/iterators.d.ts +10 -0
  231. package/dist/iterators.js +33 -0
  232. package/dist/lexer/base.d.ts +24 -0
  233. package/dist/lexer/base.js +87 -0
  234. package/dist/lexer/lexer.d.ts +8 -0
  235. package/dist/lexer/lexer.js +134 -0
  236. package/dist/lexer/literals.d.ts +18 -0
  237. package/dist/lexer/literals.js +203 -0
  238. package/dist/lexer/markup.d.ts +10 -0
  239. package/dist/lexer/markup.js +93 -0
  240. package/dist/lexer/style.d.ts +17 -0
  241. package/dist/lexer/style.js +97 -0
  242. package/dist/lexer/tables.d.ts +53 -0
  243. package/dist/lexer/tables.js +101 -0
  244. package/dist/lexer/token.d.ts +42 -0
  245. package/dist/lexer/token.js +108 -0
  246. package/dist/loader.d.ts +1 -0
  247. package/dist/loader.js +50 -0
  248. package/dist/methods.d.ts +5 -0
  249. package/dist/methods.js +81 -0
  250. package/dist/modules.d.ts +3 -0
  251. package/dist/modules.js +49 -0
  252. package/dist/names.d.ts +23 -0
  253. package/dist/names.js +267 -0
  254. package/dist/parser/base.d.ts +96 -0
  255. package/dist/parser/base.js +202 -0
  256. package/dist/parser/classes.d.ts +8 -0
  257. package/dist/parser/classes.js +164 -0
  258. package/dist/parser/control-flow.d.ts +29 -0
  259. package/dist/parser/control-flow.js +232 -0
  260. package/dist/parser/declarations.d.ts +27 -0
  261. package/dist/parser/declarations.js +238 -0
  262. package/dist/parser/decorators.d.ts +30 -0
  263. package/dist/parser/decorators.js +176 -0
  264. package/dist/parser/expressions.d.ts +15 -0
  265. package/dist/parser/expressions.js +255 -0
  266. package/dist/parser/literals.d.ts +27 -0
  267. package/dist/parser/literals.js +206 -0
  268. package/dist/parser/markup.d.ts +22 -0
  269. package/dist/parser/markup.js +193 -0
  270. package/dist/parser/parser.d.ts +14 -0
  271. package/dist/parser/parser.js +22 -0
  272. package/dist/parser/simple-statements.d.ts +22 -0
  273. package/dist/parser/simple-statements.js +156 -0
  274. package/dist/parser/statements.d.ts +37 -0
  275. package/dist/parser/statements.js +267 -0
  276. package/dist/parser/syntax.d.ts +51 -0
  277. package/dist/parser/syntax.js +173 -0
  278. package/dist/parser/types.d.ts +23 -0
  279. package/dist/parser/types.js +218 -0
  280. package/dist/recursion.d.ts +25 -0
  281. package/dist/recursion.js +170 -0
  282. package/dist/refs.d.ts +49 -0
  283. package/dist/refs.js +210 -0
  284. package/dist/run.d.ts +1 -0
  285. package/dist/run.js +21 -0
  286. package/dist/source.d.ts +15 -0
  287. package/dist/source.js +34 -0
  288. package/dist/style-modules.d.ts +17 -0
  289. package/dist/style-modules.js +49 -0
  290. package/dist/styles.d.ts +36 -0
  291. package/dist/styles.js +160 -0
  292. package/dist/svg.d.ts +8 -0
  293. package/dist/svg.js +77 -0
  294. package/dist/ts-types.d.ts +11 -0
  295. package/dist/ts-types.js +133 -0
  296. package/dist/typed-arrays.d.ts +8 -0
  297. package/dist/typed-arrays.js +43 -0
  298. package/dist/typescript/convert-base.d.ts +42 -0
  299. package/dist/typescript/convert-base.js +135 -0
  300. package/dist/typescript/convert-objects.d.ts +28 -0
  301. package/dist/typescript/convert-objects.js +245 -0
  302. package/dist/typescript/convert.d.ts +14 -0
  303. package/dist/typescript/convert.js +67 -0
  304. package/dist/typescript/importer.d.ts +37 -0
  305. package/dist/typescript/importer.js +152 -0
  306. package/dist/typescript/library.d.ts +23 -0
  307. package/dist/typescript/library.js +81 -0
  308. package/dist/vite.d.ts +11 -0
  309. package/dist/vite.js +86 -0
  310. package/dist/walk-types.d.ts +4 -0
  311. package/dist/walk-types.js +56 -0
  312. package/dist/walk.d.ts +5 -0
  313. package/dist/walk.js +315 -0
  314. package/package.json +104 -4
@@ -0,0 +1,361 @@
1
+ import { ANY, BOOL, func, method, NUMBER, nullable, property, STRING, } from "./types.js";
2
+ // Types of the DOM for markup: what `<input>` creates and which attributes are properties. Only
3
+ // the commonly used members are typed; the rest of the DOM is reached through `any`.
4
+ const p = property;
5
+ const m = (...args) => method(func(...args));
6
+ function object(name, members) {
7
+ return { kind: 'object', name, members: new Map(Object.entries(members)), call: null };
8
+ }
9
+ const NODE_MEMBERS = {
10
+ nodeType: p(NUMBER),
11
+ nodeName: p(STRING),
12
+ textContent: p(nullable(STRING)),
13
+ parentNode: p(ANY),
14
+ parentElement: p(ANY),
15
+ childNodes: p(ANY),
16
+ firstChild: p(ANY),
17
+ lastChild: p(ANY),
18
+ nextSibling: p(ANY),
19
+ previousSibling: p(ANY),
20
+ isConnected: p(BOOL),
21
+ appendChild: m([ANY], [ANY]),
22
+ removeChild: m([ANY], [ANY]),
23
+ insertBefore: m([ANY, ANY], [ANY]),
24
+ replaceChild: m([ANY, ANY], [ANY]),
25
+ cloneNode: m([BOOL], [ANY], { required: 0 }),
26
+ contains: m([ANY], [BOOL]),
27
+ hasChildNodes: m([], [BOOL]),
28
+ addEventListener: m([STRING, ANY, ANY], [], { required: 2 }),
29
+ removeEventListener: m([STRING, ANY, ANY], [], { required: 2 }),
30
+ dispatchEvent: m([ANY], [BOOL]),
31
+ };
32
+ /** Members of nodes that have children: elements and fragments. */
33
+ const PARENT_MEMBERS = {
34
+ append: m([], [], { rest: ANY }),
35
+ prepend: m([], [], { rest: ANY }),
36
+ replaceChildren: m([], [], { rest: ANY }),
37
+ querySelector: m([STRING], [ANY]),
38
+ querySelectorAll: m([STRING], [ANY]),
39
+ children: p(ANY),
40
+ firstElementChild: p(ANY),
41
+ lastElementChild: p(ANY),
42
+ childElementCount: p(NUMBER),
43
+ };
44
+ export const ELEMENT_MEMBERS = {
45
+ ...NODE_MEMBERS,
46
+ ...PARENT_MEMBERS,
47
+ // Unlike other nodes, an element always has text content.
48
+ textContent: p(STRING),
49
+ before: m([], [], { rest: ANY }),
50
+ after: m([], [], { rest: ANY }),
51
+ replaceWith: m([], [], { rest: ANY }),
52
+ remove: m([], []),
53
+ id: p(STRING),
54
+ className: p(STRING),
55
+ classList: p(ANY),
56
+ style: p(ANY),
57
+ dataset: p(ANY),
58
+ hidden: p(BOOL),
59
+ title: p(STRING),
60
+ lang: p(STRING),
61
+ dir: p(STRING),
62
+ tabIndex: p(NUMBER),
63
+ draggable: p(BOOL),
64
+ contentEditable: p(STRING),
65
+ innerHTML: p(STRING),
66
+ outerHTML: p(STRING),
67
+ innerText: p(STRING),
68
+ tagName: p(STRING),
69
+ offsetWidth: p(NUMBER),
70
+ offsetHeight: p(NUMBER),
71
+ offsetTop: p(NUMBER),
72
+ offsetLeft: p(NUMBER),
73
+ clientWidth: p(NUMBER),
74
+ clientHeight: p(NUMBER),
75
+ scrollWidth: p(NUMBER),
76
+ scrollHeight: p(NUMBER),
77
+ scrollTop: p(NUMBER),
78
+ scrollLeft: p(NUMBER),
79
+ focus: m([ANY], [], { required: 0 }),
80
+ blur: m([], []),
81
+ click: m([], []),
82
+ closest: m([STRING], [ANY]),
83
+ matches: m([STRING], [BOOL]),
84
+ getAttribute: m([STRING], [nullable(STRING)]),
85
+ setAttribute: m([STRING, ANY], []),
86
+ removeAttribute: m([STRING], []),
87
+ hasAttribute: m([STRING], [BOOL]),
88
+ toggleAttribute: m([STRING, BOOL], [BOOL], { required: 1 }),
89
+ getBoundingClientRect: m([], [ANY]),
90
+ scrollIntoView: m([ANY], [], { required: 0 }),
91
+ animate: m([ANY, ANY], [ANY], { required: 1 }),
92
+ };
93
+ const MEDIA_MEMBERS = {
94
+ src: p(STRING),
95
+ controls: p(BOOL),
96
+ autoplay: p(BOOL),
97
+ loop: p(BOOL),
98
+ muted: p(BOOL),
99
+ currentTime: p(NUMBER),
100
+ volume: p(NUMBER),
101
+ duration: p(NUMBER),
102
+ paused: p(BOOL),
103
+ play: m([], [ANY]),
104
+ pause: m([], []),
105
+ };
106
+ export const NODE = object('Node', NODE_MEMBERS);
107
+ export const HTML_ELEMENT = object('HTMLElement', ELEMENT_MEMBERS);
108
+ export const DOCUMENT_FRAGMENT = object('DocumentFragment', {
109
+ ...NODE_MEMBERS,
110
+ ...PARENT_MEMBERS,
111
+ });
112
+ /** Tags whose elements have members of their own, with the name of their type. */
113
+ const SPECIFIC_ELEMENTS = {
114
+ a: [
115
+ 'HTMLAnchorElement',
116
+ { href: p(STRING), target: p(STRING), rel: p(STRING), download: p(STRING) },
117
+ ],
118
+ button: [
119
+ 'HTMLButtonElement',
120
+ { disabled: p(BOOL), type: p(STRING), name: p(STRING), value: p(STRING), form: p(ANY) },
121
+ ],
122
+ input: [
123
+ 'HTMLInputElement',
124
+ {
125
+ value: p(STRING),
126
+ valueAsNumber: p(NUMBER),
127
+ checked: p(BOOL),
128
+ disabled: p(BOOL),
129
+ type: p(STRING),
130
+ name: p(STRING),
131
+ placeholder: p(STRING),
132
+ required: p(BOOL),
133
+ readOnly: p(BOOL),
134
+ autofocus: p(BOOL),
135
+ autocomplete: p(STRING),
136
+ min: p(STRING),
137
+ max: p(STRING),
138
+ step: p(STRING),
139
+ maxLength: p(NUMBER),
140
+ minLength: p(NUMBER),
141
+ pattern: p(STRING),
142
+ multiple: p(BOOL),
143
+ accept: p(STRING),
144
+ files: p(ANY),
145
+ form: p(ANY),
146
+ select: m([], []),
147
+ setCustomValidity: m([STRING], []),
148
+ checkValidity: m([], [BOOL]),
149
+ },
150
+ ],
151
+ textarea: [
152
+ 'HTMLTextAreaElement',
153
+ {
154
+ value: p(STRING),
155
+ placeholder: p(STRING),
156
+ disabled: p(BOOL),
157
+ readOnly: p(BOOL),
158
+ required: p(BOOL),
159
+ rows: p(NUMBER),
160
+ cols: p(NUMBER),
161
+ maxLength: p(NUMBER),
162
+ name: p(STRING),
163
+ select: m([], []),
164
+ },
165
+ ],
166
+ select: [
167
+ 'HTMLSelectElement',
168
+ {
169
+ value: p(STRING),
170
+ disabled: p(BOOL),
171
+ multiple: p(BOOL),
172
+ required: p(BOOL),
173
+ name: p(STRING),
174
+ selectedIndex: p(NUMBER),
175
+ options: p(ANY),
176
+ },
177
+ ],
178
+ option: [
179
+ 'HTMLOptionElement',
180
+ {
181
+ value: p(STRING),
182
+ selected: p(BOOL),
183
+ disabled: p(BOOL),
184
+ label: p(STRING),
185
+ text: p(STRING),
186
+ },
187
+ ],
188
+ form: [
189
+ 'HTMLFormElement',
190
+ {
191
+ action: p(STRING),
192
+ method: p(STRING),
193
+ noValidate: p(BOOL),
194
+ elements: p(ANY),
195
+ reset: m([], []),
196
+ submit: m([], []),
197
+ requestSubmit: m([ANY], [], { required: 0 }),
198
+ checkValidity: m([], [BOOL]),
199
+ },
200
+ ],
201
+ label: ['HTMLLabelElement', { htmlFor: p(STRING) }],
202
+ img: [
203
+ 'HTMLImageElement',
204
+ {
205
+ src: p(STRING),
206
+ alt: p(STRING),
207
+ srcset: p(STRING),
208
+ loading: p(STRING),
209
+ width: p(NUMBER),
210
+ height: p(NUMBER),
211
+ naturalWidth: p(NUMBER),
212
+ naturalHeight: p(NUMBER),
213
+ complete: p(BOOL),
214
+ },
215
+ ],
216
+ li: ['HTMLLIElement', { value: p(NUMBER) }],
217
+ ol: ['HTMLOListElement', { start: p(NUMBER), reversed: p(BOOL) }],
218
+ canvas: [
219
+ 'HTMLCanvasElement',
220
+ {
221
+ width: p(NUMBER),
222
+ height: p(NUMBER),
223
+ getContext: m([STRING, ANY], [ANY], { required: 1 }),
224
+ toDataURL: m([STRING], [STRING], { required: 0 }),
225
+ },
226
+ ],
227
+ video: ['HTMLVideoElement', { ...MEDIA_MEMBERS, width: p(NUMBER), height: p(NUMBER) }],
228
+ audio: ['HTMLAudioElement', MEDIA_MEMBERS],
229
+ iframe: ['HTMLIFrameElement', { src: p(STRING), allow: p(STRING) }],
230
+ progress: ['HTMLProgressElement', { value: p(NUMBER), max: p(NUMBER) }],
231
+ dialog: [
232
+ 'HTMLDialogElement',
233
+ {
234
+ open: p(BOOL),
235
+ show: m([], []),
236
+ showModal: m([], []),
237
+ close: m([STRING], [], { required: 0 }),
238
+ },
239
+ ],
240
+ details: ['HTMLDetailsElement', { open: p(BOOL) }],
241
+ td: ['HTMLTableCellElement', { colSpan: p(NUMBER), rowSpan: p(NUMBER) }],
242
+ th: ['HTMLTableCellElement', { colSpan: p(NUMBER), rowSpan: p(NUMBER) }],
243
+ };
244
+ const elementTypes = new Map();
245
+ for (const [tag, [name, members]] of Object.entries(SPECIFIC_ELEMENTS)) {
246
+ const existing = [...elementTypes.values()].find((type) => type.name === name);
247
+ elementTypes.set(tag, existing ?? object(name, { ...ELEMENT_MEMBERS, ...members }));
248
+ }
249
+ /** The type of the element `<tag>` creates. */
250
+ export function elementType(tag) {
251
+ return elementTypes.get(tag) ?? HTML_ELEMENT;
252
+ }
253
+ /**
254
+ * The type of a component's `children`: the markup between its tags. At runtime it is a
255
+ * DocumentFragment, but only placing it as `{children}` is allowed.
256
+ */
257
+ export const CONTENT = object('Content', {});
258
+ /** DOM types that programs can name, e.g. `func render() HTMLLIElement`. */
259
+ export const DOM_TYPES = new Map([
260
+ ['Node', NODE],
261
+ ['Content', CONTENT],
262
+ ['HTMLElement', HTML_ELEMENT],
263
+ ['Element', HTML_ELEMENT],
264
+ ['DocumentFragment', DOCUMENT_FRAGMENT],
265
+ ...[...elementTypes.values()].map((type) => [type.name ?? '', type]),
266
+ ]);
267
+ /** HTML attribute names whose DOM property is spelled differently. */
268
+ const PROPERTY_NAMES = {
269
+ class: 'className',
270
+ for: 'htmlFor',
271
+ tabindex: 'tabIndex',
272
+ readonly: 'readOnly',
273
+ maxlength: 'maxLength',
274
+ minlength: 'minLength',
275
+ colspan: 'colSpan',
276
+ rowspan: 'rowSpan',
277
+ contenteditable: 'contentEditable',
278
+ novalidate: 'noValidate',
279
+ };
280
+ /** Properties that cannot be assigned: attributes with these names go through setAttribute. */
281
+ const READ_ONLY = new Set([
282
+ ...Object.keys(NODE_MEMBERS),
283
+ ...Object.keys(PARENT_MEMBERS),
284
+ 'classList',
285
+ 'dataset',
286
+ 'tagName',
287
+ 'offsetWidth',
288
+ 'offsetHeight',
289
+ 'offsetTop',
290
+ 'offsetLeft',
291
+ 'clientWidth',
292
+ 'clientHeight',
293
+ 'scrollWidth',
294
+ 'scrollHeight',
295
+ 'form',
296
+ 'elements',
297
+ 'options',
298
+ 'naturalWidth',
299
+ 'naturalHeight',
300
+ 'complete',
301
+ 'duration',
302
+ 'paused',
303
+ ]);
304
+ READ_ONLY.delete('textContent');
305
+ /** The DOM property that an attribute sets, e.g. `class` → `className`; `null` for setAttribute. */
306
+ export function domProperty(tag, attribute) {
307
+ const name = Object.hasOwn(PROPERTY_NAMES, attribute) ? PROPERTY_NAMES[attribute] : attribute;
308
+ if (READ_ONLY.has(name))
309
+ return null;
310
+ const member = elementType(tag).members.get(name);
311
+ return member && !member.method ? { name, type: member.type } : null;
312
+ }
313
+ const EVENT_MEMBERS = {
314
+ type: p(STRING),
315
+ target: p(ANY),
316
+ currentTarget: p(ANY),
317
+ preventDefault: m([], []),
318
+ stopPropagation: m([], []),
319
+ stopImmediatePropagation: m([], []),
320
+ defaultPrevented: p(BOOL),
321
+ bubbles: p(BOOL),
322
+ timeStamp: p(NUMBER),
323
+ // Keyboard events
324
+ key: p(STRING),
325
+ code: p(STRING),
326
+ repeat: p(BOOL),
327
+ altKey: p(BOOL),
328
+ ctrlKey: p(BOOL),
329
+ shiftKey: p(BOOL),
330
+ metaKey: p(BOOL),
331
+ // Mouse, pointer and wheel events
332
+ clientX: p(NUMBER),
333
+ clientY: p(NUMBER),
334
+ pageX: p(NUMBER),
335
+ pageY: p(NUMBER),
336
+ offsetX: p(NUMBER),
337
+ offsetY: p(NUMBER),
338
+ movementX: p(NUMBER),
339
+ movementY: p(NUMBER),
340
+ button: p(NUMBER),
341
+ buttons: p(NUMBER),
342
+ deltaX: p(NUMBER),
343
+ deltaY: p(NUMBER),
344
+ pointerId: p(NUMBER),
345
+ relatedTarget: p(ANY),
346
+ // Input events
347
+ data: p(nullable(STRING)),
348
+ inputType: p(STRING),
349
+ isComposing: p(BOOL),
350
+ // Other events
351
+ dataTransfer: p(ANY),
352
+ touches: p(ANY),
353
+ changedTouches: p(ANY),
354
+ detail: p(ANY),
355
+ submitter: p(ANY),
356
+ };
357
+ export const EVENT = object('Event', EVENT_MEMBERS);
358
+ /** The `event` of a handler on an element: `currentTarget` is that element. */
359
+ export function eventType(element) {
360
+ return object('Event', { ...EVENT_MEMBERS, currentTarget: p(element) });
361
+ }
@@ -0,0 +1,32 @@
1
+ import type * as ast from '../ast.ts';
2
+ import type { ComponentInfo } from './context.ts';
3
+ import { FunctionChecker } from './functions.ts';
4
+ import { type ComponentType, type Type } from './types.ts';
5
+ export declare abstract class ExpressionChecker extends FunctionChecker {
6
+ /** The type of a component used as a value; implemented by ComponentValueChecker. */
7
+ protected abstract componentValue(info: ComponentInfo): ComponentType;
8
+ /** `go work(x)`: a Promise of the result; implemented by GoroutineChecker. */
9
+ protected abstract checkGo(node: ast.GoExpression): Type;
10
+ /** `chan<number>(10)`; implemented by ChannelChecker. */
11
+ protected abstract checkChan(node: ast.ChanExpression): Type;
12
+ /** `[]byte("text")`; implemented by BytesChecker. */
13
+ protected abstract checkConversion(node: ast.ConversionExpression): Type;
14
+ protected abstract checkMake(node: ast.MakeExpression): Type;
15
+ /** The type of an expression that must be a single value (not `void` or several results). */
16
+ protected checkValue(node: ast.Expression, expected?: Type | null): Type;
17
+ protected single(type: Type, node: ast.Expression): Type;
18
+ /** `expected` is the type the context wants, used to type literals and arrow functions. */
19
+ protected checkExpression(node: ast.Expression, expected: Type | null): Type;
20
+ protected computeType(node: ast.Expression, expected: Type | null): Type;
21
+ protected checkIdentifier(node: ast.Identifier): Type;
22
+ protected thisType(node: ast.NodeBase): Type;
23
+ /** `super.method()`: the members of the base class. */
24
+ protected superType(node: ast.NodeBase): Type;
25
+ protected checkArrayLiteral(node: ast.ArrayLiteral, expected: Type | null): Type;
26
+ protected checkObjectLiteral(node: ast.ObjectLiteral, expected: Type | null): Type;
27
+ /**
28
+ * `value as Type`: the types must be related, one assignable to the other, as in TypeScript:
29
+ * `element as HTMLInputElement`, `JSON.parse(text) as Config`, but not `count as string`.
30
+ */
31
+ private checkAs;
32
+ }
@@ -0,0 +1,244 @@
1
+ import { FunctionChecker } from "./functions.js";
2
+ import { expectsLiteral, callName, isUntyped } from "./helpers.js";
3
+ import { ANY, BIGINT, arrayOf, BOOL, commonType, hasUntypedBase, instanceMembers, isAssignable, literal, NEVER, nonNull, NULL, nullable, NUMBER, STRING, typeToString, UNKNOWN, } from "./types.js";
4
+ // Expressions: names, `this`, literals of arrays and objects; the operators are in operators.ts.
5
+ export class ExpressionChecker extends FunctionChecker {
6
+ /** The type of an expression that must be a single value (not `void` or several results). */
7
+ checkValue(node, expected = null) {
8
+ return this.single(this.checkExpression(node, expected), node);
9
+ }
10
+ single(type, node) {
11
+ if (type.kind === 'tuple') {
12
+ this.error(`${callName(node)} returns ${type.types.length} values: unpack them, e.g. "const a, b = ..."`, node);
13
+ return UNKNOWN;
14
+ }
15
+ if (type.kind === 'void') {
16
+ this.error(`${callName(node)} does not return a value`, node);
17
+ return UNKNOWN;
18
+ }
19
+ return type;
20
+ }
21
+ /** `expected` is the type the context wants, used to type literals and arrow functions. */
22
+ checkExpression(node, expected) {
23
+ const type = this.computeType(node, expected);
24
+ this.checkedTypes.set(node, type);
25
+ return type;
26
+ }
27
+ computeType(node, expected) {
28
+ switch (node.kind) {
29
+ case 'Identifier':
30
+ return this.checkIdentifier(node);
31
+ // A literal has a literal type only where one is expected: `filter = "all"`.
32
+ case 'NumberLiteral':
33
+ return expectsLiteral(expected) ? literal(node.value) : NUMBER;
34
+ case 'BigIntLiteral':
35
+ return BIGINT;
36
+ case 'StringLiteral':
37
+ return expectsLiteral(expected) ? literal(node.value) : STRING;
38
+ case 'TemplateLiteral':
39
+ for (const expression of node.expressions)
40
+ this.checkValue(expression);
41
+ return STRING;
42
+ case 'BooleanLiteral':
43
+ return expectsLiteral(expected) ? literal(node.value) : BOOL;
44
+ case 'NullLiteral':
45
+ return NULL;
46
+ case 'ThisExpression':
47
+ return this.thisType(node);
48
+ case 'SuperExpression':
49
+ return this.superType(node);
50
+ case 'ArrayLiteral':
51
+ return this.checkArrayLiteral(node, expected);
52
+ case 'ObjectLiteral':
53
+ return this.checkObjectLiteral(node, expected);
54
+ case 'FuncExpression':
55
+ return this.checkFuncExpression(node);
56
+ case 'ArrowFunction':
57
+ return this.checkArrowFunction(node, expected);
58
+ case 'UnaryExpression':
59
+ return this.checkUnary(node);
60
+ case 'BinaryExpression':
61
+ return this.checkBinary(node, expected);
62
+ case 'ConditionalExpression':
63
+ return this.checkConditional(node, expected);
64
+ case 'AsExpression':
65
+ return this.checkAs(node);
66
+ case 'GoExpression':
67
+ return this.checkGo(node);
68
+ case 'ChanExpression':
69
+ return this.checkChan(node);
70
+ case 'ConversionExpression':
71
+ return this.checkConversion(node);
72
+ case 'MakeExpression':
73
+ return this.checkMake(node);
74
+ case 'NewExpression':
75
+ return this.checkNew(node, expected);
76
+ case 'ElementExpression':
77
+ return this.checkElement(node);
78
+ case 'DecoratorMember':
79
+ return this.checkDecoratorMember(node);
80
+ case 'DecoratorGet':
81
+ return this.checkDecoratorGet(node);
82
+ case 'MemberExpression':
83
+ case 'IndexExpression':
84
+ case 'CallExpression': {
85
+ const [type, shortCircuits] = this.checkChain(node, expected);
86
+ return shortCircuits && type.kind !== 'tuple' && type.kind !== 'void'
87
+ ? nullable(type)
88
+ : type;
89
+ }
90
+ }
91
+ }
92
+ checkIdentifier(node) {
93
+ if (node.name === '_') {
94
+ this.error('"_" cannot be used as a value', node);
95
+ return UNKNOWN;
96
+ }
97
+ const binding = this.lookupValue(node.name);
98
+ if (!binding) {
99
+ this.error(this.lookupType(node.name)
100
+ ? `"${node.name}" is a type, not a value`
101
+ : node.name === 'make'
102
+ ? 'make takes the type of a typed array first, e.g. make([]float64, n)'
103
+ : `"${node.name}" is not defined`, node);
104
+ return UNKNOWN;
105
+ }
106
+ // A component as a value: a tag can take it from there, `<section.content />`.
107
+ if (binding.component)
108
+ return this.componentValue(binding.component);
109
+ const initializerError = this.initializerError(binding);
110
+ if (initializerError !== null) {
111
+ this.error(initializerError, node);
112
+ return UNKNOWN;
113
+ }
114
+ if (binding.type === null) {
115
+ this.error(`"${node.name}" is used before its declaration`, node);
116
+ return UNKNOWN;
117
+ }
118
+ return this.flow.get(binding) ?? binding.type;
119
+ }
120
+ thisType(node) {
121
+ if (!this.cls) {
122
+ this.error('"this" can only be used inside a class', node);
123
+ return UNKNOWN;
124
+ }
125
+ return this.cls.isStatic ? this.cls.info.value : this.cls.info.instance;
126
+ }
127
+ /** `super.method()`: the members of the base class. */
128
+ superType(node) {
129
+ const info = this.cls?.info;
130
+ if (!info) {
131
+ this.error('"super" can only be used inside a class', node);
132
+ return UNKNOWN;
133
+ }
134
+ if (info.superClass)
135
+ return this.cls?.isStatic ? info.superClass.value : info.superClass.instance;
136
+ if (hasUntypedBase(info))
137
+ return ANY;
138
+ this.error(`class "${info.name}" has no base class`, node);
139
+ return UNKNOWN;
140
+ }
141
+ checkArrayLiteral(node, expected) {
142
+ const context = expected ? nonNull(expected) : null;
143
+ const expectedElement = context?.kind === 'array' ? context.element : context?.kind === 'any' ? ANY : null;
144
+ let element = expectedElement ?? NEVER;
145
+ for (const item of node.elements) {
146
+ let type;
147
+ if (item.kind === 'SpreadElement') {
148
+ const spread = this.checkValue(item.argument, expectedElement && arrayOf(expectedElement));
149
+ if (spread.kind === 'array')
150
+ type = spread.element;
151
+ else if (spread.kind === 'any' || spread.kind === 'unknown')
152
+ type = spread;
153
+ // JS spreads any iterable: a Set, a typed array, a `[]byte`.
154
+ else if (spread.kind === 'object' && spread.iterates)
155
+ type = spread.iterates;
156
+ else {
157
+ this.error(`cannot spread ${typeToString(spread)}: it is not an array or an iterable`, item.argument);
158
+ type = UNKNOWN;
159
+ }
160
+ }
161
+ else {
162
+ type = this.checkValue(item, expectedElement);
163
+ }
164
+ if (expectedElement) {
165
+ this.expectAssignable(type, expectedElement, item.kind === 'SpreadElement' ? item.argument : item);
166
+ }
167
+ else {
168
+ element = commonType(element, type);
169
+ }
170
+ }
171
+ return arrayOf(element);
172
+ }
173
+ checkObjectLiteral(node, expected) {
174
+ let target = expected ? nonNull(expected) : null;
175
+ // `?(ScrollIntoViewOptions | bool)`: an object literal can only be the object type in it.
176
+ if (target?.kind === 'union') {
177
+ const objects = target.types.filter((type) => type.kind === 'object' || type.kind === 'class');
178
+ target = objects.length === 1 ? objects[0] : null;
179
+ }
180
+ const index = target?.kind === 'object' ? target.index : undefined;
181
+ const targetMembers = target?.kind === 'object'
182
+ ? target.members
183
+ : target?.kind === 'class'
184
+ ? instanceMembers(target.info)
185
+ : null;
186
+ const members = new Map();
187
+ const written = new Set();
188
+ let untyped = false;
189
+ for (const property of node.properties) {
190
+ if (property.kind === 'SpreadElement') {
191
+ const spread = this.checkValue(property.argument);
192
+ if (spread.kind === 'object') {
193
+ for (const [name, member] of spread.members)
194
+ members.set(name, member);
195
+ }
196
+ else if (spread.kind === 'class') {
197
+ for (const [name, member] of instanceMembers(spread.info)) {
198
+ if (member.visibility === 'public' && !member.method)
199
+ members.set(name, member);
200
+ }
201
+ }
202
+ else if (spread.kind === 'any' || spread.kind === 'unknown') {
203
+ untyped = true;
204
+ }
205
+ else {
206
+ this.error(`cannot spread ${typeToString(spread)} into an object`, property.argument);
207
+ }
208
+ continue;
209
+ }
210
+ const name = property.key.kind === 'Identifier' ? property.key.name : property.key.value;
211
+ // Fields may override those of a spread object, but not each other.
212
+ if (written.has(name))
213
+ this.error(`duplicate field "${name}"`, property.key);
214
+ written.add(name);
215
+ const expectedMember = targetMembers?.get(name) ??
216
+ (index && { type: index, method: false, visibility: 'public', owner: null });
217
+ // A field that the expected type does not have is most likely a typo.
218
+ if (targetMembers && !expectedMember && target) {
219
+ this.error(`${typeToString(target)} has no field "${name}"`, property.key);
220
+ }
221
+ let type = this.checkValue(property.value, expectedMember?.type ?? null);
222
+ if (expectedMember) {
223
+ // Reported at the field; the literal then counts as having the expected field type.
224
+ this.expectAssignable(type, expectedMember.type, property.value, ` for field "${name}"`);
225
+ type = expectedMember.type;
226
+ }
227
+ members.set(name, { type, method: false, visibility: 'public', owner: null });
228
+ }
229
+ return untyped ? ANY : { kind: 'object', name: null, members, call: null };
230
+ }
231
+ /**
232
+ * `value as Type`: the types must be related, one assignable to the other, as in TypeScript:
233
+ * `element as HTMLInputElement`, `JSON.parse(text) as Config`, but not `count as string`.
234
+ */
235
+ checkAs(node) {
236
+ const target = this.resolveType(node.type);
237
+ const source = this.checkValue(node.expression, target);
238
+ const related = isAssignable(source, target) || isAssignable(target, source);
239
+ if (!isUntyped(source) && !isUntyped(target) && !related) {
240
+ this.error(`cannot use ${typeToString(source)} as ${typeToString(target)}, even with "as": the types are not related`, node);
241
+ }
242
+ return target;
243
+ }
244
+ }
@@ -0,0 +1,18 @@
1
+ import type * as ast from '../ast.ts';
2
+ import type { Flow, Narrowing } from './context.ts';
3
+ import { type Type } from './types.ts';
4
+ /** What `typeof` gives for every value of a type, or `null` when it may give several things. */
5
+ export declare function typeofTag(type: Type): string | null;
6
+ /** The type after `typeof x == tag` is found true (`matches`) or false. */
7
+ export declare function narrowByTypeof(type: Type, tag: string, matches: boolean): Type | null;
8
+ /** `"all"`, `42` or `true` written in the code: its value, or `undefined` for other expressions. */
9
+ export declare function literalValue(node: ast.Expression): string | number | boolean | undefined;
10
+ /** A type without one literal value: what is left after `x != "all"`. */
11
+ export declare function withoutLiteral(type: Type, value: string | number | boolean): Type;
12
+ export declare function withNarrowing(flow: Flow, narrowing: Narrowing): Flow;
13
+ /** Narrowing that holds after both branches: the variables narrowed the same way in both. */
14
+ export declare function mergeFlows(a: Flow, b: Flow): Flow;
15
+ /** Go's terminating statements: execution never continues after them. */
16
+ export declare function isTerminating(node: ast.Statement): boolean;
17
+ /** Whether execution never continues after the statement, counting `break` and `continue`. */
18
+ export declare function leaves(node: ast.Statement): boolean;