react / wstein / node_modules / react / node_modules / envify / node_modules / jstransform / src / jstransform.js
80540 views/**1* Copyright 2013 Facebook, Inc.2*3* Licensed under the Apache License, Version 2.0 (the "License");4* you may not use this file except in compliance with the License.5* You may obtain a copy of the License at6*7* http://www.apache.org/licenses/LICENSE-2.08*9* Unless required by applicable law or agreed to in writing, software10* distributed under the License is distributed on an "AS IS" BASIS,11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12* See the License for the specific language governing permissions and13* limitations under the License.14*/151617/*jslint node: true*/18"use strict";1920var esprima = require('esprima-fb');21var utils = require('./utils');2223var getBoundaryNode = utils.getBoundaryNode;24var declareIdentInScope = utils.declareIdentInLocalScope;25var initScopeMetadata = utils.initScopeMetadata;26var Syntax = esprima.Syntax;2728/**29* @param {object} node30* @param {object} parentNode31* @return {boolean}32*/33function _nodeIsClosureScopeBoundary(node, parentNode) {34if (node.type === Syntax.Program) {35return true;36}3738var parentIsFunction =39parentNode.type === Syntax.FunctionDeclaration40|| parentNode.type === Syntax.FunctionExpression41|| parentNode.type === Syntax.ArrowFunctionExpression;4243var parentIsCurlylessArrowFunc =44parentNode.type === Syntax.ArrowFunctionExpression45&& node === parentNode.body;4647return parentIsFunction48&& (node.type === Syntax.BlockStatement || parentIsCurlylessArrowFunc);49}5051function _nodeIsBlockScopeBoundary(node, parentNode) {52if (node.type === Syntax.Program) {53return false;54}5556return node.type === Syntax.BlockStatement57&& parentNode.type === Syntax.CatchClause;58}5960/**61* @param {object} node62* @param {array} path63* @param {object} state64*/65function traverse(node, path, state) {66/*jshint -W004*/67// Create a scope stack entry if this is the first node we've encountered in68// its local scope69var startIndex = null;70var parentNode = path[0];71if (!Array.isArray(node) && state.localScope.parentNode !== parentNode) {72if (_nodeIsClosureScopeBoundary(node, parentNode)) {73var scopeIsStrict = state.scopeIsStrict;74if (!scopeIsStrict75&& (node.type === Syntax.BlockStatement76|| node.type === Syntax.Program)) {77scopeIsStrict =78node.body.length > 079&& node.body[0].type === Syntax.ExpressionStatement80&& node.body[0].expression.type === Syntax.Literal81&& node.body[0].expression.value === 'use strict';82}8384if (node.type === Syntax.Program) {85startIndex = state.g.buffer.length;86state = utils.updateState(state, {87scopeIsStrict: scopeIsStrict88});89} else {90startIndex = state.g.buffer.length + 1;91state = utils.updateState(state, {92localScope: {93parentNode: parentNode,94parentScope: state.localScope,95identifiers: {},96tempVarIndex: 0,97tempVars: []98},99scopeIsStrict: scopeIsStrict100});101102// All functions have an implicit 'arguments' object in scope103declareIdentInScope('arguments', initScopeMetadata(node), state);104105// Include function arg identifiers in the scope boundaries of the106// function107if (parentNode.params.length > 0) {108var param;109var metadata = initScopeMetadata(parentNode, path.slice(1), path[0]);110for (var i = 0; i < parentNode.params.length; i++) {111param = parentNode.params[i];112if (param.type === Syntax.Identifier) {113declareIdentInScope(param.name, metadata, state);114}115}116}117118// Include rest arg identifiers in the scope boundaries of their119// functions120if (parentNode.rest) {121var metadata = initScopeMetadata(122parentNode,123path.slice(1),124path[0]125);126declareIdentInScope(parentNode.rest.name, metadata, state);127}128129// Named FunctionExpressions scope their name within the body block of130// themselves only131if (parentNode.type === Syntax.FunctionExpression && parentNode.id) {132var metaData =133initScopeMetadata(parentNode, path.parentNodeslice, parentNode);134declareIdentInScope(parentNode.id.name, metaData, state);135}136}137138// Traverse and find all local identifiers in this closure first to139// account for function/variable declaration hoisting140collectClosureIdentsAndTraverse(node, path, state);141}142143if (_nodeIsBlockScopeBoundary(node, parentNode)) {144startIndex = state.g.buffer.length;145state = utils.updateState(state, {146localScope: {147parentNode: parentNode,148parentScope: state.localScope,149identifiers: {},150tempVarIndex: 0,151tempVars: []152}153});154155if (parentNode.type === Syntax.CatchClause) {156var metadata = initScopeMetadata(157parentNode,158path.slice(1),159parentNode160);161declareIdentInScope(parentNode.param.name, metadata, state);162}163collectBlockIdentsAndTraverse(node, path, state);164}165}166167// Only catchup() before and after traversing a child node168function traverser(node, path, state) {169node.range && utils.catchup(node.range[0], state);170traverse(node, path, state);171node.range && utils.catchup(node.range[1], state);172}173174utils.analyzeAndTraverse(walker, traverser, node, path, state);175176// Inject temp variables into the scope.177if (startIndex !== null) {178utils.injectTempVarDeclarations(state, startIndex);179}180}181182function collectClosureIdentsAndTraverse(node, path, state) {183utils.analyzeAndTraverse(184visitLocalClosureIdentifiers,185collectClosureIdentsAndTraverse,186node,187path,188state189);190}191192function collectBlockIdentsAndTraverse(node, path, state) {193utils.analyzeAndTraverse(194visitLocalBlockIdentifiers,195collectBlockIdentsAndTraverse,196node,197path,198state199);200}201202function visitLocalClosureIdentifiers(node, path, state) {203var metaData;204switch (node.type) {205case Syntax.ArrowFunctionExpression:206case Syntax.FunctionExpression:207// Function expressions don't get their names (if there is one) added to208// the closure scope they're defined in209return false;210case Syntax.ClassDeclaration:211case Syntax.ClassExpression:212case Syntax.FunctionDeclaration:213if (node.id) {214metaData = initScopeMetadata(getBoundaryNode(path), path.slice(), node);215declareIdentInScope(node.id.name, metaData, state);216}217return false;218case Syntax.VariableDeclarator:219// Variables have function-local scope220if (path[0].kind === 'var') {221metaData = initScopeMetadata(getBoundaryNode(path), path.slice(), node);222declareIdentInScope(node.id.name, metaData, state);223}224break;225}226}227228function visitLocalBlockIdentifiers(node, path, state) {229// TODO: Support 'let' here...maybe...one day...or something...230if (node.type === Syntax.CatchClause) {231return false;232}233}234235function walker(node, path, state) {236var visitors = state.g.visitors;237for (var i = 0; i < visitors.length; i++) {238if (visitors[i].test(node, path, state)) {239return visitors[i](traverse, node, path, state);240}241}242}243244var _astCache = {};245246function getAstForSource(source, options) {247if (_astCache[source] && !options.disableAstCache) {248return _astCache[source];249}250var ast = esprima.parse(source, {251comment: true,252loc: true,253range: true,254sourceType: options.sourceType255});256if (!options.disableAstCache) {257_astCache[source] = ast;258}259return ast;260}261262/**263* Applies all available transformations to the source264* @param {array} visitors265* @param {string} source266* @param {?object} options267* @return {object}268*/269function transform(visitors, source, options) {270options = options || {};271var ast;272try {273ast = getAstForSource(source, options);274} catch (e) {275e.message = 'Parse Error: ' + e.message;276throw e;277}278var state = utils.createState(source, ast, options);279state.g.visitors = visitors;280281if (options.sourceMap) {282var SourceMapGenerator = require('source-map').SourceMapGenerator;283state.g.sourceMap = new SourceMapGenerator({file: options.filename || 'transformed.js'});284}285286traverse(ast, [], state);287utils.catchup(source.length, state);288289var ret = {code: state.g.buffer, extra: state.g.extra};290if (options.sourceMap) {291ret.sourceMap = state.g.sourceMap;292ret.sourceMapFilename = options.filename || 'source.js';293}294return ret;295}296297exports.transform = transform;298exports.Syntax = Syntax;299300301