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.
Files changed (115) hide show
  1. package/dist/casing.d.ts +1 -4
  2. package/dist/casing.d.ts.map +1 -1
  3. package/dist/casing.js +0 -29
  4. package/dist/casing.js.map +1 -1
  5. package/dist/casing.test.js +2 -13
  6. package/dist/casing.test.js.map +1 -1
  7. package/dist/command_line_parser.d.ts +3 -3
  8. package/dist/command_line_parser.d.ts.map +1 -1
  9. package/dist/command_line_parser.js +35 -38
  10. package/dist/command_line_parser.js.map +1 -1
  11. package/dist/command_line_parser.test.js +73 -78
  12. package/dist/command_line_parser.test.js.map +1 -1
  13. package/dist/compatibility_checker.d.ts +9 -3
  14. package/dist/compatibility_checker.d.ts.map +1 -1
  15. package/dist/compatibility_checker.js +17 -4
  16. package/dist/compatibility_checker.js.map +1 -1
  17. package/dist/compatibility_checker.test.js +55 -1
  18. package/dist/compatibility_checker.test.js.map +1 -1
  19. package/dist/compiler.js +34 -17
  20. package/dist/compiler.js.map +1 -1
  21. package/dist/config.d.ts +5 -35
  22. package/dist/config.d.ts.map +1 -1
  23. package/dist/definition_finder.d.ts +1 -1
  24. package/dist/definition_finder.d.ts.map +1 -1
  25. package/dist/doc_comment_parser.d.ts +3 -0
  26. package/dist/doc_comment_parser.d.ts.map +1 -0
  27. package/dist/doc_comment_parser.js +219 -0
  28. package/dist/doc_comment_parser.js.map +1 -0
  29. package/dist/doc_comment_parser.test.d.ts +2 -0
  30. package/dist/doc_comment_parser.test.d.ts.map +1 -0
  31. package/dist/doc_comment_parser.test.js +494 -0
  32. package/dist/doc_comment_parser.test.js.map +1 -0
  33. package/dist/error_renderer.d.ts +1 -1
  34. package/dist/error_renderer.d.ts.map +1 -1
  35. package/dist/error_renderer.js +84 -65
  36. package/dist/error_renderer.js.map +1 -1
  37. package/dist/formatter.d.ts +15 -2
  38. package/dist/formatter.d.ts.map +1 -1
  39. package/dist/formatter.js +191 -234
  40. package/dist/formatter.js.map +1 -1
  41. package/dist/formatter.test.js +322 -88
  42. package/dist/formatter.test.js.map +1 -1
  43. package/dist/index.d.ts +1 -5
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +1 -4
  46. package/dist/index.js.map +1 -1
  47. package/dist/language_server.js +1 -1
  48. package/dist/language_server.js.map +1 -1
  49. package/dist/literals.d.ts +1 -2
  50. package/dist/literals.d.ts.map +1 -1
  51. package/dist/literals.js +1 -12
  52. package/dist/literals.js.map +1 -1
  53. package/dist/literals.test.js +1 -4
  54. package/dist/literals.test.js.map +1 -1
  55. package/dist/module_set.d.ts +3 -7
  56. package/dist/module_set.d.ts.map +1 -1
  57. package/dist/module_set.js +205 -51
  58. package/dist/module_set.js.map +1 -1
  59. package/dist/module_set.test.js +595 -28
  60. package/dist/module_set.test.js.map +1 -1
  61. package/dist/parser.d.ts +3 -4
  62. package/dist/parser.d.ts.map +1 -1
  63. package/dist/parser.js +185 -92
  64. package/dist/parser.js.map +1 -1
  65. package/dist/parser.test.js +243 -15
  66. package/dist/parser.test.js.map +1 -1
  67. package/dist/project_initializer.d.ts +2 -0
  68. package/dist/project_initializer.d.ts.map +1 -0
  69. package/dist/project_initializer.js +30 -0
  70. package/dist/project_initializer.js.map +1 -0
  71. package/dist/snapshotter.d.ts +3 -0
  72. package/dist/snapshotter.d.ts.map +1 -1
  73. package/dist/snapshotter.js +43 -6
  74. package/dist/snapshotter.js.map +1 -1
  75. package/dist/tokenizer.d.ts +8 -2
  76. package/dist/tokenizer.d.ts.map +1 -1
  77. package/dist/tokenizer.js +26 -20
  78. package/dist/tokenizer.js.map +1 -1
  79. package/dist/tokenizer.test.js +285 -269
  80. package/dist/tokenizer.test.js.map +1 -1
  81. package/package.json +7 -5
  82. package/src/casing.ts +1 -36
  83. package/src/command_line_parser.ts +42 -48
  84. package/src/compatibility_checker.ts +29 -7
  85. package/src/compiler.ts +35 -18
  86. package/src/definition_finder.ts +1 -1
  87. package/src/doc_comment_parser.ts +246 -0
  88. package/src/error_renderer.ts +90 -66
  89. package/src/formatter.ts +249 -238
  90. package/src/index.ts +0 -6
  91. package/src/language_server.ts +8 -8
  92. package/src/literals.ts +5 -14
  93. package/src/module_set.ts +259 -79
  94. package/src/parser.ts +213 -98
  95. package/src/project_initializer.ts +39 -0
  96. package/src/snapshotter.ts +46 -5
  97. package/src/tokenizer.ts +47 -25
  98. package/dist/encoding.d.ts +0 -2
  99. package/dist/encoding.d.ts.map +0 -1
  100. package/dist/encoding.js +0 -38
  101. package/dist/encoding.js.map +0 -1
  102. package/dist/encoding.test.d.ts +0 -2
  103. package/dist/encoding.test.d.ts.map +0 -1
  104. package/dist/encoding.test.js +0 -23
  105. package/dist/encoding.test.js.map +0 -1
  106. package/dist/index.test.d.ts +0 -2
  107. package/dist/index.test.d.ts.map +0 -1
  108. package/dist/index.test.js +0 -14
  109. package/dist/index.test.js.map +0 -1
  110. package/dist/types.d.ts +0 -375
  111. package/dist/types.d.ts.map +0 -1
  112. package/dist/types.js +0 -2
  113. package/dist/types.js.map +0 -1
  114. package/src/encoding.ts +0 -32
  115. package/src/types.ts +0 -518
@@ -26,10 +26,13 @@ describe("module set", () => {
26
26
  struct Inner(101) {}
27
27
  inner: Inner;
28
28
  zoo: other_module.Outer.Zoo;
29
+
30
+ loo_loo: struct {};
29
31
  }
30
32
 
31
33
  method GetBar(Outer.Foo): Bar;
32
34
  method GetBar2(Outer.Foo): Bar = 100;
35
+ method Search(enum {}): struct {};
33
36
  `);
34
37
  fakeFileReader.pathToCode.set("path/to/root/path/to/other/module", `
35
38
  struct Outer {
@@ -103,9 +106,10 @@ describe("module set", () => {
103
106
  { name: { text: "foo2" } },
104
107
  { name: { text: "inner" } },
105
108
  { name: { text: "zoo" } },
109
+ { name: { text: "loo_loo" } },
106
110
  ],
107
- numSlots: 4,
108
- numSlotsInclRemovedNumbers: 4,
111
+ numSlots: 5,
112
+ numSlotsInclRemovedNumbers: 5,
109
113
  },
110
114
  GetBar: {
111
115
  kind: "method",
@@ -132,6 +136,14 @@ describe("module set", () => {
132
136
  GetBar2: {
133
137
  number: 100,
134
138
  },
139
+ Search: {},
140
+ SearchRequest: {
141
+ name: {
142
+ text: "SearchRequest",
143
+ originalText: "Search",
144
+ },
145
+ },
146
+ SearchResponse: {},
135
147
  },
136
148
  declarations: [
137
149
  { name: { text: "other_module" } },
@@ -139,12 +151,18 @@ describe("module set", () => {
139
151
  { name: { text: "Bar" } },
140
152
  { name: { text: "GetBar" } },
141
153
  { name: { text: "GetBar2" } },
154
+ { name: { text: "Search" } },
155
+ { name: { text: "SearchRequest" } },
156
+ { name: { text: "SearchResponse" } },
142
157
  ],
143
158
  records: [
144
159
  { record: { name: { text: "Foo" } } },
145
160
  { record: { name: { text: "Outer" } } },
146
161
  { record: { name: { text: "Inner" }, recordNumber: 101 } },
162
+ { record: { name: { text: "LooLoo" } } },
147
163
  { record: { name: { text: "Bar" } } },
164
+ { record: { name: { text: "SearchRequest" } } },
165
+ { record: { name: { text: "SearchResponse" } } },
148
166
  ],
149
167
  },
150
168
  errors: [],
@@ -362,25 +380,6 @@ describe("module set", () => {
362
380
  const actual = moduleSet.parseAndResolve("path/to/module");
363
381
  expect(actual).toMatch({ errors: [] });
364
382
  });
365
- it("field numbering constraint not satisfied", () => {
366
- const fakeFileReader = new FakeFileReader();
367
- fakeFileReader.pathToCode.set("path/to/root/path/to/module", `
368
- struct Foo { foo: int32; }
369
- struct Bar { foo: Foo = 0; }
370
- `);
371
- const moduleSet = ModuleSet.create(fakeFileReader, "path/to/root");
372
- const actual = moduleSet.parseAndResolve("path/to/module");
373
- expect(actual).toMatch({
374
- errors: [
375
- {
376
- token: {
377
- text: "Foo",
378
- },
379
- message: "Field type references a struct with implicit numbering, but field belongs to a struct with explicit numbering",
380
- },
381
- ],
382
- });
383
- });
384
383
  describe("keyed arrays", () => {
385
384
  it("works", () => {
386
385
  const fakeFileReader = new FakeFileReader();
@@ -522,7 +521,7 @@ describe("module set", () => {
522
521
  token: {
523
522
  text: "|",
524
523
  },
525
- expected: '"]"',
524
+ expected: "']'",
526
525
  },
527
526
  ],
528
527
  });
@@ -566,7 +565,7 @@ describe("module set", () => {
566
565
  token: {
567
566
  text: "key",
568
567
  },
569
- expected: '"kind"',
568
+ expected: "'kind'",
570
569
  },
571
570
  ],
572
571
  });
@@ -693,8 +692,9 @@ describe("module set", () => {
693
692
  {
694
693
  token: {
695
694
  text: "Foo",
695
+ position: 18,
696
696
  },
697
- message: "Cannot reimport imported name 'Foo'",
697
+ message: "Cannot reimport imported record",
698
698
  },
699
699
  ],
700
700
  });
@@ -709,7 +709,7 @@ describe("module set", () => {
709
709
  struct Bar { foo: foo.Foo; }
710
710
  `);
711
711
  fakeFileReader.pathToCode.set("path/to/root/path/to/module", `
712
- import foo from "./bar";
712
+ import foo, DoesNotExist from "./bar";
713
713
  struct Zoo { foo: foo.Foo; }
714
714
  `);
715
715
  const moduleSet = ModuleSet.create(fakeFileReader, "path/to/root");
@@ -719,8 +719,15 @@ describe("module set", () => {
719
719
  {
720
720
  token: {
721
721
  text: "foo",
722
+ position: 18,
722
723
  },
723
- message: "Cannot reimport imported name 'foo'",
724
+ message: "Not a record",
725
+ },
726
+ {
727
+ token: {
728
+ text: "DoesNotExist",
729
+ },
730
+ message: "Not found",
724
731
  },
725
732
  ],
726
733
  });
@@ -746,7 +753,7 @@ describe("module set", () => {
746
753
  token: {
747
754
  text: "Foo",
748
755
  },
749
- message: "Cannot reimport imported name 'Foo'",
756
+ message: "Cannot refer to imports of imported module",
750
757
  },
751
758
  ],
752
759
  });
@@ -772,7 +779,7 @@ describe("module set", () => {
772
779
  token: {
773
780
  text: "foo",
774
781
  },
775
- message: "Cannot reimport imported name 'foo'",
782
+ message: "Cannot refer to imports of imported module",
776
783
  },
777
784
  ],
778
785
  });
@@ -1326,5 +1333,565 @@ describe("module set", () => {
1326
1333
  });
1327
1334
  });
1328
1335
  });
1336
+ describe("doc comment references", () => {
1337
+ it("resolves reference to enum field", () => {
1338
+ const fakeFileReader = new FakeFileReader();
1339
+ fakeFileReader.pathToCode.set("path/to/root/module", `
1340
+ /// Hello [Bar.OK]
1341
+ struct Foo {
1342
+ x: int32;
1343
+ }
1344
+
1345
+ enum Bar { OK; }
1346
+ `);
1347
+ const moduleSet = ModuleSet.create(fakeFileReader, "path/to/root");
1348
+ const actual = moduleSet.parseAndResolve("module");
1349
+ const fooRecord = actual.result?.records.find((r) => r.record?.name.text === "Foo");
1350
+ expect(fooRecord).toMatch({
1351
+ record: {
1352
+ name: { text: "Foo" },
1353
+ doc: {
1354
+ pieces: [
1355
+ { kind: "text", text: "Hello " },
1356
+ {
1357
+ kind: "reference",
1358
+ nameChain: [{ text: "Bar" }, { text: "OK" }],
1359
+ referee: {
1360
+ kind: "field",
1361
+ field: { name: { text: "OK" } },
1362
+ record: { name: { text: "Bar" } },
1363
+ },
1364
+ },
1365
+ ],
1366
+ },
1367
+ },
1368
+ });
1369
+ expect(actual.errors).toMatch([]);
1370
+ });
1371
+ it("resolves reference to sibling field", () => {
1372
+ const fakeFileReader = new FakeFileReader();
1373
+ fakeFileReader.pathToCode.set("path/to/root/module", `
1374
+ struct Foo {
1375
+ x: int32;
1376
+ /// Must be different from [x]
1377
+ y: int32;
1378
+ }
1379
+ `);
1380
+ const moduleSet = ModuleSet.create(fakeFileReader, "path/to/root");
1381
+ const actual = moduleSet.parseAndResolve("module");
1382
+ expect(actual).toMatch({
1383
+ result: {
1384
+ records: [
1385
+ {
1386
+ record: {
1387
+ fields: [
1388
+ { name: { text: "x" } },
1389
+ {
1390
+ name: { text: "y" },
1391
+ doc: {
1392
+ pieces: [
1393
+ { kind: "text", text: "Must be different from " },
1394
+ {
1395
+ kind: "reference",
1396
+ nameChain: [{ text: "x" }],
1397
+ referee: {
1398
+ kind: "field",
1399
+ field: { name: { text: "x" } },
1400
+ record: { name: { text: "Foo" } },
1401
+ },
1402
+ },
1403
+ ],
1404
+ },
1405
+ },
1406
+ ],
1407
+ },
1408
+ },
1409
+ ],
1410
+ },
1411
+ errors: [],
1412
+ });
1413
+ });
1414
+ it("resolves reference to record", () => {
1415
+ const fakeFileReader = new FakeFileReader();
1416
+ fakeFileReader.pathToCode.set("path/to/root/module", `
1417
+ /// See [Bar] for details
1418
+ struct Foo {
1419
+ x: int32;
1420
+ }
1421
+
1422
+ struct Bar {}
1423
+ `);
1424
+ const moduleSet = ModuleSet.create(fakeFileReader, "path/to/root");
1425
+ const actual = moduleSet.parseAndResolve("module");
1426
+ const fooRecord = actual.result?.records.find((r) => r.record?.name.text === "Foo");
1427
+ expect(fooRecord).toMatch({
1428
+ record: {
1429
+ name: { text: "Foo" },
1430
+ doc: {
1431
+ pieces: [
1432
+ { kind: "text", text: "See " },
1433
+ {
1434
+ kind: "reference",
1435
+ nameChain: [{ text: "Bar" }],
1436
+ referee: { kind: "record", name: { text: "Bar" } },
1437
+ },
1438
+ { kind: "text", text: " for details" },
1439
+ ],
1440
+ },
1441
+ },
1442
+ });
1443
+ expect(actual.errors).toMatch([]);
1444
+ });
1445
+ it("resolves reference to nested record", () => {
1446
+ const fakeFileReader = new FakeFileReader();
1447
+ fakeFileReader.pathToCode.set("path/to/root/module", `
1448
+ /// Uses [Outer.Inner]
1449
+ struct Foo {
1450
+ x: int32;
1451
+ }
1452
+
1453
+ struct Outer {
1454
+ struct Inner {}
1455
+ }
1456
+ `);
1457
+ const moduleSet = ModuleSet.create(fakeFileReader, "path/to/root");
1458
+ const actual = moduleSet.parseAndResolve("module");
1459
+ const fooRecord = actual.result?.records.find((r) => r.record?.name.text === "Foo");
1460
+ expect(fooRecord).toMatch({
1461
+ record: {
1462
+ name: { text: "Foo" },
1463
+ doc: {
1464
+ pieces: [
1465
+ { kind: "text", text: "Uses " },
1466
+ {
1467
+ kind: "reference",
1468
+ nameChain: [{ text: "Outer" }, { text: "Inner" }],
1469
+ referee: { kind: "record", name: { text: "Inner" } },
1470
+ },
1471
+ ],
1472
+ },
1473
+ },
1474
+ });
1475
+ expect(actual.errors).toMatch([]);
1476
+ });
1477
+ it("resolves absolute reference", () => {
1478
+ const fakeFileReader = new FakeFileReader();
1479
+ fakeFileReader.pathToCode.set("path/to/root/module", `
1480
+ struct Outer {
1481
+ /// Reference to [.Bar]
1482
+ struct Inner {}
1483
+ struct Bar {}
1484
+ }
1485
+
1486
+ struct Bar {}
1487
+ `);
1488
+ const moduleSet = ModuleSet.create(fakeFileReader, "path/to/root");
1489
+ const actual = moduleSet.parseAndResolve("module");
1490
+ const outerRecord = actual.result?.records.find((r) => r.record?.name.text === "Outer");
1491
+ expect(outerRecord).toMatch({
1492
+ record: {
1493
+ name: { text: "Outer" },
1494
+ nestedRecords: [
1495
+ {
1496
+ name: { text: "Inner" },
1497
+ doc: {
1498
+ pieces: [
1499
+ { kind: "text", text: "Reference to " },
1500
+ {
1501
+ kind: "reference",
1502
+ absolute: true,
1503
+ nameChain: [{ text: "Bar" }],
1504
+ referee: {
1505
+ kind: "record",
1506
+ name: { text: "Bar", colNumber: 17 },
1507
+ },
1508
+ },
1509
+ ],
1510
+ },
1511
+ },
1512
+ {
1513
+ name: { text: "Bar", colNumber: 19 },
1514
+ },
1515
+ ],
1516
+ },
1517
+ });
1518
+ expect(actual.errors).toMatch([]);
1519
+ });
1520
+ it("resolves reference to method", () => {
1521
+ const fakeFileReader = new FakeFileReader();
1522
+ fakeFileReader.pathToCode.set("path/to/root/module", `
1523
+ /// Calls [GetData]
1524
+ struct Foo {}
1525
+
1526
+ method GetData(Foo): Foo;
1527
+ `);
1528
+ const moduleSet = ModuleSet.create(fakeFileReader, "path/to/root");
1529
+ const actual = moduleSet.parseAndResolve("module");
1530
+ expect(actual).toMatch({
1531
+ result: {
1532
+ records: [
1533
+ {
1534
+ record: {
1535
+ name: { text: "Foo" },
1536
+ doc: {
1537
+ pieces: [
1538
+ { kind: "text", text: "Calls " },
1539
+ {
1540
+ kind: "reference",
1541
+ nameChain: [{ text: "GetData" }],
1542
+ referee: { kind: "method", name: { text: "GetData" } },
1543
+ },
1544
+ ],
1545
+ },
1546
+ },
1547
+ },
1548
+ ],
1549
+ },
1550
+ errors: [],
1551
+ });
1552
+ });
1553
+ it("resolves reference to constant", () => {
1554
+ const fakeFileReader = new FakeFileReader();
1555
+ fakeFileReader.pathToCode.set("path/to/root/module", `
1556
+ /// Default is [DEFAULT_VALUE]
1557
+ struct Foo {
1558
+ x: int32;
1559
+ }
1560
+
1561
+ const DEFAULT_VALUE: int32 = 42;
1562
+ `);
1563
+ const moduleSet = ModuleSet.create(fakeFileReader, "path/to/root");
1564
+ const actual = moduleSet.parseAndResolve("module");
1565
+ expect(actual).toMatch({
1566
+ result: {
1567
+ records: [
1568
+ {
1569
+ record: {
1570
+ name: { text: "Foo" },
1571
+ doc: {
1572
+ pieces: [
1573
+ { kind: "text", text: "Default is " },
1574
+ {
1575
+ kind: "reference",
1576
+ nameChain: [{ text: "DEFAULT_VALUE" }],
1577
+ referee: {
1578
+ kind: "constant",
1579
+ name: { text: "DEFAULT_VALUE" },
1580
+ },
1581
+ },
1582
+ ],
1583
+ },
1584
+ },
1585
+ },
1586
+ ],
1587
+ },
1588
+ errors: [],
1589
+ });
1590
+ });
1591
+ it("resolves reference from field type scope", () => {
1592
+ const fakeFileReader = new FakeFileReader();
1593
+ fakeFileReader.pathToCode.set("path/to/root/module", `
1594
+ struct Foo {
1595
+ /// Uses [OK] from the Bar enum
1596
+ bar: Bar;
1597
+ }
1598
+
1599
+ enum Bar { OK; }
1600
+ `);
1601
+ const moduleSet = ModuleSet.create(fakeFileReader, "path/to/root");
1602
+ const actual = moduleSet.parseAndResolve("module");
1603
+ const fooRecord = actual.result?.records.find((r) => r.record?.name.text === "Foo");
1604
+ expect(fooRecord).toMatch({
1605
+ record: {
1606
+ name: { text: "Foo" },
1607
+ fields: [
1608
+ {
1609
+ name: { text: "bar" },
1610
+ doc: {
1611
+ pieces: [
1612
+ { kind: "text", text: "Uses " },
1613
+ {
1614
+ kind: "reference",
1615
+ nameChain: [{ text: "OK" }],
1616
+ referee: {
1617
+ kind: "field",
1618
+ field: { name: { text: "OK" } },
1619
+ record: { name: { text: "Bar" } },
1620
+ },
1621
+ },
1622
+ { kind: "text", text: " from the Bar enum" },
1623
+ ],
1624
+ },
1625
+ },
1626
+ ],
1627
+ },
1628
+ });
1629
+ expect(actual.errors).toMatch([]);
1630
+ });
1631
+ it("resolves reference from method request type scope", () => {
1632
+ const fakeFileReader = new FakeFileReader();
1633
+ fakeFileReader.pathToCode.set("path/to/root/module", `
1634
+ struct Request {
1635
+ x: int32;
1636
+ }
1637
+
1638
+ struct Response {}
1639
+
1640
+ /// Input [x] must be positive
1641
+ method DoWork(Request): Response;
1642
+ `);
1643
+ const moduleSet = ModuleSet.create(fakeFileReader, "path/to/root");
1644
+ const actual = moduleSet.parseAndResolve("module");
1645
+ expect(actual).toMatch({
1646
+ result: {
1647
+ methods: [
1648
+ {
1649
+ name: { text: "DoWork" },
1650
+ doc: {
1651
+ pieces: [
1652
+ { kind: "text", text: "Input " },
1653
+ {
1654
+ kind: "reference",
1655
+ nameChain: [{ text: "x" }],
1656
+ referee: {
1657
+ kind: "field",
1658
+ field: { name: { text: "x" } },
1659
+ record: { name: { text: "Request" } },
1660
+ },
1661
+ },
1662
+ { kind: "text", text: " must be positive" },
1663
+ ],
1664
+ },
1665
+ },
1666
+ ],
1667
+ },
1668
+ errors: [],
1669
+ });
1670
+ });
1671
+ it("resolves reference from constant type scope", () => {
1672
+ const fakeFileReader = new FakeFileReader();
1673
+ fakeFileReader.pathToCode.set("path/to/root/module", `
1674
+ enum Status { OK; }
1675
+
1676
+ /// Default status is [OK]
1677
+ const DEFAULT_STATUS: Status = "OK";
1678
+ `);
1679
+ const moduleSet = ModuleSet.create(fakeFileReader, "path/to/root");
1680
+ const actual = moduleSet.parseAndResolve("module");
1681
+ expect(actual).toMatch({
1682
+ result: {
1683
+ constants: [
1684
+ {
1685
+ name: { text: "DEFAULT_STATUS" },
1686
+ doc: {
1687
+ pieces: [
1688
+ { kind: "text", text: "Default status is " },
1689
+ {
1690
+ kind: "reference",
1691
+ nameChain: [{ text: "OK" }],
1692
+ referee: {
1693
+ kind: "field",
1694
+ field: { name: { text: "OK" } },
1695
+ record: { name: { text: "Status" } },
1696
+ },
1697
+ },
1698
+ ],
1699
+ },
1700
+ },
1701
+ ],
1702
+ },
1703
+ errors: [],
1704
+ });
1705
+ });
1706
+ it("resolves multiple references in same doc comment", () => {
1707
+ const fakeFileReader = new FakeFileReader();
1708
+ fakeFileReader.pathToCode.set("path/to/root/module", `
1709
+ /// Compare [Foo] and [Bar]
1710
+ struct Baz {}
1711
+
1712
+ struct Foo {}
1713
+ struct Bar {}
1714
+ `);
1715
+ const moduleSet = ModuleSet.create(fakeFileReader, "path/to/root");
1716
+ const actual = moduleSet.parseAndResolve("module");
1717
+ const bazRecord = actual.result?.records.find((r) => r.record?.name.text === "Baz");
1718
+ expect(bazRecord).toMatch({
1719
+ record: {
1720
+ name: { text: "Baz" },
1721
+ doc: {
1722
+ pieces: [
1723
+ { kind: "text", text: "Compare " },
1724
+ {
1725
+ kind: "reference",
1726
+ nameChain: [{ text: "Foo" }],
1727
+ referee: { kind: "record", name: { text: "Foo" } },
1728
+ },
1729
+ { kind: "text", text: " and " },
1730
+ {
1731
+ kind: "reference",
1732
+ nameChain: [{ text: "Bar" }],
1733
+ referee: { kind: "record", name: { text: "Bar" } },
1734
+ },
1735
+ ],
1736
+ },
1737
+ },
1738
+ });
1739
+ expect(actual.errors).toMatch([]);
1740
+ });
1741
+ it("resolves reference through import alias", () => {
1742
+ const fakeFileReader = new FakeFileReader();
1743
+ fakeFileReader.pathToCode.set("path/to/root/module", `
1744
+ import * as other from "./other";
1745
+
1746
+ /// Uses [other.Foo]
1747
+ struct Bar {}
1748
+ `);
1749
+ fakeFileReader.pathToCode.set("path/to/root/other", `
1750
+ struct Foo {}
1751
+ `);
1752
+ const moduleSet = ModuleSet.create(fakeFileReader, "path/to/root");
1753
+ const actual = moduleSet.parseAndResolve("module");
1754
+ const barRecord = actual.result?.records.find((r) => r.record?.name.text === "Bar");
1755
+ expect(barRecord).toMatch({
1756
+ record: {
1757
+ name: { text: "Bar" },
1758
+ doc: {
1759
+ pieces: [
1760
+ { kind: "text", text: "Uses " },
1761
+ {
1762
+ kind: "reference",
1763
+ nameChain: [{ text: "other" }, { text: "Foo" }],
1764
+ referee: { kind: "record", name: { text: "Foo" } },
1765
+ },
1766
+ ],
1767
+ },
1768
+ },
1769
+ });
1770
+ expect(actual.errors).toMatch([{ message: "Unused import alias" }]);
1771
+ });
1772
+ it("resolves reference through import", () => {
1773
+ const fakeFileReader = new FakeFileReader();
1774
+ fakeFileReader.pathToCode.set("path/to/root/module", `
1775
+ import * as other from "./other";
1776
+
1777
+ /// Uses [other.Foo]
1778
+ struct Bar {}
1779
+ `);
1780
+ fakeFileReader.pathToCode.set("path/to/root/other", `
1781
+ struct Foo {}
1782
+ `);
1783
+ const moduleSet = ModuleSet.create(fakeFileReader, "path/to/root");
1784
+ const actual = moduleSet.parseAndResolve("module");
1785
+ const barRecord = actual.result?.records.find((r) => r.record?.name.text === "Bar");
1786
+ expect(barRecord).toMatch({
1787
+ record: {
1788
+ name: { text: "Bar" },
1789
+ doc: {
1790
+ pieces: [
1791
+ { kind: "text", text: "Uses " },
1792
+ {
1793
+ kind: "reference",
1794
+ nameChain: [{ text: "other" }, { text: "Foo" }],
1795
+ referee: { kind: "record", name: { text: "Foo" } },
1796
+ },
1797
+ ],
1798
+ },
1799
+ },
1800
+ });
1801
+ expect(actual.errors).toMatch([{ message: "Unused import alias" }]);
1802
+ });
1803
+ it("reports error for unresolved reference", () => {
1804
+ const fakeFileReader = new FakeFileReader();
1805
+ fakeFileReader.pathToCode.set("path/to/root/module", `
1806
+ /// See [NonExistent]
1807
+ struct Foo {}
1808
+ `);
1809
+ const moduleSet = ModuleSet.create(fakeFileReader, "path/to/root");
1810
+ const actual = moduleSet.parseAndResolve("module");
1811
+ expect(actual).toMatch({
1812
+ result: {},
1813
+ errors: [
1814
+ {
1815
+ token: { text: "[NonExistent]" },
1816
+ message: "Cannot resolve reference",
1817
+ },
1818
+ ],
1819
+ });
1820
+ });
1821
+ it("reports error for unresolved nested reference", () => {
1822
+ const fakeFileReader = new FakeFileReader();
1823
+ fakeFileReader.pathToCode.set("path/to/root/module", `
1824
+ /// See [Bar.NonExistent]
1825
+ struct Foo {}
1826
+
1827
+ struct Bar {}
1828
+ `);
1829
+ const moduleSet = ModuleSet.create(fakeFileReader, "path/to/root");
1830
+ const actual = moduleSet.parseAndResolve("module");
1831
+ expect(actual).toMatch({
1832
+ result: {},
1833
+ errors: [
1834
+ {
1835
+ token: { text: "[Bar.NonExistent]" },
1836
+ message: "Cannot resolve reference",
1837
+ },
1838
+ ],
1839
+ });
1840
+ });
1841
+ it("prioritizes nested scope over module scope", () => {
1842
+ const fakeFileReader = new FakeFileReader();
1843
+ fakeFileReader.pathToCode.set("path/to/root/module", `
1844
+ struct Outer {
1845
+ struct Inner {
1846
+ /// Reference to [Foo] (nested)
1847
+ x: int32;
1848
+ }
1849
+ struct Foo {}
1850
+ }
1851
+
1852
+ struct Foo {}
1853
+ `);
1854
+ const moduleSet = ModuleSet.create(fakeFileReader, "path/to/root");
1855
+ const actual = moduleSet.parseAndResolve("module");
1856
+ // Find the Outer record
1857
+ const outerRecord = actual.result?.records.find((r) => r.record.name.text === "Outer");
1858
+ expect(outerRecord).toMatch({
1859
+ record: {
1860
+ name: { text: "Outer" },
1861
+ nestedRecords: [
1862
+ {
1863
+ name: { text: "Inner" },
1864
+ fields: [
1865
+ {
1866
+ name: { text: "x" },
1867
+ doc: {
1868
+ pieces: [
1869
+ { kind: "text", text: "Reference to " },
1870
+ {
1871
+ kind: "reference",
1872
+ nameChain: [{ text: "Foo" }],
1873
+ // Should resolve to Outer.Foo, not the top-level Foo
1874
+ referee: {
1875
+ kind: "record",
1876
+ name: { text: "Foo" },
1877
+ },
1878
+ },
1879
+ { kind: "text", text: " (nested)" },
1880
+ ],
1881
+ },
1882
+ },
1883
+ ],
1884
+ },
1885
+ {
1886
+ name: { text: "Foo" },
1887
+ },
1888
+ ],
1889
+ },
1890
+ });
1891
+ expect(actual).toMatch({
1892
+ errors: [],
1893
+ });
1894
+ });
1895
+ });
1329
1896
  });
1330
1897
  //# sourceMappingURL=module_set.test.js.map