skir 0.0.1 → 0.0.2
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/dist/casing.d.ts +1 -4
- package/dist/casing.d.ts.map +1 -1
- package/dist/casing.js +0 -29
- package/dist/casing.js.map +1 -1
- package/dist/casing.test.js +2 -13
- package/dist/casing.test.js.map +1 -1
- package/dist/command_line_parser.d.ts +3 -3
- package/dist/command_line_parser.d.ts.map +1 -1
- package/dist/command_line_parser.js +35 -38
- package/dist/command_line_parser.js.map +1 -1
- package/dist/command_line_parser.test.js +73 -78
- package/dist/command_line_parser.test.js.map +1 -1
- package/dist/compatibility_checker.d.ts +9 -3
- package/dist/compatibility_checker.d.ts.map +1 -1
- package/dist/compatibility_checker.js +17 -4
- package/dist/compatibility_checker.js.map +1 -1
- package/dist/compatibility_checker.test.js +55 -1
- package/dist/compatibility_checker.test.js.map +1 -1
- package/dist/compiler.js +34 -17
- package/dist/compiler.js.map +1 -1
- package/dist/config.d.ts +5 -35
- package/dist/config.d.ts.map +1 -1
- package/dist/definition_finder.d.ts +1 -1
- package/dist/definition_finder.d.ts.map +1 -1
- package/dist/doc_comment_parser.d.ts +3 -0
- package/dist/doc_comment_parser.d.ts.map +1 -0
- package/dist/doc_comment_parser.js +219 -0
- package/dist/doc_comment_parser.js.map +1 -0
- package/dist/doc_comment_parser.test.d.ts +2 -0
- package/dist/doc_comment_parser.test.d.ts.map +1 -0
- package/dist/doc_comment_parser.test.js +494 -0
- package/dist/doc_comment_parser.test.js.map +1 -0
- package/dist/error_renderer.d.ts +1 -1
- package/dist/error_renderer.d.ts.map +1 -1
- package/dist/error_renderer.js +84 -65
- package/dist/error_renderer.js.map +1 -1
- package/dist/formatter.d.ts +15 -2
- package/dist/formatter.d.ts.map +1 -1
- package/dist/formatter.js +191 -234
- package/dist/formatter.js.map +1 -1
- package/dist/formatter.test.js +322 -88
- package/dist/formatter.test.js.map +1 -1
- package/dist/index.d.ts +1 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -4
- package/dist/index.js.map +1 -1
- package/dist/language_server.js +1 -1
- package/dist/language_server.js.map +1 -1
- package/dist/literals.d.ts +1 -2
- package/dist/literals.d.ts.map +1 -1
- package/dist/literals.js +1 -12
- package/dist/literals.js.map +1 -1
- package/dist/literals.test.js +1 -4
- package/dist/literals.test.js.map +1 -1
- package/dist/module_set.d.ts +3 -7
- package/dist/module_set.d.ts.map +1 -1
- package/dist/module_set.js +205 -51
- package/dist/module_set.js.map +1 -1
- package/dist/module_set.test.js +595 -28
- package/dist/module_set.test.js.map +1 -1
- package/dist/parser.d.ts +3 -4
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +185 -92
- package/dist/parser.js.map +1 -1
- package/dist/parser.test.js +243 -15
- package/dist/parser.test.js.map +1 -1
- package/dist/project_initializer.d.ts +2 -0
- package/dist/project_initializer.d.ts.map +1 -0
- package/dist/project_initializer.js +30 -0
- package/dist/project_initializer.js.map +1 -0
- package/dist/snapshotter.d.ts +3 -0
- package/dist/snapshotter.d.ts.map +1 -1
- package/dist/snapshotter.js +43 -6
- package/dist/snapshotter.js.map +1 -1
- package/dist/tokenizer.d.ts +8 -2
- package/dist/tokenizer.d.ts.map +1 -1
- package/dist/tokenizer.js +26 -20
- package/dist/tokenizer.js.map +1 -1
- package/dist/tokenizer.test.js +285 -269
- package/dist/tokenizer.test.js.map +1 -1
- package/package.json +7 -5
- package/src/casing.ts +1 -36
- package/src/command_line_parser.ts +42 -48
- package/src/compatibility_checker.ts +29 -7
- package/src/compiler.ts +35 -18
- package/src/definition_finder.ts +1 -1
- package/src/doc_comment_parser.ts +246 -0
- package/src/error_renderer.ts +90 -66
- package/src/formatter.ts +249 -238
- package/src/index.ts +0 -6
- package/src/language_server.ts +8 -8
- package/src/literals.ts +5 -14
- package/src/module_set.ts +259 -79
- package/src/parser.ts +213 -98
- package/src/project_initializer.ts +39 -0
- package/src/snapshotter.ts +46 -5
- package/src/tokenizer.ts +47 -25
- package/dist/encoding.d.ts +0 -2
- package/dist/encoding.d.ts.map +0 -1
- package/dist/encoding.js +0 -38
- package/dist/encoding.js.map +0 -1
- package/dist/encoding.test.d.ts +0 -2
- package/dist/encoding.test.d.ts.map +0 -1
- package/dist/encoding.test.js +0 -23
- package/dist/encoding.test.js.map +0 -1
- package/dist/index.test.d.ts +0 -2
- package/dist/index.test.d.ts.map +0 -1
- package/dist/index.test.js +0 -14
- package/dist/index.test.js.map +0 -1
- package/dist/types.d.ts +0 -375
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/src/encoding.ts +0 -32
- package/src/types.ts +0 -518
package/src/module_set.ts
CHANGED
|
@@ -1,40 +1,44 @@
|
|
|
1
1
|
import * as paths from "path";
|
|
2
|
+
import {
|
|
3
|
+
unquoteAndUnescape,
|
|
4
|
+
type DenseJson,
|
|
5
|
+
type ErrorSink,
|
|
6
|
+
type FieldPath,
|
|
7
|
+
type Import,
|
|
8
|
+
type ImportAlias,
|
|
9
|
+
type Method,
|
|
10
|
+
type Module,
|
|
11
|
+
type MutableArrayType,
|
|
12
|
+
type MutableConstant,
|
|
13
|
+
type MutableDocReference,
|
|
14
|
+
type MutableMethod,
|
|
15
|
+
type MutableModule,
|
|
16
|
+
type MutableRecord,
|
|
17
|
+
type MutableRecordField,
|
|
18
|
+
type MutableRecordLocation,
|
|
19
|
+
type MutableResolvedType,
|
|
20
|
+
type MutableValue,
|
|
21
|
+
type Record,
|
|
22
|
+
type RecordKey,
|
|
23
|
+
type RecordLocation,
|
|
24
|
+
type ResolvedRecordRef,
|
|
25
|
+
type ResolvedType,
|
|
26
|
+
type Result,
|
|
27
|
+
type SkirError,
|
|
28
|
+
type Token,
|
|
29
|
+
type UnresolvedRecordRef,
|
|
30
|
+
type UnresolvedType,
|
|
31
|
+
type Value,
|
|
32
|
+
} from "skir-internal";
|
|
2
33
|
import { FileReader } from "./io.js";
|
|
3
34
|
import {
|
|
4
35
|
isStringLiteral,
|
|
5
36
|
literalValueToDenseJson,
|
|
6
37
|
literalValueToIdentity,
|
|
7
|
-
unquoteAndUnescape,
|
|
8
38
|
valueHasPrimitiveType,
|
|
9
39
|
} from "./literals.js";
|
|
10
40
|
import { parseModule } from "./parser.js";
|
|
11
41
|
import { tokenizeModule } from "./tokenizer.js";
|
|
12
|
-
import type {
|
|
13
|
-
DenseJson,
|
|
14
|
-
ErrorSink,
|
|
15
|
-
FieldPath,
|
|
16
|
-
Import,
|
|
17
|
-
ImportAlias,
|
|
18
|
-
Method,
|
|
19
|
-
Module,
|
|
20
|
-
MutableArrayType,
|
|
21
|
-
MutableModule,
|
|
22
|
-
MutableRecord,
|
|
23
|
-
MutableRecordLocation,
|
|
24
|
-
MutableResolvedType,
|
|
25
|
-
MutableValue,
|
|
26
|
-
Record,
|
|
27
|
-
RecordKey,
|
|
28
|
-
RecordLocation,
|
|
29
|
-
ResolvedRecordRef,
|
|
30
|
-
ResolvedType,
|
|
31
|
-
Result,
|
|
32
|
-
SkirError,
|
|
33
|
-
Token,
|
|
34
|
-
UnresolvedRecordRef,
|
|
35
|
-
UnresolvedType,
|
|
36
|
-
Value,
|
|
37
|
-
} from "./types.js";
|
|
38
42
|
|
|
39
43
|
export class ModuleSet {
|
|
40
44
|
static create(fileReader: FileReader, rootPath: string): ModuleSet {
|
|
@@ -42,7 +46,11 @@ export class ModuleSet {
|
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
static fromMap(map: ReadonlyMap<string, string>): ModuleSet {
|
|
45
|
-
|
|
49
|
+
const result = new ModuleSet(new MapBasedModuleParser(map));
|
|
50
|
+
for (const modulePath of map.keys()) {
|
|
51
|
+
result.parseAndResolve(modulePath);
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
46
54
|
}
|
|
47
55
|
|
|
48
56
|
constructor(private readonly moduleParser: ModuleParser) {}
|
|
@@ -141,6 +149,29 @@ export class ModuleSet {
|
|
|
141
149
|
errorIsInOtherModule: true,
|
|
142
150
|
});
|
|
143
151
|
}
|
|
152
|
+
} else if (declaration.kind === "import") {
|
|
153
|
+
// Make sure that the symbols we are importing exist in the imported
|
|
154
|
+
// module and are not imported symbols themselves.
|
|
155
|
+
for (const importedName of declaration.importedNames) {
|
|
156
|
+
const importedDeclaration =
|
|
157
|
+
otherModule.result.nameToDeclaration[importedName.text];
|
|
158
|
+
if (importedDeclaration === undefined) {
|
|
159
|
+
errors.push({
|
|
160
|
+
token: importedName,
|
|
161
|
+
message: "Not found",
|
|
162
|
+
});
|
|
163
|
+
} else if (importedDeclaration.kind === "import") {
|
|
164
|
+
errors.push({
|
|
165
|
+
token: importedName,
|
|
166
|
+
message: "Cannot reimport imported record",
|
|
167
|
+
});
|
|
168
|
+
} else if (importedDeclaration.kind !== "record") {
|
|
169
|
+
errors.push({
|
|
170
|
+
token: importedName,
|
|
171
|
+
message: "Not a record",
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
144
175
|
}
|
|
145
176
|
}
|
|
146
177
|
|
|
@@ -232,7 +263,6 @@ export class ModuleSet {
|
|
|
232
263
|
const usedImports = new Set<string>();
|
|
233
264
|
const typeResolver = new TypeResolver(
|
|
234
265
|
module,
|
|
235
|
-
modulePath,
|
|
236
266
|
this.modules,
|
|
237
267
|
usedImports,
|
|
238
268
|
errors,
|
|
@@ -248,16 +278,25 @@ export class ModuleSet {
|
|
|
248
278
|
// type depends on the record where the field is defined.
|
|
249
279
|
// Store the result in the Field object.
|
|
250
280
|
this.storeFieldRecursivity(record);
|
|
251
|
-
// If the record has explicit numbering, register an error if any field
|
|
252
|
-
// has a direct dependency on a record with implicit numbering.
|
|
253
|
-
this.verifyNumberingConstraint(record, errors);
|
|
254
281
|
// Verify that the `key` field of every array type is valid.
|
|
255
282
|
for (const field of record.fields) {
|
|
256
283
|
const { type } = field;
|
|
257
284
|
if (type) {
|
|
258
285
|
this.validateArrayKeys(type, errors);
|
|
259
286
|
}
|
|
287
|
+
// Resolve the references in the doc comments of the field.
|
|
288
|
+
this.resolveDocReferences(
|
|
289
|
+
{
|
|
290
|
+
kind: "field",
|
|
291
|
+
field: field,
|
|
292
|
+
record: record,
|
|
293
|
+
},
|
|
294
|
+
module,
|
|
295
|
+
errors,
|
|
296
|
+
);
|
|
260
297
|
}
|
|
298
|
+
// Resolve the references in the doc comments of the record.
|
|
299
|
+
this.resolveDocReferences(record, module, errors);
|
|
261
300
|
}
|
|
262
301
|
// Resolve every request/response type of every method in the module.
|
|
263
302
|
// Store the result in the Method object.
|
|
@@ -290,6 +329,8 @@ export class ModuleSet {
|
|
|
290
329
|
message: `Same number as ${otherMethodName} in ${otherModulePath}`,
|
|
291
330
|
});
|
|
292
331
|
}
|
|
332
|
+
// Resolve the references in the doc comments of the method.
|
|
333
|
+
this.resolveDocReferences(method, module, errors);
|
|
293
334
|
}
|
|
294
335
|
// Resolve every constant type. Store the result in the constant object.
|
|
295
336
|
for (const constant of module.constants) {
|
|
@@ -301,6 +342,8 @@ export class ModuleSet {
|
|
|
301
342
|
constant.valueAsDenseJson = //
|
|
302
343
|
this.valueToDenseJson(constant.value, type, errors);
|
|
303
344
|
}
|
|
345
|
+
// Resolve the references in the doc comments of the constant.
|
|
346
|
+
this.resolveDocReferences(constant, module, errors);
|
|
304
347
|
}
|
|
305
348
|
|
|
306
349
|
ensureAllImportsAreUsed(module, usedImports, errors);
|
|
@@ -371,46 +414,6 @@ export class ModuleSet {
|
|
|
371
414
|
}
|
|
372
415
|
}
|
|
373
416
|
|
|
374
|
-
/**
|
|
375
|
-
* If the record has explicit numbering, register an error if any field has a
|
|
376
|
-
* direct dependency on a record with implicit numbering.
|
|
377
|
-
*/
|
|
378
|
-
private verifyNumberingConstraint(record: Record, errors: ErrorSink): void {
|
|
379
|
-
if (record.numbering !== "explicit") {
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
|
-
for (const field of record.fields) {
|
|
383
|
-
if (!field.type) continue;
|
|
384
|
-
const invalidRef = this.referencesImplicitlyNumberedRecord(field.type);
|
|
385
|
-
if (invalidRef) {
|
|
386
|
-
errors.push({
|
|
387
|
-
token: invalidRef.refToken,
|
|
388
|
-
message:
|
|
389
|
-
`Field type references a ${invalidRef.recordType} with implicit ` +
|
|
390
|
-
`numbering, but field belongs to a ${record.recordType} with ` +
|
|
391
|
-
`explicit numbering`,
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
private referencesImplicitlyNumberedRecord(
|
|
398
|
-
input: ResolvedType,
|
|
399
|
-
): ResolvedRecordRef | false {
|
|
400
|
-
switch (input.kind) {
|
|
401
|
-
case "array":
|
|
402
|
-
return this.referencesImplicitlyNumberedRecord(input.item);
|
|
403
|
-
case "optional":
|
|
404
|
-
return this.referencesImplicitlyNumberedRecord(input.other);
|
|
405
|
-
case "primitive":
|
|
406
|
-
return false;
|
|
407
|
-
case "record": {
|
|
408
|
-
const record = this.recordMap.get(input.key)!.record;
|
|
409
|
-
return record.numbering === "implicit" && input;
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
417
|
/**
|
|
415
418
|
* Verifies that the `key` field of every array type found in `topLevelType`
|
|
416
419
|
* is valid. Populates the `keyType` field of every field path.
|
|
@@ -467,7 +470,7 @@ export class ModuleSet {
|
|
|
467
470
|
if (fieldName.text !== "kind") {
|
|
468
471
|
errors.push({
|
|
469
472
|
token: fieldName,
|
|
470
|
-
expected: '
|
|
473
|
+
expected: "'kind'",
|
|
471
474
|
});
|
|
472
475
|
return undefined;
|
|
473
476
|
}
|
|
@@ -799,6 +802,171 @@ export class ModuleSet {
|
|
|
799
802
|
}
|
|
800
803
|
}
|
|
801
804
|
|
|
805
|
+
/** Resolve the references in the doc comments of the given declaration. */
|
|
806
|
+
private resolveDocReferences(
|
|
807
|
+
documentee:
|
|
808
|
+
| MutableConstant
|
|
809
|
+
| MutableMethod
|
|
810
|
+
| MutableRecord
|
|
811
|
+
| MutableRecordField,
|
|
812
|
+
module: Module,
|
|
813
|
+
errors: ErrorSink,
|
|
814
|
+
): void {
|
|
815
|
+
const doc =
|
|
816
|
+
documentee.kind === "field" ? documentee.field.doc : documentee.doc;
|
|
817
|
+
|
|
818
|
+
const docReferences = doc.pieces.filter(
|
|
819
|
+
(p): p is MutableDocReference => p.kind === "reference",
|
|
820
|
+
);
|
|
821
|
+
if (docReferences.length <= 0) {
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// Try to resolve a reference by looking it up in the given scope.
|
|
826
|
+
// Returns true if resolved, false otherwise.
|
|
827
|
+
const tryResolveReference = (
|
|
828
|
+
ref: MutableDocReference,
|
|
829
|
+
nameChain: readonly Token[],
|
|
830
|
+
scope: Record | Module,
|
|
831
|
+
): boolean => {
|
|
832
|
+
if (ref.absolute && scope !== module) {
|
|
833
|
+
return false;
|
|
834
|
+
}
|
|
835
|
+
const firstName = nameChain[0]!;
|
|
836
|
+
const match = scope.nameToDeclaration[firstName.text];
|
|
837
|
+
if (!match) {
|
|
838
|
+
return false;
|
|
839
|
+
}
|
|
840
|
+
if (nameChain.length === 1) {
|
|
841
|
+
// Single name: must refer to a declaration.
|
|
842
|
+
switch (match.kind) {
|
|
843
|
+
case "constant":
|
|
844
|
+
case "method":
|
|
845
|
+
case "record": {
|
|
846
|
+
ref.referee = match;
|
|
847
|
+
return true;
|
|
848
|
+
}
|
|
849
|
+
case "field": {
|
|
850
|
+
if (scope.kind !== "record") {
|
|
851
|
+
throw new TypeError(scope.kind);
|
|
852
|
+
}
|
|
853
|
+
ref.referee = {
|
|
854
|
+
kind: "field",
|
|
855
|
+
field: match,
|
|
856
|
+
record: scope,
|
|
857
|
+
};
|
|
858
|
+
return true;
|
|
859
|
+
}
|
|
860
|
+
case "import":
|
|
861
|
+
case "import-alias":
|
|
862
|
+
case "removed":
|
|
863
|
+
return false;
|
|
864
|
+
}
|
|
865
|
+
} else {
|
|
866
|
+
// Multi-part name: first part must be a naming scope.
|
|
867
|
+
switch (match.kind) {
|
|
868
|
+
case "record":
|
|
869
|
+
return tryResolveReference(ref, nameChain.slice(1), match);
|
|
870
|
+
case "import":
|
|
871
|
+
case "import-alias": {
|
|
872
|
+
if (scope !== module) {
|
|
873
|
+
// Cannot refer to other module's imports.
|
|
874
|
+
return false;
|
|
875
|
+
}
|
|
876
|
+
const { resolvedModulePath } = match;
|
|
877
|
+
if (!resolvedModulePath) {
|
|
878
|
+
return false;
|
|
879
|
+
}
|
|
880
|
+
const importedModule = this.modules.get(resolvedModulePath!);
|
|
881
|
+
if (!importedModule?.result) {
|
|
882
|
+
return false;
|
|
883
|
+
}
|
|
884
|
+
const newNameChain = nameChain.slice(
|
|
885
|
+
match.kind === "import" ? 0 : 1,
|
|
886
|
+
);
|
|
887
|
+
return tryResolveReference(
|
|
888
|
+
ref,
|
|
889
|
+
newNameChain,
|
|
890
|
+
importedModule.result,
|
|
891
|
+
);
|
|
892
|
+
}
|
|
893
|
+
case "constant":
|
|
894
|
+
case "field":
|
|
895
|
+
case "method":
|
|
896
|
+
case "removed":
|
|
897
|
+
return false;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
};
|
|
901
|
+
|
|
902
|
+
const { recordMap } = this;
|
|
903
|
+
// Build list of naming scopes to search, in order of priority.
|
|
904
|
+
const scopes: Array<Record | Module> = [];
|
|
905
|
+
const pushRecordAncestorsToScopes = (record: Record): void => {
|
|
906
|
+
const { key } = record;
|
|
907
|
+
const location = recordMap.get(key)!;
|
|
908
|
+
const ancestors = [...location.recordAncestors].reverse();
|
|
909
|
+
for (const ancestor of ancestors) {
|
|
910
|
+
scopes.push(ancestor);
|
|
911
|
+
}
|
|
912
|
+
};
|
|
913
|
+
const pushTypeToScopes = (type: ResolvedType | undefined): void => {
|
|
914
|
+
if (type) {
|
|
915
|
+
const recordKey = tryFindRecordForType(type);
|
|
916
|
+
if (recordKey) {
|
|
917
|
+
const { record } = recordMap.get(recordKey)!;
|
|
918
|
+
scopes.push(record);
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
switch (documentee.kind) {
|
|
923
|
+
case "constant": {
|
|
924
|
+
scopes.push(module);
|
|
925
|
+
pushTypeToScopes(documentee.type);
|
|
926
|
+
break;
|
|
927
|
+
}
|
|
928
|
+
case "field": {
|
|
929
|
+
const { field, record } = documentee;
|
|
930
|
+
pushRecordAncestorsToScopes(record);
|
|
931
|
+
scopes.push(module);
|
|
932
|
+
pushTypeToScopes(field.type);
|
|
933
|
+
break;
|
|
934
|
+
}
|
|
935
|
+
case "method": {
|
|
936
|
+
scopes.push(module);
|
|
937
|
+
pushTypeToScopes(documentee.requestType);
|
|
938
|
+
pushTypeToScopes(documentee.responseType);
|
|
939
|
+
break;
|
|
940
|
+
}
|
|
941
|
+
case "record": {
|
|
942
|
+
pushRecordAncestorsToScopes(documentee);
|
|
943
|
+
scopes.push(module);
|
|
944
|
+
break;
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
// Resolve each reference by searching through scopes in priority order.
|
|
949
|
+
for (const reference of docReferences) {
|
|
950
|
+
const { nameChain } = reference;
|
|
951
|
+
if (nameChain.length <= 0) {
|
|
952
|
+
continue;
|
|
953
|
+
}
|
|
954
|
+
let resolved = false;
|
|
955
|
+
for (const scope of scopes) {
|
|
956
|
+
if (tryResolveReference(reference, nameChain, scope)) {
|
|
957
|
+
resolved = true;
|
|
958
|
+
break;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
if (!resolved) {
|
|
962
|
+
errors.push({
|
|
963
|
+
token: reference.referenceRange,
|
|
964
|
+
message: "Cannot resolve reference",
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
|
|
802
970
|
private readonly modules = new Map<string, Result<Module | null>>();
|
|
803
971
|
private readonly mutableRecordMap = new Map<RecordKey, RecordLocation>();
|
|
804
972
|
private readonly mutableResolvedModules: MutableModule[] = [];
|
|
@@ -916,7 +1084,6 @@ function validateKeyedItems(
|
|
|
916
1084
|
class TypeResolver {
|
|
917
1085
|
constructor(
|
|
918
1086
|
private readonly module: Module,
|
|
919
|
-
private readonly modulePath: string,
|
|
920
1087
|
private readonly modules: Map<string, Result<Module | null>>,
|
|
921
1088
|
private readonly usedImports: Set<string>,
|
|
922
1089
|
private readonly errors: ErrorSink,
|
|
@@ -1006,12 +1173,12 @@ class TypeResolver {
|
|
|
1006
1173
|
} else if (newIt.kind === "record") {
|
|
1007
1174
|
it = newIt;
|
|
1008
1175
|
} else if (newIt.kind === "import" || newIt.kind === "import-alias") {
|
|
1009
|
-
const
|
|
1176
|
+
const transitiveImportError = (): SkirError => ({
|
|
1010
1177
|
token: namePart,
|
|
1011
|
-
message:
|
|
1178
|
+
message: "Cannot refer to imports of imported module",
|
|
1012
1179
|
});
|
|
1013
1180
|
if (i !== 0) {
|
|
1014
|
-
errors.push(
|
|
1181
|
+
errors.push(transitiveImportError());
|
|
1015
1182
|
return undefined;
|
|
1016
1183
|
}
|
|
1017
1184
|
usedImports.add(name);
|
|
@@ -1035,7 +1202,7 @@ class TypeResolver {
|
|
|
1035
1202
|
if (!newIt || newIt.kind !== "record") {
|
|
1036
1203
|
this.errors.push(
|
|
1037
1204
|
newIt.kind === "import" || newIt.kind === "import-alias"
|
|
1038
|
-
?
|
|
1205
|
+
? transitiveImportError()
|
|
1039
1206
|
: makeNotARecordError(namePart),
|
|
1040
1207
|
);
|
|
1041
1208
|
return undefined;
|
|
@@ -1115,7 +1282,7 @@ abstract class ModuleParserBase implements ModuleParser {
|
|
|
1115
1282
|
};
|
|
1116
1283
|
}
|
|
1117
1284
|
|
|
1118
|
-
return parseModule(tokens.result
|
|
1285
|
+
return parseModule(tokens.result);
|
|
1119
1286
|
}
|
|
1120
1287
|
}
|
|
1121
1288
|
|
|
@@ -1173,3 +1340,16 @@ function resolveModulePath(
|
|
|
1173
1340
|
}
|
|
1174
1341
|
return modulePath;
|
|
1175
1342
|
}
|
|
1343
|
+
|
|
1344
|
+
function tryFindRecordForType(type: ResolvedType): RecordKey | null {
|
|
1345
|
+
switch (type.kind) {
|
|
1346
|
+
case "array":
|
|
1347
|
+
return tryFindRecordForType(type.item);
|
|
1348
|
+
case "optional":
|
|
1349
|
+
return tryFindRecordForType(type.other);
|
|
1350
|
+
case "record":
|
|
1351
|
+
return type.key;
|
|
1352
|
+
case "primitive":
|
|
1353
|
+
return null;
|
|
1354
|
+
}
|
|
1355
|
+
}
|