@spyglassmc/mcdoc 0.3.1 → 0.3.3
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.
- package/lib/binder/index.d.ts +7 -0
- package/lib/binder/index.js +266 -168
- package/lib/colorizer/index.js +2 -2
- package/lib/common.d.ts +1 -1
- package/lib/node/index.d.ts +32 -21
- package/lib/node/index.js +76 -33
- package/lib/parser/index.d.ts +1 -1
- package/lib/parser/index.js +161 -141
- package/lib/type/index.d.ts +59 -43
- package/lib/type/index.js +138 -56
- package/lib/uri_processors.js +5 -5
- package/package.json +3 -3
package/lib/binder/index.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
import { AsyncBinder, atArray, Dev, Range, ResourceLocationNode, SymbolUtil, traversePreOrder } from '@spyglassmc/core';
|
|
1
|
+
import { AsyncBinder, atArray, Dev, Range, ResourceLocationNode, SymbolUtil, traversePreOrder, } from '@spyglassmc/core';
|
|
2
2
|
import { localeQuote, localize } from '@spyglassmc/locales';
|
|
3
|
-
import { AttributeNode, AttributeTreeNamedValuesNode, AttributeTreeNode, AttributeTreePosValuesNode, DispatcherTypeNode, DispatchStatementNode, DocCommentsNode, DynamicIndexNode, EnumBlockNode, EnumFieldNode, EnumInjectionNode, EnumNode, FloatRangeNode, IndexBodyNode, InjectionNode, IntRangeNode, ListTypeNode, LiteralNode, LiteralTypeNode, NumericTypeNode, PathNode, PrimitiveArrayTypeNode, ReferenceTypeNode, StaticIndexNode, StringTypeNode, StructBlockNode, StructMapKeyNode, StructNode, StructPairFieldNode, StructSpreadFieldNode, TopLevelNode, TupleTypeNode, TypeAliasNode, TypeBaseNode, TypedNumberNode, TypeParamBlockNode, TypeParamNode, UnionTypeNode, UseStatementNode } from '../node/index.js';
|
|
3
|
+
import { AttributeNode, AttributeTreeNamedValuesNode, AttributeTreeNode, AttributeTreePosValuesNode, DispatcherTypeNode, DispatchStatementNode, DocCommentsNode, DynamicIndexNode, EnumBlockNode, EnumFieldNode, EnumInjectionNode, EnumNode, FloatRangeNode, IndexBodyNode, InjectionNode, IntRangeNode, ListTypeNode, LiteralNode, LiteralTypeNode, NumericTypeNode, PathNode, PrimitiveArrayTypeNode, ReferenceTypeNode, StaticIndexNode, StringTypeNode, StructBlockNode, StructMapKeyNode, StructNode, StructPairFieldNode, StructSpreadFieldNode, TopLevelNode, TupleTypeNode, TypeAliasNode, TypeArgBlockNode, TypeBaseNode, TypedNumberNode, TypeParamBlockNode, TypeParamNode, UnionTypeNode, UseStatementNode, } from '../node/index.js';
|
|
4
4
|
const ModuleSymbolData = Object.freeze({
|
|
5
5
|
is(data) {
|
|
6
|
-
return !!data &&
|
|
6
|
+
return (!!data &&
|
|
7
|
+
typeof data === 'object' &&
|
|
8
|
+
typeof data.nextAnonymousIndex === 'number');
|
|
7
9
|
},
|
|
8
10
|
});
|
|
9
|
-
const TypeDefSymbolData = Object.freeze({
|
|
11
|
+
export const TypeDefSymbolData = Object.freeze({
|
|
10
12
|
is(data) {
|
|
11
|
-
return !!data &&
|
|
13
|
+
return (!!data &&
|
|
14
|
+
typeof data === 'object' &&
|
|
15
|
+
typeof data.typeDef === 'object');
|
|
12
16
|
},
|
|
13
17
|
});
|
|
14
18
|
export const fileModule = AsyncBinder.create(async (node, ctx) => {
|
|
@@ -56,7 +60,7 @@ export async function module_(node, ctx) {
|
|
|
56
60
|
* Hoist enums, structs, type aliases, and use statements under the module scope.
|
|
57
61
|
*/
|
|
58
62
|
function hoist(node, ctx) {
|
|
59
|
-
traversePreOrder(node, () => true, TopLevelNode.is, child => {
|
|
63
|
+
traversePreOrder(node, () => true, TopLevelNode.is, (child) => {
|
|
60
64
|
switch (child.type) {
|
|
61
65
|
case 'mcdoc:enum':
|
|
62
66
|
hoistEnum(child);
|
|
@@ -73,18 +77,27 @@ function hoist(node, ctx) {
|
|
|
73
77
|
}
|
|
74
78
|
});
|
|
75
79
|
function hoistEnum(node) {
|
|
76
|
-
hoistFor('enum', node, EnumNode.destruct, n => ({
|
|
80
|
+
hoistFor('enum', node, EnumNode.destruct, (n) => ({
|
|
81
|
+
typeDef: convertEnum(n, ctx),
|
|
82
|
+
}));
|
|
77
83
|
}
|
|
78
84
|
function hoistStruct(node) {
|
|
79
|
-
hoistFor('struct', node, StructNode.destruct, n => ({
|
|
85
|
+
hoistFor('struct', node, StructNode.destruct, (n) => ({
|
|
86
|
+
typeDef: convertStruct(n, ctx),
|
|
87
|
+
}));
|
|
80
88
|
}
|
|
81
89
|
function hoistTypeAlias(node) {
|
|
82
|
-
hoistFor('type_alias', node, TypeAliasNode.destruct, n => {
|
|
83
|
-
const { rhs } = TypeAliasNode.destruct(n);
|
|
90
|
+
hoistFor('type_alias', node, TypeAliasNode.destruct, (n) => {
|
|
91
|
+
const { attributes, rhs, typeParams } = TypeAliasNode.destruct(n);
|
|
84
92
|
if (!rhs) {
|
|
85
93
|
return undefined;
|
|
86
94
|
}
|
|
87
|
-
|
|
95
|
+
const ans = { typeDef: convertType(rhs, ctx) };
|
|
96
|
+
if (typeParams) {
|
|
97
|
+
bindTypeParamBlock(node, typeParams, ans, ctx);
|
|
98
|
+
}
|
|
99
|
+
ans.typeDef = attributeType(ans.typeDef, attributes, ctx);
|
|
100
|
+
return ans;
|
|
88
101
|
});
|
|
89
102
|
}
|
|
90
103
|
function hoistUseStatement(node) {
|
|
@@ -103,9 +116,12 @@ function hoist(node, ctx) {
|
|
|
103
116
|
// they will go to the definition in the imported file.
|
|
104
117
|
ctx.symbols
|
|
105
118
|
.query({ doc: ctx.doc, node }, 'mcdoc', `${ctx.moduleIdentifier}::${identifier.value}`)
|
|
106
|
-
.ifDeclared(symbol => reportDuplicatedDeclaration(ctx, symbol, identifier))
|
|
119
|
+
.ifDeclared((symbol) => reportDuplicatedDeclaration(ctx, symbol, identifier))
|
|
107
120
|
.elseEnter({
|
|
108
|
-
data: {
|
|
121
|
+
data: {
|
|
122
|
+
subcategory: 'use_statement_binding',
|
|
123
|
+
visibility: 1 /* SymbolVisibility.File */,
|
|
124
|
+
},
|
|
109
125
|
usage: { type: 'definition', node: identifier, fullRange: node },
|
|
110
126
|
});
|
|
111
127
|
}
|
|
@@ -114,12 +130,20 @@ function hoist(node, ctx) {
|
|
|
114
130
|
const name = identifier?.value ?? nextAnonymousIdentifier(node, ctx);
|
|
115
131
|
ctx.symbols
|
|
116
132
|
.query({ doc: ctx.doc, node }, 'mcdoc', `${ctx.moduleIdentifier}::${name}`)
|
|
117
|
-
.ifDeclared(symbol => reportDuplicatedDeclaration(ctx, symbol, identifier ?? node))
|
|
133
|
+
.ifDeclared((symbol) => reportDuplicatedDeclaration(ctx, symbol, identifier ?? node))
|
|
118
134
|
.elseEnter({
|
|
119
|
-
data: {
|
|
135
|
+
data: {
|
|
136
|
+
data: getData(node),
|
|
137
|
+
desc: DocCommentsNode.asText(docComments),
|
|
138
|
+
subcategory,
|
|
139
|
+
},
|
|
120
140
|
// If the current syntax structure is named, then the identifier node is entered as a definition;
|
|
121
141
|
// otherwise, an anonymous identifier is generated for the symbol and the keyword node is entered as a definition.
|
|
122
|
-
usage: {
|
|
142
|
+
usage: {
|
|
143
|
+
type: 'definition',
|
|
144
|
+
node: identifier ?? keyword,
|
|
145
|
+
fullRange: identifier && node,
|
|
146
|
+
},
|
|
123
147
|
});
|
|
124
148
|
}
|
|
125
149
|
function nextAnonymousIndex(node, ctx) {
|
|
@@ -135,41 +159,83 @@ function hoist(node, ctx) {
|
|
|
135
159
|
return `<anonymous ${nextAnonymousIndex(node, ctx)}>`;
|
|
136
160
|
}
|
|
137
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* Bind the type param block of a parent node, and modifies the `data` argument in-place to change its `typeDef` to be of template kind.
|
|
164
|
+
*/
|
|
165
|
+
function bindTypeParamBlock(node, typeParams, data, ctx) {
|
|
166
|
+
// Type parameters are added as local symbols on the type alias AST node.
|
|
167
|
+
// Thus we create a new local scope on the type alias statement node first.
|
|
168
|
+
node.locals = Object.create(null);
|
|
169
|
+
// They are also added to the type definition.
|
|
170
|
+
data.typeDef = {
|
|
171
|
+
kind: 'template',
|
|
172
|
+
child: data.typeDef,
|
|
173
|
+
typeParams: [],
|
|
174
|
+
};
|
|
175
|
+
const { params } = TypeParamBlockNode.destruct(typeParams);
|
|
176
|
+
for (const param of params) {
|
|
177
|
+
const { identifier: paramIdentifier } = TypeParamNode.destruct(param);
|
|
178
|
+
if (paramIdentifier.value) {
|
|
179
|
+
// Add the type parameter as a local symbol.
|
|
180
|
+
const paramPath = `${ctx.moduleIdentifier}::${paramIdentifier.value}`;
|
|
181
|
+
ctx.symbols
|
|
182
|
+
.query({ doc: ctx.doc, node }, 'mcdoc', paramPath)
|
|
183
|
+
.ifDeclared((symbol) => reportDuplicatedDeclaration(ctx, symbol, paramIdentifier))
|
|
184
|
+
.elseEnter({
|
|
185
|
+
data: { visibility: 0 /* SymbolVisibility.Block */ },
|
|
186
|
+
usage: {
|
|
187
|
+
type: 'declaration',
|
|
188
|
+
node: paramIdentifier,
|
|
189
|
+
fullRange: param,
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
// Also add it to the type definition.
|
|
193
|
+
data.typeDef.typeParams.push({ path: paramPath });
|
|
194
|
+
}
|
|
195
|
+
// if (constraint) {
|
|
196
|
+
// await bindPath(constraint, ctx)
|
|
197
|
+
// }
|
|
198
|
+
}
|
|
199
|
+
}
|
|
138
200
|
async function bindDispatchStatement(node, ctx) {
|
|
139
|
-
const { attributes, location, index, target } = DispatchStatementNode.destruct(node);
|
|
201
|
+
const { attributes, location, index, target, typeParams } = DispatchStatementNode.destruct(node);
|
|
140
202
|
if (!(location && index && target)) {
|
|
141
203
|
return;
|
|
142
204
|
}
|
|
143
205
|
const locationStr = ResourceLocationNode.toString(location, 'full');
|
|
144
|
-
ctx.symbols
|
|
145
|
-
.query(ctx.doc, 'mcdoc/dispatcher', locationStr)
|
|
146
|
-
.enter({
|
|
206
|
+
ctx.symbols.query(ctx.doc, 'mcdoc/dispatcher', locationStr).enter({
|
|
147
207
|
usage: { type: 'reference', node: location, fullRange: node },
|
|
148
208
|
});
|
|
149
209
|
const { parallelIndices } = IndexBodyNode.destruct(index);
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
210
|
+
if (parallelIndices.length) {
|
|
211
|
+
const data = {
|
|
212
|
+
typeDef: convertType(target, ctx),
|
|
213
|
+
};
|
|
214
|
+
if (typeParams) {
|
|
215
|
+
bindTypeParamBlock(node, typeParams, data, ctx);
|
|
216
|
+
}
|
|
217
|
+
data.typeDef = attributeType(data.typeDef, attributes, ctx);
|
|
218
|
+
for (const key of parallelIndices) {
|
|
219
|
+
if (DynamicIndexNode.is(key)) {
|
|
220
|
+
// Ignore dynamic indices in dispatch statements.
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
ctx.symbols
|
|
224
|
+
.query(ctx.doc, 'mcdoc/dispatcher', locationStr, asString(key))
|
|
225
|
+
.ifDeclared((symbol) => reportDuplicatedDeclaration(ctx, symbol, key, {
|
|
226
|
+
localeString: 'mcdoc.binder.dispatcher-statement.duplicated-key',
|
|
227
|
+
}))
|
|
228
|
+
.elseEnter({
|
|
229
|
+
data: { data },
|
|
230
|
+
usage: { type: 'definition', node: key, fullRange: node },
|
|
231
|
+
});
|
|
154
232
|
}
|
|
155
|
-
ctx.symbols
|
|
156
|
-
.query(ctx.doc, 'mcdoc/dispatcher', locationStr, asString(key))
|
|
157
|
-
.ifDeclared(symbol => reportDuplicatedDeclaration(ctx, symbol, key, { localeString: 'mcdoc.binder.dispatcher-statement.duplicated-key' }))
|
|
158
|
-
.elseEnter({
|
|
159
|
-
data: {
|
|
160
|
-
data: {
|
|
161
|
-
attributes: convertAttributes(attributes, ctx),
|
|
162
|
-
typeDef: convertType(target, ctx),
|
|
163
|
-
},
|
|
164
|
-
},
|
|
165
|
-
usage: { type: 'definition', node: key, fullRange: node },
|
|
166
|
-
});
|
|
167
233
|
}
|
|
168
234
|
await bindType(target, ctx);
|
|
169
235
|
}
|
|
170
236
|
async function bindType(node, ctx) {
|
|
171
237
|
if (DispatcherTypeNode.is(node)) {
|
|
172
|
-
bindDispatcherType(node, ctx);
|
|
238
|
+
await bindDispatcherType(node, ctx);
|
|
173
239
|
}
|
|
174
240
|
else if (EnumNode.is(node)) {
|
|
175
241
|
bindEnum(node, ctx);
|
|
@@ -179,11 +245,8 @@ async function bindType(node, ctx) {
|
|
|
179
245
|
await bindType(item, ctx);
|
|
180
246
|
}
|
|
181
247
|
else if (ReferenceTypeNode.is(node)) {
|
|
182
|
-
const { path
|
|
248
|
+
const { path } = ReferenceTypeNode.destruct(node);
|
|
183
249
|
await bindPath(path, ctx);
|
|
184
|
-
for (const param of typeParameters) {
|
|
185
|
-
await bindType(param, ctx);
|
|
186
|
-
}
|
|
187
250
|
}
|
|
188
251
|
else if (StructNode.is(node)) {
|
|
189
252
|
await bindStruct(node, ctx);
|
|
@@ -200,10 +263,22 @@ async function bindType(node, ctx) {
|
|
|
200
263
|
await bindType(member, ctx);
|
|
201
264
|
}
|
|
202
265
|
}
|
|
266
|
+
const { appendixes } = TypeBaseNode.destruct(node);
|
|
267
|
+
for (const appendix of appendixes) {
|
|
268
|
+
if (TypeArgBlockNode.is(appendix)) {
|
|
269
|
+
const { args } = TypeArgBlockNode.destruct(appendix);
|
|
270
|
+
for (const arg of args) {
|
|
271
|
+
await bindType(arg, ctx);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
203
275
|
}
|
|
204
|
-
function bindDispatcherType(node, ctx) {
|
|
276
|
+
async function bindDispatcherType(node, ctx) {
|
|
205
277
|
const { index, location } = DispatcherTypeNode.destruct(node);
|
|
206
278
|
const locationStr = ResourceLocationNode.toString(location, 'full');
|
|
279
|
+
ctx.symbols
|
|
280
|
+
.query(ctx.doc, 'mcdoc/dispatcher', locationStr)
|
|
281
|
+
.enter({ usage: { type: 'reference', node: location, fullRange: node } });
|
|
207
282
|
const { parallelIndices } = IndexBodyNode.destruct(index);
|
|
208
283
|
for (const key of parallelIndices) {
|
|
209
284
|
if (DynamicIndexNode.is(key)) {
|
|
@@ -234,7 +309,12 @@ async function bindPath(node, ctx) {
|
|
|
234
309
|
ctx.symbols
|
|
235
310
|
.query({ doc: ctx.doc, node: identNode }, 'mcdoc', pathArrayToString(identifiers))
|
|
236
311
|
.ifDeclared((_, query) => query.enter({
|
|
237
|
-
usage: {
|
|
312
|
+
usage: {
|
|
313
|
+
type: 'reference',
|
|
314
|
+
node: identNode,
|
|
315
|
+
fullRange: node,
|
|
316
|
+
skipRenaming: LiteralNode.is(identNode),
|
|
317
|
+
},
|
|
238
318
|
}))
|
|
239
319
|
.else(() => {
|
|
240
320
|
if (indexRight === 0) {
|
|
@@ -257,9 +337,15 @@ function bindEnumBlock(node, ctx, query, options = {}) {
|
|
|
257
337
|
const { fields } = EnumBlockNode.destruct(node);
|
|
258
338
|
for (const field of fields) {
|
|
259
339
|
const { identifier } = EnumFieldNode.destruct(field);
|
|
260
|
-
query.member(identifier.value, fieldQuery => fieldQuery
|
|
261
|
-
.ifDeclared(symbol => reportDuplicatedDeclaration(ctx, symbol, identifier))
|
|
262
|
-
.elseEnter({
|
|
340
|
+
query.member(identifier.value, (fieldQuery) => fieldQuery
|
|
341
|
+
.ifDeclared((symbol) => reportDuplicatedDeclaration(ctx, symbol, identifier))
|
|
342
|
+
.elseEnter({
|
|
343
|
+
usage: {
|
|
344
|
+
type: 'definition',
|
|
345
|
+
node: identifier,
|
|
346
|
+
fullRange: field,
|
|
347
|
+
},
|
|
348
|
+
}));
|
|
263
349
|
}
|
|
264
350
|
}
|
|
265
351
|
async function bindInjection(node, ctx) {
|
|
@@ -286,9 +372,11 @@ async function bindStructBlock(node, ctx, query, options = {}) {
|
|
|
286
372
|
if (StructPairFieldNode.is(field)) {
|
|
287
373
|
const { key, type } = StructPairFieldNode.destruct(field);
|
|
288
374
|
if (!StructMapKeyNode.is(key)) {
|
|
289
|
-
query.member(key.value, fieldQuery => fieldQuery
|
|
290
|
-
.ifDeclared(symbol => reportDuplicatedDeclaration(ctx, symbol, key))
|
|
291
|
-
.elseEnter({
|
|
375
|
+
query.member(key.value, (fieldQuery) => fieldQuery
|
|
376
|
+
.ifDeclared((symbol) => reportDuplicatedDeclaration(ctx, symbol, key))
|
|
377
|
+
.elseEnter({
|
|
378
|
+
usage: { type: 'definition', node: key, fullRange: field },
|
|
379
|
+
}));
|
|
292
380
|
}
|
|
293
381
|
await bindType(type, ctx);
|
|
294
382
|
}
|
|
@@ -303,39 +391,6 @@ async function bindTypeAlias(node, ctx) {
|
|
|
303
391
|
if (!identifier?.value) {
|
|
304
392
|
return;
|
|
305
393
|
}
|
|
306
|
-
if (typeParams) {
|
|
307
|
-
// Type parameters are added as local symbols on the type alias AST node.
|
|
308
|
-
node.locals = Object.create(null);
|
|
309
|
-
const { params } = TypeParamBlockNode.destruct(typeParams);
|
|
310
|
-
const query = ctx.symbols.query({ doc: ctx.doc, node }, 'mcdoc', `${ctx.moduleIdentifier}::${identifier.value}`);
|
|
311
|
-
if (query.symbol?.subcategory === 'type_alias') {
|
|
312
|
-
// Type parameters are also added to the symbol data.
|
|
313
|
-
const oldData = query.symbol.data;
|
|
314
|
-
if (!TypeDefSymbolData.is(oldData)) {
|
|
315
|
-
throw new Error('Failed to locate the typeDef data associated with a supposedly hoisted type alias symbol');
|
|
316
|
-
}
|
|
317
|
-
const data = {
|
|
318
|
-
...oldData,
|
|
319
|
-
typeParams: [],
|
|
320
|
-
};
|
|
321
|
-
query.symbol.data = data;
|
|
322
|
-
for (const param of params) {
|
|
323
|
-
const { identifier: paramIdentifier } = TypeParamNode.destruct(param);
|
|
324
|
-
if (paramIdentifier.value) {
|
|
325
|
-
// Add the type parameter as a local symbol.
|
|
326
|
-
ctx.symbols
|
|
327
|
-
.query({ doc: ctx.doc, node }, 'mcdoc', `${ctx.moduleIdentifier}::${paramIdentifier.value}`)
|
|
328
|
-
.ifDeclared(symbol => reportDuplicatedDeclaration(ctx, symbol, paramIdentifier))
|
|
329
|
-
.elseEnter({ data: { visibility: 0 /* SymbolVisibility.Block */ }, usage: { type: 'declaration', node: paramIdentifier, fullRange: param } });
|
|
330
|
-
// Also add it to the symbol data.
|
|
331
|
-
data.typeParams.push({ identifier: paramIdentifier.value });
|
|
332
|
-
}
|
|
333
|
-
// if (constraint) {
|
|
334
|
-
// await bindPath(constraint, ctx)
|
|
335
|
-
// }
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
394
|
if (rhs) {
|
|
340
395
|
await bindType(rhs, ctx);
|
|
341
396
|
}
|
|
@@ -352,10 +407,12 @@ export function registerMcdocBinders(meta) {
|
|
|
352
407
|
}
|
|
353
408
|
function reportDuplicatedDeclaration(ctx, symbol, range, options = { localeString: 'mcdoc.binder.duplicated-declaration' }) {
|
|
354
409
|
ctx.err.report(localize(options.localeString, localeQuote(symbol.identifier)), range, 2 /* ErrorSeverity.Warning */, {
|
|
355
|
-
related: [
|
|
410
|
+
related: [
|
|
411
|
+
{
|
|
356
412
|
location: SymbolUtil.getDeclaredLocation(symbol),
|
|
357
413
|
message: localize(`${options.localeString}.related`, localeQuote(symbol.identifier)),
|
|
358
|
-
}
|
|
414
|
+
},
|
|
415
|
+
],
|
|
359
416
|
});
|
|
360
417
|
}
|
|
361
418
|
function* resolvePathByStep(path, ctx, options = {}) {
|
|
@@ -381,7 +438,12 @@ function* resolvePathByStep(path, ctx, options = {}) {
|
|
|
381
438
|
default:
|
|
382
439
|
Dev.assertNever(child);
|
|
383
440
|
}
|
|
384
|
-
yield {
|
|
441
|
+
yield {
|
|
442
|
+
identifiers,
|
|
443
|
+
node: child,
|
|
444
|
+
index: i,
|
|
445
|
+
indexRight: children.length - 1 - i,
|
|
446
|
+
};
|
|
385
447
|
}
|
|
386
448
|
}
|
|
387
449
|
function resolvePath(path, ctx, options = {}) {
|
|
@@ -391,43 +453,84 @@ function identifierToUri(module, ctx) {
|
|
|
391
453
|
return ctx.symbols.global.mcdoc?.[module]?.definition?.[0]?.uri;
|
|
392
454
|
}
|
|
393
455
|
function uriToIdentifier(uri, ctx) {
|
|
394
|
-
return Object
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
})
|
|
399
|
-
?.identifier;
|
|
456
|
+
return Object.values(ctx.symbols.global.mcdoc ?? {}).find((symbol) => {
|
|
457
|
+
return (symbol.subcategory === 'module' &&
|
|
458
|
+
symbol.definition?.some((loc) => loc.uri === uri));
|
|
459
|
+
})?.identifier;
|
|
400
460
|
}
|
|
401
461
|
function pathArrayToString(path) {
|
|
402
462
|
return path ? `::${path.join('::')}` : undefined;
|
|
403
463
|
}
|
|
404
464
|
function convertType(node, ctx) {
|
|
405
465
|
switch (node.type) {
|
|
406
|
-
case 'mcdoc:enum':
|
|
407
|
-
|
|
408
|
-
case 'mcdoc:
|
|
409
|
-
|
|
410
|
-
case 'mcdoc:type/
|
|
411
|
-
|
|
412
|
-
case 'mcdoc:type/
|
|
413
|
-
|
|
414
|
-
case 'mcdoc:type/
|
|
415
|
-
|
|
416
|
-
case 'mcdoc:type/
|
|
417
|
-
|
|
418
|
-
case 'mcdoc:type/
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
466
|
+
case 'mcdoc:enum':
|
|
467
|
+
return convertEnum(node, ctx);
|
|
468
|
+
case 'mcdoc:struct':
|
|
469
|
+
return convertStruct(node, ctx);
|
|
470
|
+
case 'mcdoc:type/any':
|
|
471
|
+
return convertAny(node, ctx);
|
|
472
|
+
case 'mcdoc:type/boolean':
|
|
473
|
+
return convertBoolean(node, ctx);
|
|
474
|
+
case 'mcdoc:type/dispatcher':
|
|
475
|
+
return convertDispatcher(node, ctx);
|
|
476
|
+
case 'mcdoc:type/list':
|
|
477
|
+
return convertList(node, ctx);
|
|
478
|
+
case 'mcdoc:type/literal':
|
|
479
|
+
return convertLiteral(node, ctx);
|
|
480
|
+
case 'mcdoc:type/numeric_type':
|
|
481
|
+
return convertNumericType(node, ctx);
|
|
482
|
+
case 'mcdoc:type/primitive_array':
|
|
483
|
+
return convertPrimitiveArray(node, ctx);
|
|
484
|
+
case 'mcdoc:type/string':
|
|
485
|
+
return convertString(node, ctx);
|
|
486
|
+
case 'mcdoc:type/reference':
|
|
487
|
+
return convertReference(node, ctx);
|
|
488
|
+
case 'mcdoc:type/tuple':
|
|
489
|
+
return convertTuple(node, ctx);
|
|
490
|
+
case 'mcdoc:type/union':
|
|
491
|
+
return convertUnion(node, ctx);
|
|
492
|
+
default:
|
|
493
|
+
return Dev.assertNever(node);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
function wrapType(node, type, ctx, options = {}) {
|
|
497
|
+
const { attributes, appendixes } = TypeBaseNode.destruct(node);
|
|
498
|
+
let ans = type;
|
|
499
|
+
for (const appendix of appendixes) {
|
|
500
|
+
if (IndexBodyNode.is(appendix)) {
|
|
501
|
+
if (options.skipFirstIndexBody) {
|
|
502
|
+
options.skipFirstIndexBody = false;
|
|
503
|
+
continue;
|
|
504
|
+
}
|
|
505
|
+
ans = {
|
|
506
|
+
kind: 'indexed',
|
|
507
|
+
child: ans,
|
|
508
|
+
parallelIndices: convertIndexBody(appendix, ctx),
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
else {
|
|
512
|
+
ans = {
|
|
513
|
+
kind: 'concrete',
|
|
514
|
+
child: ans,
|
|
515
|
+
typeArgs: convertTypeArgBlock(appendix, ctx),
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
ans = attributeType(ans, attributes, ctx);
|
|
520
|
+
return ans;
|
|
521
|
+
}
|
|
522
|
+
function attributeType(type, attributes, ctx) {
|
|
523
|
+
for (const attribute of attributes) {
|
|
524
|
+
type = {
|
|
525
|
+
kind: 'attributed',
|
|
526
|
+
attribute: convertAttribute(attribute, ctx),
|
|
527
|
+
child: type,
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
return type;
|
|
428
531
|
}
|
|
429
532
|
function convertAttributes(nodes, ctx) {
|
|
430
|
-
return undefineEmptyArray(nodes.map(n => convertAttribute(n, ctx)));
|
|
533
|
+
return undefineEmptyArray(nodes.map((n) => convertAttribute(n, ctx)));
|
|
431
534
|
}
|
|
432
535
|
function undefineEmptyArray(array) {
|
|
433
536
|
return array.length ? array : undefined;
|
|
@@ -468,11 +571,11 @@ function convertAttributeTree(node, ctx) {
|
|
|
468
571
|
return ans;
|
|
469
572
|
}
|
|
470
573
|
function convertIndexBodies(nodes, ctx) {
|
|
471
|
-
return undefineEmptyArray(nodes.map(n => convertIndexBody(n, ctx)));
|
|
574
|
+
return undefineEmptyArray(nodes.map((n) => convertIndexBody(n, ctx)));
|
|
472
575
|
}
|
|
473
576
|
function convertIndexBody(node, ctx) {
|
|
474
577
|
const { parallelIndices } = IndexBodyNode.destruct(node);
|
|
475
|
-
return parallelIndices.map(n => convertIndex(n, ctx));
|
|
578
|
+
return parallelIndices.map((n) => convertIndex(n, ctx));
|
|
476
579
|
}
|
|
477
580
|
function convertIndex(node, ctx) {
|
|
478
581
|
return StaticIndexNode.is(node)
|
|
@@ -492,23 +595,28 @@ function convertDynamicIndex(node, ctx) {
|
|
|
492
595
|
accessor: keys.map(asString),
|
|
493
596
|
};
|
|
494
597
|
}
|
|
598
|
+
function convertTypeArgBlock(node, ctx) {
|
|
599
|
+
const { args } = TypeArgBlockNode.destruct(node);
|
|
600
|
+
return args.map((a) => convertType(a, ctx));
|
|
601
|
+
}
|
|
495
602
|
function convertEnum(node, ctx) {
|
|
496
603
|
const { block, enumKind, identifier } = EnumNode.destruct(node);
|
|
497
604
|
// Shortcut if the typeDef has been added to the enum symbol.
|
|
498
605
|
const symbol = identifier?.symbol ?? node.symbol;
|
|
499
|
-
if (symbol &&
|
|
606
|
+
if (symbol &&
|
|
607
|
+
TypeDefSymbolData.is(symbol.data) &&
|
|
608
|
+
symbol.data.typeDef.kind === 'enum') {
|
|
500
609
|
return symbol.data.typeDef;
|
|
501
610
|
}
|
|
502
|
-
return {
|
|
503
|
-
...convertBase(node, ctx),
|
|
611
|
+
return wrapType(node, {
|
|
504
612
|
kind: 'enum',
|
|
505
613
|
enumKind,
|
|
506
614
|
values: convertEnumBlock(block, ctx),
|
|
507
|
-
};
|
|
615
|
+
}, ctx);
|
|
508
616
|
}
|
|
509
617
|
function convertEnumBlock(node, ctx) {
|
|
510
618
|
const { fields } = EnumBlockNode.destruct(node);
|
|
511
|
-
return fields.map(n => convertEnumField(n, ctx));
|
|
619
|
+
return fields.map((n) => convertEnumField(n, ctx));
|
|
512
620
|
}
|
|
513
621
|
function convertEnumField(node, ctx) {
|
|
514
622
|
const { attributes, identifier, value } = EnumFieldNode.destruct(node);
|
|
@@ -529,18 +637,19 @@ function convertStruct(node, ctx) {
|
|
|
529
637
|
const { block, identifier } = StructNode.destruct(node);
|
|
530
638
|
// Shortcut if the typeDef has been added to the struct symbol.
|
|
531
639
|
const symbol = identifier?.symbol ?? node.symbol;
|
|
532
|
-
if (symbol &&
|
|
640
|
+
if (symbol &&
|
|
641
|
+
TypeDefSymbolData.is(symbol.data) &&
|
|
642
|
+
symbol.data.typeDef.kind === 'struct') {
|
|
533
643
|
return symbol.data.typeDef;
|
|
534
644
|
}
|
|
535
|
-
return {
|
|
536
|
-
...convertBase(node, ctx),
|
|
645
|
+
return wrapType(node, {
|
|
537
646
|
kind: 'struct',
|
|
538
647
|
fields: convertStructBlock(block, ctx),
|
|
539
|
-
};
|
|
648
|
+
}, ctx);
|
|
540
649
|
}
|
|
541
650
|
function convertStructBlock(node, ctx) {
|
|
542
651
|
const { fields } = StructBlockNode.destruct(node);
|
|
543
|
-
return fields.map(n => convertStructField(n, ctx));
|
|
652
|
+
return fields.map((n) => convertStructField(n, ctx));
|
|
544
653
|
}
|
|
545
654
|
function convertStructField(node, ctx) {
|
|
546
655
|
return StructPairFieldNode.is(node)
|
|
@@ -575,51 +684,46 @@ function convertStructSpreadField(node, ctx) {
|
|
|
575
684
|
};
|
|
576
685
|
}
|
|
577
686
|
function convertAny(node, ctx) {
|
|
578
|
-
return {
|
|
579
|
-
...convertBase(node, ctx),
|
|
687
|
+
return wrapType(node, {
|
|
580
688
|
kind: 'any',
|
|
581
|
-
};
|
|
689
|
+
}, ctx);
|
|
582
690
|
}
|
|
583
691
|
function convertBoolean(node, ctx) {
|
|
584
|
-
return {
|
|
585
|
-
...convertBase(node, ctx),
|
|
692
|
+
return wrapType(node, {
|
|
586
693
|
kind: 'boolean',
|
|
587
|
-
};
|
|
694
|
+
}, ctx);
|
|
588
695
|
}
|
|
589
696
|
function convertDispatcher(node, ctx) {
|
|
590
697
|
const { index, location } = DispatcherTypeNode.destruct(node);
|
|
591
|
-
return {
|
|
592
|
-
...convertBase(node, ctx, {
|
|
593
|
-
skipFirstIndexBody: true,
|
|
594
|
-
}),
|
|
698
|
+
return wrapType(node, {
|
|
595
699
|
kind: 'dispatcher',
|
|
596
|
-
|
|
700
|
+
parallelIndices: convertIndexBody(index, ctx),
|
|
597
701
|
registry: ResourceLocationNode.toString(location, 'full'),
|
|
598
|
-
};
|
|
702
|
+
}, ctx, { skipFirstIndexBody: true });
|
|
599
703
|
}
|
|
600
704
|
function convertList(node, ctx) {
|
|
601
705
|
const { item, lengthRange } = ListTypeNode.destruct(node);
|
|
602
|
-
return {
|
|
603
|
-
...convertBase(node, ctx),
|
|
706
|
+
return wrapType(node, {
|
|
604
707
|
kind: 'list',
|
|
605
708
|
item: convertType(item, ctx),
|
|
606
709
|
lengthRange: convertRange(lengthRange, ctx),
|
|
607
|
-
};
|
|
710
|
+
}, ctx);
|
|
608
711
|
}
|
|
609
712
|
function convertRange(node, ctx) {
|
|
610
713
|
if (!node) {
|
|
611
714
|
return undefined;
|
|
612
715
|
}
|
|
613
|
-
const { kind, min, max } = FloatRangeNode.is(node)
|
|
716
|
+
const { kind, min, max } = FloatRangeNode.is(node)
|
|
717
|
+
? FloatRangeNode.destruct(node)
|
|
718
|
+
: IntRangeNode.destruct(node);
|
|
614
719
|
return { kind, min: min?.value, max: max?.value };
|
|
615
720
|
}
|
|
616
721
|
function convertLiteral(node, ctx) {
|
|
617
722
|
const { value } = LiteralTypeNode.destruct(node);
|
|
618
|
-
return {
|
|
619
|
-
...convertBase(node, ctx),
|
|
723
|
+
return wrapType(node, {
|
|
620
724
|
kind: 'literal',
|
|
621
725
|
value: convertLiteralValue(value, ctx),
|
|
622
|
-
};
|
|
726
|
+
}, ctx);
|
|
623
727
|
}
|
|
624
728
|
function convertLiteralValue(node, ctx) {
|
|
625
729
|
if (LiteralNode.is(node)) {
|
|
@@ -649,53 +753,47 @@ function convertLiteralNumberSuffix(node, ctx) {
|
|
|
649
753
|
}
|
|
650
754
|
function convertNumericType(node, ctx) {
|
|
651
755
|
const { numericKind, valueRange } = NumericTypeNode.destruct(node);
|
|
652
|
-
return {
|
|
653
|
-
...convertBase(node, ctx),
|
|
756
|
+
return wrapType(node, {
|
|
654
757
|
kind: numericKind.value,
|
|
655
758
|
valueRange: convertRange(valueRange, ctx),
|
|
656
|
-
};
|
|
759
|
+
}, ctx);
|
|
657
760
|
}
|
|
658
761
|
function convertPrimitiveArray(node, ctx) {
|
|
659
|
-
const { arrayKind, lengthRange, valueRange } = PrimitiveArrayTypeNode
|
|
660
|
-
|
|
661
|
-
|
|
762
|
+
const { arrayKind, lengthRange, valueRange } = PrimitiveArrayTypeNode
|
|
763
|
+
.destruct(node);
|
|
764
|
+
return wrapType(node, {
|
|
662
765
|
kind: `${arrayKind.value}_array`,
|
|
663
766
|
lengthRange: convertRange(lengthRange, ctx),
|
|
664
767
|
valueRange: convertRange(valueRange, ctx),
|
|
665
|
-
};
|
|
768
|
+
}, ctx);
|
|
666
769
|
}
|
|
667
770
|
function convertString(node, ctx) {
|
|
668
771
|
const { lengthRange } = StringTypeNode.destruct(node);
|
|
669
|
-
return {
|
|
670
|
-
...convertBase(node, ctx),
|
|
772
|
+
return wrapType(node, {
|
|
671
773
|
kind: 'string',
|
|
672
774
|
lengthRange: convertRange(lengthRange, ctx),
|
|
673
|
-
};
|
|
775
|
+
}, ctx);
|
|
674
776
|
}
|
|
675
777
|
function convertReference(node, ctx) {
|
|
676
|
-
const { path
|
|
677
|
-
return {
|
|
678
|
-
...convertBase(node, ctx),
|
|
778
|
+
const { path } = ReferenceTypeNode.destruct(node);
|
|
779
|
+
return wrapType(node, {
|
|
679
780
|
kind: 'reference',
|
|
680
781
|
path: pathArrayToString(resolvePath(path, ctx)),
|
|
681
|
-
|
|
682
|
-
};
|
|
782
|
+
}, ctx);
|
|
683
783
|
}
|
|
684
784
|
function convertTuple(node, ctx) {
|
|
685
785
|
const { items } = TupleTypeNode.destruct(node);
|
|
686
|
-
return {
|
|
687
|
-
...convertBase(node, ctx),
|
|
786
|
+
return wrapType(node, {
|
|
688
787
|
kind: 'tuple',
|
|
689
|
-
items: items.map(n => convertType(n, ctx)),
|
|
690
|
-
};
|
|
788
|
+
items: items.map((n) => convertType(n, ctx)),
|
|
789
|
+
}, ctx);
|
|
691
790
|
}
|
|
692
791
|
function convertUnion(node, ctx) {
|
|
693
792
|
const { members } = UnionTypeNode.destruct(node);
|
|
694
|
-
return {
|
|
695
|
-
...convertBase(node, ctx),
|
|
793
|
+
return wrapType(node, {
|
|
696
794
|
kind: 'union',
|
|
697
|
-
members: members.map(n => convertType(n, ctx)),
|
|
698
|
-
};
|
|
795
|
+
members: members.map((n) => convertType(n, ctx)),
|
|
796
|
+
}, ctx);
|
|
699
797
|
}
|
|
700
798
|
function asString(node) {
|
|
701
799
|
if (ResourceLocationNode.is(node)) {
|