simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

index.js (6367B)


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