@oicl-lit/analyzer 0.14.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.
- package/LICENSE +28 -0
- package/README.md +76 -0
- package/index.d.ts +10 -0
- package/index.d.ts.map +1 -0
- package/index.js +10 -0
- package/index.js.map +1 -0
- package/lib/analyzer.d.ts +47 -0
- package/lib/analyzer.d.ts.map +1 -0
- package/lib/analyzer.js +90 -0
- package/lib/analyzer.js.map +1 -0
- package/lib/custom-elements/custom-elements.d.ts +33 -0
- package/lib/custom-elements/custom-elements.d.ts.map +1 -0
- package/lib/custom-elements/custom-elements.js +124 -0
- package/lib/custom-elements/custom-elements.js.map +1 -0
- package/lib/custom-elements/events.d.ts +19 -0
- package/lib/custom-elements/events.d.ts.map +1 -0
- package/lib/custom-elements/events.js +25 -0
- package/lib/custom-elements/events.js.map +1 -0
- package/lib/diagnostic-code.d.ts +21 -0
- package/lib/diagnostic-code.d.ts.map +1 -0
- package/lib/diagnostic-code.js +20 -0
- package/lib/diagnostic-code.js.map +1 -0
- package/lib/errors.d.ts +24 -0
- package/lib/errors.d.ts.map +1 -0
- package/lib/errors.js +17 -0
- package/lib/errors.js.map +1 -0
- package/lib/javascript/classes.d.ts +50 -0
- package/lib/javascript/classes.d.ts.map +1 -0
- package/lib/javascript/classes.js +307 -0
- package/lib/javascript/classes.js.map +1 -0
- package/lib/javascript/functions.d.ts +31 -0
- package/lib/javascript/functions.d.ts.map +1 -0
- package/lib/javascript/functions.js +144 -0
- package/lib/javascript/functions.js.map +1 -0
- package/lib/javascript/jsdoc.d.ts +67 -0
- package/lib/javascript/jsdoc.d.ts.map +1 -0
- package/lib/javascript/jsdoc.js +244 -0
- package/lib/javascript/jsdoc.js.map +1 -0
- package/lib/javascript/mixins.d.ts +45 -0
- package/lib/javascript/mixins.d.ts.map +1 -0
- package/lib/javascript/mixins.js +147 -0
- package/lib/javascript/mixins.js.map +1 -0
- package/lib/javascript/modules.d.ts +42 -0
- package/lib/javascript/modules.d.ts.map +1 -0
- package/lib/javascript/modules.js +277 -0
- package/lib/javascript/modules.js.map +1 -0
- package/lib/javascript/packages.d.ts +18 -0
- package/lib/javascript/packages.d.ts.map +1 -0
- package/lib/javascript/packages.js +53 -0
- package/lib/javascript/packages.js.map +1 -0
- package/lib/javascript/variables.d.ts +29 -0
- package/lib/javascript/variables.d.ts.map +1 -0
- package/lib/javascript/variables.js +143 -0
- package/lib/javascript/variables.js.map +1 -0
- package/lib/lit/decorators.d.ts +36 -0
- package/lib/lit/decorators.d.ts.map +1 -0
- package/lib/lit/decorators.js +32 -0
- package/lib/lit/decorators.js.map +1 -0
- package/lib/lit/lit-element.d.ts +39 -0
- package/lib/lit/lit-element.d.ts.map +1 -0
- package/lib/lit/lit-element.js +96 -0
- package/lib/lit/lit-element.js.map +1 -0
- package/lib/lit/modules.d.ts +28 -0
- package/lib/lit/modules.d.ts.map +1 -0
- package/lib/lit/modules.js +62 -0
- package/lib/lit/modules.js.map +1 -0
- package/lib/lit/properties.d.ts +43 -0
- package/lib/lit/properties.d.ts.map +1 -0
- package/lib/lit/properties.js +268 -0
- package/lib/lit/properties.js.map +1 -0
- package/lib/lit/template.d.ts +110 -0
- package/lib/lit/template.d.ts.map +1 -0
- package/lib/lit/template.js +412 -0
- package/lib/lit/template.js.map +1 -0
- package/lib/lit-element/decorators.d.ts +11 -0
- package/lib/lit-element/decorators.d.ts.map +1 -0
- package/lib/lit-element/decorators.js +11 -0
- package/lib/lit-element/decorators.js.map +1 -0
- package/lib/lit-element/lit-element.d.ts +11 -0
- package/lib/lit-element/lit-element.d.ts.map +1 -0
- package/lib/lit-element/lit-element.js +11 -0
- package/lib/lit-element/lit-element.js.map +1 -0
- package/lib/lit-element/properties.d.ts +11 -0
- package/lib/lit-element/properties.d.ts.map +1 -0
- package/lib/lit-element/properties.js +11 -0
- package/lib/lit-element/properties.js.map +1 -0
- package/lib/model.d.ts +506 -0
- package/lib/model.d.ts.map +1 -0
- package/lib/model.js +392 -0
- package/lib/model.js.map +1 -0
- package/lib/package-analyzer.d.ts +25 -0
- package/lib/package-analyzer.d.ts.map +1 -0
- package/lib/package-analyzer.js +81 -0
- package/lib/package-analyzer.js.map +1 -0
- package/lib/paths.d.ts +24 -0
- package/lib/paths.d.ts.map +1 -0
- package/lib/paths.js +35 -0
- package/lib/paths.js.map +1 -0
- package/lib/references.d.ts +107 -0
- package/lib/references.d.ts.map +1 -0
- package/lib/references.js +345 -0
- package/lib/references.js.map +1 -0
- package/lib/types.d.ts +25 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +257 -0
- package/lib/types.js.map +1 -0
- package/lib/utils.d.ts +22 -0
- package/lib/utils.d.ts.map +1 -0
- package/lib/utils.js +51 -0
- package/lib/utils.js.map +1 -0
- package/package-analyzer.d.ts +8 -0
- package/package-analyzer.d.ts.map +1 -0
- package/package-analyzer.js +8 -0
- package/package-analyzer.js.map +1 -0
- package/package.json +109 -0
package/lib/paths.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/lib/paths.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkBH;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,IAAkB,EAClB,WAAyB,EACzB,SAAiB,EACJ,EAAE;IACf,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,QAAQ,IAAI,wBAAwB,WAAW,EAAE,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACrD,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACrC,yDAAyD;QACzD,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CAAC,QAAQ,IAAI,wBAAwB,WAAW,EAAE,CAAC,CAAC;QACrE,CAAC;QACD,WAAW,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,WAA0B,CAAC;AACpC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,IAAkB,EAClB,QAA2B,EAC3B,UAAU,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,EAC1B,EAAE;IACF,IAAI,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,GAAG,IAAI,IAAI,GAAG,EAAE,CAAC;QAClC,IAAI,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrC,OAAO,QAAQ,CAAC;QAClB,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,qBAAqB,CAAC,CAAC;AAClE,CAAC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2022 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nimport {AnalyzerInterface} from './model.js';\n\n/**\n * An absolute path\n */\nexport type AbsolutePath = string & {\n __absolutePathBrand: never;\n};\n\n/**\n * A path relative to a package root\n */\nexport type PackagePath = string & {\n __packagePathBrand: never;\n};\n\n/**\n * Convert an absolute path to a package-relative path\n */\nexport const absoluteToPackage = (\n path: AbsolutePath,\n packageRoot: AbsolutePath,\n seperator: string\n): PackagePath => {\n if (!path.startsWith(packageRoot)) {\n throw new Error(`path ${path} is not contained in ${packageRoot}`);\n }\n let packagePath = path.substring(packageRoot.length);\n if (!packageRoot.endsWith(seperator)) {\n // Make sure we don't have path='/abc/def' and root='/ab'\n if (!packagePath.startsWith(seperator)) {\n throw new Error(`path ${path} is not contained in ${packageRoot}`);\n }\n packagePath = packagePath.substring(1, packagePath.length);\n }\n return packagePath as PackagePath;\n};\n\nexport const resolveExtension = (\n path: AbsolutePath,\n analyzer: AnalyzerInterface,\n extensions = ['js', 'mjs']\n) => {\n if (analyzer.fs.fileExists(path)) {\n return path;\n }\n for (const ext of extensions) {\n const fileName = `${path}.${ext}`;\n if (analyzer.fs.fileExists(fileName)) {\n return fileName;\n }\n }\n throw new Error(`Could not resolve ${path} to a file on disk.`);\n};\n"]}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
5
|
+
*/
|
|
6
|
+
import type ts from 'typescript';
|
|
7
|
+
import { AnalyzerInterface, LocalNameOrReference, Reference } from './model.js';
|
|
8
|
+
/**
|
|
9
|
+
* Returns a ts.Symbol for a name in scope at a given location in the AST.
|
|
10
|
+
* TODO(kschaaf): There are ~1748 symbols in scope of a typical hello world,
|
|
11
|
+
* due to DOM globals. Perf might become an issue here.
|
|
12
|
+
*/
|
|
13
|
+
export declare const getSymbolForName: (name: string, location: ts.Node, analyzer: AnalyzerInterface) => ts.Symbol | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Returns an analyzer `Reference` object for the given identifier.
|
|
16
|
+
*
|
|
17
|
+
* If the symbol's declaration was imported, the Reference will be based on
|
|
18
|
+
* the import's module specifier; otherwise the Reference will point to the
|
|
19
|
+
* current module being analyzed.
|
|
20
|
+
*/
|
|
21
|
+
export declare const getReferenceForIdentifier: (identifier: ts.Identifier, analyzer: AnalyzerInterface) => Reference | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Returns an analyzer `Reference` model for the given ts.Symbol.
|
|
24
|
+
*
|
|
25
|
+
* If the symbol's declaration was imported, the Reference will be based on
|
|
26
|
+
* the import's module specifier; otherwise the Reference will point to the
|
|
27
|
+
* current module being analyzed.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getReferenceForSymbol(symbol: ts.Symbol, location: ts.Node, analyzer: AnalyzerInterface): Reference | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Returns a `Reference` for a symbol that was imported.
|
|
32
|
+
*
|
|
33
|
+
* There are 4 main categories of imports we cover:
|
|
34
|
+
*
|
|
35
|
+
* 1. A symbol imported from a URL. The declaration will be an
|
|
36
|
+
* ImportModuleSpecifier and its module path will be parsable as a URL.
|
|
37
|
+
*
|
|
38
|
+
* 2. A symbol imported from a relative file within this package. The
|
|
39
|
+
* declaration will be an ImportModuleSpecifier and its module path will
|
|
40
|
+
* start with a '.'
|
|
41
|
+
*
|
|
42
|
+
* 3. A symbol imported from an absolute path. The declaration will be an
|
|
43
|
+
* ImportModuleSpecifier and its module path will start with a '/' This is a
|
|
44
|
+
* weird case to cover in the analyzer because it isn't portable.
|
|
45
|
+
*
|
|
46
|
+
* 4. A symbol imported from an external package. The declaration will be an
|
|
47
|
+
* ImportModuleSpecifier and its module path will not start with a '.'
|
|
48
|
+
*/
|
|
49
|
+
export declare const getImportReference: (specifier: string, location: ts.Node, name: string, analyzer: AnalyzerInterface) => Reference;
|
|
50
|
+
/**
|
|
51
|
+
* Returns a `Reference` for a symbol that was imported.
|
|
52
|
+
*/
|
|
53
|
+
export declare const getImportReferenceForSpecifierExpression: (specifierExpression: ts.Expression, name: string, analyzer: AnalyzerInterface) => Reference;
|
|
54
|
+
/**
|
|
55
|
+
* For a given export clause and (optional) specifier from an export statement,
|
|
56
|
+
* returns an array of objects mapping the export name to a
|
|
57
|
+
* LocalNameOrReference, which is a string name that can be looked up directly
|
|
58
|
+
* in `getDeclaration()` of the declaring module for local declarations, or a
|
|
59
|
+
* `Reference` in the case of re-exported declarations.
|
|
60
|
+
*
|
|
61
|
+
* For example:
|
|
62
|
+
* ```
|
|
63
|
+
* import {a} from 'foo';
|
|
64
|
+
* const b = 'b';
|
|
65
|
+
* const c = 'c';
|
|
66
|
+
* export {a as x, b as y, c};
|
|
67
|
+
* ```
|
|
68
|
+
* This would return (using pseudo-code for Reference objects):
|
|
69
|
+
* ```
|
|
70
|
+
* [
|
|
71
|
+
* {name: 'x', reference: new Reference('a', 'foo')},
|
|
72
|
+
* {name: 'y', reference: 'b'},
|
|
73
|
+
* {name: 'c', reference: 'c'},
|
|
74
|
+
* ]
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* This also handles explicit re-export syntax, which all become References:
|
|
78
|
+
* ```
|
|
79
|
+
* export {a as x, b as y, c} from 'foo';
|
|
80
|
+
* ```
|
|
81
|
+
*
|
|
82
|
+
* Finally, this handles namespace exports, which become a single Reference:
|
|
83
|
+
* ```
|
|
84
|
+
* export * as ns from 'foo';
|
|
85
|
+
* ```
|
|
86
|
+
* becomes:
|
|
87
|
+
* ```
|
|
88
|
+
* [{name: 'ns', reference: new Reference('*', 'foo')}]
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export declare const getExportReferences: (exportClause: ts.NamedExportBindings, moduleSpecifier: ts.Expression | undefined, analyzer: AnalyzerInterface) => Array<{
|
|
92
|
+
exportName: string;
|
|
93
|
+
decNameOrRef: LocalNameOrReference;
|
|
94
|
+
}>;
|
|
95
|
+
/**
|
|
96
|
+
* Returns the specifier string from a specifier expression.
|
|
97
|
+
*
|
|
98
|
+
* For a given import statement:
|
|
99
|
+
* ```
|
|
100
|
+
* import {foo} from 'foo/bar.js';
|
|
101
|
+
* ```
|
|
102
|
+
* The specifierExpression is the string literal 'foo/bar.js' whose getText()
|
|
103
|
+
* includes the quotes. This function returns the string value without the
|
|
104
|
+
* quotes.
|
|
105
|
+
*/
|
|
106
|
+
export declare const getSpecifierString: (specifierExpression: ts.Expression) => string;
|
|
107
|
+
//# sourceMappingURL=references.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"references.d.ts","sourceRoot":"","sources":["../src/lib/references.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AACjC,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,SAAS,EAEV,MAAM,YAAY,CAAC;AAYpB;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAM,MAAM,EACZ,UAAU,EAAE,CAAC,IAAI,EACjB,UAAU,iBAAiB,KAC1B,EAAE,CAAC,MAAM,GAAG,SAQd,CAAC;AAmCF;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,GACpC,YAAY,EAAE,CAAC,UAAU,EACzB,UAAU,iBAAiB,0BAgB5B,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,EAAE,CAAC,MAAM,EACjB,QAAQ,EAAE,EAAE,CAAC,IAAI,EACjB,QAAQ,EAAE,iBAAiB,GAC1B,SAAS,GAAG,SAAS,CAgDvB;AAsBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,kBAAkB,GAC7B,WAAW,MAAM,EACjB,UAAU,EAAE,CAAC,IAAI,EACjB,MAAM,MAAM,EACZ,UAAU,iBAAiB,cAuD5B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wCAAwC,GACnD,qBAAqB,EAAE,CAAC,UAAU,EAClC,MAAM,MAAM,EACZ,UAAU,iBAAiB,cAI5B,CAAC;AA2BF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,mBAAmB,GAC9B,cAAc,EAAE,CAAC,mBAAmB,EACpC,iBAAiB,EAAE,CAAC,UAAU,GAAG,SAAS,EAC1C,UAAU,iBAAiB,KAC1B,KAAK,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,oBAAoB,CAAA;CAAC,CAoFhE,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,GAAI,qBAAqB,EAAE,CAAC,UAAU,WAIpE,CAAC"}
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
5
|
+
*/
|
|
6
|
+
import { Reference, } from './model.js';
|
|
7
|
+
import { getResolvedExportFromSourcePath, getPathForModuleSpecifier, getModuleInfo, } from './javascript/modules.js';
|
|
8
|
+
import { createDiagnostic } from './errors.js';
|
|
9
|
+
import { DiagnosticCode } from './diagnostic-code.js';
|
|
10
|
+
const npmModule = /^(?<package>(@[^/]+\/[^/]+)|[^/]+)\/?(?<module>.*)$/;
|
|
11
|
+
/**
|
|
12
|
+
* Returns a ts.Symbol for a name in scope at a given location in the AST.
|
|
13
|
+
* TODO(kschaaf): There are ~1748 symbols in scope of a typical hello world,
|
|
14
|
+
* due to DOM globals. Perf might become an issue here.
|
|
15
|
+
*/
|
|
16
|
+
export const getSymbolForName = (name, location, analyzer) => {
|
|
17
|
+
return analyzer.program
|
|
18
|
+
.getTypeChecker()
|
|
19
|
+
.getSymbolsInScope(location, analyzer.typescript.SymbolFlags.All)
|
|
20
|
+
.filter((s) => s.name === name)[0];
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Returns the module specifier expression for a declaration if it was imported,
|
|
24
|
+
* or `undefined` if the declaration was not imported.
|
|
25
|
+
*/
|
|
26
|
+
const getImportSpecifierInfo = (ts, declaration) => {
|
|
27
|
+
// TODO(kschaaf) support the various import syntaxes, e.g. `import {foo as bar} from 'baz'`
|
|
28
|
+
if (ts.isImportSpecifier(declaration) &&
|
|
29
|
+
ts.isNamedImports(declaration.parent) &&
|
|
30
|
+
ts.isImportClause(declaration.parent.parent) &&
|
|
31
|
+
ts.isImportDeclaration(declaration.parent.parent.parent)) {
|
|
32
|
+
const specifierExpression = declaration.parent.parent.parent.moduleSpecifier;
|
|
33
|
+
const specifier = getSpecifierString(specifierExpression);
|
|
34
|
+
return {
|
|
35
|
+
specifier,
|
|
36
|
+
location: specifierExpression,
|
|
37
|
+
name: declaration.propertyName?.text ?? declaration.name.text,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Returns an analyzer `Reference` object for the given identifier.
|
|
44
|
+
*
|
|
45
|
+
* If the symbol's declaration was imported, the Reference will be based on
|
|
46
|
+
* the import's module specifier; otherwise the Reference will point to the
|
|
47
|
+
* current module being analyzed.
|
|
48
|
+
*/
|
|
49
|
+
export const getReferenceForIdentifier = (identifier, analyzer) => {
|
|
50
|
+
const symbol = analyzer.program
|
|
51
|
+
.getTypeChecker()
|
|
52
|
+
.getSymbolAtLocation(identifier);
|
|
53
|
+
if (symbol === undefined) {
|
|
54
|
+
analyzer.addDiagnostic(createDiagnostic({
|
|
55
|
+
typescript: analyzer.typescript,
|
|
56
|
+
node: identifier,
|
|
57
|
+
message: `Could not find symbol for identifier.`,
|
|
58
|
+
}));
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
return getReferenceForSymbol(symbol, identifier, analyzer);
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Returns an analyzer `Reference` model for the given ts.Symbol.
|
|
65
|
+
*
|
|
66
|
+
* If the symbol's declaration was imported, the Reference will be based on
|
|
67
|
+
* the import's module specifier; otherwise the Reference will point to the
|
|
68
|
+
* current module being analyzed.
|
|
69
|
+
*/
|
|
70
|
+
export function getReferenceForSymbol(symbol, location, analyzer) {
|
|
71
|
+
const { name: symbolName } = symbol;
|
|
72
|
+
// TODO(kschaaf): Do we need to check other declarations? The assumption is
|
|
73
|
+
// that even with multiple declarations (e.g. because of class interface +
|
|
74
|
+
// constructor), the reference would point to the same location for all,
|
|
75
|
+
// or else (in the case of e.g. namespace augmentation) it will be global
|
|
76
|
+
// and not need a specific module specifier.
|
|
77
|
+
const declaration = symbol?.declarations?.[0];
|
|
78
|
+
if (declaration === undefined) {
|
|
79
|
+
analyzer.addDiagnostic(createDiagnostic({
|
|
80
|
+
typescript: analyzer.typescript,
|
|
81
|
+
node: location,
|
|
82
|
+
message: `Could not find declaration for symbol '${symbolName}'`,
|
|
83
|
+
}));
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
const declarationSourceFile = declaration.getSourceFile();
|
|
87
|
+
const locationSourceFile = location.getSourceFile();
|
|
88
|
+
// There are three top-level cases to cover:
|
|
89
|
+
// 1. A global symbol that wasn't imported.
|
|
90
|
+
// 2. An imported symbol
|
|
91
|
+
// 3. A symbol declared in this file.
|
|
92
|
+
if (declarationSourceFile !== locationSourceFile) {
|
|
93
|
+
// If the reference declaration doesn't exist in this module, it must have
|
|
94
|
+
// been a global (whose declaration is in an ambient .d.ts file)
|
|
95
|
+
// TODO(kschaaf): We might want to further differentiate e.g. DOM globals
|
|
96
|
+
// (that don't have any e.g. source to link to) from other ambient
|
|
97
|
+
// declarations where we could at least point to a declaration file
|
|
98
|
+
return getGlobalReference(declarationSourceFile, symbolName, analyzer);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
// For all other cases, the symbol's declaration node will be in this file,
|
|
102
|
+
// either as an ImportDeclaration or a normal declaration.
|
|
103
|
+
const importInfo = getImportSpecifierInfo(analyzer.typescript, declaration);
|
|
104
|
+
if (importInfo !== undefined) {
|
|
105
|
+
// Declaration was imported
|
|
106
|
+
return getImportReference(importInfo.specifier, importInfo.location, importInfo.name, analyzer);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
// Declared in this file: use the current package and module
|
|
110
|
+
return getLocalReference(location, symbolName, analyzer);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Returns a `Reference` for a global symbol that was not imported.
|
|
116
|
+
*/
|
|
117
|
+
const getGlobalReference = (declarationSourceFile, name, analyzer) => {
|
|
118
|
+
return new Reference({
|
|
119
|
+
name,
|
|
120
|
+
isGlobal: true,
|
|
121
|
+
dereference: () => getResolvedExportFromSourcePath(declarationSourceFile.fileName, name, analyzer),
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Returns a `Reference` for a symbol that was imported.
|
|
126
|
+
*
|
|
127
|
+
* There are 4 main categories of imports we cover:
|
|
128
|
+
*
|
|
129
|
+
* 1. A symbol imported from a URL. The declaration will be an
|
|
130
|
+
* ImportModuleSpecifier and its module path will be parsable as a URL.
|
|
131
|
+
*
|
|
132
|
+
* 2. A symbol imported from a relative file within this package. The
|
|
133
|
+
* declaration will be an ImportModuleSpecifier and its module path will
|
|
134
|
+
* start with a '.'
|
|
135
|
+
*
|
|
136
|
+
* 3. A symbol imported from an absolute path. The declaration will be an
|
|
137
|
+
* ImportModuleSpecifier and its module path will start with a '/' This is a
|
|
138
|
+
* weird case to cover in the analyzer because it isn't portable.
|
|
139
|
+
*
|
|
140
|
+
* 4. A symbol imported from an external package. The declaration will be an
|
|
141
|
+
* ImportModuleSpecifier and its module path will not start with a '.'
|
|
142
|
+
*/
|
|
143
|
+
export const getImportReference = (specifier, location, name, analyzer) => {
|
|
144
|
+
const { path } = analyzer;
|
|
145
|
+
let refPackage;
|
|
146
|
+
let refModule;
|
|
147
|
+
// Check whether it is a URL, absolute, package local, or external
|
|
148
|
+
try {
|
|
149
|
+
new URL(specifier);
|
|
150
|
+
refPackage = '';
|
|
151
|
+
refModule = specifier;
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
if (specifier[0] === '.') {
|
|
155
|
+
// Relative import from this package: use the current package and
|
|
156
|
+
// module path relative to this module
|
|
157
|
+
const sourceFilePath = location.getSourceFile().fileName;
|
|
158
|
+
const module = getModuleInfo(sourceFilePath, analyzer);
|
|
159
|
+
refPackage = module.packageJson.name;
|
|
160
|
+
refModule = path
|
|
161
|
+
.join(path.dirname(module.jsPath), specifier)
|
|
162
|
+
.replace(/\\/g, '/');
|
|
163
|
+
}
|
|
164
|
+
else if (analyzer.path.isAbsolute(specifier)) {
|
|
165
|
+
// Absolute import; no package, just use the entire path as the
|
|
166
|
+
// module
|
|
167
|
+
refPackage = '';
|
|
168
|
+
refModule = specifier;
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
// External import: extract the npm package (taking care to respect
|
|
172
|
+
// npm orgs) and module specifier (if any)
|
|
173
|
+
const info = specifier.match(npmModule);
|
|
174
|
+
if (info?.groups) {
|
|
175
|
+
refPackage = info.groups.package;
|
|
176
|
+
refModule = info.groups.module || undefined;
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
analyzer.addDiagnostic(createDiagnostic({
|
|
180
|
+
typescript: analyzer.typescript,
|
|
181
|
+
node: location,
|
|
182
|
+
message: `External npm package could not be parsed from module specifier '${specifier}'.`,
|
|
183
|
+
}));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return new Reference({
|
|
188
|
+
name,
|
|
189
|
+
package: refPackage,
|
|
190
|
+
module: refModule,
|
|
191
|
+
dereference: () => {
|
|
192
|
+
const path = getPathForModuleSpecifier(specifier, location, analyzer);
|
|
193
|
+
if (path === undefined) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
return getResolvedExportFromSourcePath(path, name, analyzer);
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* Returns a `Reference` for a symbol that was imported.
|
|
202
|
+
*/
|
|
203
|
+
export const getImportReferenceForSpecifierExpression = (specifierExpression, name, analyzer) => {
|
|
204
|
+
const specifier = getSpecifierString(specifierExpression);
|
|
205
|
+
return getImportReference(specifier, specifierExpression, name, analyzer);
|
|
206
|
+
};
|
|
207
|
+
/**
|
|
208
|
+
* Returns a `Reference` to a symbol declared in the current source file.
|
|
209
|
+
*/
|
|
210
|
+
const getLocalReference = (location, name, analyzer) => {
|
|
211
|
+
const module = getModuleInfo(location.getSourceFile().fileName, analyzer);
|
|
212
|
+
return new Reference({
|
|
213
|
+
name,
|
|
214
|
+
package: module.packageJson.name,
|
|
215
|
+
module: module.jsPath.replace(/\\/g, '/'),
|
|
216
|
+
dereference: () => getResolvedExportFromSourcePath(location.getSourceFile().fileName, name, analyzer),
|
|
217
|
+
});
|
|
218
|
+
};
|
|
219
|
+
/**
|
|
220
|
+
* For a given export clause and (optional) specifier from an export statement,
|
|
221
|
+
* returns an array of objects mapping the export name to a
|
|
222
|
+
* LocalNameOrReference, which is a string name that can be looked up directly
|
|
223
|
+
* in `getDeclaration()` of the declaring module for local declarations, or a
|
|
224
|
+
* `Reference` in the case of re-exported declarations.
|
|
225
|
+
*
|
|
226
|
+
* For example:
|
|
227
|
+
* ```
|
|
228
|
+
* import {a} from 'foo';
|
|
229
|
+
* const b = 'b';
|
|
230
|
+
* const c = 'c';
|
|
231
|
+
* export {a as x, b as y, c};
|
|
232
|
+
* ```
|
|
233
|
+
* This would return (using pseudo-code for Reference objects):
|
|
234
|
+
* ```
|
|
235
|
+
* [
|
|
236
|
+
* {name: 'x', reference: new Reference('a', 'foo')},
|
|
237
|
+
* {name: 'y', reference: 'b'},
|
|
238
|
+
* {name: 'c', reference: 'c'},
|
|
239
|
+
* ]
|
|
240
|
+
* ```
|
|
241
|
+
*
|
|
242
|
+
* This also handles explicit re-export syntax, which all become References:
|
|
243
|
+
* ```
|
|
244
|
+
* export {a as x, b as y, c} from 'foo';
|
|
245
|
+
* ```
|
|
246
|
+
*
|
|
247
|
+
* Finally, this handles namespace exports, which become a single Reference:
|
|
248
|
+
* ```
|
|
249
|
+
* export * as ns from 'foo';
|
|
250
|
+
* ```
|
|
251
|
+
* becomes:
|
|
252
|
+
* ```
|
|
253
|
+
* [{name: 'ns', reference: new Reference('*', 'foo')}]
|
|
254
|
+
* ```
|
|
255
|
+
*/
|
|
256
|
+
export const getExportReferences = (exportClause, moduleSpecifier, analyzer) => {
|
|
257
|
+
const { typescript } = analyzer;
|
|
258
|
+
const refs = [];
|
|
259
|
+
if (typescript.isNamedExports(exportClause)) {
|
|
260
|
+
for (const el of exportClause.elements) {
|
|
261
|
+
const exportName = el.name.getText();
|
|
262
|
+
const localNameNode = el.propertyName ?? el.name;
|
|
263
|
+
const localName = localNameNode.getText();
|
|
264
|
+
if (moduleSpecifier !== undefined) {
|
|
265
|
+
// This was an explicit re-export (e.g. `export {a} from 'foo'`), so add
|
|
266
|
+
// a Reference
|
|
267
|
+
const specifier = getSpecifierString(moduleSpecifier);
|
|
268
|
+
refs.push({
|
|
269
|
+
exportName,
|
|
270
|
+
decNameOrRef: getImportReference(specifier, moduleSpecifier, localName, analyzer),
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
// Get the declaration for this symbol, so we can determine if
|
|
275
|
+
// it was declared locally or not. Note we use name-based searching
|
|
276
|
+
// to find the symbol, because `getSymbolAtLocation()` for
|
|
277
|
+
// `export {Foo}` will annoyingly just point back to the export
|
|
278
|
+
// line, rather than the location it was actually declared.
|
|
279
|
+
const symbol = getSymbolForName(localName, localNameNode, analyzer);
|
|
280
|
+
const decl = symbol?.declarations?.[0];
|
|
281
|
+
if (symbol === undefined || decl === undefined) {
|
|
282
|
+
analyzer.addDiagnostic(createDiagnostic({
|
|
283
|
+
typescript,
|
|
284
|
+
node: el,
|
|
285
|
+
message: `Could not find declaration for symbol`,
|
|
286
|
+
}));
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
if (typescript.isImportSpecifier(decl)) {
|
|
290
|
+
// If the declaration was an import specifier, this means it's being
|
|
291
|
+
// re-exported, so add a Reference
|
|
292
|
+
const ref = getReferenceForSymbol(symbol, decl, analyzer);
|
|
293
|
+
if (ref !== undefined) {
|
|
294
|
+
refs.push({
|
|
295
|
+
exportName,
|
|
296
|
+
decNameOrRef: ref,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
// Otherwise, the declaration is local, so just add its name; this
|
|
302
|
+
// can be looked up directly in `getDeclaration` for the module
|
|
303
|
+
refs.push({ exportName, decNameOrRef: localName });
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
else if (
|
|
309
|
+
// e.g. `export * as ns from 'foo'`;
|
|
310
|
+
typescript.isNamespaceExport(exportClause) &&
|
|
311
|
+
moduleSpecifier !== undefined) {
|
|
312
|
+
const specifier = getSpecifierString(moduleSpecifier);
|
|
313
|
+
refs.push({
|
|
314
|
+
exportName: exportClause.name.getText(),
|
|
315
|
+
decNameOrRef: getImportReference(specifier, moduleSpecifier, '*', analyzer),
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
analyzer.addDiagnostic(createDiagnostic({
|
|
320
|
+
typescript,
|
|
321
|
+
node: exportClause,
|
|
322
|
+
message: `Unhandled form of ExportDeclaration`,
|
|
323
|
+
category: typescript.DiagnosticCategory.Warning,
|
|
324
|
+
code: DiagnosticCode.UNSUPPORTED,
|
|
325
|
+
}));
|
|
326
|
+
}
|
|
327
|
+
return refs;
|
|
328
|
+
};
|
|
329
|
+
/**
|
|
330
|
+
* Returns the specifier string from a specifier expression.
|
|
331
|
+
*
|
|
332
|
+
* For a given import statement:
|
|
333
|
+
* ```
|
|
334
|
+
* import {foo} from 'foo/bar.js';
|
|
335
|
+
* ```
|
|
336
|
+
* The specifierExpression is the string literal 'foo/bar.js' whose getText()
|
|
337
|
+
* includes the quotes. This function returns the string value without the
|
|
338
|
+
* quotes.
|
|
339
|
+
*/
|
|
340
|
+
export const getSpecifierString = (specifierExpression) => {
|
|
341
|
+
// A specifier expression is always expected to be a quoted string literal.
|
|
342
|
+
// Slice off the quotes and return the text.
|
|
343
|
+
return specifierExpression.getText().slice(1, -1);
|
|
344
|
+
};
|
|
345
|
+
//# sourceMappingURL=references.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"references.js","sourceRoot":"","sources":["../src/lib/references.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2022 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nimport type ts from 'typescript';\nimport {\n AnalyzerInterface,\n LocalNameOrReference,\n Reference,\n TypeScript,\n} from './model.js';\nimport {\n getResolvedExportFromSourcePath,\n getPathForModuleSpecifier,\n getModuleInfo,\n} from './javascript/modules.js';\nimport {AbsolutePath} from './paths.js';\nimport {createDiagnostic} from './errors.js';\nimport {DiagnosticCode} from './diagnostic-code.js';\n\nconst npmModule = /^(?<package>(@[^/]+\\/[^/]+)|[^/]+)\\/?(?<module>.*)$/;\n\n/**\n * Returns a ts.Symbol for a name in scope at a given location in the AST.\n * TODO(kschaaf): There are ~1748 symbols in scope of a typical hello world,\n * due to DOM globals. Perf might become an issue here.\n */\nexport const getSymbolForName = (\n name: string,\n location: ts.Node,\n analyzer: AnalyzerInterface\n): ts.Symbol | undefined => {\n return analyzer.program\n .getTypeChecker()\n .getSymbolsInScope(\n location,\n (analyzer.typescript.SymbolFlags as unknown as {All: number}).All\n )\n .filter((s) => s.name === name)[0];\n};\n\ninterface ModuleSpecifierInfo {\n specifier: string;\n location: ts.Node;\n name: string;\n}\n\n/**\n * Returns the module specifier expression for a declaration if it was imported,\n * or `undefined` if the declaration was not imported.\n */\nconst getImportSpecifierInfo = (\n ts: TypeScript,\n declaration: ts.Node\n): ModuleSpecifierInfo | undefined => {\n // TODO(kschaaf) support the various import syntaxes, e.g. `import {foo as bar} from 'baz'`\n if (\n ts.isImportSpecifier(declaration) &&\n ts.isNamedImports(declaration.parent) &&\n ts.isImportClause(declaration.parent.parent) &&\n ts.isImportDeclaration(declaration.parent.parent.parent)\n ) {\n const specifierExpression =\n declaration.parent.parent.parent.moduleSpecifier;\n const specifier = getSpecifierString(specifierExpression);\n return {\n specifier,\n location: specifierExpression,\n name: declaration.propertyName?.text ?? declaration.name.text,\n };\n }\n return undefined;\n};\n\n/**\n * Returns an analyzer `Reference` object for the given identifier.\n *\n * If the symbol's declaration was imported, the Reference will be based on\n * the import's module specifier; otherwise the Reference will point to the\n * current module being analyzed.\n */\nexport const getReferenceForIdentifier = (\n identifier: ts.Identifier,\n analyzer: AnalyzerInterface\n) => {\n const symbol = analyzer.program\n .getTypeChecker()\n .getSymbolAtLocation(identifier);\n if (symbol === undefined) {\n analyzer.addDiagnostic(\n createDiagnostic({\n typescript: analyzer.typescript,\n node: identifier,\n message: `Could not find symbol for identifier.`,\n })\n );\n return undefined;\n }\n return getReferenceForSymbol(symbol, identifier, analyzer);\n};\n\n/**\n * Returns an analyzer `Reference` model for the given ts.Symbol.\n *\n * If the symbol's declaration was imported, the Reference will be based on\n * the import's module specifier; otherwise the Reference will point to the\n * current module being analyzed.\n */\nexport function getReferenceForSymbol(\n symbol: ts.Symbol,\n location: ts.Node,\n analyzer: AnalyzerInterface\n): Reference | undefined {\n const {name: symbolName} = symbol;\n // TODO(kschaaf): Do we need to check other declarations? The assumption is\n // that even with multiple declarations (e.g. because of class interface +\n // constructor), the reference would point to the same location for all,\n // or else (in the case of e.g. namespace augmentation) it will be global\n // and not need a specific module specifier.\n const declaration = symbol?.declarations?.[0];\n if (declaration === undefined) {\n analyzer.addDiagnostic(\n createDiagnostic({\n typescript: analyzer.typescript,\n node: location,\n message: `Could not find declaration for symbol '${symbolName}'`,\n })\n );\n return undefined;\n }\n const declarationSourceFile = declaration.getSourceFile();\n const locationSourceFile = location.getSourceFile();\n // There are three top-level cases to cover:\n // 1. A global symbol that wasn't imported.\n // 2. An imported symbol\n // 3. A symbol declared in this file.\n if (declarationSourceFile !== locationSourceFile) {\n // If the reference declaration doesn't exist in this module, it must have\n // been a global (whose declaration is in an ambient .d.ts file)\n // TODO(kschaaf): We might want to further differentiate e.g. DOM globals\n // (that don't have any e.g. source to link to) from other ambient\n // declarations where we could at least point to a declaration file\n return getGlobalReference(declarationSourceFile, symbolName, analyzer);\n } else {\n // For all other cases, the symbol's declaration node will be in this file,\n // either as an ImportDeclaration or a normal declaration.\n const importInfo = getImportSpecifierInfo(analyzer.typescript, declaration);\n if (importInfo !== undefined) {\n // Declaration was imported\n return getImportReference(\n importInfo.specifier,\n importInfo.location,\n importInfo.name,\n analyzer\n );\n } else {\n // Declared in this file: use the current package and module\n return getLocalReference(location, symbolName, analyzer);\n }\n }\n}\n\n/**\n * Returns a `Reference` for a global symbol that was not imported.\n */\nconst getGlobalReference = (\n declarationSourceFile: ts.SourceFile,\n name: string,\n analyzer: AnalyzerInterface\n) => {\n return new Reference({\n name,\n isGlobal: true,\n dereference: () =>\n getResolvedExportFromSourcePath(\n declarationSourceFile.fileName as AbsolutePath,\n name,\n analyzer\n ),\n });\n};\n\n/**\n * Returns a `Reference` for a symbol that was imported.\n *\n * There are 4 main categories of imports we cover:\n *\n * 1. A symbol imported from a URL. The declaration will be an\n * ImportModuleSpecifier and its module path will be parsable as a URL.\n *\n * 2. A symbol imported from a relative file within this package. The\n * declaration will be an ImportModuleSpecifier and its module path will\n * start with a '.'\n *\n * 3. A symbol imported from an absolute path. The declaration will be an\n * ImportModuleSpecifier and its module path will start with a '/' This is a\n * weird case to cover in the analyzer because it isn't portable.\n *\n * 4. A symbol imported from an external package. The declaration will be an\n * ImportModuleSpecifier and its module path will not start with a '.'\n */\nexport const getImportReference = (\n specifier: string,\n location: ts.Node,\n name: string,\n analyzer: AnalyzerInterface\n) => {\n const {path} = analyzer;\n let refPackage;\n let refModule;\n // Check whether it is a URL, absolute, package local, or external\n try {\n new URL(specifier);\n refPackage = '';\n refModule = specifier;\n } catch {\n if (specifier[0] === '.') {\n // Relative import from this package: use the current package and\n // module path relative to this module\n const sourceFilePath = location.getSourceFile().fileName as AbsolutePath;\n const module = getModuleInfo(sourceFilePath, analyzer);\n refPackage = module.packageJson.name;\n refModule = path\n .join(path.dirname(module.jsPath), specifier)\n .replace(/\\\\/g, '/');\n } else if (analyzer.path.isAbsolute(specifier)) {\n // Absolute import; no package, just use the entire path as the\n // module\n refPackage = '';\n refModule = specifier;\n } else {\n // External import: extract the npm package (taking care to respect\n // npm orgs) and module specifier (if any)\n const info = specifier.match(npmModule);\n if (info?.groups) {\n refPackage = info.groups.package;\n refModule = info.groups.module || undefined;\n } else {\n analyzer.addDiagnostic(\n createDiagnostic({\n typescript: analyzer.typescript,\n node: location,\n message: `External npm package could not be parsed from module specifier '${specifier}'.`,\n })\n );\n }\n }\n }\n return new Reference({\n name,\n package: refPackage,\n module: refModule,\n dereference: () => {\n const path = getPathForModuleSpecifier(specifier, location, analyzer);\n if (path === undefined) {\n return;\n }\n return getResolvedExportFromSourcePath(path, name, analyzer);\n },\n });\n};\n\n/**\n * Returns a `Reference` for a symbol that was imported.\n */\nexport const getImportReferenceForSpecifierExpression = (\n specifierExpression: ts.Expression,\n name: string,\n analyzer: AnalyzerInterface\n) => {\n const specifier = getSpecifierString(specifierExpression);\n return getImportReference(specifier, specifierExpression, name, analyzer);\n};\n\n/**\n * Returns a `Reference` to a symbol declared in the current source file.\n */\nconst getLocalReference = (\n location: ts.Node,\n name: string,\n analyzer: AnalyzerInterface\n) => {\n const module = getModuleInfo(\n location.getSourceFile().fileName as AbsolutePath,\n analyzer\n );\n return new Reference({\n name,\n package: module.packageJson.name,\n module: module.jsPath.replace(/\\\\/g, '/'),\n dereference: () =>\n getResolvedExportFromSourcePath(\n location.getSourceFile().fileName as AbsolutePath,\n name,\n analyzer\n ),\n });\n};\n\n/**\n * For a given export clause and (optional) specifier from an export statement,\n * returns an array of objects mapping the export name to a\n * LocalNameOrReference, which is a string name that can be looked up directly\n * in `getDeclaration()` of the declaring module for local declarations, or a\n * `Reference` in the case of re-exported declarations.\n *\n * For example:\n * ```\n * import {a} from 'foo';\n * const b = 'b';\n * const c = 'c';\n * export {a as x, b as y, c};\n * ```\n * This would return (using pseudo-code for Reference objects):\n * ```\n * [\n * {name: 'x', reference: new Reference('a', 'foo')},\n * {name: 'y', reference: 'b'},\n * {name: 'c', reference: 'c'},\n * ]\n * ```\n *\n * This also handles explicit re-export syntax, which all become References:\n * ```\n * export {a as x, b as y, c} from 'foo';\n * ```\n *\n * Finally, this handles namespace exports, which become a single Reference:\n * ```\n * export * as ns from 'foo';\n * ```\n * becomes:\n * ```\n * [{name: 'ns', reference: new Reference('*', 'foo')}]\n * ```\n */\nexport const getExportReferences = (\n exportClause: ts.NamedExportBindings,\n moduleSpecifier: ts.Expression | undefined,\n analyzer: AnalyzerInterface\n): Array<{exportName: string; decNameOrRef: LocalNameOrReference}> => {\n const {typescript} = analyzer;\n const refs: Array<{exportName: string; decNameOrRef: string | Reference}> =\n [];\n if (typescript.isNamedExports(exportClause)) {\n for (const el of exportClause.elements) {\n const exportName = el.name.getText();\n const localNameNode = el.propertyName ?? el.name;\n const localName = localNameNode.getText();\n if (moduleSpecifier !== undefined) {\n // This was an explicit re-export (e.g. `export {a} from 'foo'`), so add\n // a Reference\n const specifier = getSpecifierString(moduleSpecifier);\n refs.push({\n exportName,\n decNameOrRef: getImportReference(\n specifier,\n moduleSpecifier,\n localName,\n analyzer\n ),\n });\n } else {\n // Get the declaration for this symbol, so we can determine if\n // it was declared locally or not. Note we use name-based searching\n // to find the symbol, because `getSymbolAtLocation()` for\n // `export {Foo}` will annoyingly just point back to the export\n // line, rather than the location it was actually declared.\n const symbol = getSymbolForName(localName, localNameNode, analyzer);\n const decl = symbol?.declarations?.[0];\n if (symbol === undefined || decl === undefined) {\n analyzer.addDiagnostic(\n createDiagnostic({\n typescript,\n node: el,\n message: `Could not find declaration for symbol`,\n })\n );\n continue;\n }\n if (typescript.isImportSpecifier(decl)) {\n // If the declaration was an import specifier, this means it's being\n // re-exported, so add a Reference\n const ref = getReferenceForSymbol(symbol, decl, analyzer);\n if (ref !== undefined) {\n refs.push({\n exportName,\n decNameOrRef: ref,\n });\n }\n } else {\n // Otherwise, the declaration is local, so just add its name; this\n // can be looked up directly in `getDeclaration` for the module\n refs.push({exportName, decNameOrRef: localName});\n }\n }\n }\n } else if (\n // e.g. `export * as ns from 'foo'`;\n typescript.isNamespaceExport(exportClause) &&\n moduleSpecifier !== undefined\n ) {\n const specifier = getSpecifierString(moduleSpecifier);\n refs.push({\n exportName: exportClause.name.getText(),\n decNameOrRef: getImportReference(\n specifier,\n moduleSpecifier,\n '*',\n analyzer\n ),\n });\n } else {\n analyzer.addDiagnostic(\n createDiagnostic({\n typescript,\n node: exportClause,\n message: `Unhandled form of ExportDeclaration`,\n category: typescript.DiagnosticCategory.Warning,\n code: DiagnosticCode.UNSUPPORTED,\n })\n );\n }\n return refs;\n};\n\n/**\n * Returns the specifier string from a specifier expression.\n *\n * For a given import statement:\n * ```\n * import {foo} from 'foo/bar.js';\n * ```\n * The specifierExpression is the string literal 'foo/bar.js' whose getText()\n * includes the quotes. This function returns the string value without the\n * quotes.\n */\nexport const getSpecifierString = (specifierExpression: ts.Expression) => {\n // A specifier expression is always expected to be a quoted string literal.\n // Slice off the quotes and return the text.\n return specifierExpression.getText().slice(1, -1);\n};\n"]}
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
5
|
+
*/
|
|
6
|
+
import type ts from 'typescript';
|
|
7
|
+
import { Type, AnalyzerInterface } from './model.js';
|
|
8
|
+
export type TypeScript = typeof ts;
|
|
9
|
+
/**
|
|
10
|
+
* Returns an analyzer `Type` object for the given type string,
|
|
11
|
+
* evaluated at the given location.
|
|
12
|
+
*
|
|
13
|
+
* Used for parsing types from JSDoc.
|
|
14
|
+
*/
|
|
15
|
+
export declare const getTypeForTypeString: (typeString: string, location: ts.Node, analyzer: AnalyzerInterface) => Type | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Returns an analyzer `Type` object for the given AST node.
|
|
18
|
+
*/
|
|
19
|
+
export declare const getTypeForNode: (node: ts.Node, analyzer: AnalyzerInterface) => Type;
|
|
20
|
+
/**
|
|
21
|
+
* Converts a ts.Type into an analyzer Type object (which wraps
|
|
22
|
+
* the ts.Type, but also provides analyzer Reference objects).
|
|
23
|
+
*/
|
|
24
|
+
export declare const getTypeForType: (type: ts.Type, location: ts.Node, analyzer: AnalyzerInterface) => Type;
|
|
25
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/lib/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC,OAAO,EAAC,IAAI,EAAa,iBAAiB,EAAC,MAAM,YAAY,CAAC;AAc9D,MAAM,MAAM,UAAU,GAAG,OAAO,EAAE,CAAC;AAEnC;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAC/B,YAAY,MAAM,EAClB,UAAU,EAAE,CAAC,IAAI,EACjB,UAAU,iBAAiB,KAC1B,IAAI,GAAG,SAyBT,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,GACzB,MAAM,EAAE,CAAC,IAAI,EACb,UAAU,iBAAiB,KAC1B,IAMF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,cAAc,GACzB,MAAM,EAAE,CAAC,IAAI,EACb,UAAU,EAAE,CAAC,IAAI,EACjB,UAAU,iBAAiB,KAC1B,IAkCF,CAAC"}
|