index.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  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. "use strict";
  45. /* eslint no-underscore-dangle: ["error", { "allow": ["__currentScope"] }] */
  46. const assert = require("assert");
  47. const ScopeManager = require("./scope-manager");
  48. const Referencer = require("./referencer");
  49. const Reference = require("./reference");
  50. const Variable = require("./variable");
  51. const Scope = require("./scope").Scope;
  52. const version = require("../package.json").version;
  53. /**
  54. * Set the default options
  55. * @returns {Object} options
  56. */
  57. function defaultOptions() {
  58. return {
  59. optimistic: false,
  60. directive: false,
  61. nodejsScope: false,
  62. impliedStrict: false,
  63. sourceType: "script", // one of ['script', 'module']
  64. ecmaVersion: 5,
  65. childVisitorKeys: null,
  66. fallback: "iteration"
  67. };
  68. }
  69. /**
  70. * Preform deep update on option object
  71. * @param {Object} target - Options
  72. * @param {Object} override - Updates
  73. * @returns {Object} Updated options
  74. */
  75. function updateDeeply(target, override) {
  76. /**
  77. * Is hash object
  78. * @param {Object} value - Test value
  79. * @returns {boolean} Result
  80. */
  81. function isHashObject(value) {
  82. return typeof value === "object" && value instanceof Object && !(value instanceof Array) && !(value instanceof RegExp);
  83. }
  84. for (const key in override) {
  85. if (override.hasOwnProperty(key)) {
  86. const val = override[key];
  87. if (isHashObject(val)) {
  88. if (isHashObject(target[key])) {
  89. updateDeeply(target[key], val);
  90. } else {
  91. target[key] = updateDeeply({}, val);
  92. }
  93. } else {
  94. target[key] = val;
  95. }
  96. }
  97. }
  98. return target;
  99. }
  100. /**
  101. * Main interface function. Takes an Espree syntax tree and returns the
  102. * analyzed scopes.
  103. * @function analyze
  104. * @param {espree.Tree} tree - Abstract Syntax Tree
  105. * @param {Object} providedOptions - Options that tailor the scope analysis
  106. * @param {boolean} [providedOptions.optimistic=false] - the optimistic flag
  107. * @param {boolean} [providedOptions.directive=false]- the directive flag
  108. * @param {boolean} [providedOptions.ignoreEval=false]- whether to check 'eval()' calls
  109. * @param {boolean} [providedOptions.nodejsScope=false]- whether the whole
  110. * script is executed under node.js environment. When enabled, escope adds
  111. * a function scope immediately following the global scope.
  112. * @param {boolean} [providedOptions.impliedStrict=false]- implied strict mode
  113. * (if ecmaVersion >= 5).
  114. * @param {string} [providedOptions.sourceType='script']- the source type of the script. one of 'script' and 'module'
  115. * @param {number} [providedOptions.ecmaVersion=5]- which ECMAScript version is considered
  116. * @param {Object} [providedOptions.childVisitorKeys=null] - Additional known visitor keys. See [esrecurse](https://github.com/estools/esrecurse)'s the `childVisitorKeys` option.
  117. * @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.
  118. * @returns {ScopeManager} ScopeManager
  119. */
  120. function analyze(tree, providedOptions) {
  121. const options = updateDeeply(defaultOptions(), providedOptions);
  122. const scopeManager = new ScopeManager(options);
  123. const referencer = new Referencer(options, scopeManager);
  124. referencer.visit(tree);
  125. assert(scopeManager.__currentScope === null, "currentScope should be null.");
  126. return scopeManager;
  127. }
  128. module.exports = {
  129. /** @name module:escope.version */
  130. version,
  131. /** @name module:escope.Reference */
  132. Reference,
  133. /** @name module:escope.Variable */
  134. Variable,
  135. /** @name module:escope.Scope */
  136. Scope,
  137. /** @name module:escope.ScopeManager */
  138. ScopeManager,
  139. analyze
  140. };
  141. /* vim: set sw=4 ts=4 et tw=80 : */