UNPKG

vue-property-decorator-transpiler

Version:

Transpiles classes written in vue-property-decorator back to simple Vue component global registration.

226 lines 9.78 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; const typescript_1 = __importStar(require("typescript")); const vue_template_compiler_1 = require("vue-template-compiler"); function getFunction(m, s, name) { var _a, _b; if (!name) name = (_a = m.name) === null || _a === void 0 ? void 0 : _a.getText(s); let body = (_b = m.body) === null || _b === void 0 ? void 0 : _b.getText(s); let param = m.parameters.map(p => p.name.getText(s)).join(","); return `${name}(${param})${body}`; } function getDecoratorArguments(m, decorator, s) { if (typeof m.decorators === "undefined") return undefined; for (let d of m.decorators) { if (typescript_1.default.isCallExpression(d.expression) && typescript_1.default.isIdentifier(d.expression.expression) && d.expression.expression.escapedText == decorator) { return d.expression.arguments.map(a => a.getText(s)); } } return undefined; } function getComponentOption(dec) { if (dec.decorators) for (let d of dec.decorators) { if (typescript_1.default.isIdentifier(d.expression) && d.expression.escapedText == "Component") return {}; if (typescript_1.default.isCallExpression(d.expression) && typescript_1.default.isIdentifier(d.expression.expression) && d.expression.expression.escapedText == "Component" && d.expression.arguments.length) { let op = d.expression.arguments[0]; if (typescript_1.default.isObjectLiteralExpression(op)) { let result = {}; for (let p of op.properties) { if (typescript_1.default.isPropertyAssignment(p) && typescript_1.default.isIdentifier(p.name)) { if (typescript_1.default.isStringLiteral(p.initializer)) { if (p.name.escapedText == "name") result.name = p.initializer.text; if (p.name.escapedText == "template") result.template = p.initializer.text; } else if (p.name.escapedText == "mixins") { result.mixins = p.initializer; } } } return result; } } } return undefined; } /** Built-in hooks of Vue.js */ var LIFECYCLE_HOOKS = [ 'beforeCreate', 'created', 'beforeMount', 'mounted', 'beforeUpdate', 'updated', 'beforeDestroy', 'destroyed', 'activated', 'deactivated', 'errorCaptured', 'serverPrefetch' ]; function findClassDeclaration(statements) { var _a, _b, _c, _d; for (var s of statements) { if (typescript_1.default.isClassDeclaration(s) && ((_a = s.modifiers) === null || _a === void 0 ? void 0 : _a.some(m => m.kind == typescript_1.default.SyntaxKind.ExportKeyword)) && ((_b = s.modifiers) === null || _b === void 0 ? void 0 : _b.some(m => m.kind == typescript_1.default.SyntaxKind.DefaultKeyword))) { let comOption = getComponentOption(s); if (comOption !== undefined) { let exp = (_d = (_c = s.heritageClauses) === null || _c === void 0 ? void 0 : _c[0].types) === null || _d === void 0 ? void 0 : _d[0].expression; if (exp && typescript_1.default.isIdentifier(exp)) { let parent = exp.escapedText; if (parent != "Vue") comOption.extends = parent; } return { statement: s, option: comOption }; } } } throw new Error("Cannot find class declaration"); } function classToComponentOptionString(statement, sourceFile, option) { let props = []; let data = []; let watch = []; let computed = []; let methods = []; let events = []; let provides = []; let injects = []; for (let member of statement.members) { if (!member.name) continue; let name = member.name.getText(sourceFile); if (typescript_1.default.isPropertyDeclaration(member)) { let ini = member.initializer; let init = ini ? ini.getText(sourceFile) : "undefined"; let prop = getDecoratorArguments(member, "Prop", sourceFile); let inject = getDecoratorArguments(member, "Inject", sourceFile); if (prop) { if (ini) props.push(`${name}:{type:${prop[0]},default:${init}}`); else props.push(`${name}:${prop[0]}`); } else if (inject !== undefined) { if (!inject.length) inject[0] = `'${name}'`; injects.push(`${name}: ${inject[0]}`); } else { data.push(`${name}:${init}`); let provide = getDecoratorArguments(member, "Provide", sourceFile); if (provide) provides.push(`${provide}: this.${name}`); } } if (typescript_1.default.isGetAccessor(member)) { computed.push(getFunction(member, sourceFile)); } if (typescript_1.default.isMethodDeclaration(member)) { let func = getFunction(member, sourceFile), abstract = false; if (member.modifiers) for (let mod of member.modifiers) { if (mod.kind == typescript_1.SyntaxKind.AbstractKeyword) abstract = true; if (mod.kind == typescript_1.SyntaxKind.AsyncKeyword) func = "async " + func; } if (abstract) continue; let tag = getDecoratorArguments(member, "Watch", sourceFile); if (tag) watch.push(getFunction(member, sourceFile, tag[0])); else { if (LIFECYCLE_HOOKS.includes(name)) events.push(func); else methods.push(func); } } } let options = []; if (option.extends) options.push(`mixins: [${option.extends}]`); else if (option.mixins) options.push(`mixins: ${option.mixins.getText(sourceFile)}`); if (data.length) options.push(`data() { return { ${data.join(",")} }; }`); if (props.length) options.push(`props: { ${props.join(",")} }`); if (provides.length) options.push(`provide() { return { ${provides.join(",")} }; }`); if (injects.length) options.push(`inject: { ${injects.join(",")} }`); if (watch.length) options.push(`watch: { ${watch.join(",")} }`); if (computed.length) options.push(`computed: { ${computed.join(",")} }`); if (methods.length) options.push(`methods: { ${methods.join(",")} }`); options.push(...events); return options; } /** * Transpile the default exported class to Vue component global registration. * @param code Original Typescript code. */ function VPDtoJs(code, template, constMode = false) { var _a; var sourceFile = typescript_1.default.createSourceFile("vue.ts", code, typescript_1.default.ScriptTarget.ESNext, false); var { statement, option } = findClassDeclaration(sourceFile.statements); let comName = "name" in option ? option.name : (_a = statement.name) === null || _a === void 0 ? void 0 : _a.escapedText.toString(); if (!comName) throw new Error("Component needs to have a name"); let options = classToComponentOptionString(statement, sourceFile, option); if (template) { let com = vue_template_compiler_1.compile(template); if (com.staticRenderFns.length > 0) { let fns = com.staticRenderFns.map(f => `function(){${f}}`).join(","); options.unshift(`staticRenderFns: [ ${fns} ]`); } options.unshift(`render() { ${com.render} }`); } else if (option.template) { options.unshift(`template: '${option.template}'`); } // Put into Vue component syntax let output = constMode ? `const ${comName} = { ${options.join(",")} };` : `Vue.component('${comName.toLowerCase()}', { ${options.join(",")} });`; // Transpile into JavaScript output = typescript_1.default.transpile(output, { target: typescript_1.default.ScriptTarget.ESNext }); return output; } module.exports = VPDtoJs; //# sourceMappingURL=index.js.map