@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.
Files changed (115) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +76 -0
  3. package/index.d.ts +10 -0
  4. package/index.d.ts.map +1 -0
  5. package/index.js +10 -0
  6. package/index.js.map +1 -0
  7. package/lib/analyzer.d.ts +47 -0
  8. package/lib/analyzer.d.ts.map +1 -0
  9. package/lib/analyzer.js +90 -0
  10. package/lib/analyzer.js.map +1 -0
  11. package/lib/custom-elements/custom-elements.d.ts +33 -0
  12. package/lib/custom-elements/custom-elements.d.ts.map +1 -0
  13. package/lib/custom-elements/custom-elements.js +124 -0
  14. package/lib/custom-elements/custom-elements.js.map +1 -0
  15. package/lib/custom-elements/events.d.ts +19 -0
  16. package/lib/custom-elements/events.d.ts.map +1 -0
  17. package/lib/custom-elements/events.js +25 -0
  18. package/lib/custom-elements/events.js.map +1 -0
  19. package/lib/diagnostic-code.d.ts +21 -0
  20. package/lib/diagnostic-code.d.ts.map +1 -0
  21. package/lib/diagnostic-code.js +20 -0
  22. package/lib/diagnostic-code.js.map +1 -0
  23. package/lib/errors.d.ts +24 -0
  24. package/lib/errors.d.ts.map +1 -0
  25. package/lib/errors.js +17 -0
  26. package/lib/errors.js.map +1 -0
  27. package/lib/javascript/classes.d.ts +50 -0
  28. package/lib/javascript/classes.d.ts.map +1 -0
  29. package/lib/javascript/classes.js +307 -0
  30. package/lib/javascript/classes.js.map +1 -0
  31. package/lib/javascript/functions.d.ts +31 -0
  32. package/lib/javascript/functions.d.ts.map +1 -0
  33. package/lib/javascript/functions.js +144 -0
  34. package/lib/javascript/functions.js.map +1 -0
  35. package/lib/javascript/jsdoc.d.ts +67 -0
  36. package/lib/javascript/jsdoc.d.ts.map +1 -0
  37. package/lib/javascript/jsdoc.js +244 -0
  38. package/lib/javascript/jsdoc.js.map +1 -0
  39. package/lib/javascript/mixins.d.ts +45 -0
  40. package/lib/javascript/mixins.d.ts.map +1 -0
  41. package/lib/javascript/mixins.js +147 -0
  42. package/lib/javascript/mixins.js.map +1 -0
  43. package/lib/javascript/modules.d.ts +42 -0
  44. package/lib/javascript/modules.d.ts.map +1 -0
  45. package/lib/javascript/modules.js +277 -0
  46. package/lib/javascript/modules.js.map +1 -0
  47. package/lib/javascript/packages.d.ts +18 -0
  48. package/lib/javascript/packages.d.ts.map +1 -0
  49. package/lib/javascript/packages.js +53 -0
  50. package/lib/javascript/packages.js.map +1 -0
  51. package/lib/javascript/variables.d.ts +29 -0
  52. package/lib/javascript/variables.d.ts.map +1 -0
  53. package/lib/javascript/variables.js +143 -0
  54. package/lib/javascript/variables.js.map +1 -0
  55. package/lib/lit/decorators.d.ts +36 -0
  56. package/lib/lit/decorators.d.ts.map +1 -0
  57. package/lib/lit/decorators.js +32 -0
  58. package/lib/lit/decorators.js.map +1 -0
  59. package/lib/lit/lit-element.d.ts +39 -0
  60. package/lib/lit/lit-element.d.ts.map +1 -0
  61. package/lib/lit/lit-element.js +96 -0
  62. package/lib/lit/lit-element.js.map +1 -0
  63. package/lib/lit/modules.d.ts +28 -0
  64. package/lib/lit/modules.d.ts.map +1 -0
  65. package/lib/lit/modules.js +62 -0
  66. package/lib/lit/modules.js.map +1 -0
  67. package/lib/lit/properties.d.ts +43 -0
  68. package/lib/lit/properties.d.ts.map +1 -0
  69. package/lib/lit/properties.js +268 -0
  70. package/lib/lit/properties.js.map +1 -0
  71. package/lib/lit/template.d.ts +110 -0
  72. package/lib/lit/template.d.ts.map +1 -0
  73. package/lib/lit/template.js +412 -0
  74. package/lib/lit/template.js.map +1 -0
  75. package/lib/lit-element/decorators.d.ts +11 -0
  76. package/lib/lit-element/decorators.d.ts.map +1 -0
  77. package/lib/lit-element/decorators.js +11 -0
  78. package/lib/lit-element/decorators.js.map +1 -0
  79. package/lib/lit-element/lit-element.d.ts +11 -0
  80. package/lib/lit-element/lit-element.d.ts.map +1 -0
  81. package/lib/lit-element/lit-element.js +11 -0
  82. package/lib/lit-element/lit-element.js.map +1 -0
  83. package/lib/lit-element/properties.d.ts +11 -0
  84. package/lib/lit-element/properties.d.ts.map +1 -0
  85. package/lib/lit-element/properties.js +11 -0
  86. package/lib/lit-element/properties.js.map +1 -0
  87. package/lib/model.d.ts +506 -0
  88. package/lib/model.d.ts.map +1 -0
  89. package/lib/model.js +392 -0
  90. package/lib/model.js.map +1 -0
  91. package/lib/package-analyzer.d.ts +25 -0
  92. package/lib/package-analyzer.d.ts.map +1 -0
  93. package/lib/package-analyzer.js +81 -0
  94. package/lib/package-analyzer.js.map +1 -0
  95. package/lib/paths.d.ts +24 -0
  96. package/lib/paths.d.ts.map +1 -0
  97. package/lib/paths.js +35 -0
  98. package/lib/paths.js.map +1 -0
  99. package/lib/references.d.ts +107 -0
  100. package/lib/references.d.ts.map +1 -0
  101. package/lib/references.js +345 -0
  102. package/lib/references.js.map +1 -0
  103. package/lib/types.d.ts +25 -0
  104. package/lib/types.d.ts.map +1 -0
  105. package/lib/types.js +257 -0
  106. package/lib/types.js.map +1 -0
  107. package/lib/utils.d.ts +22 -0
  108. package/lib/utils.d.ts.map +1 -0
  109. package/lib/utils.js +51 -0
  110. package/lib/utils.js.map +1 -0
  111. package/package-analyzer.d.ts +8 -0
  112. package/package-analyzer.d.ts.map +1 -0
  113. package/package-analyzer.js +8 -0
  114. package/package-analyzer.js.map +1 -0
  115. package/package.json +109 -0
@@ -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"}