rooklang 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/CHANGELOG.md +235 -0
  2. package/CHANGELOG.ru.md +235 -0
  3. package/dist/aliases.d.ts +2 -0
  4. package/dist/aliases.js +83 -0
  5. package/dist/ast/declarations.d.ts +18 -0
  6. package/dist/ast/expressions.d.ts +14 -1
  7. package/dist/ast/markup.d.ts +2 -0
  8. package/dist/ast/statements.d.ts +2 -2
  9. package/dist/checker/assignments.js +2 -1
  10. package/dist/checker/base.d.ts +3 -0
  11. package/dist/checker/base.js +1 -1
  12. package/dist/checker/builtins.js +5 -1
  13. package/dist/checker/calls.d.ts +2 -0
  14. package/dist/checker/calls.js +18 -3
  15. package/dist/checker/classes.js +8 -0
  16. package/dist/checker/component-bindings.d.ts +16 -0
  17. package/dist/checker/component-bindings.js +65 -2
  18. package/dist/checker/context.d.ts +12 -0
  19. package/dist/checker/declarations.d.ts +2 -0
  20. package/dist/checker/declarations.js +38 -3
  21. package/dist/checker/expressions.d.ts +1 -0
  22. package/dist/checker/expressions.js +17 -1
  23. package/dist/checker/flow.d.ts +1 -1
  24. package/dist/checker/flow.js +10 -0
  25. package/dist/checker/functions.d.ts +2 -0
  26. package/dist/checker/functions.js +33 -7
  27. package/dist/checker/goroutines.d.ts +2 -2
  28. package/dist/checker/goroutines.js +2 -2
  29. package/dist/checker/imports.d.ts +10 -0
  30. package/dist/checker/imports.js +73 -6
  31. package/dist/checker/initializers.d.ts +12 -0
  32. package/dist/checker/initializers.js +80 -0
  33. package/dist/checker/loops.js +3 -1
  34. package/dist/checker/members.js +1 -0
  35. package/dist/checker/resolution.d.ts +2 -0
  36. package/dist/checker/resolution.js +13 -2
  37. package/dist/checker/statements.d.ts +5 -0
  38. package/dist/checker/statements.js +26 -3
  39. package/dist/checker/tagged-unions.d.ts +6 -0
  40. package/dist/checker/tagged-unions.js +31 -1
  41. package/dist/checker/tags.d.ts +6 -0
  42. package/dist/checker/tags.js +44 -0
  43. package/dist/checker/types/constructors.js +10 -1
  44. package/dist/checker/types/params.js +33 -7
  45. package/dist/checker/types/printing.js +5 -1
  46. package/dist/checker/types/relations.js +2 -1
  47. package/dist/codegen/analysis.d.ts +6 -0
  48. package/dist/codegen/analysis.js +24 -0
  49. package/dist/codegen/calls.d.ts +2 -0
  50. package/dist/codegen/calls.js +23 -1
  51. package/dist/codegen/component-props.js +8 -1
  52. package/dist/codegen/control-flow.d.ts +3 -0
  53. package/dist/codegen/control-flow.js +17 -0
  54. package/dist/codegen/expressions.d.ts +4 -1
  55. package/dist/codegen/expressions.js +4 -15
  56. package/dist/codegen/functions.d.ts +2 -0
  57. package/dist/codegen/functions.js +13 -0
  58. package/dist/codegen/mutations.d.ts +6 -0
  59. package/dist/codegen/mutations.js +36 -0
  60. package/dist/codegen/options.d.ts +2 -0
  61. package/dist/codegen/reactive.js +9 -5
  62. package/dist/codegen/simple-statements.js +3 -1
  63. package/dist/codegen/statements.d.ts +4 -0
  64. package/dist/codegen/statements.js +37 -1
  65. package/dist/codegen/updates.d.ts +6 -1
  66. package/dist/codegen/updates.js +13 -2
  67. package/dist/compile.js +2 -0
  68. package/dist/completion.js +2 -1
  69. package/dist/declarations.js +18 -0
  70. package/dist/lexer/base.d.ts +3 -2
  71. package/dist/lexer/base.js +14 -5
  72. package/dist/lexer/lexer.js +3 -0
  73. package/dist/lexer/token.d.ts +6 -1
  74. package/dist/lexer/token.js +0 -1
  75. package/dist/modules.js +4 -3
  76. package/dist/parser/base.d.ts +5 -0
  77. package/dist/parser/base.js +9 -1
  78. package/dist/parser/classes.js +4 -3
  79. package/dist/parser/declarations.d.ts +2 -0
  80. package/dist/parser/declarations.js +25 -2
  81. package/dist/parser/decorators.js +1 -1
  82. package/dist/parser/expressions.js +6 -0
  83. package/dist/parser/literals.d.ts +2 -4
  84. package/dist/parser/literals.js +12 -24
  85. package/dist/parser/objects.d.ts +8 -0
  86. package/dist/parser/objects.js +51 -0
  87. package/dist/parser/params.d.ts +37 -4
  88. package/dist/parser/params.js +143 -9
  89. package/dist/parser/postfix.d.ts +5 -0
  90. package/dist/parser/postfix.js +36 -0
  91. package/dist/parser/simple-statements.d.ts +2 -0
  92. package/dist/parser/simple-statements.js +50 -0
  93. package/dist/parser/statements.js +8 -6
  94. package/dist/parser/syntax.js +0 -1
  95. package/dist/parser/types.d.ts +0 -4
  96. package/dist/parser/types.js +17 -32
  97. package/dist/project-modules.js +21 -0
  98. package/dist/reexports.d.ts +4 -0
  99. package/dist/reexports.js +56 -0
  100. package/dist/typescript/importer.d.ts +4 -0
  101. package/dist/typescript/importer.js +27 -3
  102. package/dist/typescript/library.js +5 -2
  103. package/dist/walk.js +12 -0
  104. package/package.json +4 -2
@@ -96,6 +96,10 @@ export class SimpleStatementParser extends ParserBase {
96
96
  // `data, err = try JSON.parse(text)`: the value and the error, as from a call.
97
97
  if (values.length === 1 && value?.kind === 'TryExpression')
98
98
  return;
99
+ if (values.length === 1 && value?.kind === 'ConditionalExpression') {
100
+ this.error('a conditional expression gives one value, not the results of a call: unpack them in the branches of if/else, e.g. if ok { a, err = two() } else { a, err = other() }', start, this.span(start).end);
101
+ return;
102
+ }
99
103
  this.error(`assignment mismatch: ${plural(targets, 'variable')} but ${plural(values.length, 'value')}`, start, this.span(start).end);
100
104
  }
101
105
  /** `delete scores[name]`: removes a field, so the target is one. */
@@ -135,6 +139,49 @@ export class SimpleStatementParser extends ParserBase {
135
139
  end: body.end,
136
140
  };
137
141
  }
142
+ /** `const { name, size: bytes, ...rest } = file`: fields of an object, one level deep. */
143
+ parseDestructuring(start, exported, keyword) {
144
+ const names = [];
145
+ const keys = [];
146
+ let rest = false;
147
+ this.expect('{');
148
+ this.parseList('}', () => {
149
+ if (rest)
150
+ this.fail('...rest is the last name: it gets the other fields');
151
+ if (this.accept('...')) {
152
+ rest = true;
153
+ names.push(this.parseIdentifier('variable name'));
154
+ return;
155
+ }
156
+ const token = this.peek();
157
+ const key = this.check('String') ? this.parseStringLiteral() : this.parsePropertyName();
158
+ if (this.accept(':')) {
159
+ names.push(this.parseIdentifier('variable name'));
160
+ }
161
+ else if (key.kind === 'Identifier' && token.kind === 'Identifier') {
162
+ names.push({ ...key });
163
+ }
164
+ else {
165
+ const shown = token.kind === 'String' ? token.text : `"${token.text}"`;
166
+ this.fail(`${shown} needs a name to take its value, e.g. { ${token.text}: name }`);
167
+ }
168
+ keys.push(key);
169
+ });
170
+ this.expect('=', '"=" and the object: a pattern takes its fields from a value');
171
+ const value = this.parseExpression();
172
+ return {
173
+ kind: 'VariableDeclaration',
174
+ exported,
175
+ keyword,
176
+ isPublic: false,
177
+ names,
178
+ type: null,
179
+ values: [value],
180
+ body: null,
181
+ pattern: { keys, rest },
182
+ ...this.span(start),
183
+ };
184
+ }
138
185
  parseVariableDeclaration(start, exported) {
139
186
  const token = this.next();
140
187
  const keyword = token.kind === 'const'
@@ -142,6 +189,9 @@ export class SimpleStatementParser extends ParserBase {
142
189
  : token.text === 'state' || token.text === 'derived' || token.text === 'ref'
143
190
  ? token.text
144
191
  : 'let';
192
+ if (this.check('{') && (keyword === 'const' || keyword === 'let')) {
193
+ return this.parseDestructuring(start, exported, keyword);
194
+ }
145
195
  const names = [this.parseIdentifier('variable name')];
146
196
  while (this.accept(','))
147
197
  names.push(this.parseIdentifier('variable name'));
@@ -158,14 +158,15 @@ export class StatementParser extends SimpleStatementParser {
158
158
  return this.parseDecorated(start, exported);
159
159
  case 'interface':
160
160
  return this.parseInterface(start, exported);
161
- case 'type': {
162
- const declaration = this.parseTypeAlias(start, exported);
163
- this.endStatement();
164
- return declaration;
165
- }
166
161
  default: {
167
162
  if (this.isDecoratorDeclaration())
168
163
  return this.parseDecoratorDeclaration(start, exported);
164
+ // `type` is a keyword only before the name of a type: `const type = blob.type` is a name.
165
+ if (this.checkWord('type') && this.peek(1).kind === 'Identifier') {
166
+ const declaration = this.parseTypeAlias(start, exported);
167
+ this.endStatement();
168
+ return declaration;
169
+ }
169
170
  // `data` and `abstract` are keywords only before `class`: elsewhere they are names.
170
171
  let words = this.checkWord('abstract') ? 1 : 0;
171
172
  if (this.peek(words).text === 'data')
@@ -178,8 +179,9 @@ export class StatementParser extends SimpleStatementParser {
178
179
  }
179
180
  /** A statement ends with a newline or `;`, or right before the `}` that closes its block. */
180
181
  endStatement() {
181
- if (this.accept(';') || this.check('}') || this.check('EOF'))
182
+ if (this.accept(';') || this.check('}') || this.check('EOF') || this.afterTypeArguments()) {
182
183
  return;
184
+ }
183
185
  const token = this.peek();
184
186
  if (token.kind === '++' || token.kind === '--') {
185
187
  this.fail(`"${token.kind}" is a statement and cannot be used inside an expression`);
@@ -83,7 +83,6 @@ export const STATEMENT_KEYWORDS = new Set([
83
83
  'const',
84
84
  'class',
85
85
  'interface',
86
- 'type',
87
86
  'return',
88
87
  'if',
89
88
  'for',
@@ -13,10 +13,6 @@ export declare abstract class TypeParser extends ClassParser {
13
13
  * names, which only document them.
14
14
  */
15
15
  protected parseParenthesizedType(): ast.TypeNode;
16
- /** The type of a parameter of a function type, after its name if it has one, kept in `names`. */
17
- private parseParamType;
18
- /** `paths []string` in `(paths []string) => Shape`: a name before the type of a parameter. */
19
- private startsNamedParam;
20
16
  /** `{ name string; x, y number; area() number }`, separated by newlines, `;` or `,`. */
21
17
  protected parseTypeMembers(): ast.TypeMember[];
22
18
  protected parseTypeMember(): ast.TypeMember[];
@@ -78,9 +78,17 @@ export class TypeParser extends ClassParser {
78
78
  this.next();
79
79
  this.expect('(');
80
80
  const names = [];
81
- const params = this.parseList(')', () => this.parseParamType(names));
81
+ const params = this.groupParams(this.parseList(')', () => this.parseParamType(names)), names);
82
+ const rest = this.restOf(params, names);
82
83
  const results = this.parseResults();
83
- return { kind: 'FuncType', params, results, ...iterator(names), ...this.span(start) };
84
+ return {
85
+ kind: 'FuncType',
86
+ params,
87
+ ...(rest ? { rest } : {}),
88
+ results,
89
+ ...iterator(names),
90
+ ...this.span(start),
91
+ };
84
92
  }
85
93
  // `chan T`, `chan<- T` that only sends, `<-chan T` that only receives.
86
94
  case 'chan': {
@@ -133,7 +141,7 @@ export class TypeParser extends ClassParser {
133
141
  parseParenthesizedType() {
134
142
  const start = this.next().start;
135
143
  const names = [];
136
- const params = this.parseList(')', () => this.parseParamType(names));
144
+ const params = this.groupParams(this.parseList(')', () => this.parseParamType(names)), names);
137
145
  if (this.accept('=>')) {
138
146
  const result = this.parseType();
139
147
  const voids = result.kind === 'TypeReference' && result.name.name === 'void';
@@ -156,39 +164,16 @@ export class TypeParser extends ClassParser {
156
164
  end: start,
157
165
  });
158
166
  }
159
- /** The type of a parameter of a function type, after its name if it has one, kept in `names`. */
160
- parseParamType(names) {
161
- names.push(this.check('Identifier') && this.startsNamedParam() ? this.next().text : '');
162
- return this.parseType();
163
- }
164
- /** `paths []string` in `(paths []string) => Shape`: a name before the type of a parameter. */
165
- startsNamedParam() {
166
- const next = this.peek(1);
167
- switch (next.kind) {
168
- case 'Identifier':
169
- case '?':
170
- case '{':
171
- case '(':
172
- case 'func':
173
- case 'chan':
174
- case '<-':
175
- case 'String':
176
- case 'Number':
177
- return true;
178
- // `x []number` is named.
179
- case '[':
180
- return this.peek(2).kind === ']';
181
- default:
182
- return false;
183
- }
184
- }
185
167
  /** `{ name string; x, y number; area() number }`, separated by newlines, `;` or `,`. */
186
168
  parseTypeMembers() {
187
169
  this.expect('{');
188
170
  const members = [];
189
171
  this.parseSeparated(() => this.check('}'), () => {
190
172
  members.push(...this.parseTypeMember());
191
- if (!this.accept(',') && !this.accept(';') && !this.check('}')) {
173
+ if (!this.accept(',') &&
174
+ !this.accept(';') &&
175
+ !this.check('}') &&
176
+ !this.afterTypeArguments()) {
192
177
  this.fail(`expected newline, ";" or "}" after member, found ${describe(this.peek())}`);
193
178
  }
194
179
  });
@@ -210,8 +195,8 @@ export class TypeParser extends ClassParser {
210
195
  }
211
196
  const name = this.parsePropertyName('member name');
212
197
  if (this.check('(')) {
213
- const params = this.parseParams(false);
214
- const results = this.parseResults();
198
+ const params = this.parseParams(false, { rest: 'typed' });
199
+ const results = this.parseResults(true);
215
200
  return [{ kind: 'MethodSignature', name, params, results, ...this.span(start) }];
216
201
  }
217
202
  // `x, y number` declares several properties of the same type.
@@ -7,6 +7,8 @@ const SKIPPED = new Set(['node_modules', 'dist', 'build', 'out', 'coverage']);
7
7
  /** A bound on the files read, for a file opened in a directory as big as the home directory. */
8
8
  const MAX_FILES = 5000;
9
9
  const parsed = new Map();
10
+ /** The modules being read, for `export ... from` that go round in a cycle. */
11
+ const reading = new Set();
10
12
  /** The names exported by the other `.rk` modules of the package of `filename`. */
11
13
  export function projectExports(filename) {
12
14
  const self = resolve(filename);
@@ -69,7 +71,10 @@ function exportsOf(path) {
69
71
  const cached = parsed.get(path);
70
72
  if (cached?.version === version)
71
73
  return cached.names;
74
+ if (reading.has(path))
75
+ return [];
72
76
  let names;
77
+ reading.add(path);
73
78
  try {
74
79
  const { program } = parse(readFileSync(path, 'utf8'), { markup: markupFor(path) });
75
80
  names = program.body.flatMap((statement) => exported(statement, path));
@@ -77,11 +82,16 @@ function exportsOf(path) {
77
82
  catch {
78
83
  names = [];
79
84
  }
85
+ finally {
86
+ reading.delete(path);
87
+ }
80
88
  parsed.set(path, { version, names });
81
89
  return names;
82
90
  }
83
91
  function exported(statement, path) {
84
92
  const name = (node, kind, spaces) => ({ name: node.name, kind, spaces, path });
93
+ if (statement.kind === 'ExportFromDeclaration')
94
+ return reexported(statement, path);
85
95
  if (!('exported' in statement) || !statement.exported)
86
96
  return [];
87
97
  switch (statement.kind) {
@@ -104,3 +114,14 @@ function exported(statement, path) {
104
114
  return [];
105
115
  }
106
116
  }
117
+ /** `export { Rows } from "./rows.rk"`: the names of that module, as this one exports them. */
118
+ function reexported(statement, path) {
119
+ if (!statement.source.value.endsWith('.rk'))
120
+ return [];
121
+ const names = exportsOf(resolve(dirname(path), statement.source.value));
122
+ if (!statement.specifiers)
123
+ return names.map((each) => ({ ...each, path }));
124
+ return statement.specifiers.flatMap(({ imported, local }) => names
125
+ .filter((each) => each.name === imported.name)
126
+ .map((each) => ({ ...each, name: local.name, path })));
127
+ }
@@ -0,0 +1,4 @@
1
+ import type * as ast from './ast.ts';
2
+ import type { ImportResult } from './checker/checker.ts';
3
+ /** The JS names that each `export { ... } from` passes on, `name` or `name as other`. */
4
+ export declare function reexportedNames(program: ast.Program, importModule: ((specifier: string) => ImportResult) | undefined): Map<ast.ExportFromDeclaration, string[]>;
@@ -0,0 +1,56 @@
1
+ import { packageExports } from "./codegen/imported.js";
2
+ import { listenersName } from "./codegen/shared.js";
3
+ import { decoratedName } from "./decorators.js";
4
+ // `export { Rows } from "./rows.rk"` in JS: a component or a decorator goes with the hidden names
5
+ // that the modules using it import from where they import it (codegen/imported.ts), and state with
6
+ // its listeners. `export *` passes them all on by itself.
7
+ /** The JS names that each `export { ... } from` passes on, `name` or `name as other`. */
8
+ export function reexportedNames(program, importModule) {
9
+ const found = new Map();
10
+ for (const statement of program.body) {
11
+ if (statement.kind !== 'ExportFromDeclaration' || !statement.specifiers)
12
+ continue;
13
+ const result = statement.source.value.endsWith('.rk')
14
+ ? importModule?.(statement.source.value)
15
+ : undefined;
16
+ const exports = result && 'exports' in result ? result.exports : undefined;
17
+ const names = [];
18
+ const add = (name, as = name) => names.push(name === as ? name : `${name} as ${as}`);
19
+ for (const { imported, local } of statement.specifiers) {
20
+ const name = imported.name;
21
+ // Without the types of the module, the name is passed on as it is written.
22
+ if (!exports) {
23
+ add(name, local.name);
24
+ continue;
25
+ }
26
+ const component = exports.components?.get(name);
27
+ const decorator = exports.decorators?.get(name);
28
+ if (exports.values.has(name))
29
+ add(name, local.name);
30
+ if (exports.shared?.has(name))
31
+ add(listenersName(name), listenersName(local.name));
32
+ if (component) {
33
+ add(`$$${name}`);
34
+ for (const hidden of packageNames(name, component.inline))
35
+ add(hidden);
36
+ }
37
+ if (decorator) {
38
+ for (const used of decorator.moduleNames)
39
+ add(decoratedName(name, used));
40
+ for (const hidden of packageNames(name, decorator.inline))
41
+ add(hidden);
42
+ }
43
+ }
44
+ found.set(statement, [...new Set(names)]);
45
+ }
46
+ return found;
47
+ }
48
+ /** The hidden names that inlining the component or decorator `root` imports from its module. */
49
+ function packageNames(root, inline) {
50
+ if (!inline)
51
+ return [];
52
+ return [
53
+ ...packageExports(new Map([[root, inline]]), (name) => name).keys(),
54
+ ...[...inline.functions.keys()].map((other) => `$$${other}`),
55
+ ];
56
+ }
@@ -14,6 +14,8 @@ export declare class DeclarationImporter {
14
14
  private readonly shared;
15
15
  private libraryTypes;
16
16
  private readonly results;
17
+ /** The paths of each tsconfig.json, by its path. */
18
+ private readonly configPaths;
17
19
  /** The exports of the module `specifier` imported from the file `fromFile`. */
18
20
  import(fromFile: string, specifier: string): ImportResult;
19
21
  /**
@@ -23,6 +25,8 @@ export declare class DeclarationImporter {
23
25
  library(fromFile: string): Library | undefined;
24
26
  private loadTypeScript;
25
27
  private resolve;
28
+ /** `paths` of the nearest tsconfig.json, `@/lib/*`, which imports of the file may use. */
29
+ private pathsFor;
26
30
  private addTypeRoots;
27
31
  private options;
28
32
  /**
@@ -1,6 +1,6 @@
1
1
  import { existsSync, readdirSync } from 'node:fs';
2
2
  import { createRequire } from 'node:module';
3
- import { dirname, join } from 'node:path';
3
+ import { dirname, join, resolve } from 'node:path';
4
4
  import { TypeConverter } from "./convert.js";
5
5
  import { LibraryTypes } from "./library.js";
6
6
  // Types of imports that are not `.rk` modules: npm packages, `node:` modules and `.ts` files.
@@ -22,6 +22,8 @@ export class DeclarationImporter {
22
22
  shared = new Map();
23
23
  libraryTypes;
24
24
  results = new Map();
25
+ /** The paths of each tsconfig.json, by its path. */
26
+ configPaths = new Map();
25
27
  /** The exports of the module `specifier` imported from the file `fromFile`. */
26
28
  import(fromFile, specifier) {
27
29
  const key = `${dirname(fromFile)}\0${specifier}`;
@@ -65,7 +67,8 @@ export class DeclarationImporter {
65
67
  }
66
68
  resolve(ts, fromFile, specifier) {
67
69
  this.addTypeRoots(fromFile);
68
- const { resolvedModule } = ts.resolveModuleName(specifier, fromFile, this.options(ts), ts.sys);
70
+ const options = { ...this.options(ts), ...this.pathsFor(ts, fromFile) };
71
+ const { resolvedModule } = ts.resolveModuleName(specifier, fromFile, options, ts.sys);
69
72
  if (resolvedModule) {
70
73
  const file = resolvedModule.resolvedFileName;
71
74
  // A JS file without declarations next to it.
@@ -78,7 +81,9 @@ export class DeclarationImporter {
78
81
  const { program, converter } = this.current(ts);
79
82
  const source = program.getSourceFile(file);
80
83
  const module = source && program.getTypeChecker().getSymbolAtLocation(source);
81
- return module ? { exports: converter.moduleExports(module) } : undefined;
84
+ if (module)
85
+ return { exports: converter.moduleExports(module) };
86
+ // `@types/bun` only refers to `bun-types`, whose `declare module "bun"` declares the module.
82
87
  }
83
88
  // `node:fs`, `fs`: modules declared with `declare module "..."`, as in @types/node.
84
89
  const { program, converter } = this.current(ts);
@@ -89,6 +94,25 @@ export class DeclarationImporter {
89
94
  .find((module) => module.name === name);
90
95
  return ambient ? { exports: converter.moduleExports(ambient) } : undefined;
91
96
  }
97
+ /** `paths` of the nearest tsconfig.json, `@/lib/*`, which imports of the file may use. */
98
+ pathsFor(ts, fromFile) {
99
+ const config = ts.findConfigFile(dirname(fromFile), (path) => ts.sys.fileExists(path));
100
+ if (!config)
101
+ return {};
102
+ let options = this.configPaths.get(config);
103
+ if (!options) {
104
+ const { config: json } = ts.readConfigFile(config, (path) => ts.sys.readFile(path));
105
+ const compilerOptions = json?.compilerOptions;
106
+ options = compilerOptions?.paths
107
+ ? {
108
+ paths: compilerOptions.paths,
109
+ baseUrl: resolve(dirname(config), compilerOptions.baseUrl ?? '.'),
110
+ }
111
+ : {};
112
+ this.configPaths.set(config, options);
113
+ }
114
+ return options;
115
+ }
92
116
  addTypeRoots(fromFile) {
93
117
  for (let directory = dirname(fromFile);; directory = dirname(directory)) {
94
118
  const types = join(directory, 'node_modules', '@types');
@@ -16,8 +16,11 @@ export class LibraryTypes {
16
16
  const lib = program.getSourceFile(ts.getDefaultLibFilePath(program.getCompilerOptions()));
17
17
  if (!lib)
18
18
  return;
19
- for (const symbol of this.checker.getSymbolsInScope(lib, ts.SymbolFlags.Value)) {
20
- this.values.set(symbol.name, symbol);
19
+ // `declare global { export import Bun = BunModule }` of bun-types is an alias of a module.
20
+ for (const symbol of this.checker.getSymbolsInScope(lib, ts.SymbolFlags.Value | ts.SymbolFlags.Alias)) {
21
+ const value = symbol.flags & ts.SymbolFlags.Alias ? this.checker.getAliasedSymbol(symbol) : symbol;
22
+ if (value.flags & ts.SymbolFlags.Value)
23
+ this.values.set(symbol.name, value);
21
24
  }
22
25
  for (const symbol of this.checker.getSymbolsInScope(lib, ts.SymbolFlags.Type)) {
23
26
  this.types.set(symbol.name, symbol);
package/dist/walk.js CHANGED
@@ -14,6 +14,11 @@ export function forEachChild(node, visit) {
14
14
  case 'BlockStatement':
15
15
  each(node.body);
16
16
  break;
17
+ case 'ExportFromDeclaration':
18
+ if (node.specifiers)
19
+ each(node.specifiers);
20
+ visit(node.source);
21
+ break;
17
22
  case 'ImportDeclaration':
18
23
  optional(node.defaultImport);
19
24
  optional(node.namespaceImport);
@@ -182,6 +187,13 @@ export function forEachChild(node, visit) {
182
187
  case 'StyleStatement':
183
188
  each(node.parts);
184
189
  break;
190
+ case 'NonNullExpression':
191
+ visit(node.expression);
192
+ break;
193
+ case 'TaggedTemplateExpression':
194
+ visit(node.tag);
195
+ visit(node.quasi);
196
+ break;
185
197
  case 'TemplateLiteral':
186
198
  node.quasis.forEach((quasi, i) => {
187
199
  visit(quasi);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rooklang",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "A language with JavaScript semantics, Go-style syntax, goroutines on real threads and static types that compiles to readable JavaScript",
5
5
  "keywords": [
6
6
  "rooklang",
@@ -60,7 +60,9 @@
60
60
  },
61
61
  "files": [
62
62
  "dist",
63
- "src/runtime/*.js"
63
+ "src/runtime/*.js",
64
+ "CHANGELOG.md",
65
+ "CHANGELOG.ru.md"
64
66
  ],
65
67
  "scripts": {
66
68
  "rook": "node src/cli.ts",