UNPKG

polymer-analyzer

Version:
135 lines 5.66 kB
"use strict"; /** * @license * Copyright (c) 2016 The Polymer Project Authors. All rights reserved. * This code may only be used under the BSD style license found at * http://polymer.github.io/LICENSE.txt * The complete set of authors may be found at * http://polymer.github.io/AUTHORS.txt * The complete set of contributors may be found at * http://polymer.github.io/CONTRIBUTORS.txt * Code distributed by Google as part of the polymer project is also * subject to an additional IP rights grant found at * http://polymer.github.io/PATENTS.txt */ Object.defineProperty(exports, "__esModule", { value: true }); const generator_1 = require("@babel/generator"); const indent = require("indent"); const document_1 = require("../parser/document"); const estraverse_shim_1 = require("./estraverse-shim"); /** * babel.Node#type is one of around a hundred string literals. We don't have * a direct reference to the type that represents any of those string literals * though. We can get a reference by taking a Node and using the `typeof` * operator, and it doesn't need to be a real Node as all of this happens at * analysis time, and nothing happens at runtime. */ // tslint:disable-next-line: no-any const __exampleNode = null; class JavaScriptDocument extends document_1.ParsedDocument { constructor(from) { super(from); this.type = 'js'; this.visitorSkips = new Map(); this.parsedAsSourceType = from.parsedAsSourceType; } visit(visitors) { /** * Applies all visiting callbacks from `visitors`. */ const applyScanners = (callbackName, node, parent, path) => { for (const visitor of visitors) { if (_shouldSkip(visitor, callbackName, node.type)) { continue; } if (callbackName in visitor) { // TODO(rictic): is there a maintainable way to enforce the // mapping between callback names and the types of the first // arg? const result = // tslint:disable-next-line: no-any visitor[callbackName](node, parent, path); if (result) { handleVisitorResult(result, callbackName, visitor, node.type); } } } }; // a visitor to break early, or to skip a subtree of the AST. We need to // track this ourselves because we're running all the visitors at once. const _shouldSkip = (visitor, callbackName, nodeType) => { const skipRecord = this.visitorSkips.get(visitor); if (!skipRecord) { return false; } if (callbackName === `enter${nodeType}`) { skipRecord.depth += 1; return true; } else if (callbackName === `leave${nodeType}`) { skipRecord.depth -= 1; if (skipRecord.depth === 0) { this.visitorSkips.delete(visitor); // Note that we don't `continue` here. This is deliberate so that // we call the leave handler for the node where we started // skipping. } else { return true; } } else { return true; } }; const handleVisitorResult = (visitorOption, callbackName, visitor, nodeType) => { switch (visitorOption) { case estraverse_shim_1.VisitorOption.Remove: throw new Error(`estraverse.VisitorOption.Remove not ` + `supported by JavascriptDocument`); case estraverse_shim_1.VisitorOption.Break: visitors = visitors.filter((v) => v !== visitor); break; case estraverse_shim_1.VisitorOption.Skip: if (callbackName.startsWith('leave')) { throw new Error(`estraverse.VisitorOption.Skip was returned from ` + `${callbackName} but it's not supported in a leave method`); } this.visitorSkips.set(visitor, { type: nodeType, depth: 1 }); break; } }; estraverse_shim_1.traverse(this.ast, { enter(node, parent, path) { applyScanners(`enter${node.type}`, node, parent, path); }, leave(node, parent, path) { applyScanners(`leave${node.type}`, node, parent, path); } }); } _sourceRangeForNode(node) { if (!node || !node.loc) { return; } return { file: this.url, // Note: estree uses 1-indexed lines, but SourceRange uses 0 indexed. start: { line: (node.loc.start.line - 1), column: node.loc.start.column }, end: { line: (node.loc.end.line - 1), column: node.loc.end.column } }; } stringify(options = {}) { const { prettyPrint = true } = options; const formatOptions = { comments: prettyPrint, retainLines: false, quotes: 'single', minified: !prettyPrint, }; const code = generator_1.default(this.ast, formatOptions).code + '\n'; return options.indent != null ? indent(code, options.indent * 2) : code; } } exports.JavaScriptDocument = JavaScriptDocument; //# sourceMappingURL=javascript-document.js.map