UNPKG

@tririga/tri-polymer-upgrade

Version:

A tool for converting TRIRIGA UX views from Polymer 1 to Polymer 3

266 lines (237 loc) 7.35 kB
const astTypes = require("ast-types"); const parse5 = require("parse5"); const dom5 = require("dom5"); const os = require("os"); const jsc = require("jscodeshift"); const fse = require("fs-extra"); const path = require("path"); const polymerUrlMap = require("../config/polymer-url-map.json"); // Copyright (c) 2014 The Polymer Authors. All rights reserved. /** * Yields the NodePath for each statement at the top level of `program`. * * Like `yield* program.body` except it yields NodePaths rather than * Nodes, so that the caller can mutate the AST with the NodePath api. */ function* getTopLevelStatements(program) { const nodePaths = []; astTypes.visit(program, { visitNode(path) { if (!path.parent) { // toplevel program this.traverse(path); return; } if (path.parent.node.type !== 'Program') { // not a toplevel statement, skip it return false; } this.traverse(path); // ok, path.node must be a toplevel statement of the program. nodePaths.push(path); return; } }); yield* nodePaths; } module.exports.getTopLevelStatements = getTopLevelStatements; function escapeTemplateElement(cooked) { const raw = cooked.replace(/(<\/script|\\|`|\$)/g, (_match, group) => { switch (group) { case `<\/script`: return '&lt;/script'; case '\\': return '\\\\'; case '`': return '\\`'; case '$': return '\\$'; default: throw new Error(`oops!: ${group}`); } }); return raw; } module.exports.escapeTemplateElement = escapeTemplateElement; /** * Serialize a the element template to string and prepend the css styles to it. * Wrapped the resulting string as a template literal. */ function serializeTemplate(scannedElement) { const lines = parse5.serialize(scannedElement.template).split('\n'); // Remove empty / whitespace-only leading lines. while (/^\s*$/.test(lines[0])) { lines.shift(); } // Remove empty / whitespace-only trailing lines. while (/^\s*$/.test(lines[lines.length - 1])) { lines.pop(); } let cooked = lines.join(os.EOL); cooked = `${os.EOL}${cooked}${os.EOL}\t`; let css = scannedElement.css ? scannedElement.css.content : ""; let hasCss = css && css.length > 0; let hasInclude = scannedElement.cssInclude && scannedElement.cssInclude.length > 0; if (hasCss || hasInclude) { css = css.replace(/\n\t/g, "\n\t\t"); cooked = `${os.EOL}\t\t<style${hasInclude ? ` include="${scannedElement.cssInclude}"` : ""}>${os.EOL}${css}${os.EOL}\t\t</style>${os.EOL}${cooked}`; } const raw = escapeTemplateElement(cooked); return jsc.templateLiteral([jsc.templateElement({ cooked, raw }, true)], []); } module.exports.serializeTemplate = serializeTemplate; function getPolymerElementDefinition(program) { let polymerFunctionCallArgument = null; astTypes.visit(program, { visitCallExpression(path) { // a call expression and the function name is Polymer if (path.node.callee.type == "Identifier" && path.node.callee.name == "Polymer") { polymerFunctionCallArgument = path.node.arguments[0]; this.abort(); } this.traverse(path); } }); return polymerFunctionCallArgument; } module.exports.getPolymerElementDefinition = getPolymerElementDefinition; function getPolymerElementCall(program) { let polymerFunctionCall = null; astTypes.visit(program, { visitCallExpression(path) { // a call expression and the function name is Polymer if (path.node.callee.type == "Identifier" && path.node.callee.name == "Polymer") { polymerFunctionCall = path.parent.node; this.abort(); } this.traverse(path); } }); return polymerFunctionCall; } module.exports.getPolymerElementCall = getPolymerElementCall; function getCommentsFromTexts(commentTexts) { const recastComments = commentTexts.map((comment) => { const escapedComment = comment.replace(/\*\//g, '*\\/'); return { type: "Block", leading: true, trailing: false, value: escapedComment, }; }); return recastComments; } module.exports.getCommentsFromTexts = getCommentsFromTexts; function convertUrlImport(url) { if (url.endsWith("polymer/polymer.html")) { return url.replace("polymer/polymer.html", "@polymer/polymer/polymer-legacy.js") } const newUrl = url.replace(".html", ".js"); if (!newUrl.startsWith("../")) { return "./" + newUrl } const urlPieces = newUrl.split("/"); let packageName = null; let i = 0; do { ++i; packageName = urlPieces[i]; } while (packageName == ".."); if (packageName && polymerUrlMap[packageName]) { urlPieces[i] = polymerUrlMap[packageName].url; return urlPieces.join("/"); } return newUrl; } module.exports.convertUrlImport = convertUrlImport; function* getElementsUsingPolymerNamespace(arrayExpression) { let elementsPath = []; astTypes.visit(arrayExpression, { visitMemberExpression(path) { if (path.node.object.name == "Polymer") { elementsPath.push(path); } return false; } }); yield* elementsPath; } module.exports.getElementsUsingPolymerNamespace = getElementsUsingPolymerNamespace; function getRelativePath(filePath, baseDir) { const fileStrToReplace = process.platform === "win32" ? "file:\\" : "file:"; const processedFilePath = decodeURIComponent(path.normalize(filePath)).replace(fileStrToReplace, ""); return path.relative(baseDir, processedFilePath); } module.exports.getRelativePath = getRelativePath; function moveFile(srcPath, baseDir, outputDir) { const relativePath = getRelativePath(srcPath, baseDir); const destPath = path.join(outputDir, relativePath); return fse.copy(srcPath.replace("file://", ""), destPath); } module.exports.moveFile = moveFile; function dashToCamelCase(dash) { if (dash.indexOf('-') < 0) { return dash; } return dash.replace(/-[a-z]/g, m => m[1].toUpperCase()); } module.exports.dashToCamelCase = dashToCamelCase; function serializeHTMLNode(node) { const container = parse5.treeAdapters.default.createDocumentFragment(); dom5.append(container, node); return parse5.serialize(container); } module.exports.serializeHTMLNode = serializeHTMLNode; function getNodePropertyByName(node, propertyName) { let result = null; astTypes.visit(node, { visitProperty(path) { if (path.parent.node == node && path.node.type == "Property" && path.node.key.type == "Identifier" && path.node.key.name == propertyName) { result = path.node; this.abort(); } return false; } }); return result; } module.exports.getNodePropertyByName = getNodePropertyByName; function addImport(scannedDoc, importUrl, exportName) { for (let i = 0; i < scannedDoc.imports.length; i++) { const item = scannedDoc.imports[i]; if (item.url == importUrl) { if (item.exports.indexOf(exportName) < 0) { item.exports.push(exportName); }; return; } } scannedDoc.imports.push({ url: importUrl, exports: [exportName] }) } module.exports.addImport = addImport; function addHtmlImport(imports, url) { let exist = imports.some((importUrl) => { return importUrl == url; }); if (!exist) { imports.push(url); } return imports; } module.exports.addHtmlImport = addHtmlImport; function getModuleUrlCallExp(packageName, relativePath) { return jsc.callExpression( jsc.identifier("getModuleUrl"), [jsc.literal(`${packageName}/${relativePath.replace(".html",".js")}`)] ); } module.exports.getModuleUrlCallExp = getModuleUrlCallExp;