@velarscript/compiler 0.10.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 (159) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +70 -0
  3. package/dist/analyzer.d.ts +1175 -0
  4. package/dist/analyzer.d.ts.map +1 -0
  5. package/dist/analyzer.js +12130 -0
  6. package/dist/analyzer.js.map +1 -0
  7. package/dist/application-package-host.d.ts +28 -0
  8. package/dist/application-package-host.d.ts.map +1 -0
  9. package/dist/application-package-host.js +2 -0
  10. package/dist/application-package-host.js.map +1 -0
  11. package/dist/ast.d.ts +853 -0
  12. package/dist/ast.d.ts.map +1 -0
  13. package/dist/ast.js +245 -0
  14. package/dist/ast.js.map +1 -0
  15. package/dist/class-runtime.d.ts +6 -0
  16. package/dist/class-runtime.d.ts.map +1 -0
  17. package/dist/class-runtime.js +45 -0
  18. package/dist/class-runtime.js.map +1 -0
  19. package/dist/collection-lowering-runtime.d.ts +7 -0
  20. package/dist/collection-lowering-runtime.d.ts.map +1 -0
  21. package/dist/collection-lowering-runtime.js +952 -0
  22. package/dist/collection-lowering-runtime.js.map +1 -0
  23. package/dist/collection-runtime.d.ts +16 -0
  24. package/dist/collection-runtime.d.ts.map +1 -0
  25. package/dist/collection-runtime.js +231 -0
  26. package/dist/collection-runtime.js.map +1 -0
  27. package/dist/core-vocabulary.d.ts +141 -0
  28. package/dist/core-vocabulary.d.ts.map +1 -0
  29. package/dist/core-vocabulary.js +88 -0
  30. package/dist/core-vocabulary.js.map +1 -0
  31. package/dist/diagnostic.d.ts +42 -0
  32. package/dist/diagnostic.d.ts.map +1 -0
  33. package/dist/diagnostic.js +66 -0
  34. package/dist/diagnostic.js.map +1 -0
  35. package/dist/embedded-javascript.d.ts +74 -0
  36. package/dist/embedded-javascript.d.ts.map +1 -0
  37. package/dist/embedded-javascript.js +341 -0
  38. package/dist/embedded-javascript.js.map +1 -0
  39. package/dist/embedded-module.d.ts +11 -0
  40. package/dist/embedded-module.d.ts.map +1 -0
  41. package/dist/embedded-module.js +67 -0
  42. package/dist/embedded-module.js.map +1 -0
  43. package/dist/embedded-source.d.ts +19 -0
  44. package/dist/embedded-source.d.ts.map +1 -0
  45. package/dist/embedded-source.js +61 -0
  46. package/dist/embedded-source.js.map +1 -0
  47. package/dist/emitter.d.ts +188 -0
  48. package/dist/emitter.d.ts.map +1 -0
  49. package/dist/emitter.js +3254 -0
  50. package/dist/emitter.js.map +1 -0
  51. package/dist/error-runtime.d.ts +17 -0
  52. package/dist/error-runtime.d.ts.map +1 -0
  53. package/dist/error-runtime.js +109 -0
  54. package/dist/error-runtime.js.map +1 -0
  55. package/dist/extension.d.ts +373 -0
  56. package/dist/extension.d.ts.map +1 -0
  57. package/dist/extension.js +25 -0
  58. package/dist/extension.js.map +1 -0
  59. package/dist/formatter.d.ts +13 -0
  60. package/dist/formatter.d.ts.map +1 -0
  61. package/dist/formatter.js +1440 -0
  62. package/dist/formatter.js.map +1 -0
  63. package/dist/framework-host.d.ts +87 -0
  64. package/dist/framework-host.d.ts.map +1 -0
  65. package/dist/framework-host.js +2 -0
  66. package/dist/framework-host.js.map +1 -0
  67. package/dist/index.d.ts +75 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +932 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/interpolated-string.d.ts +47 -0
  72. package/dist/interpolated-string.d.ts.map +1 -0
  73. package/dist/interpolated-string.js +344 -0
  74. package/dist/interpolated-string.js.map +1 -0
  75. package/dist/json-runtime.d.ts +2 -0
  76. package/dist/json-runtime.d.ts.map +1 -0
  77. package/dist/json-runtime.js +193 -0
  78. package/dist/json-runtime.js.map +1 -0
  79. package/dist/language-guidance.d.ts +31 -0
  80. package/dist/language-guidance.d.ts.map +1 -0
  81. package/dist/language-guidance.js +187 -0
  82. package/dist/language-guidance.js.map +1 -0
  83. package/dist/lexer.d.ts +85 -0
  84. package/dist/lexer.d.ts.map +1 -0
  85. package/dist/lexer.js +1004 -0
  86. package/dist/lexer.js.map +1 -0
  87. package/dist/limits.d.ts +2 -0
  88. package/dist/limits.d.ts.map +1 -0
  89. package/dist/limits.js +2 -0
  90. package/dist/limits.js.map +1 -0
  91. package/dist/mechanical-fix.d.ts +26 -0
  92. package/dist/mechanical-fix.d.ts.map +1 -0
  93. package/dist/mechanical-fix.js +61 -0
  94. package/dist/mechanical-fix.js.map +1 -0
  95. package/dist/narrowing-runtime.d.ts +5 -0
  96. package/dist/narrowing-runtime.d.ts.map +1 -0
  97. package/dist/narrowing-runtime.js +27 -0
  98. package/dist/narrowing-runtime.js.map +1 -0
  99. package/dist/number-runtime.d.ts +3 -0
  100. package/dist/number-runtime.d.ts.map +1 -0
  101. package/dist/number-runtime.js +37 -0
  102. package/dist/number-runtime.js.map +1 -0
  103. package/dist/parser.d.ts +245 -0
  104. package/dist/parser.d.ts.map +1 -0
  105. package/dist/parser.js +3582 -0
  106. package/dist/parser.js.map +1 -0
  107. package/dist/primitive-runtime.d.ts +4 -0
  108. package/dist/primitive-runtime.d.ts.map +1 -0
  109. package/dist/primitive-runtime.js +39 -0
  110. package/dist/primitive-runtime.js.map +1 -0
  111. package/dist/promise-runtime.d.ts +6 -0
  112. package/dist/promise-runtime.d.ts.map +1 -0
  113. package/dist/promise-runtime.js +86 -0
  114. package/dist/promise-runtime.js.map +1 -0
  115. package/dist/reactive-bridge-runtime.d.ts +7 -0
  116. package/dist/reactive-bridge-runtime.d.ts.map +1 -0
  117. package/dist/reactive-bridge-runtime.js +112 -0
  118. package/dist/reactive-bridge-runtime.js.map +1 -0
  119. package/dist/runtime-abi.d.ts +24 -0
  120. package/dist/runtime-abi.d.ts.map +1 -0
  121. package/dist/runtime-abi.js +24 -0
  122. package/dist/runtime-abi.js.map +1 -0
  123. package/dist/semantic.d.ts +142 -0
  124. package/dist/semantic.d.ts.map +1 -0
  125. package/dist/semantic.js +845 -0
  126. package/dist/semantic.js.map +1 -0
  127. package/dist/source-names.d.ts +32 -0
  128. package/dist/source-names.d.ts.map +1 -0
  129. package/dist/source-names.js +101 -0
  130. package/dist/source-names.js.map +1 -0
  131. package/dist/source.d.ts +19 -0
  132. package/dist/source.d.ts.map +1 -0
  133. package/dist/source.js +64 -0
  134. package/dist/source.js.map +1 -0
  135. package/dist/text-runtime.d.ts +2 -0
  136. package/dist/text-runtime.d.ts.map +1 -0
  137. package/dist/text-runtime.js +285 -0
  138. package/dist/text-runtime.js.map +1 -0
  139. package/dist/token.d.ts +19 -0
  140. package/dist/token.d.ts.map +1 -0
  141. package/dist/token.js +51 -0
  142. package/dist/token.js.map +1 -0
  143. package/dist/type-registry-runtime.d.ts +7 -0
  144. package/dist/type-registry-runtime.d.ts.map +1 -0
  145. package/dist/type-registry-runtime.js +51 -0
  146. package/dist/type-registry-runtime.js.map +1 -0
  147. package/dist/type-validation-runtime.d.ts +17 -0
  148. package/dist/type-validation-runtime.d.ts.map +1 -0
  149. package/dist/type-validation-runtime.js +150 -0
  150. package/dist/type-validation-runtime.js.map +1 -0
  151. package/dist/types.d.ts +356 -0
  152. package/dist/types.d.ts.map +1 -0
  153. package/dist/types.js +1170 -0
  154. package/dist/types.js.map +1 -0
  155. package/dist/utf8-runtime.d.ts +7 -0
  156. package/dist/utf8-runtime.d.ts.map +1 -0
  157. package/dist/utf8-runtime.js +43 -0
  158. package/dist/utf8-runtime.js.map +1 -0
  159. package/package.json +48 -0
@@ -0,0 +1,845 @@
1
+ import { spanIdentity } from "./source.js";
2
+ import { describeType, formatTypeReference } from "./types.js";
3
+ const MAX_SEMANTIC_MEMBERS = 10_000;
4
+ export function semanticBindingKey(span, name) {
5
+ return `${span.start}:${name}`;
6
+ }
7
+ export function buildSemanticIndex(program, source, bindingTypes = new Map(), bindingMembers = new Map(), expressionTypes = new Map(), expressionMembers = new Map(), expressionOwners = new Map(), objectPropertyOwners = new Map(), bindingEntryOwners = new Map(), jsxAttributeOwners = new Map(), expressionContexts = new Map(), expressionContextMembers = new Map(), semanticExtensions = []) {
8
+ const symbols = [];
9
+ const references = [];
10
+ const memberReferences = [];
11
+ const imports = [];
12
+ const moduleReferences = [];
13
+ const expressions = [];
14
+ const expressionKeys = new Set();
15
+ const rootScope = { id: 0, parentId: null, span: { start: 0, end: source.text.length }, bindings: new Map() };
16
+ const scopes = [rootScope];
17
+ const allScopes = [rootScope];
18
+ const describedMemberCache = new Map();
19
+ const describeMembers = (memberTypes) => {
20
+ const cached = describedMemberCache.get(memberTypes);
21
+ if (cached)
22
+ return cached;
23
+ const described = [...memberTypes].slice(0, MAX_SEMANTIC_MEMBERS).map(([memberName, memberType]) => ({
24
+ name: memberName,
25
+ kind: memberType.kind === "function" || memberType.kind === "intrinsic" || memberType.kind === "action" ? "method" : "field",
26
+ type: describeType(memberType),
27
+ }));
28
+ describedMemberCache.set(memberTypes, described);
29
+ return described;
30
+ };
31
+ const declarations = new WeakMap();
32
+ let extensionContext;
33
+ let nextScopeId = 1;
34
+ const callable = (type) => type?.kind === "function" || type?.kind === "intrinsic" || type?.kind === "action";
35
+ const currentScope = () => scopes.at(-1);
36
+ const enterScope = (scopeSpan) => {
37
+ const scope = { id: nextScopeId++, parentId: currentScope().id, span: scopeSpan, bindings: new Map() };
38
+ scopes.push(scope);
39
+ allScopes.push(scope);
40
+ };
41
+ const exitScope = () => { scopes.pop(); };
42
+ const lookup = (name) => {
43
+ for (let index = scopes.length - 1; index >= 0; index -= 1) {
44
+ const found = scopes[index].bindings.get(name);
45
+ if (found)
46
+ return found;
47
+ }
48
+ return null;
49
+ };
50
+ const declare = (owner, name, kind, declarationSpan, selectionSpan, exported = false, mutable = false, lexical = true, container, explicitType, staticMember = false, options = {}) => {
51
+ const existing = declarations.get(owner);
52
+ if (existing)
53
+ return existing;
54
+ const key = semanticBindingKey(declarationSpan, name);
55
+ const type = bindingTypes.get(key);
56
+ const memberTypes = bindingMembers.get(key) ?? new Map();
57
+ const members = describeMembers(memberTypes);
58
+ const symbol = {
59
+ id: `${source.path}#${selectionSpan.start}:${name}`,
60
+ name,
61
+ kind,
62
+ path: source.path,
63
+ span: declarationSpan,
64
+ selectionSpan,
65
+ scopeId: currentScope().id,
66
+ exported,
67
+ mutable,
68
+ private: options.private ?? false,
69
+ type: explicitType ?? (type ? describeType(type) : null),
70
+ documentation: documentationBefore(source, options.documentationStart ?? declarationSpan.start),
71
+ members,
72
+ ...(callable(type) ? { callable: true } : {}),
73
+ ...(options.typeTarget ? { typeTarget: options.typeTarget } : {}),
74
+ ...(container ? { container } : {}),
75
+ ...(kind === "method" || kind === "field" ? { static: staticMember } : {}),
76
+ ...(options.sourceTypeHint ?? kind === "variable" ? { sourceTypeHint: true } : {}),
77
+ ...(options.presentationKind ? { presentationKind: options.presentationKind } : {}),
78
+ };
79
+ symbols.push(symbol);
80
+ if (lexical)
81
+ currentScope().bindings.set(name, symbol);
82
+ declarations.set(owner, symbol);
83
+ return symbol;
84
+ };
85
+ const reference = (name, valueSpan, write = false, call = false) => {
86
+ references.push({ name, path: source.path, span: valueSpan, symbolId: lookup(name)?.id ?? null, write, ...(call ? { call: true } : {}) });
87
+ };
88
+ const typeSyntaxReferences = (syntax) => {
89
+ switch (syntax.kind) {
90
+ case "NamedTypeSyntax":
91
+ if (lookup(syntax.name))
92
+ reference(syntax.name, syntax.span);
93
+ break;
94
+ case "EnumMemberTypeSyntax":
95
+ if (lookup(syntax.enumName))
96
+ reference(syntax.enumName, syntax.enumNameSpan);
97
+ {
98
+ const owner = lookup(syntax.enumName);
99
+ const bindingType = owner ? bindingTypes.get(semanticBindingKey(owner.span, owner.name)) : null;
100
+ const identity = bindingType?.kind === "enumObject" ? bindingType.identity : syntax.enumName;
101
+ const localMember = owner?.kind === "enum"
102
+ ? symbols.find((symbol) => symbol.kind === "enum-member" && symbol.container === owner.name && symbol.name === syntax.member)
103
+ : null;
104
+ if (localMember) {
105
+ references.push({ name: syntax.member, path: source.path, span: syntax.memberSpan, symbolId: localMember.id, write: false });
106
+ }
107
+ memberReferences.push({
108
+ name: syntax.member,
109
+ path: source.path,
110
+ span: syntax.memberSpan,
111
+ ownerType: syntax.enumName,
112
+ ownerKind: "enum",
113
+ ownerIdentity: identity,
114
+ syntax: "access",
115
+ shorthand: false,
116
+ });
117
+ }
118
+ break;
119
+ case "GenericTypeSyntax":
120
+ if (lookup(syntax.name))
121
+ reference(syntax.name, syntax.nameSpan);
122
+ for (const argument of syntax.arguments)
123
+ typeSyntaxReferences(argument);
124
+ break;
125
+ case "ReadonlyTypeSyntax":
126
+ case "OptionalTypeSyntax":
127
+ typeSyntaxReferences(syntax.inner);
128
+ break;
129
+ case "UnionTypeSyntax":
130
+ for (const member of syntax.members)
131
+ typeSyntaxReferences(member);
132
+ break;
133
+ case "FunctionTypeSyntax":
134
+ for (const parameter of syntax.parameters)
135
+ typeSyntaxReferences(parameter.type);
136
+ typeSyntaxReferences(syntax.result);
137
+ break;
138
+ }
139
+ };
140
+ const typeReferences = (type) => {
141
+ if (type)
142
+ typeSyntaxReferences(type.syntax);
143
+ };
144
+ const nameSpan = (span, name, from = span.start) => findNameSpan(source.text, span, name, from);
145
+ const recordMemberReference = (name, referenceSpan, owner, syntax, shorthand = false) => {
146
+ const extensionOwner = owner.kind === "extension" ? owner : null;
147
+ memberReferences.push({
148
+ name,
149
+ path: source.path,
150
+ span: referenceSpan,
151
+ ownerType: extensionOwner?.nominal ?? ("name" in owner ? owner.name : describeType(owner)),
152
+ ownerKind: owner.kind,
153
+ ...("identity" in owner && owner.identity ? { ownerIdentity: owner.identity } : {}),
154
+ ...(extensionOwner?.nominal
155
+ ? { ownerIdentity: `${extensionOwner.extensionId}:${extensionOwner.family}:${extensionOwner.nominal}` }
156
+ : {}),
157
+ ...(extensionOwner?.metadata?.semanticSymbolKind
158
+ ? { ownerSymbolKind: extensionOwner.metadata.semanticSymbolKind }
159
+ : {}),
160
+ syntax,
161
+ shorthand,
162
+ });
163
+ };
164
+ const moduleSourceSpan = (valueSpan) => valueSpan.end - valueSpan.start >= 2
165
+ ? { start: valueSpan.start + 1, end: valueSpan.end - 1 }
166
+ : valueSpan;
167
+ const declareImport = (statement) => {
168
+ moduleReferences.push({ source: statement.source, span: moduleSourceSpan(statement.sourceSpan), dynamic: false });
169
+ for (const specifier of statement.specifiers) {
170
+ const words = wordSpans(source.text, specifier.span);
171
+ const importedSpan = specifier.namespace
172
+ ? words[0] ?? specifier.span
173
+ : words.find((word) => source.text.slice(word.start, word.end) === specifier.imported) ?? words[0] ?? specifier.span;
174
+ const localSpan = [...words].reverse().find((word) => source.text.slice(word.start, word.end) === specifier.local) ?? importedSpan;
175
+ const symbol = declare(specifier, specifier.local, "import", specifier.span, localSpan);
176
+ imports.push({
177
+ source: statement.source,
178
+ imported: specifier.imported,
179
+ importedSpan,
180
+ local: specifier.local,
181
+ localSpan,
182
+ localSymbolId: symbol.id,
183
+ namespace: specifier.namespace,
184
+ });
185
+ }
186
+ };
187
+ const declareReExport = (statement) => {
188
+ moduleReferences.push({ source: statement.source, span: moduleSourceSpan(statement.sourceSpan), dynamic: false });
189
+ for (const specifier of statement.specifiers) {
190
+ const words = wordSpans(source.text, specifier.span);
191
+ const importedSpan = words.find((word) => source.text.slice(word.start, word.end) === specifier.imported) ?? words[0] ?? specifier.span;
192
+ const exportedSpan = [...words].reverse().find((word) => source.text.slice(word.start, word.end) === specifier.exported) ?? importedSpan;
193
+ // A re-export is not a lexical binding: the exported alias is visible to
194
+ // importers only, so the symbol stays out of the module scope chain.
195
+ const symbol = declare(specifier, specifier.exported, "import", specifier.span, exportedSpan, true, false, false);
196
+ imports.push({
197
+ source: statement.source,
198
+ imported: specifier.imported,
199
+ importedSpan,
200
+ local: specifier.exported,
201
+ localSpan: exportedSpan,
202
+ localSymbolId: symbol.id,
203
+ namespace: false,
204
+ });
205
+ }
206
+ };
207
+ const predeclareTopLevel = () => {
208
+ for (const statement of program.body) {
209
+ switch (statement.kind) {
210
+ case "ImportDeclaration":
211
+ declareImport(statement);
212
+ break;
213
+ case "ReExportDeclaration":
214
+ declareReExport(statement);
215
+ break;
216
+ case "TypeDeclaration":
217
+ declare(statement, statement.name, "type", statement.span, nameSpan(statement.span, statement.name), statement.exported);
218
+ break;
219
+ case "TypeAliasDeclaration":
220
+ declare(statement, statement.name, "type", statement.span, nameSpan(statement.span, statement.name), statement.exported, false, true, undefined, formatTypeReference(statement.target), false, { ...(statement.target.syntax.kind === "NamedTypeSyntax" ? { typeTarget: statement.target.syntax.name } : {}) });
221
+ break;
222
+ case "EnumDeclaration": {
223
+ declare(statement, statement.name, "enum", statement.span, nameSpan(statement.span, statement.name), statement.exported);
224
+ for (const member of statement.members) {
225
+ declare(member, member.name, "enum-member", member.span, member.span, false, false, false, statement.name, `${statement.name}.${member.name}`);
226
+ }
227
+ break;
228
+ }
229
+ case "ClassDeclaration":
230
+ declare(statement, statement.name, "class", statement.span, nameSpan(statement.span, statement.name), statement.exported);
231
+ break;
232
+ case "FunctionDeclaration":
233
+ declare(statement, statement.name, "function", statement.span, nameSpan(statement.span, statement.name), statement.exported);
234
+ break;
235
+ default:
236
+ for (const extension of semanticExtensions)
237
+ if (extension.predeclare?.(statement, extensionContext))
238
+ break;
239
+ break;
240
+ }
241
+ }
242
+ };
243
+ const visitPattern = (pattern, kind, declarationSpan, mutable, exported, documentationStart) => {
244
+ if (pattern.kind === "NameBindingPattern") {
245
+ declare(pattern, pattern.name, kind, declarationSpan.start === pattern.span.start ? pattern.span : declarationSpan, pattern.span, exported, mutable, true, undefined, undefined, false, { ...(documentationStart === undefined ? {} : { documentationStart }) });
246
+ }
247
+ else if (pattern.kind === "ListBindingPattern") {
248
+ for (const element of pattern.elements)
249
+ if (element)
250
+ visitPattern(element, kind, element.span, mutable, exported, documentationStart);
251
+ if (pattern.rest)
252
+ visitPattern(pattern.rest, kind, pattern.rest.span, mutable, exported, documentationStart);
253
+ }
254
+ else {
255
+ for (const entry of pattern.entries) {
256
+ const owner = bindingEntryOwners.get(`${entry.span.start}:${entry.property}`);
257
+ if (owner) {
258
+ const shorthand = entry.pattern.kind === "NameBindingPattern"
259
+ && entry.pattern.name === entry.property
260
+ && entry.pattern.span.start === entry.span.start;
261
+ recordMemberReference(entry.property, nameSpan(entry.span, entry.property), owner, "binding-key", shorthand);
262
+ }
263
+ visitPattern(entry.pattern, kind, entry.pattern.span, mutable, exported, documentationStart);
264
+ }
265
+ if (pattern.rest)
266
+ visitPattern(pattern.rest, kind, pattern.rest.span, mutable, exported, documentationStart);
267
+ }
268
+ };
269
+ const visitMatchPattern = (pattern) => {
270
+ switch (pattern.kind) {
271
+ case "MatchValuePattern":
272
+ for (const value of pattern.values)
273
+ visitExpression(value);
274
+ break;
275
+ case "MatchTypePattern":
276
+ typeReferences(pattern.type);
277
+ break;
278
+ case "MatchWildcardPattern":
279
+ break;
280
+ case "MatchCapturePattern":
281
+ if (pattern.binding.name !== "_") {
282
+ declare(pattern.binding, pattern.binding.name, "variable", pattern.binding.span, pattern.binding.span);
283
+ }
284
+ break;
285
+ case "MatchAsPattern":
286
+ visitMatchPattern(pattern.pattern);
287
+ if (pattern.binding.name !== "_") {
288
+ declare(pattern.binding, pattern.binding.name, "variable", pattern.binding.span, pattern.binding.span);
289
+ }
290
+ break;
291
+ case "MatchListPattern":
292
+ for (const element of pattern.elements)
293
+ visitMatchPattern(element);
294
+ if (pattern.rest && pattern.rest.name !== "_") {
295
+ declare(pattern.rest, pattern.rest.name, "variable", pattern.rest.span, pattern.rest.span);
296
+ }
297
+ break;
298
+ case "MatchObjectPattern":
299
+ for (const entry of pattern.entries) {
300
+ const owner = bindingEntryOwners.get(`${entry.span.start}:${entry.property}`);
301
+ if (owner) {
302
+ const shorthand = entry.pattern.kind === "MatchCapturePattern"
303
+ && entry.pattern.binding.name === entry.property
304
+ && entry.pattern.span.start === entry.span.start;
305
+ recordMemberReference(entry.property, nameSpan(entry.span, entry.property), owner, "binding-key", shorthand);
306
+ }
307
+ visitMatchPattern(entry.pattern);
308
+ }
309
+ if (pattern.rest && pattern.rest.name !== "_") {
310
+ declare(pattern.rest, pattern.rest.name, "variable", pattern.rest.span, pattern.rest.span);
311
+ }
312
+ break;
313
+ }
314
+ };
315
+ const visitExpression = (expression, write = false) => {
316
+ const expressionKey = spanIdentity(expression.span);
317
+ const expressionType = expressionTypes.get(expressionKey);
318
+ const expressionOwner = expressionOwners.get(expressionKey);
319
+ const expressionContext = expressionContexts.get(expressionKey);
320
+ const describedContextMembers = expressionContext
321
+ ? describeMembers(expressionContextMembers.get(expressionKey) ?? new Map())
322
+ : [];
323
+ const describedExpressionMembers = describeMembers(expressionMembers.get(expressionKey) ?? new Map());
324
+ const callableExpression = callable(expressionType);
325
+ const indexableExpression = (expression.kind !== "IdentifierExpression" || expressionType !== undefined)
326
+ && expression.kind !== "LiteralExpression" && expression.kind !== "SuperExpression";
327
+ if (expressionType && indexableExpression
328
+ && (describedExpressionMembers.length > 0 || callableExpression || expression.kind === "MemberExpression" || expressionContext)
329
+ && !expressionKeys.has(expressionKey)) {
330
+ expressionKeys.add(expressionKey);
331
+ expressions.push({
332
+ span: expression.span,
333
+ type: describeType(expressionType),
334
+ members: describedExpressionMembers,
335
+ ...(callableExpression ? { callable: true } : {}),
336
+ ...(expressionContext ? { contextType: describeType(expressionContext), contextMembers: describedContextMembers } : {}),
337
+ ...(expression.kind === "MemberExpression" ? {
338
+ memberName: expression.property,
339
+ selectionSpan: { start: expression.span.end - expression.property.length, end: expression.span.end },
340
+ ...(expressionOwner ? {
341
+ ownerType: expressionOwner.kind === "extension" && expressionOwner.nominal
342
+ ? expressionOwner.nominal
343
+ : describeType(expressionOwner),
344
+ ownerKind: expressionOwner.kind,
345
+ ...(expressionOwner.kind === "extension" && expressionOwner.metadata?.semanticSymbolKind
346
+ ? { ownerSymbolKind: expressionOwner.metadata.semanticSymbolKind }
347
+ : {}),
348
+ ...(expressionOwner.kind === "extension" && expressionOwner.nominal
349
+ ? { ownerIdentity: `${expressionOwner.extensionId}:${expressionOwner.family}:${expressionOwner.nominal}` }
350
+ : {}),
351
+ } : {}),
352
+ } : {}),
353
+ });
354
+ }
355
+ for (const extension of semanticExtensions)
356
+ if (extension.visitExpression?.(expression, extensionContext))
357
+ return;
358
+ switch (expression.kind) {
359
+ case "IdentifierExpression":
360
+ reference(expression.name, expression.span, write);
361
+ break;
362
+ case "SuperExpression": break;
363
+ case "DynamicImportExpression":
364
+ moduleReferences.push({ source: expression.source, span: moduleSourceSpan(expression.sourceSpan), dynamic: true });
365
+ break;
366
+ case "FStringExpression":
367
+ for (const part of expression.parts)
368
+ if (part.kind === "expression")
369
+ visitExpression(part.value);
370
+ break;
371
+ case "ListExpression":
372
+ for (const element of expression.elements)
373
+ visitExpression(element);
374
+ break;
375
+ case "ObjectExpression":
376
+ for (const property of expression.properties) {
377
+ if (property.kind === "ObjectProperty") {
378
+ const owner = objectPropertyOwners.get(`${property.span.start}:${property.name}`);
379
+ if (owner) {
380
+ const shorthand = property.value.kind === "IdentifierExpression"
381
+ && property.value.name === property.name
382
+ && property.value.span.start === property.span.start;
383
+ recordMemberReference(property.name, nameSpan(property.span, property.name), owner, "object-key", shorthand);
384
+ }
385
+ }
386
+ visitExpression(property.value);
387
+ }
388
+ break;
389
+ case "SpreadExpression":
390
+ visitExpression(expression.value);
391
+ break;
392
+ case "UnaryExpression":
393
+ visitExpression(expression.operand);
394
+ break;
395
+ case "TryExpression":
396
+ visitExpression(expression.value);
397
+ break;
398
+ case "BinaryExpression":
399
+ visitExpression(expression.left);
400
+ visitExpression(expression.right);
401
+ break;
402
+ case "AssignmentExpression":
403
+ visitExpression(expression.target);
404
+ visitExpression(expression.value);
405
+ break;
406
+ case "ComparisonChainExpression":
407
+ for (const operand of expression.operands)
408
+ visitExpression(operand);
409
+ break;
410
+ case "ConditionalExpression":
411
+ visitExpression(expression.condition);
412
+ visitExpression(expression.thenValue);
413
+ visitExpression(expression.elseValue);
414
+ break;
415
+ case "IsExpression":
416
+ visitExpression(expression.value);
417
+ typeReferences(expression.type);
418
+ break;
419
+ case "ArrowFunctionExpression":
420
+ enterScope(expression.span);
421
+ for (const parameter of expression.parameters) {
422
+ if (parameter.defaultValue)
423
+ visitExpression(parameter.defaultValue);
424
+ typeReferences(parameter.type);
425
+ declare(parameter, parameter.name, "parameter", parameter.span, { start: parameter.span.start, end: parameter.span.start + parameter.name.length });
426
+ }
427
+ visitExpression(expression.body);
428
+ exitScope();
429
+ break;
430
+ case "CallExpression":
431
+ if (expression.callee.kind === "IdentifierExpression")
432
+ reference(expression.callee.name, expression.callee.span, false, true);
433
+ else
434
+ visitExpression(expression.callee);
435
+ for (const argument of expression.arguments)
436
+ visitExpression(argument);
437
+ break;
438
+ case "MemberExpression": {
439
+ if (expressionOwner) {
440
+ recordMemberReference(expression.property, { start: expression.span.end - expression.property.length, end: expression.span.end }, expressionOwner, "access");
441
+ }
442
+ visitExpression(expression.object);
443
+ if (expression.object.kind === "IdentifierExpression") {
444
+ const owner = lookup(expression.object.name);
445
+ const member = owner?.kind === "enum"
446
+ ? symbols.find((symbol) => symbol.kind === "enum-member" && symbol.container === owner.name && symbol.name === expression.property)
447
+ : null;
448
+ if (member) {
449
+ const end = expression.span.end;
450
+ references.push({ name: expression.property, path: source.path, span: { start: end - expression.property.length, end }, symbolId: member.id, write: false });
451
+ }
452
+ }
453
+ break;
454
+ }
455
+ case "IndexExpression":
456
+ visitExpression(expression.object);
457
+ visitExpression(expression.index);
458
+ break;
459
+ case "LiteralExpression": break;
460
+ }
461
+ };
462
+ const visitFunction = (statement, method = false, container, memberKind = "method", explicitType) => {
463
+ if (method)
464
+ declare(statement, statement.name, memberKind, statement.span, nameSpan(statement.span, statement.name), false, false, false, container, explicitType, "static" in statement && statement.static === true, { ...("private" in statement && statement.private ? { private: true } : {}) });
465
+ enterScope(statement.span);
466
+ for (const parameter of statement.parameters) {
467
+ if (parameter.defaultValue)
468
+ visitExpression(parameter.defaultValue);
469
+ typeReferences(parameter.type);
470
+ declare(parameter, parameter.name, "parameter", parameter.span, { start: parameter.span.start, end: parameter.span.start + parameter.name.length });
471
+ }
472
+ typeReferences(statement.returnType);
473
+ for (const child of statement.body)
474
+ visitStatement(child);
475
+ exitScope();
476
+ };
477
+ const visitBlock = (body, fallbackSpan) => {
478
+ const scopeSpan = body.length > 0
479
+ ? { start: body[0].span.start, end: body.at(-1).span.end }
480
+ : fallbackSpan;
481
+ enterScope(scopeSpan);
482
+ for (const child of body)
483
+ visitStatement(child);
484
+ exitScope();
485
+ };
486
+ const visitStatement = (statement) => {
487
+ for (const extension of semanticExtensions)
488
+ if (extension.visitStatement?.(statement, extensionContext))
489
+ return;
490
+ switch (statement.kind) {
491
+ case "ImportDeclaration": break;
492
+ case "ReExportDeclaration": break;
493
+ case "EmbeddedJavaScriptDeclaration":
494
+ for (const capture of statement.captures) {
495
+ typeReferences(capture.type);
496
+ reference(capture.name, capture.nameSpan);
497
+ }
498
+ break;
499
+ case "ExternModuleDeclaration":
500
+ for (const declaration of statement.functions) {
501
+ const selection = nameSpan(declaration.span, declaration.name);
502
+ declare(declaration, declaration.name, "function", declaration.span, selection, true, false, false);
503
+ for (const parameter of declaration.parameters)
504
+ typeReferences(parameter.type);
505
+ typeReferences(declaration.returnType);
506
+ }
507
+ for (const declaration of statement.constants) {
508
+ const selection = nameSpan(declaration.span, declaration.name);
509
+ declare(declaration, declaration.name, "variable", declaration.span, selection, true, false, true, undefined, formatTypeReference(declaration.type));
510
+ typeReferences(declaration.type);
511
+ }
512
+ for (const declaration of statement.classes) {
513
+ declare(declaration, declaration.name, "class", declaration.span, nameSpan(declaration.span, declaration.name), true);
514
+ for (const parameter of declaration.parameters) {
515
+ if (parameter.binding) {
516
+ declare(parameter, parameter.name, "field", parameter.span, nameSpan(parameter.span, parameter.name), false, parameter.binding === "let", false, declaration.name);
517
+ }
518
+ typeReferences(parameter.type);
519
+ }
520
+ for (const field of declaration.fields) {
521
+ declare(field, field.name, "field", field.span, nameSpan(field.span, field.name), false, field.mutable, false, declaration.name, undefined, field.static);
522
+ typeReferences(field.type);
523
+ }
524
+ for (const getter of declaration.getters) {
525
+ declare(getter, getter.name, "field", getter.span, nameSpan(getter.span, getter.name), false, false, false, declaration.name, formatTypeReference(getter.type), getter.static);
526
+ typeReferences(getter.type);
527
+ }
528
+ for (const method of declaration.methods) {
529
+ declare(method, method.name, "method", method.span, nameSpan(method.span, method.name), false, false, false, declaration.name);
530
+ for (const parameter of method.parameters)
531
+ typeReferences(parameter.type);
532
+ typeReferences(method.returnType);
533
+ }
534
+ }
535
+ break;
536
+ case "TypeDeclaration":
537
+ for (const field of statement.fields) {
538
+ const selection = nameSpan(field.span, field.name);
539
+ declare(field, field.name, "field", field.span, selection, false, false, false, statement.name);
540
+ typeReferences(field.type);
541
+ }
542
+ break;
543
+ case "TypeAliasDeclaration":
544
+ typeReferences(statement.target);
545
+ break;
546
+ case "EnumDeclaration":
547
+ break;
548
+ case "ClassDeclaration":
549
+ if (statement.base) {
550
+ reference(statement.base.name, { start: statement.base.span.start, end: statement.base.span.start + statement.base.name.length });
551
+ }
552
+ enterScope(statement.span);
553
+ for (const parameter of statement.parameters) {
554
+ if (parameter.defaultValue)
555
+ visitExpression(parameter.defaultValue);
556
+ typeReferences(parameter.type);
557
+ const selection = { start: parameter.span.start, end: parameter.span.start + parameter.name.length };
558
+ const symbol = parameter.binding
559
+ ? declare(parameter, parameter.name, "field", parameter.span, selection, false, parameter.binding === "let", false, statement.name, undefined, false, { ...(parameter.private ? { private: true } : {}) })
560
+ : declare(parameter, parameter.name, "parameter", parameter.span, selection);
561
+ currentScope().bindings.set(parameter.name, symbol);
562
+ }
563
+ if (statement.base)
564
+ for (const argument of statement.base.arguments)
565
+ visitExpression(argument);
566
+ for (const field of statement.fields) {
567
+ declare(field, field.name, "field", field.span, nameSpan(field.span, field.name), false, field.binding === "let", false, statement.name, formatTypeReference(field.type), field.static, { ...(field.private ? { private: true } : {}) });
568
+ typeReferences(field.type);
569
+ if (!field.static && field.initializer)
570
+ visitExpression(field.initializer);
571
+ }
572
+ if (statement.initialization)
573
+ visitBlock(statement.initialization.body, statement.initialization.span);
574
+ if (statement.dispose)
575
+ visitBlock(statement.dispose.body, statement.dispose.span);
576
+ if (statement.iterate)
577
+ visitBlock(statement.iterate.body, statement.iterate.span);
578
+ exitScope();
579
+ for (const field of statement.fields)
580
+ if (field.static && field.initializer)
581
+ visitExpression(field.initializer);
582
+ for (const getter of statement.getters)
583
+ visitFunction(getter, true, statement.name, "field", getter.returnType ? formatTypeReference(getter.returnType) : undefined);
584
+ for (const method of statement.methods)
585
+ visitFunction(method, true, statement.name);
586
+ break;
587
+ case "VariableDeclaration":
588
+ visitExpression(statement.initializer);
589
+ typeReferences(statement.type);
590
+ visitPattern(statement.pattern, "variable", statement.pattern.span, statement.binding === "let", statement.exported, statement.span.start);
591
+ break;
592
+ case "TestDeclaration":
593
+ // A test body is an ordinary block for navigation and rename.
594
+ visitBlock(statement.body, statement.span);
595
+ break;
596
+ case "UsingDeclaration":
597
+ // D43 item 69: an owned resource is an ordinary immutable binding as
598
+ // far as navigation and rename are concerned.
599
+ visitExpression(statement.initializer);
600
+ declare(statement, statement.name, "variable", statement.span, statement.nameSpan, false);
601
+ break;
602
+ case "FunctionDeclaration":
603
+ if (!declarations.has(statement))
604
+ declare(statement, statement.name, "function", statement.span, nameSpan(statement.span, statement.name), statement.exported);
605
+ visitFunction(statement);
606
+ break;
607
+ case "ReturnStatement":
608
+ if (statement.value)
609
+ visitExpression(statement.value);
610
+ break;
611
+ case "ThrowStatement":
612
+ visitExpression(statement.value);
613
+ break;
614
+ case "AssertStatement":
615
+ visitExpression(statement.condition);
616
+ if (statement.message)
617
+ visitExpression(statement.message);
618
+ break;
619
+ case "IfStatement":
620
+ visitExpression(statement.condition);
621
+ visitBlock(statement.thenBody, statement.span);
622
+ if (statement.elseBody)
623
+ visitBlock(statement.elseBody, statement.span);
624
+ break;
625
+ case "MatchStatement":
626
+ visitExpression(statement.value);
627
+ for (const branch of statement.cases) {
628
+ enterScope(branch.span);
629
+ visitMatchPattern(branch.pattern);
630
+ if (branch.guard)
631
+ visitExpression(branch.guard);
632
+ for (const child of branch.body)
633
+ visitStatement(child);
634
+ exitScope();
635
+ }
636
+ break;
637
+ case "ForStatement":
638
+ visitExpression(statement.iterable);
639
+ enterScope(statement.span);
640
+ visitPattern(statement.pattern, "variable", statement.pattern.span, false, false);
641
+ if (statement.secondPattern)
642
+ visitPattern(statement.secondPattern, "variable", statement.secondPattern.span, false, false);
643
+ for (const child of statement.body)
644
+ visitStatement(child);
645
+ exitScope();
646
+ break;
647
+ case "WhileStatement":
648
+ visitExpression(statement.condition);
649
+ visitBlock(statement.body, statement.span);
650
+ break;
651
+ case "TryStatement":
652
+ visitBlock(statement.tryBody, statement.span);
653
+ if (statement.catchBody) {
654
+ const catchSpan = statement.catchBody.length > 0
655
+ ? { start: statement.catchBody[0].span.start, end: statement.catchBody.at(-1).span.end }
656
+ : statement.span;
657
+ enterScope(catchSpan);
658
+ if (statement.catchName) {
659
+ const selection = nameSpan(statement.span, statement.catchName, statement.tryBody.at(-1)?.span.end ?? statement.span.start);
660
+ declare({ statement, role: "catch" }, statement.catchName, "catch", statement.span, selection);
661
+ }
662
+ for (const child of statement.catchBody)
663
+ visitStatement(child);
664
+ exitScope();
665
+ }
666
+ if (statement.finallyBody)
667
+ visitBlock(statement.finallyBody, statement.span);
668
+ break;
669
+ case "AssignmentStatement":
670
+ visitExpression(statement.target, true);
671
+ visitExpression(statement.value);
672
+ break;
673
+ case "ExpressionStatement":
674
+ visitExpression(statement.expression);
675
+ break;
676
+ case "AsyncStatement":
677
+ visitExpression(statement.expression);
678
+ break;
679
+ case "BreakStatement":
680
+ case "ContinueStatement":
681
+ case "PassStatement": break;
682
+ }
683
+ };
684
+ extensionContext = {
685
+ declare(owner, name, kind, declarationSpan, selectionSpan, options = {}) {
686
+ return declare(owner, name, kind, declarationSpan, selectionSpan, options.exported ?? false, options.mutable ?? false, options.lexical ?? true, options.container, options.explicitType, options.static ?? false, {
687
+ ...(options.documentationStart === undefined ? {} : { documentationStart: options.documentationStart }),
688
+ ...(options.private === undefined ? {} : { private: options.private }),
689
+ ...(options.typeTarget === undefined ? {} : { typeTarget: options.typeTarget }),
690
+ ...(options.sourceTypeHint === undefined ? {} : { sourceTypeHint: options.sourceTypeHint }),
691
+ ...(options.presentationKind === undefined ? {} : { presentationKind: options.presentationKind }),
692
+ });
693
+ },
694
+ hasDeclaration: (owner) => declarations.has(owner),
695
+ nameSpan,
696
+ typeReferences,
697
+ reference,
698
+ recordMemberReference,
699
+ jsxAttributeOwner: (attributeSpan, name) => jsxAttributeOwners.get(`${attributeSpan.start}:${name}`),
700
+ enterScope,
701
+ exitScope,
702
+ visitExpression: (expression) => visitExpression(expression),
703
+ visitStatement,
704
+ visitBlock,
705
+ visitFunction: (statement) => visitFunction(statement),
706
+ };
707
+ predeclareTopLevel();
708
+ for (const statement of program.body)
709
+ visitStatement(statement);
710
+ return {
711
+ path: source.path,
712
+ symbols,
713
+ references,
714
+ memberReferences,
715
+ imports,
716
+ moduleReferences,
717
+ scopes: allScopes.map(({ id, parentId, span: scopeSpan }) => ({ id, parentId, span: scopeSpan })),
718
+ expressions,
719
+ };
720
+ }
721
+ const MAX_DOCUMENTATION_CHARS = 16_384;
722
+ function documentationBefore(source, declarationStart) {
723
+ const location = source.location(declarationStart);
724
+ const lineStart = source.lineStarts[location.line - 1] ?? 0;
725
+ const indentation = source.text.slice(lineStart, declarationStart);
726
+ if (!/^[ \t]*$/u.test(indentation))
727
+ return null;
728
+ const lines = [];
729
+ for (let lineNumber = location.line - 1; lineNumber > 0; lineNumber -= 1) {
730
+ const line = source.lineText(lineNumber);
731
+ if (!line.startsWith(`${indentation}///`))
732
+ break;
733
+ const suffix = line.slice(indentation.length + 3);
734
+ lines.unshift(suffix.startsWith(" ") ? suffix.slice(1) : suffix);
735
+ }
736
+ while (lines[0] === "")
737
+ lines.shift();
738
+ while (lines.at(-1) === "")
739
+ lines.pop();
740
+ if (lines.length === 0)
741
+ return null;
742
+ const documentation = lines.join("\n");
743
+ return documentation.length <= MAX_DOCUMENTATION_CHARS
744
+ ? documentation
745
+ : `${documentation.slice(0, MAX_DOCUMENTATION_CHARS - 1)}…`;
746
+ }
747
+ export function semanticVisibleSymbolsAt(index, offset) {
748
+ const scopesById = new Map(index.scopes.map((scope) => [scope.id, scope]));
749
+ const depths = new Map();
750
+ const depthOf = (scope) => {
751
+ const cached = depths.get(scope.id);
752
+ if (cached !== undefined)
753
+ return cached;
754
+ const parent = scope.parentId === null ? null : scopesById.get(scope.parentId) ?? null;
755
+ const depth = parent ? depthOf(parent) + 1 : 0;
756
+ depths.set(scope.id, depth);
757
+ return depth;
758
+ };
759
+ let active = scopesById.get(0);
760
+ let activeDepth = active ? depthOf(active) : -1;
761
+ for (const scope of index.scopes) {
762
+ if (offset < scope.span.start || offset > scope.span.end)
763
+ continue;
764
+ const depth = depthOf(scope);
765
+ if (depth > activeDepth) {
766
+ active = scope;
767
+ activeDepth = depth;
768
+ }
769
+ }
770
+ if (!active)
771
+ return [];
772
+ const activeScopeIds = [];
773
+ for (let scope = active; scope;) {
774
+ activeScopeIds.push(scope.id);
775
+ scope = scope.parentId === null ? undefined : scopesById.get(scope.parentId);
776
+ }
777
+ const lexicalKinds = new Set([
778
+ "import", "type", "enum", "class", "function", "variable", "parameter", "catch",
779
+ ]);
780
+ const rootHoistedKinds = new Set(["import", "type", "enum", "class", "function"]);
781
+ const names = new Set();
782
+ const output = [];
783
+ const activeSet = new Set(activeScopeIds);
784
+ const symbolsByScope = new Map();
785
+ for (const symbol of index.symbols) {
786
+ if (!activeSet.has(symbol.scopeId))
787
+ continue;
788
+ const bucket = symbolsByScope.get(symbol.scopeId) ?? [];
789
+ bucket.push(symbol);
790
+ symbolsByScope.set(symbol.scopeId, bucket);
791
+ }
792
+ for (const scopeId of activeScopeIds) {
793
+ for (const symbol of symbolsByScope.get(scopeId) ?? []) {
794
+ const extensionKind = symbol.kind.startsWith("extension:");
795
+ if ((!lexicalKinds.has(symbol.kind) && !extensionKind) || names.has(symbol.name))
796
+ continue;
797
+ const hoisted = rootHoistedKinds.has(symbol.kind)
798
+ || symbol.kind.startsWith("extension:function:")
799
+ || symbol.kind.startsWith("extension:class:");
800
+ if (symbol.selectionSpan.start > offset && !(scopeId === 0 && hoisted))
801
+ continue;
802
+ names.add(symbol.name);
803
+ output.push(symbol);
804
+ }
805
+ }
806
+ return output;
807
+ }
808
+ export function semanticSymbolAt(index, offset) {
809
+ const declaration = index.symbols.find((symbol) => contains(symbol.selectionSpan, offset));
810
+ if (declaration)
811
+ return declaration;
812
+ const reference = index.references.find((item) => contains(item.span, offset));
813
+ return reference?.symbolId ? index.symbols.find((symbol) => symbol.id === reference.symbolId) ?? null : null;
814
+ }
815
+ export function semanticImportAt(index, offset) {
816
+ return index.imports.find((item) => contains(item.importedSpan, offset) || contains(item.localSpan, offset)) ?? null;
817
+ }
818
+ export function semanticModuleReferenceAt(index, offset) {
819
+ return index.moduleReferences.find((item) => contains(item.span, offset)) ?? null;
820
+ }
821
+ function contains(span, offset) {
822
+ return offset >= span.start && offset < span.end;
823
+ }
824
+ function wordSpans(text, valueSpan) {
825
+ const value = text.slice(valueSpan.start, valueSpan.end);
826
+ return [...value.matchAll(/[A-Za-z_$][A-Za-z0-9_$]*/gu)].map((match) => {
827
+ const start = valueSpan.start + (match.index ?? 0);
828
+ return { start, end: start + match[0].length };
829
+ });
830
+ }
831
+ function findNameSpan(text, valueSpan, name, from) {
832
+ const startAt = Math.max(valueSpan.start, from);
833
+ const value = text.slice(startAt, valueSpan.end);
834
+ const pattern = new RegExp(`(?:^|[^A-Za-z0-9_$])(${escapeRegExp(name)})(?![A-Za-z0-9_$])`, "u");
835
+ const match = pattern.exec(value);
836
+ if (!match)
837
+ return { start: startAt, end: Math.min(valueSpan.end, startAt + name.length) };
838
+ const prefix = match[0].length - match[1].length;
839
+ const start = startAt + match.index + prefix;
840
+ return { start, end: start + name.length };
841
+ }
842
+ function escapeRegExp(value) {
843
+ return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
844
+ }
845
+ //# sourceMappingURL=semantic.js.map