index.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /*
  2. Copyright (C) 2012-2014 Yusuke Suzuki <utatane.tea@gmail.com>
  3. Copyright (C) 2013 Alex Seville <hi@alexanderseville.com>
  4. Copyright (C) 2014 Thiago de Arruda <tpadilha84@gmail.com>
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions are met:
  7. * Redistributions of source code must retain the above copyright
  8. notice, this list of conditions and the following disclaimer.
  9. * Redistributions in binary form must reproduce the above copyright
  10. notice, this list of conditions and the following disclaimer in the
  11. documentation and/or other materials provided with the distribution.
  12. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  13. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  14. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  15. ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  16. DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  17. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  18. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  19. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  21. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. */
  23. /**
  24. * Escope (<a href="http://github.com/estools/escope">escope</a>) is an <a
  25. * href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMAScript</a>
  26. * scope analyzer extracted from the <a
  27. * href="http://github.com/estools/esmangle">esmangle project</a/>.
  28. * <p>
  29. * <em>escope</em> finds lexical scopes in a source program, i.e. areas of that
  30. * program where different occurrences of the same identifier refer to the same
  31. * variable. With each scope the contained variables are collected, and each
  32. * identifier reference in code is linked to its corresponding variable (if
  33. * possible).
  34. * <p>
  35. * <em>escope</em> works on a syntax tree of the parsed source code which has
  36. * to adhere to the <a
  37. * href="https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API">
  38. * Mozilla Parser API</a>. E.g. <a href="https://github.com/eslint/espree">espree</a> is a parser
  39. * that produces such syntax trees.
  40. * <p>
  41. * The main interface is the {@link analyze} function.
  42. * @module escope
  43. */
  44. import { assert } from "./assert.js";
  45. import ScopeManager from "./scope-manager.js";
  46. import Referencer from "./referencer.js";
  47. import Reference from "./reference.js";
  48. import Variable from "./variable.js";
  49. import eslintScopeVersion from "./version.js";
  50. /**
  51. * Set the default options
  52. * @returns {Object} options
  53. */
  54. function defaultOptions() {
  55. return {
  56. optimistic: false,
  57. nodejsScope: false,
  58. impliedStrict: false,
  59. sourceType: "script", // one of ['script', 'module', 'commonjs']
  60. ecmaVersion: 5,
  61. childVisitorKeys: null,
  62. fallback: "iteration"
  63. };
  64. }
  65. /**
  66. * Preform deep update on option object
  67. * @param {Object} target Options
  68. * @param {Object} override Updates
  69. * @returns {Object} Updated options
  70. */
  71. function updateDeeply(target, override) {
  72. /**
  73. * Is hash object
  74. * @param {Object} value Test value
  75. * @returns {boolean} Result
  76. */
  77. function isHashObject(value) {
  78. return typeof value === "object" && value instanceof Object && !(value instanceof Array) && !(value instanceof RegExp);
  79. }
  80. for (const key in override) {
  81. if (Object.hasOwn(override, key)) {
  82. const val = override[key];
  83. if (isHashObject(val)) {
  84. if (isHashObject(target[key])) {
  85. updateDeeply(target[key], val);
  86. } else {
  87. target[key] = updateDeeply({}, val);
  88. }
  89. } else {
  90. target[key] = val;
  91. }
  92. }
  93. }
  94. return target;
  95. }
  96. /**
  97. * Main interface function. Takes an Espree syntax tree and returns the
  98. * analyzed scopes.
  99. * @function analyze
  100. * @param {espree.Tree} tree Abstract Syntax Tree
  101. * @param {Object} providedOptions Options that tailor the scope analysis
  102. * @param {boolean} [providedOptions.optimistic=false] the optimistic flag
  103. * @param {boolean} [providedOptions.ignoreEval=false] whether to check 'eval()' calls
  104. * @param {boolean} [providedOptions.nodejsScope=false] whether the whole
  105. * script is executed under node.js environment. When enabled, escope adds
  106. * a function scope immediately following the global scope.
  107. * @param {boolean} [providedOptions.impliedStrict=false] implied strict mode
  108. * (if ecmaVersion >= 5).
  109. * @param {string} [providedOptions.sourceType='script'] the source type of the script. one of 'script', 'module', and 'commonjs'
  110. * @param {number} [providedOptions.ecmaVersion=5] which ECMAScript version is considered
  111. * @param {Object} [providedOptions.childVisitorKeys=null] Additional known visitor keys. See [esrecurse](https://github.com/estools/esrecurse)'s the `childVisitorKeys` option.
  112. * @param {string} [providedOptions.fallback='iteration'] A kind of the fallback in order to encounter with unknown node. See [esrecurse](https://github.com/estools/esrecurse)'s the `fallback` option.
  113. * @returns {ScopeManager} ScopeManager
  114. */
  115. function analyze(tree, providedOptions) {
  116. const options = updateDeeply(defaultOptions(), providedOptions);
  117. const scopeManager = new ScopeManager(options);
  118. const referencer = new Referencer(options, scopeManager);
  119. referencer.visit(tree);
  120. assert(scopeManager.__currentScope === null, "currentScope should be null.");
  121. return scopeManager;
  122. }
  123. export {
  124. /** @name module:escope.version */
  125. eslintScopeVersion as version,
  126. /** @name module:escope.Reference */
  127. Reference,
  128. /** @name module:escope.Variable */
  129. Variable,
  130. /** @name module:escope.ScopeManager */
  131. ScopeManager,
  132. /** @name module:escope.Referencer */
  133. Referencer,
  134. analyze
  135. };
  136. /** @name module:escope.Definition */
  137. export { Definition } from "./definition.js";
  138. /** @name module:escope.PatternVisitor */
  139. export { default as PatternVisitor } from "./pattern-visitor.js";
  140. /** @name module:escope.Scope */
  141. export { Scope } from "./scope.js";
  142. /* vim: set sw=4 ts=4 et tw=80 : */