carrick 0.3.119 → 0.3.121

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.
@@ -14,6 +14,7 @@
14
14
  * | `compare` | `=== !== == != < > <= >= instanceof in` | the left operand | the left operand |
15
15
  * | `ident` | an identifier in expression position | itself | itself |
16
16
  * | `impl` | a `call` or `member` whose declaration has no body | an implementation of it | nothing |
17
+ * | `decl` | a `call` or `member` on a union of declaring types | one of those declarations | nothing |
17
18
  * | `jsx` | a JSX opening or self-closing element's tag | the tag's name | the tag |
18
19
  *
19
20
  * An `impl` row (version 2, carrick#2430) follows the `call` or `member` row
@@ -24,9 +25,18 @@
24
25
  * initializer. Its `decl_*` name the implementing declaration. Past
25
26
  * {@link IMPL_CAP} the row is one, with {@link FLAG_TOO_MANY} and nothing else.
26
27
  *
27
- * A row's key is `(start, end, kind)`, except that several `impl` rows share
28
- * one: TypeScript `getStart()`/`getEnd()` of the node, in UTF-16 code units
29
- * from the start of the file, which is what the scanner's `sidecar_position`
28
+ * A `decl` row (version 3, carrick#2448) follows the `call` or `member` row
29
+ * it belongs to, before its `impl` rows, and has its span: one per
30
+ * declaration of the member when the receiver is a union whose constituents
31
+ * declare it at more than one place (`(pick ? a : b).get()` with two
32
+ * classes). That row names only the first of them. Each constituent's
33
+ * declaration is its own member's, or, for a member with none (a mapped
34
+ * type's), the declaration of the constituent type itself. Sorted and capped
35
+ * as `impl` rows are; `type_text` is `null`.
36
+ *
37
+ * A row's key is `(start, end, kind)`, except that several `impl` rows, and
38
+ * several `decl` rows, share one: TypeScript `getStart()`/`getEnd()` of the
39
+ * node, in UTF-16 code units from the start of the file, which is what the scanner's `sidecar_position`
30
40
  * gives for an SWC span. Every path written is relative to the scanned repo's
31
41
  * root, with `/` separators.
32
42
  *
@@ -49,7 +59,7 @@ import { WriteGuard, installedPackageDirectory, isDeclarationFileName, moduleExp
49
59
  import { attributedDeclaration, installedPackageOf } from './declaration-attribution.js';
50
60
  import { typeToStringAsDeclared } from './print-type.js';
51
61
  /** The format's version, written in the header. */
52
- export const POSITION_ROWS_VERSION = 2;
62
+ export const POSITION_ROWS_VERSION = 3;
53
63
  /** The type is `any`, declared or inferred. Never set with the error type. */
54
64
  export const FLAG_ANY = 1;
55
65
  /** The type is the compiler's error type: something did not resolve. */
@@ -58,7 +68,7 @@ export const FLAG_ERROR_TYPE = 2;
58
68
  export const FLAG_CHECKER_THREW = 4;
59
69
  /** The declaration is outside the checkout, not the default library and in no installed package. */
60
70
  export const FLAG_DECLARATION_UNNAMED = 8;
61
- /** An `impl` row standing for more implementations than {@link IMPL_CAP}; it names none. */
71
+ /** An `impl` or `decl` row standing for more than {@link IMPL_CAP} rows of its kind; it names none. */
62
72
  export const FLAG_TOO_MANY = 16;
63
73
  /**
64
74
  * The declaration is published under the row's symbol name: its module
@@ -69,7 +79,7 @@ export const FLAG_TOO_MANY = 16;
69
79
  export const FLAG_PUBLISHED = 32;
70
80
  /** The declaration is what its module exports as `export =` or `default` (carrick#2508). */
71
81
  export const FLAG_MODULE_DEFAULT = 64;
72
- /** The most implementations one declaration's `impl` rows list. */
82
+ /** The most `impl` rows one declaration lists, and the most `decl` rows one position lists. */
73
83
  export const IMPL_CAP = 16;
74
84
  const COMPARE_OPERATORS = new Set([
75
85
  ts.SyntaxKind.EqualsEqualsEqualsToken,
@@ -405,6 +415,8 @@ class PositionWalker {
405
415
  const row = this.row(kind, node, sourceFile);
406
416
  rows.push(row);
407
417
  if ((kind === 'call' || kind === 'member') && !(row[8] & FLAG_CHECKER_THREW)) {
418
+ for (const decl of this.declRows(kind, node))
419
+ rows.push(['decl', row[1], row[2], ...tail(decl)]);
408
420
  for (const impl of this.implRows(kind, node))
409
421
  rows.push(['impl', row[1], row[2], ...tail(impl)]);
410
422
  }
@@ -580,18 +592,17 @@ class PositionWalker {
580
592
  * constituent that has the property; with several the row is left as it is.
581
593
  */
582
594
  ownerDeclaration(kind, node, symbol) {
583
- if (kind !== 'member' && kind !== 'call')
584
- return undefined;
585
- const named = nameNodeOf(kind, node);
586
- const access = named?.parent;
587
- if (!access || !(ts.isPropertyAccessExpression(access) || ts.isElementAccessExpression(access))) {
595
+ const receiver = this.receiverOf(kind, node);
596
+ if (!receiver)
588
597
  return undefined;
589
- }
590
- const receiver = this.checker.getTypeAtLocation(access.expression);
591
598
  const holders = (receiver.isUnionOrIntersection() ? receiver.types : [receiver]).filter((constituent) => constituent.getProperty(symbol.name) !== undefined);
592
599
  if (holders.length !== 1)
593
600
  return undefined;
594
- const owner = holders[0].getSymbol() ?? holders[0].aliasSymbol;
601
+ return this.typeDeclaration(holders[0]);
602
+ }
603
+ /** The declaration of a type's symbol, else of its alias symbol: a mapped type node, or the alias naming it. */
604
+ typeDeclaration(type) {
605
+ const owner = type.getSymbol() ?? type.aliasSymbol;
595
606
  return attributedDeclaration(() => this.program, owner?.declarations ?? []);
596
607
  }
597
608
  /**
@@ -656,6 +667,60 @@ class PositionWalker {
656
667
  return ((exports.byName.get(symbol.getName()) === symbol ? FLAG_PUBLISHED : 0) |
657
668
  (exports.wholes.includes(symbol) ? FLAG_MODULE_DEFAULT : 0));
658
669
  }
670
+ /** The type of the object a `member` or `call` row's name is read on, if the name is read on one. */
671
+ receiverOf(kind, node) {
672
+ if (kind !== 'member' && kind !== 'call')
673
+ return undefined;
674
+ const access = nameNodeOf(kind, node)?.parent;
675
+ if (!access || !(ts.isPropertyAccessExpression(access) || ts.isElementAccessExpression(access))) {
676
+ return undefined;
677
+ }
678
+ return this.checker.getTypeAtLocation(access.expression);
679
+ }
680
+ /**
681
+ * The `decl` rows of a `call` or `member` row (spans unset): one per
682
+ * declaration the receiver's union constituents give the member, when they
683
+ * give more than one (carrick#2448). A constituent's declaration is its
684
+ * member's ({@link attributedDeclaration}), or, for a member with none, the
685
+ * constituent type's own ({@link typeDeclaration}). Two instantiations of
686
+ * one generic class, or one class and `undefined`, give one, and no row.
687
+ * A throw writes one row flagged {@link FLAG_CHECKER_THREW}.
688
+ */
689
+ declRows(kind, node) {
690
+ const found = new Set();
691
+ let name;
692
+ try {
693
+ const symbol = this.symbolOf(kind, node);
694
+ const receiver = this.receiverOf(kind, node);
695
+ if (!symbol || !receiver || !receiver.isUnion())
696
+ return [];
697
+ name = ts.symbolName(symbol);
698
+ for (const constituent of receiver.types) {
699
+ const member = constituent.getProperty(symbol.name);
700
+ if (!member)
701
+ continue;
702
+ const declaration = attributedDeclaration(() => this.program, member.declarations ?? []) ?? this.typeDeclaration(constituent);
703
+ if (declaration)
704
+ found.add(declaration);
705
+ }
706
+ }
707
+ catch {
708
+ return [['decl', 0, 0, null, null, null, null, null, FLAG_CHECKER_THREW]];
709
+ }
710
+ if (found.size < 2)
711
+ return [];
712
+ if (found.size > IMPL_CAP)
713
+ return [['decl', 0, 0, null, null, null, null, null, FLAG_TOO_MANY]];
714
+ const rows = [...found].map((declaration) => {
715
+ const file = declaration.getSourceFile();
716
+ const start = declaration.getStart(file);
717
+ const { declFile, declLine, declPackage } = this.located(file, start);
718
+ const flags = declFile === null ? FLAG_DECLARATION_UNNAMED : 0;
719
+ return { start, row: ['decl', 0, 0, name, declFile, declLine, declPackage, null, flags] };
720
+ });
721
+ rows.sort((a, b) => compareNames(a.row[4], b.row[4]) || a.start - b.start);
722
+ return rows.map(({ row }) => row);
723
+ }
659
724
  /** The row's symbol, following aliases to a target that has a declaration. */
660
725
  symbolOf(kind, node) {
661
726
  let symbol;
@@ -854,6 +919,7 @@ function nameNodeOf(kind, node) {
854
919
  case 'ident':
855
920
  return node;
856
921
  case 'impl':
922
+ case 'decl':
857
923
  return undefined;
858
924
  case 'jsx':
859
925
  // The tag: `<Badge>`, `<ui.Button>`, `<this.Panel>`; a namespaced