usage.js 25 KB

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