123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- /**
- * Copyright 2013-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- */
- var Syntax = require('esprima-fb').Syntax;
- var utils = require('../src/utils');
- /**
- * Replaces `undefined` with `(void 0)` when it appears as an rvalue and is
- * undeclared in the lexical scope.
- *
- * Example:
- *
- * (function() {
- * foo.undefined = bar;
- * ({undefined: foo});
- *
- * var bar = undefined;
- * bar = undefined;
- * foo.bar = undefined;
- * undefined.foo = bar;
- * foo[undefined] = bar;
- * ({foo: undefined});
- * })(undefined);
- *
- * (function(undefined) { // declared here
- * return undefined;
- * })(1);
- *
- * (function() {
- * var undefined; // declared here
- * undefined = 1; // assignment to declared variable
- * return undefined;
- * })();
- *
- * (function(undefined) { // declared here
- * return (function() {
- * return undefined; // respects lexical scope
- * })();
- * })();
- *
- * Becomes:
- *
- * (function() {
- * foo.undefined = bar;
- * ({undefined: foo});
- *
- * var bar = (void 0);
- * bar = (void 0);
- * foo.bar = (void 0);
- * (void 0).foo = bar;
- * foo[(void 0)] = bar;
- * ({foo: (void 0)});
- * })((void 0));
- *
- * (function(undefined) { // declared here
- * return undefined;
- * })(1);
- *
- * (function() {
- * var undefined; // declared here
- * undefined = 1; // assignment to declared variable
- * return undefined;
- * })();
- *
- * (function(undefined) { // declared here
- * return (function() {
- * return undefined; // respects lexical scope
- * })();
- * })();
- *
- *
- *
- * NOTE: Any assignment to `undefined` where `undefined` is not declared in the
- * lexical scope will result in an exception.
- */
- function visitIdentifierUndefined(traverse, node, path, state) {
- utils.catchup(node.range[1], state, function(value) {
- return '(void 0)';
- });
- }
- visitIdentifierUndefined.test = function(node, path, state) {
- if (
- node.type === Syntax.Identifier
- && node.name === 'undefined'
- && !utils.identWithinLexicalScope('undefined', state)
- ) {
- if (path[0]) {
- switch (path[0].type) {
- case Syntax.FunctionDeclaration:
- case Syntax.FunctionExpression:
- case Syntax.ArrowFunctionExpression:
- // skips: function params
- if (node !== path[0].body) {
- return false;
- }
- break;
- case Syntax.AssignmentExpression:
- // throws for: `undefined = foo` (where `undefined` is not declared)
- if (node === path[0].left) {
- throw new Error(
- 'Illegal assignment to `undefined`. '
- + 'This breaks assumptions of the transform.'
- );
- }
- break;
- case Syntax.MemberExpression:
- // skips: `foo.undefined` but not `foo[undefined]`
- if (node === path[0].property && !path[0].computed) {
- return false;
- }
- break;
- case Syntax.VariableDeclarator:
- // skips: `var undefined`
- if (node !== path[0].init) {
- return false;
- }
- break;
- case Syntax.Property:
- // skips: `undefined: foo`
- if (node === path[0].key) {
- return false;
- }
- break;
- }
- }
- return true;
- }
- return false;
- };
- exports.visitorList = [
- visitIdentifierUndefined
- ];
|