rooklang 0.0.0-stage → 0.3.1

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 +195 -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 +105 -4
@@ -0,0 +1,100 @@
1
+ // Names for completion in editors that the types cannot list: the members of strings, numbers and
2
+ // arrays in builtins.ts are found by name, and without a library there is no list of HTML tags.
3
+ // tests/completion.test.ts checks that each member listed here exists.
4
+ export const STRING_MEMBERS = [
5
+ 'length',
6
+ 'at',
7
+ 'charAt',
8
+ 'charCodeAt',
9
+ 'codePointAt',
10
+ 'indexOf',
11
+ 'lastIndexOf',
12
+ 'includes',
13
+ 'startsWith',
14
+ 'endsWith',
15
+ 'slice',
16
+ 'substring',
17
+ 'toUpperCase',
18
+ 'toLowerCase',
19
+ 'trim',
20
+ 'trimStart',
21
+ 'trimEnd',
22
+ 'normalize',
23
+ 'toString',
24
+ 'split',
25
+ 'replace',
26
+ 'replaceAll',
27
+ 'repeat',
28
+ 'padStart',
29
+ 'padEnd',
30
+ 'concat',
31
+ 'localeCompare',
32
+ 'match',
33
+ ];
34
+ export const NUMBER_MEMBERS = ['toFixed', 'toPrecision', 'toString', 'toLocaleString'];
35
+ export const BOOL_MEMBERS = ['toString'];
36
+ export const BIGINT_MEMBERS = ['toString', 'toLocaleString', 'valueOf'];
37
+ export const ARRAY_MEMBERS = [
38
+ 'length',
39
+ 'push',
40
+ 'unshift',
41
+ 'pop',
42
+ 'shift',
43
+ 'at',
44
+ 'indexOf',
45
+ 'lastIndexOf',
46
+ 'includes',
47
+ 'join',
48
+ 'slice',
49
+ 'splice',
50
+ 'concat',
51
+ 'reverse',
52
+ 'fill',
53
+ 'sort',
54
+ 'map',
55
+ 'flatMap',
56
+ 'filter',
57
+ 'find',
58
+ 'findLast',
59
+ 'findIndex',
60
+ 'findLastIndex',
61
+ 'some',
62
+ 'every',
63
+ 'forEach',
64
+ 'reduce',
65
+ 'entries',
66
+ 'keys',
67
+ 'values',
68
+ 'toString',
69
+ ];
70
+ /** HTML tags, for completion without TypeScript's `HTMLElementTagNameMap`. */
71
+ export const HTML_TAGS = [
72
+ ...['a', 'abbr', 'address', 'article', 'aside', 'audio', 'b', 'blockquote', 'br', 'button'],
73
+ ...['canvas', 'caption', 'code', 'col', 'colgroup', 'data', 'datalist', 'dd', 'del', 'details'],
74
+ ...['dfn', 'dialog', 'div', 'dl', 'dt', 'em', 'fieldset', 'figcaption', 'figure', 'footer'],
75
+ ...['form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'i', 'iframe', 'img'],
76
+ ...['input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'mark', 'menu', 'meter', 'nav'],
77
+ ...['object', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q'],
78
+ ...['s', 'samp', 'search', 'section', 'select', 'slot', 'small', 'source', 'span', 'strong'],
79
+ ...['sub', 'summary', 'sup', 'svg', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot'],
80
+ ...['th', 'thead', 'time', 'tr', 'track', 'u', 'ul', 'var', 'video', 'wbr'],
81
+ ];
82
+ /** Event attributes as programs write them: `on` and the event in camel case. */
83
+ export const EVENT_ATTRIBUTES = [
84
+ ...['onClick', 'onDblClick', 'onContextMenu', 'onAuxClick'],
85
+ ...['onInput', 'onChange', 'onSubmit', 'onReset', 'onInvalid', 'onSelect'],
86
+ ...['onKeyDown', 'onKeyUp', 'onFocus', 'onBlur', 'onFocusIn', 'onFocusOut'],
87
+ ...['onMouseDown', 'onMouseUp', 'onMouseMove', 'onMouseEnter', 'onMouseLeave', 'onMouseOver'],
88
+ ...['onMouseOut', 'onWheel', 'onScroll', 'onScrollEnd'],
89
+ ...['onPointerDown', 'onPointerUp', 'onPointerMove', 'onPointerEnter', 'onPointerLeave'],
90
+ ...['onPointerCancel', 'onTouchStart', 'onTouchMove', 'onTouchEnd', 'onTouchCancel'],
91
+ ...['onDragStart', 'onDrag', 'onDragEnd', 'onDragEnter', 'onDragOver', 'onDragLeave', 'onDrop'],
92
+ ...['onCopy', 'onCut', 'onPaste', 'onLoad', 'onError', 'onToggle', 'onClose', 'onCancel'],
93
+ ...['onAnimationStart', 'onAnimationEnd', 'onTransitionEnd'],
94
+ ...['onPlay', 'onPause', 'onEnded', 'onTimeUpdate', 'onVolumeChange'],
95
+ ];
96
+ /** DOM properties that attributes spell differently. */
97
+ export const ATTRIBUTE_NAMES = new Map([
98
+ ['className', 'class'],
99
+ ['htmlFor', 'for'],
100
+ ]);
@@ -0,0 +1,25 @@
1
+ import type * as ast from '../ast.ts';
2
+ import { IteratorChecker } from './iterators.ts';
3
+ import type { CompletionResult } from './context.ts';
4
+ import { type Type } from './types.ts';
5
+ export declare abstract class CompletionChecker extends IteratorChecker {
6
+ protected completion: CompletionResult | null;
7
+ private atCursor;
8
+ /** The first check of the cursor counts: a component's body, for one, is checked for each use. */
9
+ private complete;
10
+ protected checkIdentifier(node: ast.Identifier): Type;
11
+ protected checkChain(node: ast.MemberExpression | ast.IndexExpression | ast.CallExpression, expected?: Type | null): [Type, boolean];
12
+ protected resolveTypeName(name: ast.Identifier, typeArgs?: readonly ast.TypeNode[]): Type;
13
+ protected checkElement(node: ast.ElementExpression): Type;
14
+ private valueNames;
15
+ private bindingCompletion;
16
+ private typeNames;
17
+ private tagNames;
18
+ /** Properties of a component, or attributes and events of an element, not given yet. */
19
+ private attributeNames;
20
+ /** The members of a value of type `type` that the code here may use. */
21
+ private membersOf;
22
+ /** Whether the code here may use a member: private and protected ones only in their classes. */
23
+ private canUse;
24
+ private scopes;
25
+ }
@@ -0,0 +1,222 @@
1
+ import { IteratorChecker } from "./iterators.js";
2
+ import { ARRAY_MEMBERS, ATTRIBUTE_NAMES, BIGINT_MEMBERS, BOOL_MEMBERS, EVENT_ATTRIBUTES, HTML_TAGS, NUMBER_MEMBERS, STRING_MEMBERS, } from "./completion-names.js";
3
+ import { isSubclass, literalBase, memberNames, memberTypeOf, nonNull, typeToString, union, UNKNOWN, } from "./types.js";
4
+ // Completion in editors (src/completion.ts): the editor writes the name `options.completion` where
5
+ // the cursor is, and this layer lists what can be written there when the check reaches that name:
6
+ // the names in scope, the members of the value before a dot, the types, the tags of markup or the
7
+ // attributes of an element. The name itself is not an error: the check goes on as if it were
8
+ // `unknown`.
9
+ const PRIMITIVE_MEMBERS = {
10
+ string: STRING_MEMBERS,
11
+ number: NUMBER_MEMBERS,
12
+ bigint: BIGINT_MEMBERS,
13
+ bool: BOOL_MEMBERS,
14
+ };
15
+ export class CompletionChecker extends IteratorChecker {
16
+ completion = null;
17
+ atCursor(node) {
18
+ return node.name === this.options.completion;
19
+ }
20
+ /** The first check of the cursor counts: a component's body, for one, is checked for each use. */
21
+ complete(context, items) {
22
+ this.completion ??= { context, items: items() };
23
+ }
24
+ checkIdentifier(node) {
25
+ if (!this.atCursor(node))
26
+ return super.checkIdentifier(node);
27
+ this.complete('value', () => this.valueNames());
28
+ return UNKNOWN;
29
+ }
30
+ checkChain(node, expected = null) {
31
+ if (node.kind !== 'MemberExpression' || !this.atCursor(node.property)) {
32
+ return super.checkChain(node, expected);
33
+ }
34
+ const [object] = node.object.kind === 'SuperExpression'
35
+ ? [this.superType(node.object)]
36
+ : this.chainPart(node.object);
37
+ this.complete('member', () => [...this.membersOf(nonNull(object))].map(([name, member]) => ({
38
+ name,
39
+ kind: member.method ? 'method' : 'property',
40
+ detail: typeToString(member.type),
41
+ })));
42
+ return [UNKNOWN, false];
43
+ }
44
+ resolveTypeName(name, typeArgs = []) {
45
+ if (!this.atCursor(name))
46
+ return super.resolveTypeName(name, typeArgs);
47
+ this.complete('type', () => this.typeNames());
48
+ return UNKNOWN;
49
+ }
50
+ checkElement(node) {
51
+ const { tag } = node;
52
+ if (tag && this.atCursor(tag)) {
53
+ this.complete('tag', () => this.tagNames());
54
+ return UNKNOWN;
55
+ }
56
+ const cursor = node.attributes.some((attribute) => attribute.kind === 'JsxAttribute' && this.atCursor(attribute.name));
57
+ if (tag && cursor)
58
+ this.complete('attribute', () => this.attributeNames(node, tag.name));
59
+ return super.checkElement(node);
60
+ }
61
+ // ─── Lists ─────────────────────────────────────────────────────────────────────────────────────
62
+ valueNames() {
63
+ const found = new Map();
64
+ // An inner declaration hides an outer one with the same name.
65
+ for (const scope of this.scopes()) {
66
+ for (const binding of scope.values.values()) {
67
+ if (!found.has(binding.name))
68
+ found.set(binding.name, this.bindingCompletion(binding));
69
+ }
70
+ }
71
+ for (const name of this.options.library?.names?.('value') ?? []) {
72
+ if (!found.has(name))
73
+ found.set(name, { name, kind: 'variable' });
74
+ }
75
+ return [...found.values()];
76
+ }
77
+ bindingCompletion(binding) {
78
+ const { name, kind, component } = binding;
79
+ if (component) {
80
+ return { name, kind: 'component', detail: typeToString(this.componentValue(component)) };
81
+ }
82
+ const type = binding.type && (this.flow.get(binding) ?? binding.type);
83
+ const detail = type ? { detail: typeToString(type) } : {};
84
+ if (kind === 'function' || type?.kind === 'function')
85
+ return { name, kind: 'function', ...detail };
86
+ if (kind === 'class' || type?.kind === 'classValue')
87
+ return { name, kind: 'class', ...detail };
88
+ return { name, kind: kind === 'const' ? 'constant' : 'variable', ...detail };
89
+ }
90
+ typeNames() {
91
+ const found = new Map();
92
+ for (const scope of this.scopes()) {
93
+ for (const [name, entry] of scope.types) {
94
+ if (!found.has(name)) {
95
+ found.set(name, { name, kind: entry.kind === 'class' ? 'class' : 'type' });
96
+ }
97
+ }
98
+ }
99
+ for (const name of this.options.library?.names?.('type') ?? []) {
100
+ if (!found.has(name))
101
+ found.set(name, { name, kind: 'type' });
102
+ }
103
+ return [...found.values()];
104
+ }
105
+ tagNames() {
106
+ const components = [...this.scopes()].flatMap((scope) => [...scope.values.values()].flatMap((binding) => binding.component ? [this.bindingCompletion(binding)] : []));
107
+ const tags = this.options.library?.names?.('tag') ?? HTML_TAGS;
108
+ return [...components, ...[...tags].map((name) => ({ name, kind: 'tag' }))];
109
+ }
110
+ /** Properties of a component, or attributes and events of an element, not given yet. */
111
+ attributeNames(node, tag) {
112
+ const given = new Set(node.attributes.flatMap((attribute) => attribute.kind === 'JsxAttribute' ? [attribute.name.name] : []));
113
+ const items = [{ name: 'ref', kind: 'attribute' }];
114
+ if (/^[A-Z]/.test(tag)) {
115
+ const info = this.lookupValue(tag)?.component;
116
+ if (!info)
117
+ return [];
118
+ this.resolveProps(info);
119
+ for (const [name, prop] of info.props) {
120
+ if (name !== 'children') {
121
+ items.push({ name, kind: 'property', detail: typeToString(prop.type) });
122
+ }
123
+ }
124
+ }
125
+ else {
126
+ for (const [property, member] of this.membersOf(this.elementOf(tag))) {
127
+ // Members like `onclick` from TypeScript's lib are events, which are written `onClick`.
128
+ if (member.method || member.type.kind === 'function' || property.startsWith('on'))
129
+ continue;
130
+ const name = ATTRIBUTE_NAMES.get(property) ?? property;
131
+ items.push({ name, kind: 'attribute', detail: typeToString(member.type) });
132
+ }
133
+ for (const name of EVENT_ATTRIBUTES)
134
+ items.push({ name, kind: 'attribute' });
135
+ }
136
+ return items.filter((item) => !given.has(item.name));
137
+ }
138
+ // ─── Members ───────────────────────────────────────────────────────────────────────────────────
139
+ /** The members of a value of type `type` that the code here may use. */
140
+ membersOf(type) {
141
+ const members = new Map();
142
+ const add = (names, find) => {
143
+ for (const name of names) {
144
+ const member = members.has(name) ? undefined : find(name);
145
+ if (member && member !== 'any')
146
+ members.set(name, member);
147
+ }
148
+ };
149
+ switch (type.kind) {
150
+ case 'literal':
151
+ return this.membersOf(literalBase(type));
152
+ case 'param':
153
+ return type.constraint ? this.membersOf(type.constraint) : members;
154
+ case 'string':
155
+ case 'number':
156
+ case 'bigint':
157
+ case 'bool': {
158
+ const library = this.options.library?.primitive(type.kind);
159
+ add(PRIMITIVE_MEMBERS[type.kind], (name) => this.memberOf(type, name));
160
+ if (library?.kind === 'object')
161
+ add(memberNames(library.members), (name) => this.memberOf(type, name));
162
+ break;
163
+ }
164
+ case 'array': {
165
+ const library = this.options.library?.array(type.element);
166
+ const find = (name) => this.arrayMemberOf(type.element, name);
167
+ add(ARRAY_MEMBERS, find);
168
+ if (library?.kind === 'object')
169
+ add(memberNames(library.members), find);
170
+ break;
171
+ }
172
+ case 'object':
173
+ add(memberNames(type.members), (name) => type.members.get(name));
174
+ break;
175
+ case 'class':
176
+ case 'classValue':
177
+ for (let info = type.info; info; info = info.superClass) {
178
+ this.ensureClassResolved(info);
179
+ for (const [name, member] of type.kind === 'class' ? info.members : info.statics) {
180
+ if (members.has(name) || !this.canUse(member))
181
+ continue;
182
+ members.set(name, type.kind === 'class' && type.args
183
+ ? { ...member, type: memberTypeOf(type, member) }
184
+ : member);
185
+ }
186
+ }
187
+ break;
188
+ // The members that every type of the union has.
189
+ case 'union': {
190
+ const [first, ...rest] = type.types.map((each) => this.membersOf(each));
191
+ for (const [name, member] of first ?? []) {
192
+ const others = rest.map((each) => each.get(name));
193
+ if (others.some((other) => other === undefined))
194
+ continue;
195
+ const all = [member, ...others];
196
+ members.set(name, {
197
+ ...member,
198
+ type: union(all.map((each) => each.type)),
199
+ method: all.every((each) => each.method),
200
+ });
201
+ }
202
+ break;
203
+ }
204
+ default:
205
+ break;
206
+ }
207
+ return members;
208
+ }
209
+ /** Whether the code here may use a member: private and protected ones only in their classes. */
210
+ canUse({ owner, visibility }) {
211
+ if (!owner || visibility === 'public')
212
+ return true;
213
+ const current = this.cls?.info;
214
+ return visibility === 'private'
215
+ ? current === owner
216
+ : current !== undefined && isSubclass(current, owner);
217
+ }
218
+ *scopes() {
219
+ for (let scope = this.scope; scope; scope = scope.parent)
220
+ yield scope;
221
+ }
222
+ }
@@ -0,0 +1,11 @@
1
+ import type * as ast from '../ast.ts';
2
+ import { ComponentChecker } from './components.ts';
3
+ import type { ComponentInfo } from './context.ts';
4
+ import { type ComponentType, type Type } from './types.ts';
5
+ export declare abstract class ComponentValueChecker extends ComponentChecker {
6
+ /** `Card` as a value: `comp(title string, kind ?Kind)`, without `...attrs`. */
7
+ protected componentValue(info: ComponentInfo): ComponentType;
8
+ /** `<section.content title="Hi" />`: the attributes are checked against the type of the value. */
9
+ protected checkValueTagUse(node: ast.ElementExpression, tag: ast.Identifier, value: ast.Expression): Type;
10
+ private checkValueTagAttributes;
11
+ }
@@ -0,0 +1,88 @@
1
+ import { ComponentChecker } from "./components.js";
2
+ import { isUntyped } from "./helpers.js";
3
+ const upperFirst = (name) => name.charAt(0).toUpperCase() + name.slice(1);
4
+ import { isNullable, typeToString, UNKNOWN, } from "./types.js";
5
+ // Components as values: `content: Intro` has the type `comp()`, and a tag takes the component
6
+ // from a value, `<section.content />`, or `<Page />` when `Page` is a variable. Such a tag passes
7
+ // the properties by their positions in the type, so the component is a function in its module.
8
+ export class ComponentValueChecker extends ComponentChecker {
9
+ /** `Card` as a value: `comp(title string, kind ?Kind)`, without `...attrs`. */
10
+ componentValue(info) {
11
+ const params = info.node.params.flatMap((param) => {
12
+ const prop = info.props.get(param.name.name);
13
+ return param.rest || !prop ? [] : [{ name: param.name.name, ...prop }];
14
+ });
15
+ return { kind: 'component', params };
16
+ }
17
+ /** `<section.content title="Hi" />`: the attributes are checked against the type of the value. */
18
+ checkValueTagUse(node, tag, value) {
19
+ const type = this.checkValue(value);
20
+ const name = tag.name;
21
+ if (isUntyped(type) || type.kind !== 'component') {
22
+ if (isNullable(type)) {
23
+ // Only variables are narrowed, so a path goes into one first.
24
+ const variable = /^[A-Z]/.test(name) ? name : upperFirst(name.split('.').at(-1));
25
+ const show = `{if ${variable} != null { <${variable} /> }}`;
26
+ this.error(name === variable
27
+ ? `<${name}> may be null: show it with {if}, e.g. ${show}`
28
+ : `<${name}> may be null: put it into a variable and show it with {if}, e.g. const ${variable} = ${name}, then ${show}`, tag);
29
+ }
30
+ else if (!isUntyped(type)) {
31
+ this.error(`<${name}> is ${typeToString(type)}, not a component: give it a type like comp(title string)`, tag);
32
+ }
33
+ else if (type.kind === 'any' && (node.attributes.length > 0 || node.children.length > 0)) {
34
+ // The tag passes the properties by position, which only the type knows.
35
+ this.error(`<${name}> is any, so the order of its properties is not known: give it a type like comp(title string)`, tag);
36
+ }
37
+ this.checkValueTagAttributes(node, null);
38
+ return this.dom.node;
39
+ }
40
+ this.checkValueTagAttributes(node, type);
41
+ return this.dom.node;
42
+ }
43
+ checkValueTagAttributes(node, type) {
44
+ const name = node.tag.name;
45
+ const given = new Set();
46
+ for (const attribute of node.attributes) {
47
+ if (attribute.kind === 'JsxSpreadAttribute') {
48
+ this.checkValue(attribute.argument);
49
+ // After the error, missing properties would only repeat it.
50
+ for (const param of type?.params ?? [])
51
+ given.add(param.name);
52
+ this.error(`<${name}> takes its component from a value, so its properties are passed one by one, not spread`, attribute);
53
+ continue;
54
+ }
55
+ const attributeName = attribute.name.name;
56
+ const param = type?.params.find((each) => each.name === attributeName);
57
+ if (attributeName === 'ref') {
58
+ this.error(`ref cannot point to <${name}>: its component is a value, so its element is not known in advance`, attribute);
59
+ continue;
60
+ }
61
+ if (given.has(attributeName)) {
62
+ this.error(`duplicate property "${attributeName}"`, attribute.name);
63
+ }
64
+ given.add(attributeName);
65
+ if (attributeName === 'children' && param) {
66
+ this.error(`pass children between the tags: <${name}>...</${name}>`, attribute.name);
67
+ }
68
+ else if (param) {
69
+ this.checkProp(attribute, param.type, name);
70
+ }
71
+ else if (type) {
72
+ this.error(`<${name}> has no property "${attributeName}"`, attribute.name);
73
+ }
74
+ else {
75
+ this.checkProp(attribute, UNKNOWN, name);
76
+ }
77
+ }
78
+ for (const param of type?.params ?? []) {
79
+ if (!param.optional && !given.has(param.name)) {
80
+ this.error(`<${name}> needs the property "${param.name}"`, node.tag);
81
+ }
82
+ }
83
+ if (type && node.children.length > 0 && !type.params.some((each) => each.name === 'children')) {
84
+ this.error(`<${name}> takes no children`, node.children[0]);
85
+ }
86
+ this.checkChildren(node.children);
87
+ }
88
+ }
@@ -0,0 +1,37 @@
1
+ import type * as ast from '../ast.ts';
2
+ import type { ComponentInfo } from './context.ts';
3
+ import { ForwardingChecker } from './forwarding.ts';
4
+ import { type Type } from './types.ts';
5
+ export declare abstract class ComponentChecker extends ForwardingChecker {
6
+ protected resolveProps(info: ComponentInfo): void;
7
+ /** The body runs once where the component is used and must end with `return <markup>`. */
8
+ protected checkComponentBody(info: ComponentInfo): void;
9
+ /** `<Card title="Profile">...</Card>`: properties are checked like the arguments of a call. */
10
+ protected checkComponentUse(node: ast.ElementExpression, tag: ast.Identifier): Type;
11
+ /**
12
+ * `<Product {...product} />`: fields of the object with the names of properties are passed as
13
+ * those properties; other fields are ignored. Adds the names of the given properties to `given`.
14
+ */
15
+ protected checkSpreadProps(argument: ast.Expression, info: ComponentInfo, component: string, given: Set<string>): void;
16
+ protected checkProp(attribute: ast.JsxAttribute, type: Type, component: string): void;
17
+ /**
18
+ * The component's code is inlined where it is used, so the names of the module that it uses
19
+ * must not be hidden there by local declarations.
20
+ */
21
+ protected checkHygiene(info: ComponentInfo, tag: ast.Identifier): void;
22
+ /** The type of `<Card />`: what its markup creates, through the wrappers of its decorators. */
23
+ protected componentResult(info: ComponentInfo, seen: Set<ComponentInfo>): Type;
24
+ /** What the markup the component itself returns creates. */
25
+ protected ownResult(info: ComponentInfo, seen: Set<ComponentInfo>): Type;
26
+ /** The type of the markup a component returns, found without checking it again. */
27
+ protected markupType(value: ast.Expression | undefined, seen: Set<ComponentInfo>): Type;
28
+ /**
29
+ * A component may use itself, but some use on the cycle must be under a condition (if, for, a
30
+ * branch of `?:`...), or creating the component never ends.
31
+ */
32
+ protected checkEndlessRecursion(): void;
33
+ /** `@html-tag` components: valid and different tags, and properties HTMLElement does not have. */
34
+ protected checkHtmlTags(): void;
35
+ /** The type of a property of a web component of this module, by its tag and an attribute. */
36
+ protected webComponentProperty(tag: string, attribute: string): Type | null;
37
+ }