Exemplo n.º 1
0
  mark(node) {
    let loc = node.loc;
    if (!loc) return; // no location info

    let map = this.map;
    if (!map) return; // no source map

    if (t.isProgram(node) || t.isFile(node)) return; // illegal mapping nodes

    let position = this.position;

    let generated = {
      line: position.line,
      column: position.column
    };

    let original = loc.start;

    // Avoid emitting duplicates on either side. Duplicated
    // original values creates unnecesssarily large source maps
    // and increases compile time. Duplicates on the generated
    // side can lead to incorrect mappings.
    if (comparePosition(original, this.last.original)
        || comparePosition(generated, this.last.generated)) {
      return;
    }

    this.last = {
      source: loc.filename || this.opts.sourceFileName,
      generated: generated,
      original: original
    };

    map.addMapping(this.last);
  }
Exemplo n.º 2
0
  run() {
    let block = this.block;
    if (block._letDone) return;
    block._letDone = true;

    let needsClosure = this.getLetReferences();

    // this is a block within a `Function/Program` so we can safely leave it be
    if (t.isFunction(this.parent) || t.isProgram(this.block)) {
      this.updateScopeInfo();
      return;
    }

    // we can skip everything
    if (!this.hasLetReferences) return;

    if (needsClosure) {
      this.wrapClosure();
    } else {
      this.remap();
    }

    this.updateScopeInfo();

    if (this.loopLabel && !t.isLabeledStatement(this.loopParent)) {
      return t.labeledStatement(this.loopLabel, this.loop);
    }
  }
Exemplo n.º 3
0
  print(node, parent, opts = {}) {
    if (!node) return;

    this._lastPrintedIsEmptyStatement = false;

    if (parent && parent._compact) {
      node._compact = true;
    }

    let oldInAux = this.insideAux;
    this.insideAux = !node.loc;

    let oldConcise = this.format.concise;
    if (node._compact) {
      this.format.concise = true;
    }

    let printMethod = this[node.type];
    if (!printMethod) {
      throw new ReferenceError(`unknown node of type ${JSON.stringify(node.type)} with constructor ${JSON.stringify(node && node.constructor.name)}`);
    }

    this._printStack.push(node);

    if (node.loc) this.printAuxAfterComment();
    this.printAuxBeforeComment(oldInAux);

    let needsParens = n.needsParens(node, parent, this._printStack);
    if (needsParens) this.push("(");

    this.printLeadingComments(node, parent);

    this.catchUp(node);

    this._printNewline(true, node, parent, opts);

    if (opts.before) opts.before();

    let loc = (t.isProgram(node) || t.isFile(node)) ? null : node.loc;
    this.withSource("start", loc, () => {
      this._print(node, parent);
    });

    // Check again if any of our children may have left an aux comment on the stack
    if (node.loc) this.printAuxAfterComment();

    this.printTrailingComments(node, parent);

    if (needsParens) this.push(")");

    // end
    this._printStack.pop();
    if (opts.after) opts.after();

    this.format.concise = oldConcise;
    this.insideAux = oldInAux;

    this._printNewline(false, node, parent, opts);
  }
Exemplo n.º 4
0
export function replaceWith(replacement) {
  this.resync();

  if (this.removed) {
    throw new Error("You can't replace this node, we've already removed it");
  }

  if (replacement instanceof NodePath) {
    replacement = replacement.node;
  }

  if (!replacement) {
    throw new Error("You passed `path.replaceWith()` a falsy node, use `path.remove()` instead");
  }

  if (this.node === replacement) {
    return;
  }

  if (this.isProgram() && !t.isProgram(replacement)) {
    throw new Error("You can only replace a Program root node with another Program node");
  }

  if (Array.isArray(replacement)) {
    throw new Error("Don't use `path.replaceWith()` with an array of nodes, use `path.replaceWithMultiple()`");
  }

  if (typeof replacement === "string") {
    throw new Error("Don't use `path.replaceWith()` with a source string, use `path.replaceWithSourceString()`");
  }

  // replacing a statement with an expression so wrap it in an expression statement
  if (this.isNodeType("Statement") && t.isExpression(replacement) && !this.canHaveVariableDeclarationOrExpression()) {
    replacement = t.expressionStatement(replacement);
  }

  // replacing an expression with a statement so let's explode it
  if (this.isNodeType("Expression") && t.isStatement(replacement)) {
    return this.replaceExpressionWithStatements([replacement]);
  }

  let oldNode = this.node;
  if (oldNode) {
    t.inheritsComments(replacement, oldNode);
    t.removeComments(oldNode);
  }

  // replace the node
  this._replaceWith(replacement);
  this.type = replacement.type;

  // potentially create new scope
  this.setScope();

  // requeue for visiting
  this.requeue();
}
Exemplo n.º 5
0
function getCommentPool(path) {
  var commentPool;

  // Comments at the Program scope:
  if (t.isProgram(path.node) && path.node.innerComments && path.node.innerComments.length) {
    commentPool = path.node.innerComments;
  }
  else if (t.isProgram(path.node) && path.node.body.leadingComments && path.node.body.leadingComments.length) {
    commentPool = path.node.body.leadingComments;
  }
  else if (path.node.leadingComments && path.node.leadingComments.length) {
    commentPool = path.node.leadingComments;
  }

  if (commentPool) {
    // Handle an edge-case with babel against ES6 destructured identifiers;
    // it seems to attach the leading comments to both the VariableDeclaration
    // node as well as the first identifier inside of it, so for the following
    // snippet:
    //
    //     /**
    //      * @module
    //      */
    //      var { Assertion } = require('chai');
    //
    // leadingComments will be set both on VariableDeclaration as well as
    // Identifier(Assertion).
    //
    // We'll handle the VariableDeclaration and forget about the
    // destructured variable identifier altogether.
    if (ASTUtils.isCommentedDestructuredProperty(path)) {
      debugLog('Ignoring comment pool on destructured property at %s', dumpLocation(path.node, 'line'))
      return;
    }

    const withoutDuplicates = discardDuplicateComments(commentPool)

    if (withoutDuplicates.length !== commentPool.length) {
      debugLog('Discarded %d comments identified as duplicate', commentPool.length - withoutDuplicates.length)
    }

    return withoutDuplicates;
  }
}
Exemplo n.º 6
0
/**
 * transform function which operates on each discovered example block
 * @callback transformCallback
 * @param {Object} options
 * @param {ast} options.comment
 * @param {string} options.name
 * @param {string} options.filename
 * @param {string} options.type
 */

 /**
 * Extracts comment blocks from the source code in the specified file
 * @param {transformCallback} transform
 * @param {string} filename
 * @returns {Array<ast>}
 */
export default function extract(transform, filename) {
  // eslint-disable-next-line no-sync
  const code = fs.readFileSync(filename, {encoding: `utf8`});

  const ast = parse(code, {sourceFilename: filename});

  const results = [];

  let done = false;
  traverse(ast, {
    enter(path) {
      if (path.node.leadingComments) {
        path.node.leadingComments
          .filter(isJSDocComment)
          .forEach((comment) => {
            const result = doctrine.parse(comment.value, {
              unwrap: true,
              sloppy: true,
              recoverable: true,
              lineNumbers: true
            });

            if (result.tags) {
              result.tags.forEach((tag) => {
                if (tag.title === `example`) {
                  results.push(transform({
                    comment: tag.description,
                    name: getNodeName(path.node),
                    filename: path.node.loc.filename,
                    type: path.node.type
                  }));
                }
              });
            }
          });
      }
    },
    Program: {
      exit(path) {
        if (isProgram(path)) {
          if (done) {
            return;
          }
          path.pushContainer(`body`, results);
          done = true;
        }
      }
    }
  });

  return ast;
}
Exemplo n.º 7
0
/**
 * Should we pull this component path?
 * Currently: is it considered "top level"? Ie. not in closures/constructors etc.
 */
function shouldPullComponent(path) {
  let tPath = path.parentPath;
  while (tPath) {
    if (T.isProgram(tPath)) {
      return true;
    }

    if (
      !T.isExportDefaultDeclaration(tPath) &&
      !T.isExportNamedDeclaration(tPath) &&
      !T.isVariableDeclaration(tPath)
    ) {
      break;
    }

    tPath = tPath.parentPath;
  }

  return false;
}
Exemplo n.º 8
0
/** Pull TOP LEVEL symbols out of our ast */
function pullSymbols(ast) {
  const symbols = [];

  // TODO: Need to think hard about how we store each symbol "type" to allow easy resolution later

  function pushVariableDeclarator(node) {
    symbols.push({
      name: node.id.name,
      type: resolveType(node.init),
    });
  }

  function pushVariableDeclaration(node) {
    node.declarations.forEach(declNode => pushVariableDeclarator(declNode));
  }

  function pushFunctionDeclaration(node) {
    symbols.push({
      name: node.id.name,
      type: resolveType(node),
    });
  }

  function pushClassDeclaration(node) {
    symbols.push({
      name: node.id.name,
      type: resolveType(node),
    });
  }

  function pushExportSpecifier(node, {source, sourceName} = {}) {
    symbols.push({
      name: `export::${node.exported.name}`,
      type: resolveType(node, {source, sourceName}),
    });
  }

  function pushExportDeclaration(node) {
    // We'll collect two symbols for export declarations. One is
    // the declared value/type and the other will simply be a pointer
    // with name `export::symbolName`
    if (T.isFunctionDeclaration(node)) {
      pushFunctionDeclaration(node);
      symbols.push({
        name: `export::${node.id.name}`,
        type: resolveType(node.id),
      });
    } else if (T.isVariableDeclaration(node)) {
      pushVariableDeclaration(node);
      node.declarations.forEach(declNode =>
        symbols.push({
          name: `export::${declNode.id.name}`,
          type: resolveType(declNode.id),
        }));
    } else if (T.isClassDeclaration(node)) {
      pushClassDeclaration(node);
      symbols.push({
        name: `export::${node.id.name}`,
        type: resolveType(node.id),
      });
    }
  }

  function pushExportNamedDeclaration(node) {
    if (node.declaration) {
      pushExportDeclaration(node.declaration);
    } else {
      const source = node.source ? node.source.value : undefined;
      node.specifiers.forEach(spec =>
        pushExportSpecifier(spec, {source, sourceName: spec.local.name}));
    }
  }

  function pushExportDefaultDeclaration(node) {
    const decl = node.declaration;

    if (T.isFunctionDeclaration(decl)) {
      pushFunctionDeclaration(decl);
      symbols.push({
        name: `export::default`,
        type: resolveType(decl.id),
      });
    } else if (T.isVariableDeclaration(decl)) {
      pushVariableDeclaration(decl);
      decl.declarations.forEach(vDecl =>
        symbols.push({
          name: `export::default`,
          type: resolveType(vDecl.id),
        }));
    } else if (T.isClassDeclaration(decl)) {
      pushClassDeclaration(decl);
      symbols.push({
        name: `export::default`,
        type: resolveType(decl.id),
      });
    } else {
      symbols.push({
        name: `export::default`,
        type: resolveType(decl),
      });
    }
  }

  function pushImportDeclaration(node) {
    const source = node.source.value;
    node.specifiers.forEach(spec =>
      symbols.push({
        name: T.isIdentifier(spec.exported)
          ? spec.exported.value
          : spec.local.name,
        type: resolveType(spec, {source, sourceName: spec.local.name}),
      }));
  }

  const visitor = {
    FunctionDeclaration(path) {
      if (T.isProgram(path.parent)) {
        pushFunctionDeclaration(path.node);
      }
      path.skip();
    },
    VariableDeclaration(path) {
      if (T.isProgram(path.parent)) {
        pushVariableDeclaration(path.node);
      }
      path.skip();
    },
    ClassDeclaration(path) {
      if (T.isProgram(path.parent)) {
        pushClassDeclaration(path.node);
      }
      path.skip();
    },
    ExportNamedDeclaration(path) {
      pushExportNamedDeclaration(path.node);
      path.skip();
    },
    ExportDefaultDeclaration(path) {
      pushExportDefaultDeclaration(path.node);
      path.skip();
    },
    ImportDeclaration(path) {
      pushImportDeclaration(path.node);
      path.skip();
    },
  };

  traverse(ast, visitor);
  return [...symbols];
}
Exemplo n.º 9
0
parsedFiles.forEach(function(file) {
  var namedExports = {};
  var localVariableMap = {};

  traverse(file.ast, {
    enter(path) {
      // replace require calls with the corresponding value
      var r;
      if ((r = getRequireValue(path.node, file))) {
        path.replaceWith(r);
        return;
      }

      // if we see `var foo = require('bar')` we can just inline the variable
      // representing `require('bar')` wherever `foo` was used.
      if (
        t.isVariableDeclaration(path.node) &&
        path.node.declarations.length === 1 &&
        t.isIdentifier(path.node.declarations[0].id) &&
        (r = getRequireValue(path.node.declarations[0].init, file))
      ) {
        var newName = 'compiled_local_variable_reference_' + getUniqueIndex();
        path.scope.rename(path.node.declarations[0].id.name, newName);
        localVariableMap[newName] = r;
        path.remove();
        return;
      }

      // rename all top level functions to keep them local to the module
      if (t.isFunctionDeclaration(path.node) && t.isProgram(path.parent)) {
        path.scope.rename(path.node.id.name, file.property + '_local_fn_' + path.node.id.name);
        return;
      }

      // rename all top level variables to keep them local to the module
      if (t.isVariableDeclaration(path.node) && t.isProgram(path.parent)) {
        path.node.declarations.forEach(function(declaration) {
          path.scope.rename(
            declaration.id.name,
            file.property + '_local_var_' + declaration.id.name
          );
        });
        return;
      }

      // replace module.exports.bar with a variable for the named export
      if (
        t.isMemberExpression(path.node, { computed: false }) &&
        isModuleDotExports(path.node.object)
      ) {
        var name = path.node.property.name;
        var identifier = t.identifier(file.property + '_export_' + name);
        path.replaceWith(identifier);
        namedExports[name] = identifier;
      }
    },
  });
  traverse(file.ast, {
    enter(path) {
      if (
        t.isIdentifier(path.node) &&
        Object.prototype.hasOwnProperty.call(localVariableMap, path.node.name)
      ) {
        path.replaceWith(localVariableMap[path.node.name]);
      }
    },
  });
  var defaultExports = t.objectExpression(
    Object.keys(namedExports).map(function(name) {
      return t.objectProperty(t.identifier(name), namedExports[name]);
    })
  );
  moduleExportsByPath[file.filename] = {
    namedExports: namedExports,
    defaultExports: defaultExports,
  };
  statements.push(
    t.variableDeclaration(
      'var',
      Object.keys(namedExports).map(function(name) {
        return t.variableDeclarator(namedExports[name]);
      })
    )
  );
  statements.push.apply(statements, file.ast.program.body);
});