usage.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.collectVariableUsage = exports.getDeclarationDomain = exports.getUsageDomain = exports.UsageDomain = exports.DeclarationDomain = void 0;
  4. const util_1 = require("./util");
  5. const ts = require("typescript");
  6. var DeclarationDomain;
  7. (function (DeclarationDomain) {
  8. DeclarationDomain[DeclarationDomain["Namespace"] = 1] = "Namespace";
  9. DeclarationDomain[DeclarationDomain["Type"] = 2] = "Type";
  10. DeclarationDomain[DeclarationDomain["Value"] = 4] = "Value";
  11. DeclarationDomain[DeclarationDomain["Import"] = 8] = "Import";
  12. DeclarationDomain[DeclarationDomain["Any"] = 7] = "Any";
  13. })(DeclarationDomain = exports.DeclarationDomain || (exports.DeclarationDomain = {}));
  14. var UsageDomain;
  15. (function (UsageDomain) {
  16. UsageDomain[UsageDomain["Namespace"] = 1] = "Namespace";
  17. UsageDomain[UsageDomain["Type"] = 2] = "Type";
  18. UsageDomain[UsageDomain["Value"] = 4] = "Value";
  19. UsageDomain[UsageDomain["ValueOrNamespace"] = 5] = "ValueOrNamespace";
  20. UsageDomain[UsageDomain["Any"] = 7] = "Any";
  21. UsageDomain[UsageDomain["TypeQuery"] = 8] = "TypeQuery";
  22. })(UsageDomain = exports.UsageDomain || (exports.UsageDomain = {}));
  23. // TODO handle cases where values are used only for their types, e.g. `declare [propSymbol]: number`
  24. function getUsageDomain(node) {
  25. const parent = node.parent;
  26. switch (parent.kind) {
  27. case ts.SyntaxKind.TypeReference:
  28. return node.originalKeywordKind !== ts.SyntaxKind.ConstKeyword ? 2 /* Type */ : undefined;
  29. case ts.SyntaxKind.ExpressionWithTypeArguments:
  30. return parent.parent.token === ts.SyntaxKind.ImplementsKeyword ||
  31. parent.parent.parent.kind === ts.SyntaxKind.InterfaceDeclaration
  32. ? 2 /* Type */
  33. : 4 /* Value */;
  34. case ts.SyntaxKind.TypeQuery:
  35. return 5 /* ValueOrNamespace */ | 8 /* TypeQuery */;
  36. case ts.SyntaxKind.QualifiedName:
  37. if (parent.left === node) {
  38. if (getEntityNameParent(parent).kind === ts.SyntaxKind.TypeQuery)
  39. return 1 /* Namespace */ | 8 /* TypeQuery */;
  40. return 1 /* Namespace */;
  41. }
  42. break;
  43. case ts.SyntaxKind.ExportSpecifier:
  44. // either {name} or {propertyName as name}
  45. if (parent.propertyName === undefined ||
  46. parent.propertyName === node)
  47. return 7 /* Any */; // TODO handle type-only exports
  48. break;
  49. case ts.SyntaxKind.ExportAssignment:
  50. return 7 /* Any */;
  51. // Value
  52. case ts.SyntaxKind.BindingElement:
  53. if (parent.initializer === node)
  54. return 5 /* ValueOrNamespace */;
  55. break;
  56. case ts.SyntaxKind.Parameter:
  57. case ts.SyntaxKind.EnumMember:
  58. case ts.SyntaxKind.PropertyDeclaration:
  59. case ts.SyntaxKind.VariableDeclaration:
  60. case ts.SyntaxKind.PropertyAssignment:
  61. case ts.SyntaxKind.PropertyAccessExpression:
  62. case ts.SyntaxKind.ImportEqualsDeclaration:
  63. if (parent.name !== node)
  64. return 5 /* ValueOrNamespace */; // TODO handle type-only imports
  65. break;
  66. case ts.SyntaxKind.JsxAttribute:
  67. case ts.SyntaxKind.FunctionDeclaration:
  68. case ts.SyntaxKind.FunctionExpression:
  69. case ts.SyntaxKind.NamespaceImport:
  70. case ts.SyntaxKind.ClassDeclaration:
  71. case ts.SyntaxKind.ClassExpression:
  72. case ts.SyntaxKind.ModuleDeclaration:
  73. case ts.SyntaxKind.MethodDeclaration:
  74. case ts.SyntaxKind.EnumDeclaration:
  75. case ts.SyntaxKind.GetAccessor:
  76. case ts.SyntaxKind.SetAccessor:
  77. case ts.SyntaxKind.LabeledStatement:
  78. case ts.SyntaxKind.BreakStatement:
  79. case ts.SyntaxKind.ContinueStatement:
  80. case ts.SyntaxKind.ImportClause:
  81. case ts.SyntaxKind.ImportSpecifier:
  82. case ts.SyntaxKind.TypePredicate: // TODO this actually references a parameter
  83. case ts.SyntaxKind.MethodSignature:
  84. case ts.SyntaxKind.PropertySignature:
  85. case ts.SyntaxKind.NamespaceExportDeclaration:
  86. case ts.SyntaxKind.NamespaceExport:
  87. case ts.SyntaxKind.InterfaceDeclaration:
  88. case ts.SyntaxKind.TypeAliasDeclaration:
  89. case ts.SyntaxKind.TypeParameter:
  90. case ts.SyntaxKind.NamedTupleMember:
  91. break;
  92. default:
  93. return 5 /* ValueOrNamespace */;
  94. }
  95. }
  96. exports.getUsageDomain = getUsageDomain;
  97. function getDeclarationDomain(node) {
  98. switch (node.parent.kind) {
  99. case ts.SyntaxKind.TypeParameter:
  100. case ts.SyntaxKind.InterfaceDeclaration:
  101. case ts.SyntaxKind.TypeAliasDeclaration:
  102. return 2 /* Type */;
  103. case ts.SyntaxKind.ClassDeclaration:
  104. case ts.SyntaxKind.ClassExpression:
  105. return 2 /* Type */ | 4 /* Value */;
  106. case ts.SyntaxKind.EnumDeclaration:
  107. return 7 /* Any */;
  108. case ts.SyntaxKind.NamespaceImport:
  109. case ts.SyntaxKind.ImportClause:
  110. return 7 /* Any */ | 8 /* Import */; // TODO handle type-only imports
  111. case ts.SyntaxKind.ImportEqualsDeclaration:
  112. case ts.SyntaxKind.ImportSpecifier:
  113. return node.parent.name === node
  114. ? 7 /* Any */ | 8 /* Import */ // TODO handle type-only imports
  115. : undefined;
  116. case ts.SyntaxKind.ModuleDeclaration:
  117. return 1 /* Namespace */;
  118. case ts.SyntaxKind.Parameter:
  119. if (node.parent.parent.kind === ts.SyntaxKind.IndexSignature || node.originalKeywordKind === ts.SyntaxKind.ThisKeyword)
  120. return;
  121. // falls through
  122. case ts.SyntaxKind.BindingElement:
  123. case ts.SyntaxKind.VariableDeclaration:
  124. return node.parent.name === node ? 4 /* Value */ : undefined;
  125. case ts.SyntaxKind.FunctionDeclaration:
  126. case ts.SyntaxKind.FunctionExpression:
  127. return 4 /* Value */;
  128. }
  129. }
  130. exports.getDeclarationDomain = getDeclarationDomain;
  131. function collectVariableUsage(sourceFile) {
  132. return new UsageWalker().getUsage(sourceFile);
  133. }
  134. exports.collectVariableUsage = collectVariableUsage;
  135. class AbstractScope {
  136. constructor(_global) {
  137. this._global = _global;
  138. this._variables = new Map();
  139. this._uses = [];
  140. this._namespaceScopes = undefined;
  141. this._enumScopes = undefined;
  142. }
  143. addVariable(identifier, name, selector, exported, domain) {
  144. const variables = this.getDestinationScope(selector).getVariables();
  145. const declaration = {
  146. domain,
  147. exported,
  148. declaration: name,
  149. };
  150. const variable = variables.get(identifier);
  151. if (variable === undefined) {
  152. variables.set(identifier, {
  153. domain,
  154. declarations: [declaration],
  155. uses: [],
  156. });
  157. }
  158. else {
  159. variable.domain |= domain;
  160. variable.declarations.push(declaration);
  161. }
  162. }
  163. addUse(use) {
  164. this._uses.push(use);
  165. }
  166. getVariables() {
  167. return this._variables;
  168. }
  169. getFunctionScope() {
  170. return this;
  171. }
  172. end(cb) {
  173. if (this._namespaceScopes !== undefined)
  174. this._namespaceScopes.forEach((value) => value.finish(cb));
  175. this._namespaceScopes = this._enumScopes = undefined;
  176. this._applyUses();
  177. this._variables.forEach((variable) => {
  178. for (const declaration of variable.declarations) {
  179. const result = {
  180. declarations: [],
  181. domain: declaration.domain,
  182. exported: declaration.exported,
  183. inGlobalScope: this._global,
  184. uses: [],
  185. };
  186. for (const other of variable.declarations)
  187. if (other.domain & declaration.domain)
  188. result.declarations.push(other.declaration);
  189. for (const use of variable.uses)
  190. if (use.domain & declaration.domain)
  191. result.uses.push(use);
  192. cb(result, declaration.declaration, this);
  193. }
  194. });
  195. }
  196. // tslint:disable-next-line:prefer-function-over-method
  197. markExported(_name) { } // only relevant for the root scope
  198. createOrReuseNamespaceScope(name, _exported, ambient, hasExportStatement) {
  199. let scope;
  200. if (this._namespaceScopes === undefined) {
  201. this._namespaceScopes = new Map();
  202. }
  203. else {
  204. scope = this._namespaceScopes.get(name);
  205. }
  206. if (scope === undefined) {
  207. scope = new NamespaceScope(ambient, hasExportStatement, this);
  208. this._namespaceScopes.set(name, scope);
  209. }
  210. else {
  211. scope.refresh(ambient, hasExportStatement);
  212. }
  213. return scope;
  214. }
  215. createOrReuseEnumScope(name, _exported) {
  216. let scope;
  217. if (this._enumScopes === undefined) {
  218. this._enumScopes = new Map();
  219. }
  220. else {
  221. scope = this._enumScopes.get(name);
  222. }
  223. if (scope === undefined) {
  224. scope = new EnumScope(this);
  225. this._enumScopes.set(name, scope);
  226. }
  227. return scope;
  228. }
  229. _applyUses() {
  230. for (const use of this._uses)
  231. if (!this._applyUse(use))
  232. this._addUseToParent(use);
  233. this._uses = [];
  234. }
  235. _applyUse(use, variables = this._variables) {
  236. const variable = variables.get(use.location.text);
  237. if (variable === undefined || (variable.domain & use.domain) === 0)
  238. return false;
  239. variable.uses.push(use);
  240. return true;
  241. }
  242. _addUseToParent(_use) { } // tslint:disable-line:prefer-function-over-method
  243. }
  244. class RootScope extends AbstractScope {
  245. constructor(_exportAll, global) {
  246. super(global);
  247. this._exportAll = _exportAll;
  248. this._exports = undefined;
  249. this._innerScope = new NonRootScope(this, 1 /* Function */);
  250. }
  251. addVariable(identifier, name, selector, exported, domain) {
  252. if (domain & 8 /* Import */)
  253. return super.addVariable(identifier, name, selector, exported, domain);
  254. return this._innerScope.addVariable(identifier, name, selector, exported, domain);
  255. }
  256. addUse(use, origin) {
  257. if (origin === this._innerScope)
  258. return super.addUse(use);
  259. return this._innerScope.addUse(use);
  260. }
  261. markExported(id) {
  262. if (this._exports === undefined) {
  263. this._exports = [id.text];
  264. }
  265. else {
  266. this._exports.push(id.text);
  267. }
  268. }
  269. end(cb) {
  270. this._innerScope.end((value, key) => {
  271. value.exported = value.exported || this._exportAll
  272. || this._exports !== undefined && this._exports.includes(key.text);
  273. value.inGlobalScope = this._global;
  274. return cb(value, key, this);
  275. });
  276. return super.end((value, key, scope) => {
  277. value.exported = value.exported || scope === this
  278. && this._exports !== undefined && this._exports.includes(key.text);
  279. return cb(value, key, scope);
  280. });
  281. }
  282. getDestinationScope() {
  283. return this;
  284. }
  285. }
  286. class NonRootScope extends AbstractScope {
  287. constructor(_parent, _boundary) {
  288. super(false);
  289. this._parent = _parent;
  290. this._boundary = _boundary;
  291. }
  292. _addUseToParent(use) {
  293. return this._parent.addUse(use, this);
  294. }
  295. getDestinationScope(selector) {
  296. return this._boundary & selector
  297. ? this
  298. : this._parent.getDestinationScope(selector);
  299. }
  300. }
  301. class EnumScope extends NonRootScope {
  302. constructor(parent) {
  303. super(parent, 1 /* Function */);
  304. }
  305. end() {
  306. this._applyUses();
  307. }
  308. }
  309. class ConditionalTypeScope extends NonRootScope {
  310. constructor(parent) {
  311. super(parent, 8 /* ConditionalType */);
  312. this._state = 0 /* Initial */;
  313. }
  314. updateState(newState) {
  315. this._state = newState;
  316. }
  317. addUse(use) {
  318. if (this._state === 2 /* TrueType */)
  319. return void this._uses.push(use);
  320. return this._parent.addUse(use, this);
  321. }
  322. }
  323. class FunctionScope extends NonRootScope {
  324. constructor(parent) {
  325. super(parent, 1 /* Function */);
  326. }
  327. beginBody() {
  328. this._applyUses();
  329. }
  330. }
  331. class AbstractNamedExpressionScope extends NonRootScope {
  332. constructor(_name, _domain, parent) {
  333. super(parent, 1 /* Function */);
  334. this._name = _name;
  335. this._domain = _domain;
  336. }
  337. end(cb) {
  338. this._innerScope.end(cb);
  339. return cb({
  340. declarations: [this._name],
  341. domain: this._domain,
  342. exported: false,
  343. uses: this._uses,
  344. inGlobalScope: false,
  345. }, this._name, this);
  346. }
  347. addUse(use, source) {
  348. if (source !== this._innerScope)
  349. return this._innerScope.addUse(use);
  350. if (use.domain & this._domain && use.location.text === this._name.text) {
  351. this._uses.push(use);
  352. }
  353. else {
  354. return this._parent.addUse(use, this);
  355. }
  356. }
  357. getFunctionScope() {
  358. return this._innerScope;
  359. }
  360. getDestinationScope() {
  361. return this._innerScope;
  362. }
  363. }
  364. class FunctionExpressionScope extends AbstractNamedExpressionScope {
  365. constructor(name, parent) {
  366. super(name, 4 /* Value */, parent);
  367. this._innerScope = new FunctionScope(this);
  368. }
  369. beginBody() {
  370. return this._innerScope.beginBody();
  371. }
  372. }
  373. class ClassExpressionScope extends AbstractNamedExpressionScope {
  374. constructor(name, parent) {
  375. super(name, 4 /* Value */ | 2 /* Type */, parent);
  376. this._innerScope = new NonRootScope(this, 1 /* Function */);
  377. }
  378. }
  379. class BlockScope extends NonRootScope {
  380. constructor(_functionScope, parent) {
  381. super(parent, 2 /* Block */);
  382. this._functionScope = _functionScope;
  383. }
  384. getFunctionScope() {
  385. return this._functionScope;
  386. }
  387. }
  388. function mapDeclaration(declaration) {
  389. return {
  390. declaration,
  391. exported: true,
  392. domain: getDeclarationDomain(declaration),
  393. };
  394. }
  395. class NamespaceScope extends NonRootScope {
  396. constructor(_ambient, _hasExport, parent) {
  397. super(parent, 1 /* Function */);
  398. this._ambient = _ambient;
  399. this._hasExport = _hasExport;
  400. this._innerScope = new NonRootScope(this, 1 /* Function */);
  401. this._exports = undefined;
  402. }
  403. finish(cb) {
  404. return super.end(cb);
  405. }
  406. end(cb) {
  407. this._innerScope.end((variable, key, scope) => {
  408. if (scope !== this._innerScope ||
  409. !variable.exported && (!this._ambient || this._exports !== undefined && !this._exports.has(key.text)))
  410. return cb(variable, key, scope);
  411. const namespaceVar = this._variables.get(key.text);
  412. if (namespaceVar === undefined) {
  413. this._variables.set(key.text, {
  414. declarations: variable.declarations.map(mapDeclaration),
  415. domain: variable.domain,
  416. uses: [...variable.uses],
  417. });
  418. }
  419. else {
  420. outer: for (const declaration of variable.declarations) {
  421. for (const existing of namespaceVar.declarations)
  422. if (existing.declaration === declaration)
  423. continue outer;
  424. namespaceVar.declarations.push(mapDeclaration(declaration));
  425. }
  426. namespaceVar.domain |= variable.domain;
  427. for (const use of variable.uses) {
  428. if (namespaceVar.uses.includes(use))
  429. continue;
  430. namespaceVar.uses.push(use);
  431. }
  432. }
  433. });
  434. this._applyUses();
  435. this._innerScope = new NonRootScope(this, 1 /* Function */);
  436. }
  437. createOrReuseNamespaceScope(name, exported, ambient, hasExportStatement) {
  438. if (!exported && (!this._ambient || this._hasExport))
  439. return this._innerScope.createOrReuseNamespaceScope(name, exported, ambient || this._ambient, hasExportStatement);
  440. return super.createOrReuseNamespaceScope(name, exported, ambient || this._ambient, hasExportStatement);
  441. }
  442. createOrReuseEnumScope(name, exported) {
  443. if (!exported && (!this._ambient || this._hasExport))
  444. return this._innerScope.createOrReuseEnumScope(name, exported);
  445. return super.createOrReuseEnumScope(name, exported);
  446. }
  447. addUse(use, source) {
  448. if (source !== this._innerScope)
  449. return this._innerScope.addUse(use);
  450. this._uses.push(use);
  451. }
  452. refresh(ambient, hasExport) {
  453. this._ambient = ambient;
  454. this._hasExport = hasExport;
  455. }
  456. markExported(name, _as) {
  457. if (this._exports === undefined)
  458. this._exports = new Set();
  459. this._exports.add(name.text);
  460. }
  461. getDestinationScope() {
  462. return this._innerScope;
  463. }
  464. }
  465. function getEntityNameParent(name) {
  466. let parent = name.parent;
  467. while (parent.kind === ts.SyntaxKind.QualifiedName)
  468. parent = parent.parent;
  469. return parent;
  470. }
  471. // TODO class decorators resolve outside of class, element and parameter decorator resolve inside/at the class
  472. // TODO computed property name resolves inside/at the cass
  473. // TODO this and super in all of them are resolved outside of the class
  474. class UsageWalker {
  475. constructor() {
  476. this._result = new Map();
  477. }
  478. getUsage(sourceFile) {
  479. const variableCallback = (variable, key) => {
  480. this._result.set(key, variable);
  481. };
  482. const isModule = ts.isExternalModule(sourceFile);
  483. this._scope = new RootScope(sourceFile.isDeclarationFile && isModule && !containsExportStatement(sourceFile), !isModule);
  484. const cb = (node) => {
  485. if (util_1.isBlockScopeBoundary(node))
  486. return continueWithScope(node, new BlockScope(this._scope.getFunctionScope(), this._scope), handleBlockScope);
  487. switch (node.kind) {
  488. case ts.SyntaxKind.ClassExpression:
  489. return continueWithScope(node, node.name !== undefined
  490. ? new ClassExpressionScope(node.name, this._scope)
  491. : new NonRootScope(this._scope, 1 /* Function */));
  492. case ts.SyntaxKind.ClassDeclaration:
  493. this._handleDeclaration(node, true, 4 /* Value */ | 2 /* Type */);
  494. return continueWithScope(node, new NonRootScope(this._scope, 1 /* Function */));
  495. case ts.SyntaxKind.InterfaceDeclaration:
  496. case ts.SyntaxKind.TypeAliasDeclaration:
  497. this._handleDeclaration(node, true, 2 /* Type */);
  498. return continueWithScope(node, new NonRootScope(this._scope, 4 /* Type */));
  499. case ts.SyntaxKind.EnumDeclaration:
  500. this._handleDeclaration(node, true, 7 /* Any */);
  501. return continueWithScope(node, this._scope.createOrReuseEnumScope(node.name.text, util_1.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword)));
  502. case ts.SyntaxKind.ModuleDeclaration:
  503. return this._handleModule(node, continueWithScope);
  504. case ts.SyntaxKind.MappedType:
  505. return continueWithScope(node, new NonRootScope(this._scope, 4 /* Type */));
  506. case ts.SyntaxKind.FunctionExpression:
  507. case ts.SyntaxKind.ArrowFunction:
  508. case ts.SyntaxKind.Constructor:
  509. case ts.SyntaxKind.MethodDeclaration:
  510. case ts.SyntaxKind.FunctionDeclaration:
  511. case ts.SyntaxKind.GetAccessor:
  512. case ts.SyntaxKind.SetAccessor:
  513. case ts.SyntaxKind.MethodSignature:
  514. case ts.SyntaxKind.CallSignature:
  515. case ts.SyntaxKind.ConstructSignature:
  516. case ts.SyntaxKind.ConstructorType:
  517. case ts.SyntaxKind.FunctionType:
  518. return this._handleFunctionLikeDeclaration(node, cb, variableCallback);
  519. case ts.SyntaxKind.ConditionalType:
  520. return this._handleConditionalType(node, cb, variableCallback);
  521. // End of Scope specific handling
  522. case ts.SyntaxKind.VariableDeclarationList:
  523. this._handleVariableDeclaration(node);
  524. break;
  525. case ts.SyntaxKind.Parameter:
  526. if (node.parent.kind !== ts.SyntaxKind.IndexSignature &&
  527. (node.name.kind !== ts.SyntaxKind.Identifier ||
  528. node.name.originalKeywordKind !== ts.SyntaxKind.ThisKeyword))
  529. this._handleBindingName(node.name, false, false);
  530. break;
  531. case ts.SyntaxKind.EnumMember:
  532. this._scope.addVariable(util_1.getPropertyName(node.name), node.name, 1 /* Function */, true, 4 /* Value */);
  533. break;
  534. case ts.SyntaxKind.ImportClause:
  535. case ts.SyntaxKind.ImportSpecifier:
  536. case ts.SyntaxKind.NamespaceImport:
  537. case ts.SyntaxKind.ImportEqualsDeclaration:
  538. this._handleDeclaration(node, false, 7 /* Any */ | 8 /* Import */);
  539. break;
  540. case ts.SyntaxKind.TypeParameter:
  541. this._scope.addVariable(node.name.text, node.name, node.parent.kind === ts.SyntaxKind.InferType ? 8 /* InferType */ : 7 /* Type */, false, 2 /* Type */);
  542. break;
  543. case ts.SyntaxKind.ExportSpecifier:
  544. if (node.propertyName !== undefined)
  545. return this._scope.markExported(node.propertyName, node.name);
  546. return this._scope.markExported(node.name);
  547. case ts.SyntaxKind.ExportAssignment:
  548. if (node.expression.kind === ts.SyntaxKind.Identifier)
  549. return this._scope.markExported(node.expression);
  550. break;
  551. case ts.SyntaxKind.Identifier:
  552. const domain = getUsageDomain(node);
  553. if (domain !== undefined)
  554. this._scope.addUse({ domain, location: node });
  555. return;
  556. }
  557. return ts.forEachChild(node, cb);
  558. };
  559. const continueWithScope = (node, scope, next = forEachChild) => {
  560. const savedScope = this._scope;
  561. this._scope = scope;
  562. next(node);
  563. this._scope.end(variableCallback);
  564. this._scope = savedScope;
  565. };
  566. const handleBlockScope = (node) => {
  567. if (node.kind === ts.SyntaxKind.CatchClause && node.variableDeclaration !== undefined)
  568. this._handleBindingName(node.variableDeclaration.name, true, false);
  569. return ts.forEachChild(node, cb);
  570. };
  571. ts.forEachChild(sourceFile, cb);
  572. this._scope.end(variableCallback);
  573. return this._result;
  574. function forEachChild(node) {
  575. return ts.forEachChild(node, cb);
  576. }
  577. }
  578. _handleConditionalType(node, cb, varCb) {
  579. const savedScope = this._scope;
  580. const scope = this._scope = new ConditionalTypeScope(savedScope);
  581. cb(node.checkType);
  582. scope.updateState(1 /* Extends */);
  583. cb(node.extendsType);
  584. scope.updateState(2 /* TrueType */);
  585. cb(node.trueType);
  586. scope.updateState(3 /* FalseType */);
  587. cb(node.falseType);
  588. scope.end(varCb);
  589. this._scope = savedScope;
  590. }
  591. _handleFunctionLikeDeclaration(node, cb, varCb) {
  592. if (node.decorators !== undefined)
  593. node.decorators.forEach(cb);
  594. const savedScope = this._scope;
  595. if (node.kind === ts.SyntaxKind.FunctionDeclaration)
  596. this._handleDeclaration(node, false, 4 /* Value */);
  597. const scope = this._scope = node.kind === ts.SyntaxKind.FunctionExpression && node.name !== undefined
  598. ? new FunctionExpressionScope(node.name, savedScope)
  599. : new FunctionScope(savedScope);
  600. if (node.name !== undefined)
  601. cb(node.name);
  602. if (node.typeParameters !== undefined)
  603. node.typeParameters.forEach(cb);
  604. node.parameters.forEach(cb);
  605. if (node.type !== undefined)
  606. cb(node.type);
  607. if (node.body !== undefined) {
  608. scope.beginBody();
  609. cb(node.body);
  610. }
  611. scope.end(varCb);
  612. this._scope = savedScope;
  613. }
  614. _handleModule(node, next) {
  615. if (node.flags & ts.NodeFlags.GlobalAugmentation)
  616. return next(node, this._scope.createOrReuseNamespaceScope('-global', false, true, false));
  617. if (node.name.kind === ts.SyntaxKind.Identifier) {
  618. const exported = isNamespaceExported(node);
  619. this._scope.addVariable(node.name.text, node.name, 1 /* Function */, exported, 1 /* Namespace */ | 4 /* Value */);
  620. const ambient = util_1.hasModifier(node.modifiers, ts.SyntaxKind.DeclareKeyword);
  621. return next(node, this._scope.createOrReuseNamespaceScope(node.name.text, exported, ambient, ambient && namespaceHasExportStatement(node)));
  622. }
  623. return next(node, this._scope.createOrReuseNamespaceScope(`"${node.name.text}"`, false, true, namespaceHasExportStatement(node)));
  624. }
  625. _handleDeclaration(node, blockScoped, domain) {
  626. if (node.name !== undefined)
  627. this._scope.addVariable(node.name.text, node.name, blockScoped ? 3 /* Block */ : 1 /* Function */, util_1.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword), domain);
  628. }
  629. _handleBindingName(name, blockScoped, exported) {
  630. if (name.kind === ts.SyntaxKind.Identifier)
  631. return this._scope.addVariable(name.text, name, blockScoped ? 3 /* Block */ : 1 /* Function */, exported, 4 /* Value */);
  632. util_1.forEachDestructuringIdentifier(name, (declaration) => {
  633. this._scope.addVariable(declaration.name.text, declaration.name, blockScoped ? 3 /* Block */ : 1 /* Function */, exported, 4 /* Value */);
  634. });
  635. }
  636. _handleVariableDeclaration(declarationList) {
  637. const blockScoped = util_1.isBlockScopedVariableDeclarationList(declarationList);
  638. const exported = declarationList.parent.kind === ts.SyntaxKind.VariableStatement &&
  639. util_1.hasModifier(declarationList.parent.modifiers, ts.SyntaxKind.ExportKeyword);
  640. for (const declaration of declarationList.declarations)
  641. this._handleBindingName(declaration.name, blockScoped, exported);
  642. }
  643. }
  644. function isNamespaceExported(node) {
  645. return node.parent.kind === ts.SyntaxKind.ModuleDeclaration || util_1.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword);
  646. }
  647. function namespaceHasExportStatement(ns) {
  648. if (ns.body === undefined || ns.body.kind !== ts.SyntaxKind.ModuleBlock)
  649. return false;
  650. return containsExportStatement(ns.body);
  651. }
  652. function containsExportStatement(block) {
  653. for (const statement of block.statements)
  654. if (statement.kind === ts.SyntaxKind.ExportDeclaration || statement.kind === ts.SyntaxKind.ExportAssignment)
  655. return true;
  656. return false;
  657. }
  658. //# sourceMappingURL=usage.js.map