UNPKG

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