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,220 @@
1
+ import { instanceMembers } from "./classes.js";
2
+ import { arrayOf, func, nonNull, nullable, union } from "./constructors.js";
3
+ import { instantiate } from "./generics.js";
4
+ import { memberNames } from "./lazy.js";
5
+ import { VOID, } from "./model.js";
6
+ import { typesEqual } from "./relations.js";
7
+ // Type parameters: substituting type arguments and inferring them from the arguments of a call.
8
+ /** Whether a type mentions type parameters: any of them, or only those in `only`. */
9
+ export function containsTypeParam(type, only = null, seen = new Set()) {
10
+ if (seen.has(type))
11
+ return false;
12
+ seen.add(type);
13
+ const contains = (each) => containsTypeParam(each, only, seen);
14
+ switch (type.kind) {
15
+ case 'param':
16
+ return only === null || only.has(type);
17
+ case 'object':
18
+ if (type.typeParams?.some((param) => only === null || only.has(param)))
19
+ return true;
20
+ if (type.instanceOf)
21
+ return type.instanceOf.args.some(contains);
22
+ // A named interface without parameters cannot use them; an object type literal might.
23
+ if (type.name !== null)
24
+ return false;
25
+ return [...type.members.values()].some((member) => contains(member.type));
26
+ case 'class':
27
+ return (type.args ?? []).some(contains);
28
+ case 'array':
29
+ return contains(type.element);
30
+ case 'nullable':
31
+ return contains(type.type);
32
+ case 'union':
33
+ return type.types.some(contains);
34
+ case 'function':
35
+ return [...type.params, ...type.results].some(contains);
36
+ case 'component':
37
+ return type.params.some((param) => contains(param.type));
38
+ default:
39
+ return false;
40
+ }
41
+ }
42
+ /** Replaces inferred type parameters; with `fallback`, also those that were not inferred. */
43
+ export function substitute(type, bindings, fallback) {
44
+ switch (type.kind) {
45
+ case 'param':
46
+ return bindings.get(type) ?? fallback ?? type;
47
+ case 'array':
48
+ return arrayOf(substitute(type.element, bindings, fallback));
49
+ case 'nullable':
50
+ return nullable(substitute(type.type, bindings, fallback));
51
+ case 'union':
52
+ return union(type.types.map((member) => substitute(member, bindings, fallback)));
53
+ case 'class':
54
+ return type.args
55
+ ? { ...type, args: type.args.map((arg) => substitute(arg, bindings, fallback)) }
56
+ : type;
57
+ case 'object':
58
+ return substituteObject(type, bindings, fallback);
59
+ case 'function': {
60
+ // A generic method of a generic interface keeps its own parameters: `map<U>` of `Box<T>`.
61
+ // A default that uses the interface's parameters needs a parameter of its own:
62
+ // `then<TResult1 = T>` of `Promise<Response>` has the default Response.
63
+ const own = new Map(bindings);
64
+ const typeParams = type.typeParams
65
+ .filter((param) => !bindings.has(param))
66
+ .map((param) => {
67
+ if (!param.default || !containsTypeParam(param.default, new Set(bindings.keys()))) {
68
+ return param;
69
+ }
70
+ const fresh = freshParam(param, substitute(param.default, bindings));
71
+ own.set(param, fresh);
72
+ return fresh;
73
+ });
74
+ const sub = (each) => substitute(each, own, fallback);
75
+ const result = func(type.params.map(sub), type.results.map(sub), {
76
+ required: type.required,
77
+ ...(type.rest ? { rest: sub(type.rest) } : {}),
78
+ typeParams,
79
+ ...(type.iterator ? { iterator: true } : {}),
80
+ });
81
+ if (type.overloads) {
82
+ result.overloads = type.overloads.map((overload) => sub(overload));
83
+ }
84
+ return result;
85
+ }
86
+ case 'component':
87
+ return {
88
+ kind: 'component',
89
+ params: type.params.map((param) => ({
90
+ ...param,
91
+ type: substitute(param.type, bindings, fallback),
92
+ })),
93
+ };
94
+ default:
95
+ return type;
96
+ }
97
+ }
98
+ const freshParams = new WeakMap();
99
+ /** A copy of a type parameter with another default; the same copy for the same default. */
100
+ function freshParam(param, fallback) {
101
+ let copies = freshParams.get(param);
102
+ if (!copies) {
103
+ copies = [];
104
+ freshParams.set(param, copies);
105
+ }
106
+ let copy = copies.find((each) => each.default && typesEqual(each.default, fallback));
107
+ if (!copy) {
108
+ copy = { ...param, default: fallback };
109
+ copies.push(copy);
110
+ }
111
+ return copy;
112
+ }
113
+ function substituteObject(type, bindings, fallback) {
114
+ const sub = (each) => substitute(each, bindings, fallback);
115
+ if (type.typeParams && type.typeParams.length > 0) {
116
+ return instantiate(type, type.typeParams.map(sub));
117
+ }
118
+ if (type.instanceOf) {
119
+ return instantiate(type.instanceOf.template, type.instanceOf.args.map(sub));
120
+ }
121
+ // A named interface without parameters cannot use them; an object type literal might.
122
+ if (type.name !== null || !containsTypeParam(type))
123
+ return type;
124
+ const members = new Map();
125
+ for (const [name, member] of type.members)
126
+ members.set(name, { ...member, type: sub(member.type) });
127
+ return { ...type, members, call: type.call && sub(type.call) };
128
+ }
129
+ const MAX_STRUCTURAL_DEPTH = 3;
130
+ /** Infers type parameters in `param` from the argument type `arg`. */
131
+ export function inferTypeParams(param, arg, bindings, depth = 0) {
132
+ if (!containsTypeParam(param))
133
+ return;
134
+ const infer = (p, a) => inferTypeParams(p, a, bindings, depth);
135
+ switch (param.kind) {
136
+ case 'param':
137
+ if (!bindings.has(param) && arg.kind !== 'unknown' && arg.kind !== 'never') {
138
+ bindings.set(param, arg);
139
+ }
140
+ break;
141
+ case 'array':
142
+ if (arg.kind === 'array')
143
+ infer(param.element, arg.element);
144
+ break;
145
+ case 'nullable':
146
+ infer(param.type, nonNull(arg));
147
+ break;
148
+ case 'union': {
149
+ // `T | PromiseLike<T>` from `Promise<string>`: a member with structure first, so that T is
150
+ // string, not the whole promise; then a bare parameter.
151
+ const members = param.types.filter((member) => containsTypeParam(member));
152
+ for (const member of members) {
153
+ if (member.kind === 'param')
154
+ continue;
155
+ const trial = new Map(bindings);
156
+ inferTypeParams(member, arg, trial, depth);
157
+ if (trial.size > bindings.size) {
158
+ for (const [key, value] of trial)
159
+ bindings.set(key, value);
160
+ return;
161
+ }
162
+ }
163
+ const bare = members.find((member) => member.kind === 'param');
164
+ if (bare)
165
+ infer(bare, arg);
166
+ break;
167
+ }
168
+ case 'class':
169
+ if (arg.kind === 'class' && arg.info === param.info && param.args && arg.args) {
170
+ param.args.forEach((each, i) => infer(each, arg.args[i]));
171
+ }
172
+ break;
173
+ case 'object': {
174
+ if (param.instanceOf &&
175
+ arg.kind === 'object' &&
176
+ arg.instanceOf?.template === param.instanceOf.template) {
177
+ param.instanceOf.args.forEach((each, i) => infer(each, arg.instanceOf.args[i]));
178
+ break;
179
+ }
180
+ // Structurally: `{ value T }` from `{ value number }`. Types refer to themselves, and the
181
+ // methods of generic interfaces give ever new instances (`then` of a promise gives a
182
+ // promise), so only a few levels deep, as in TypeScript.
183
+ if (depth >= MAX_STRUCTURAL_DEPTH)
184
+ break;
185
+ const members = arg.kind === 'object'
186
+ ? arg.members
187
+ : arg.kind === 'class'
188
+ ? instanceMembers(arg.info)
189
+ : null;
190
+ if (!members)
191
+ break;
192
+ for (const name of memberNames(param.members)) {
193
+ const found = members.get(name);
194
+ const member = found && param.members.get(name);
195
+ if (member)
196
+ inferTypeParams(member.type, found.type, bindings, depth + 1);
197
+ }
198
+ break;
199
+ }
200
+ case 'function':
201
+ if (arg.kind === 'function') {
202
+ param.params.forEach((p, i) => {
203
+ const a = arg.params[i];
204
+ if (a)
205
+ infer(p, a);
206
+ });
207
+ // A callback without a result gives void: `then(text => { ... })`.
208
+ if (arg.results.length === 0 && param.results.length === 1)
209
+ infer(param.results[0], VOID);
210
+ param.results.forEach((r, i) => {
211
+ const a = arg.results[i];
212
+ if (a)
213
+ infer(r, a);
214
+ });
215
+ }
216
+ break;
217
+ default:
218
+ break;
219
+ }
220
+ }
@@ -0,0 +1,6 @@
1
+ import type { Type } from './model.ts';
2
+ /** `[]byte`: a Uint8Array, of the lib files or the built-in one. */
3
+ export declare function isBytes(type: Type): boolean;
4
+ /** The name of a typed array, `[]float64` or `Float64Array`, or null for other types. */
5
+ export declare function typedArrayOf(type: Type): string | null;
6
+ export declare function typeToString(type: Type): string;
@@ -0,0 +1,109 @@
1
+ import { TYPED_ARRAYS, typedArrayName } from "../../typed-arrays.js";
2
+ import { ERROR_CLASS } from "./classes.js";
3
+ import { nullable } from "./constructors.js";
4
+ // Types as text, for messages.
5
+ /** How deep object types without a name are printed with their members. */
6
+ const MAX_OBJECT_DEPTH = 3;
7
+ /** How many members of an object type without a name are printed: `globalThis` has hundreds. */
8
+ const MAX_OBJECT_MEMBERS = 8;
9
+ let objectDepth = 0;
10
+ /** `[]byte`: a Uint8Array, of the lib files or the built-in one. */
11
+ export function isBytes(type) {
12
+ return typedArrayOf(type) === 'Uint8Array';
13
+ }
14
+ /** The name of a typed array, `[]float64` or `Float64Array`, or null for other types. */
15
+ export function typedArrayOf(type) {
16
+ const name = type.kind === 'object' ? (type.instanceOf?.template.name ?? type.name) : null;
17
+ return name !== null && TYPED_ARRAYS.has(name) ? name : null;
18
+ }
19
+ export function typeToString(type) {
20
+ switch (type.kind) {
21
+ case 'number':
22
+ case 'bigint':
23
+ case 'string':
24
+ case 'bool':
25
+ case 'any':
26
+ case 'void':
27
+ case 'null':
28
+ case 'never':
29
+ case 'unknown':
30
+ return type.kind;
31
+ case 'array':
32
+ return `[]${grouped(type.element)}`;
33
+ case 'nullable':
34
+ if (type.type === ERROR_CLASS.instance)
35
+ return 'error';
36
+ return `?${grouped(type.type)}`;
37
+ case 'union':
38
+ return type.name ?? type.types.map(typeToString).join(' | ');
39
+ case 'literal':
40
+ return typeof type.value === 'string' ? JSON.stringify(type.value) : String(type.value);
41
+ case 'function': {
42
+ const params = type.params.map((param, i) => typeToString(i < type.required ? param : nullable(param)));
43
+ if (type.rest)
44
+ params.push(`...${typeToString(type.rest)}`);
45
+ return `func(${type.iterator ? 'yield ' : ''}${params.join(', ')})${resultsToString(type.results)}`;
46
+ }
47
+ // A property that may be left out is printed as nullable, as it is written in the type.
48
+ case 'component': {
49
+ const params = type.params.map((param) => `${param.name} ${typeToString(param.optional && param.name !== 'children' ? nullable(param.type) : param.type)}`);
50
+ return `comp(${params.join(', ')})`;
51
+ }
52
+ case 'object': {
53
+ const typed = typedArrayOf(type);
54
+ if (typed !== null)
55
+ return typedArrayName(typed);
56
+ // `chan T`, `chan<- T` and `<-chan T` are written with spaces, not as type arguments.
57
+ if (type.instanceOf &&
58
+ (type.name === 'chan' || type.name === 'chan<-' || type.name === '<-chan')) {
59
+ return `${type.name} ${typeToString(type.instanceOf.args[0])}`;
60
+ }
61
+ if (type.instanceOf && type.name !== null) {
62
+ return `${type.name}<${type.instanceOf.args.map(typeToString).join(', ')}>`;
63
+ }
64
+ if (type.name !== null)
65
+ return type.name;
66
+ // Types from a `.d.ts` may contain themselves without a name.
67
+ if (objectDepth >= MAX_OBJECT_DEPTH)
68
+ return '{ ... }';
69
+ objectDepth++;
70
+ try {
71
+ const members = [...type.members]
72
+ .slice(0, MAX_OBJECT_MEMBERS)
73
+ .map(([name, member]) => `${name} ${typeToString(member.type)}`);
74
+ if (type.members.size > MAX_OBJECT_MEMBERS)
75
+ members.push('...');
76
+ if (type.numberIndex)
77
+ members.unshift(`[number]: ${typeToString(type.numberIndex)}`);
78
+ if (type.index)
79
+ members.unshift(`[string]: ${typeToString(type.index)}`);
80
+ return members.length === 0 ? '{}' : `{ ${members.join('; ')} }`;
81
+ }
82
+ finally {
83
+ objectDepth--;
84
+ }
85
+ }
86
+ case 'class':
87
+ return type.args
88
+ ? `${type.info.name}<${type.args.map(typeToString).join(', ')}>`
89
+ : type.info.name;
90
+ case 'classValue':
91
+ return `class ${type.info.name}`;
92
+ case 'tuple':
93
+ return `(${type.types.map(typeToString).join(', ')})`;
94
+ case 'param':
95
+ return type.name;
96
+ }
97
+ }
98
+ /** A union without a name needs parentheses after `[]` and `?`: `[](string | number)`. */
99
+ function grouped(type) {
100
+ const text = typeToString(type);
101
+ return type.kind === 'union' && type.name === undefined ? `(${text})` : text;
102
+ }
103
+ function resultsToString(results) {
104
+ if (results.length === 0)
105
+ return '';
106
+ if (results.length === 1)
107
+ return ` ${typeToString(results[0])}`;
108
+ return ` (${results.map(typeToString).join(', ')})`;
109
+ }
@@ -0,0 +1,16 @@
1
+ import { type Type } from './model.ts';
2
+ /** Whether a value of type `source` can be used where `target` is expected. */
3
+ export declare function isAssignable(source: Type, target: Type): boolean;
4
+ export declare function assignable(source: Type, target: Type, assuming: [Type, Type][]): boolean;
5
+ /** Why `source` is not assignable to an object or class `target`, e.g. `missing field "y"`. */
6
+ export declare function explainMismatch(source: Type, target: Type): string | null;
7
+ /**
8
+ * Can values of these types be compared with `==`? Literals must be able to be equal:
9
+ * `filter == "activ"` is an error when `filter` is `"all" | "active"`.
10
+ */
11
+ export declare function isComparable(a: Type, b: Type): boolean;
12
+ /** A type that both can be used as, e.g. for array elements: one of them, or their union. */
13
+ export declare function commonType(a: Type, b: Type): Type;
14
+ export declare function typesEqual(a: Type, b: Type): boolean;
15
+ /** Types that a variable can have without an initial value: `0`, `""`, `false`, `[]`, `null`. */
16
+ export declare function hasZeroValue(type: Type): boolean;
@@ -0,0 +1,294 @@
1
+ import { instanceMembers, isSubclass, publicMembers } from "./classes.js";
2
+ import { memberNames } from "./lazy.js";
3
+ import { isNullable, literalBase, nonNull, union } from "./constructors.js";
4
+ import { UNKNOWN, VOID, } from "./model.js";
5
+ import { typedArrayOf, typeToString } from "./printing.js";
6
+ // Relations between types: assignability, comparison, equality, common types.
7
+ /** Whether a value of type `source` can be used where `target` is expected. */
8
+ export function isAssignable(source, target) {
9
+ return assignable(source, target, []);
10
+ }
11
+ export function assignable(source, target, assuming) {
12
+ if (source === target)
13
+ return true;
14
+ if (source.kind === 'any' || source.kind === 'unknown' || source.kind === 'never')
15
+ return true;
16
+ if (target.kind === 'any' || target.kind === 'unknown')
17
+ return true;
18
+ if (target.kind === 'nullable') {
19
+ if (source.kind === 'null')
20
+ return true;
21
+ return assignable(nonNull(source), target.type, assuming);
22
+ }
23
+ if (source.kind === 'nullable' || source.kind === 'null')
24
+ return false;
25
+ // A union can be used where each of its members can; a union accepts what one member accepts.
26
+ if (source.kind === 'union')
27
+ return source.types.every((type) => assignable(type, target, assuming));
28
+ if (target.kind === 'union')
29
+ return target.types.some((type) => assignable(source, type, assuming));
30
+ if (target.kind === 'literal')
31
+ return source.kind === 'literal' && source.value === target.value;
32
+ if (source.kind === 'literal')
33
+ return assignable(literalBase(source), target, assuming);
34
+ // Recursive types (e.g. `next ?Node`): assume the pair matches while checking it.
35
+ if (assuming.some(([s, t]) => s === source && t === target))
36
+ return true;
37
+ const nested = [...assuming, [source, target]];
38
+ // Inside a generic function, `T Shape` can be used as a `Shape`.
39
+ if (source.kind === 'param' && source !== target) {
40
+ return source.constraint ? assignable(source.constraint, target, nested) : false;
41
+ }
42
+ switch (target.kind) {
43
+ case 'number':
44
+ case 'bigint':
45
+ case 'string':
46
+ case 'bool':
47
+ case 'void':
48
+ return source.kind === target.kind;
49
+ case 'null':
50
+ case 'never':
51
+ case 'param':
52
+ return false;
53
+ case 'array':
54
+ return source.kind === 'array' && assignable(source.element, target.element, nested);
55
+ case 'tuple':
56
+ return (source.kind === 'tuple' &&
57
+ source.types.length === target.types.length &&
58
+ source.types.every((type, i) => assignable(type, target.types[i], nested)));
59
+ case 'function':
60
+ return source.kind === 'function' && functionAssignable(source, target, nested);
61
+ case 'component':
62
+ return source.kind === 'component' && componentAssignable(source, target, nested);
63
+ case 'classValue':
64
+ return source.kind === 'classValue' && isSubclass(source.info, target.info);
65
+ case 'class': {
66
+ if (source.kind === 'class' && source.info === target.info && target.args) {
67
+ return (source.args ?? []).every((arg, i) => assignable(arg, target.args[i], nested));
68
+ }
69
+ if (source.kind === 'class' && isSubclass(source.info, target.info))
70
+ return true;
71
+ // Private and protected members make a class nominal, as in TypeScript.
72
+ const members = instanceMembers(target.info);
73
+ if ([...members.values()].some((member) => member.visibility !== 'public'))
74
+ return false;
75
+ return missingMember(source, members, nested) === null;
76
+ }
77
+ case 'object': {
78
+ // A channel both takes and gives values, so `chan number` is not a `chan ?number`, as in Go;
79
+ // `chan any` is any channel, for `close(ch)`. A `chan T` is also a channel of one
80
+ // direction, `chan<- T` or `<-chan T`, but not the other way round.
81
+ const direction = target.instanceOf
82
+ ? CHAN_NAMES.get(target.instanceOf.template.name ?? '')
83
+ : undefined;
84
+ if (target.instanceOf && direction !== undefined) {
85
+ const element = target.instanceOf.args[0];
86
+ const from = source.kind === 'object' && source.instanceOf
87
+ ? CHAN_NAMES.get(source.instanceOf.template.name ?? '')
88
+ : undefined;
89
+ return (source.kind === 'object' &&
90
+ from !== undefined &&
91
+ (from === direction || from === 'both' || element.kind === 'any') &&
92
+ (element.kind === 'any' ||
93
+ (assignable(source.instanceOf.args[0], element, nested) &&
94
+ assignable(element, source.instanceOf.args[0], nested))));
95
+ }
96
+ // A callable interface from a `.d.ts`: `interface Listener { (event: Event): void }`.
97
+ if (target.call) {
98
+ const call = source.kind === 'function' ? source : source.kind === 'object' ? source.call : null;
99
+ if (!call || !functionAssignable(call, target.call, nested))
100
+ return false;
101
+ if (source.kind === 'function')
102
+ return target.members.size === 0;
103
+ }
104
+ if (target.index && !indexAssignable(source, target.index, nested))
105
+ return false;
106
+ if (target.numberIndex && !numberIndexAssignable(source, target.numberIndex, nested)) {
107
+ return false;
108
+ }
109
+ return missingMember(source, target.members, nested) === null;
110
+ }
111
+ }
112
+ }
113
+ /** `{ [string]: T }` accepts an object whose own index and fields are all `T`. */
114
+ /** The templates of channel types by name (channel.ts): no other type can have these names. */
115
+ const CHAN_NAMES = new Map([
116
+ ['chan', 'both'],
117
+ ['chan<-', 'send'],
118
+ ['<-chan', 'receive'],
119
+ ]);
120
+ function indexAssignable(source, index, assuming) {
121
+ if (source.kind !== 'object')
122
+ return false;
123
+ if (source.index && !assignable(source.index, index, assuming))
124
+ return false;
125
+ return [...memberNames(source.members)].every((name) => {
126
+ const member = source.members.get(name);
127
+ return !member || member.method || assignable(member.type, index, assuming);
128
+ });
129
+ }
130
+ /** `ArrayLike<T>` from a `.d.ts` accepts an array, a string or a typed array of `T`. */
131
+ function numberIndexAssignable(source, index, assuming) {
132
+ if (source.kind === 'array')
133
+ return assignable(source.element, index, assuming);
134
+ if (source.kind === 'string')
135
+ return assignable(source, index, assuming);
136
+ return (source.kind === 'object' &&
137
+ source.numberIndex !== undefined &&
138
+ assignable(source.numberIndex, index, assuming));
139
+ }
140
+ function functionAssignable(source, target, assuming) {
141
+ // An iterator is a JS generator: it does not take the callback that a function of its shape does.
142
+ if (Boolean(source.iterator) !== Boolean(target.iterator))
143
+ return false;
144
+ if (source.typeParams.length > 0 || target.typeParams.length > 0)
145
+ return true;
146
+ // A function may ignore parameters it is given, but not require more than it gets.
147
+ if (source.required > target.params.length && target.rest === null)
148
+ return false;
149
+ const shared = Math.min(source.params.length, target.params.length);
150
+ for (let i = 0; i < shared; i++) {
151
+ if (!assignable(target.params[i], source.params[i], assuming))
152
+ return false;
153
+ }
154
+ // A callback that returns something can be used where nothing is expected.
155
+ if (target.results.length === 0)
156
+ return true;
157
+ // And one that returns nothing where `void` may be returned, as `TResult | PromiseLike<TResult>`
158
+ // of `then` once TResult is void.
159
+ if (source.results.length === 0 && target.results.length === 1) {
160
+ return assignable(VOID, target.results[0], assuming);
161
+ }
162
+ return (source.results.length === target.results.length &&
163
+ source.results.every((type, i) => assignable(type, target.results[i], assuming)));
164
+ }
165
+ /**
166
+ * A tag passes the properties of `target` by position, so `source` must have the same names in
167
+ * the same order, and may have more only if they can be left out. A property with a default
168
+ * value takes a nullable one: null gives it the default value.
169
+ */
170
+ function componentAssignable(source, target, assuming) {
171
+ return (source.params.every((param, i) => i < target.params.length || param.optional) &&
172
+ target.params.every((expected, i) => {
173
+ const param = source.params[i];
174
+ if (!param || param.name !== expected.name || (expected.optional && !param.optional)) {
175
+ return false;
176
+ }
177
+ return (assignable(expected.type, param.type, assuming) ||
178
+ (param.optional && assignable(nonNull(expected.type), param.type, assuming)));
179
+ }));
180
+ }
181
+ /**
182
+ * The first member of `members` that `source` lacks or has with an incompatible type, or `null`
183
+ * if there is none. Properties with a nullable type may be missing.
184
+ */
185
+ function missingMember(source, members, assuming) {
186
+ const own = publicMembers(source);
187
+ if (own === null)
188
+ return { name: '', found: null, expected: UNKNOWN };
189
+ for (const [name, member] of members) {
190
+ const found = own.get(name);
191
+ if (!found) {
192
+ if (!member.method && isNullable(member.type))
193
+ continue;
194
+ return { name, found: null, expected: member.type };
195
+ }
196
+ if (!assignable(found.type, member.type, assuming)) {
197
+ return { name, found: found.type, expected: member.type };
198
+ }
199
+ }
200
+ return null;
201
+ }
202
+ /** Why `source` is not assignable to an object or class `target`, e.g. `missing field "y"`. */
203
+ export function explainMismatch(source, target) {
204
+ // `Stack<number>` and `Stack<string>`: the type arguments already say what differs.
205
+ if (source.kind === 'class' && target.kind === 'class' && source.info === target.info) {
206
+ return null;
207
+ }
208
+ const members = target.kind === 'object'
209
+ ? target.members
210
+ : target.kind === 'class'
211
+ ? instanceMembers(target.info)
212
+ : null;
213
+ if (members === null || publicMembers(source) === null)
214
+ return null;
215
+ const missing = missingMember(source, members, []);
216
+ if (missing === null)
217
+ return null;
218
+ if (missing.found === null)
219
+ return `missing "${missing.name}"`;
220
+ return `"${missing.name}" is ${typeToString(missing.found)}, not ${typeToString(missing.expected)}`;
221
+ }
222
+ /**
223
+ * Can values of these types be compared with `==`? Literals must be able to be equal:
224
+ * `filter == "activ"` is an error when `filter` is `"all" | "active"`.
225
+ */
226
+ export function isComparable(a, b) {
227
+ if (a.kind === 'null' || b.kind === 'null')
228
+ return true;
229
+ const x = nonNull(a);
230
+ const y = nonNull(b);
231
+ if (x.kind === 'union')
232
+ return x.types.some((type) => isComparable(type, y));
233
+ if (y.kind === 'union')
234
+ return y.types.some((type) => isComparable(x, type));
235
+ return isAssignable(x, y) || isAssignable(y, x);
236
+ }
237
+ /** A type that both can be used as, e.g. for array elements: one of them, or their union. */
238
+ export function commonType(a, b) {
239
+ if (isAssignable(b, a))
240
+ return a.kind === 'never' ? b : a;
241
+ if (isAssignable(a, b))
242
+ return b;
243
+ return union([a, b]);
244
+ }
245
+ export function typesEqual(a, b) {
246
+ if (a === b)
247
+ return true;
248
+ if (a.kind === 'array' && b.kind === 'array')
249
+ return typesEqual(a.element, b.element);
250
+ if (a.kind === 'nullable' && b.kind === 'nullable')
251
+ return typesEqual(a.type, b.type);
252
+ if (a.kind === 'literal' && b.kind === 'literal')
253
+ return a.value === b.value;
254
+ if (a.kind === 'class' && b.kind === 'class') {
255
+ return (a.info === b.info && (a.args ?? []).every((arg, i) => typesEqual(arg, b.args?.[i] ?? arg)));
256
+ }
257
+ if (a.kind === 'object' && b.kind === 'object' && a.instanceOf && b.instanceOf) {
258
+ return (a.instanceOf.template === b.instanceOf.template &&
259
+ a.instanceOf.args.every((arg, i) => typesEqual(arg, b.instanceOf.args[i])));
260
+ }
261
+ if (a.kind === 'component' && b.kind === 'component') {
262
+ return (a.params.length === b.params.length &&
263
+ a.params.every((param, i) => {
264
+ const other = b.params[i];
265
+ return (param.name === other.name &&
266
+ param.optional === other.optional &&
267
+ typesEqual(param.type, other.type));
268
+ }));
269
+ }
270
+ if (a.kind === 'union' && b.kind === 'union') {
271
+ return (a.types.length === b.types.length &&
272
+ a.types.every((type) => b.types.some((other) => typesEqual(type, other))));
273
+ }
274
+ return false;
275
+ }
276
+ /** Types that a variable can have without an initial value: `0`, `""`, `false`, `[]`, `null`. */
277
+ export function hasZeroValue(type) {
278
+ if (typedArrayOf(type) !== null)
279
+ return true;
280
+ switch (type.kind) {
281
+ case 'number':
282
+ case 'bigint':
283
+ case 'string':
284
+ case 'bool':
285
+ case 'array':
286
+ case 'nullable':
287
+ case 'null':
288
+ case 'any':
289
+ case 'unknown':
290
+ return true;
291
+ default:
292
+ return false;
293
+ }
294
+ }
@@ -0,0 +1,9 @@
1
+ export * from './types/model.ts';
2
+ export * from './types/constructors.ts';
3
+ export * from './types/lazy.ts';
4
+ export * from './types/generics.ts';
5
+ export * from './types/classes.ts';
6
+ export * from './types/relations.ts';
7
+ export * from './types/params.ts';
8
+ export * from './types/printing.ts';
9
+ export * from './types/bytes.ts';
@@ -0,0 +1,10 @@
1
+ // The types of the checker, by topic in src/checker/types/.
2
+ export * from "./types/model.js";
3
+ export * from "./types/constructors.js";
4
+ export * from "./types/lazy.js";
5
+ export * from "./types/generics.js";
6
+ export * from "./types/classes.js";
7
+ export * from "./types/relations.js";
8
+ export * from "./types/params.js";
9
+ export * from "./types/printing.js";
10
+ export * from "./types/bytes.js";
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};