/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at . */ // @flow import parseScriptTags from "parse-script-tags"; import * as babelParser from "@babel/parser"; import * as t from "@babel/types"; import isEmpty from "lodash/isEmpty"; import { getSource } from "../sources"; let ASTs = new Map(); function _parse(code, opts) { return babelParser.parse(code, { ...opts, tokens: true }); } const sourceOptions = { generated: { sourceType: "unambiguous", tokens: true, plugins: ["objectRestSpread"] }, original: { sourceType: "unambiguous", tokens: true, plugins: [ "jsx", "flow", "doExpressions", "decorators-legacy", "objectRestSpread", "classProperties", "exportDefaultFrom", "exportNamespaceFrom", "asyncGenerators", "functionBind", "functionSent", "dynamicImport", "react-jsx" ] } }; export function parse(text: ?string, opts?: Object): any { let ast; if (!text) { return; } try { ast = _parse(text, opts); } catch (error) { console.error(error); ast = {}; } return ast; } // Custom parser for parse-script-tags that adapts its input structure to // our parser's signature function htmlParser({ source, line }) { return parse(source, { startLine: line }); } const VUE_COMPONENT_START = /^\s* p !== "flow" && p !== "decorators" && p !== "decorators2" && (p !== "jsx" || contentType.match(/typescript-jsx/)) ), "decorators-legacy", "typescript" ] }; ast = parse(source.text, options); } ASTs.set(source.id, ast); return ast; } export function clearASTs() { ASTs = new Map(); } type Visitor = { enter: Function }; export function traverseAst(sourceId: string, visitor: Visitor, state?: T) { const ast = getAst(sourceId); if (isEmpty(ast)) { return null; } t.traverse(ast, visitor, state); return ast; } export function hasNode(rootNode: Node, predicate: Function) { try { t.traverse(rootNode, { enter: (node, ancestors) => { if (predicate(node, ancestors)) { throw new Error("MATCH"); } } }); } catch (e) { if (e.message === "MATCH") { return true; } } return false; } export function replaceNode(ancestors: Object[], node: Object) { const parent = ancestors[ancestors.length - 1]; if (typeof parent.index === "number") { if (Array.isArray(node)) { parent.node[parent.key].splice(parent.index, 1, ...node); } else { parent.node[parent.key][parent.index] = node; } } else { parent.node[parent.key] = node; } }