@linden.dev/vue-unclassify
Version:
Create Vue 3 script setup SFC from Vue2/3 class based TypeScript SFCs
526 lines (525 loc) • 25.8 kB
JavaScript
;
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
exports.__esModule = true;
exports.transpile = exports.transpileTemplate = void 0;
var astTools_1 = require("./astTools");
var removeExports = ['vue-property-decorator', 'vue-class-component', 'vue-facing-decorator', ' Vue ', ' Vue, '];
function transpileTemplate(codeText, context) {
var emits = __spreadArray([], __read(codeText.matchAll(/\$emit\s?\(['"]([a-zA-Z0-9]+)['"]/g)), false).map(function (x) { return x[1]; });
if (context)
context.emits = __spreadArray([], __read(new Set(emits)), false);
return codeText.replace(/\$emit\s?\(/g, 'emit(');
}
exports.transpileTemplate = transpileTemplate;
function transpile(codeText, templateContext) {
var e_1, _a, e_2, _b, e_3, _c, e_4, _d, e_5, _e, e_6, _f, e_7, _g, e_8, _h, e_9, _j, e_10, _k;
var _l, _m, _o;
// Fixup: interface before @Component -> syntax error
codeText = codeText.replace(/@Component[\(\s$]/, ';$&');
var code = (0, astTools_1.parseTS)(codeText);
var xformed = '';
var issues = [];
function emitSectionHeader(text) {
emitLine("// ".concat(text));
}
function emitLine(text) {
var _a;
if ((_a = text === null || text === void 0 ? void 0 : text.trim()) === null || _a === void 0 ? void 0 : _a.length) {
xformed += text;
emitNewLine();
}
}
function emitNewLine() {
xformed += code.newLine;
}
function emitComments(node) {
var comments = code.getCommentsFor(node);
if (comments === null || comments === void 0 ? void 0 : comments.length) {
emitNewLine();
xformed += comments;
}
}
// Imports
emitLine('import { ref, computed, watch, onMounted } from \'vue\'');
code.ast.body.filter(function (x) { return x.type === 'ImportDeclaration'; })
.map(code.getSource)
.filter(function (x) { return !removeExports.some(function (r) { return x.includes(r); }); })
.map(emitLine);
emitNewLine();
// Try vue-facing-decorator style class def first (class X extends Vue ... export default X)
var classNode = code.ast.body.find(function (x) { var _a; return x.type === 'ClassDeclaration' && ((_a = x.superClass) === null || _a === void 0 ? void 0 : _a.type) === 'Identifier' && x.superClass.name === 'Vue'; });
if (classNode == null) {
// Try old style (export default class X)
var expDefNode = code.ast.body.find(function (x) { return x.type === 'ExportDefaultDeclaration'; });
if (((_l = expDefNode === null || expDefNode === void 0 ? void 0 : expDefNode.declaration) === null || _l === void 0 ? void 0 : _l.type) === 'ClassDeclaration')
classNode = expDefNode === null || expDefNode === void 0 ? void 0 : expDefNode.declaration;
}
var className = classNode && code.getSource(classNode.id);
// Code outside class
var ignoredOutsideTypes = ['EmptyStatement', 'ExportDefaultDeclaration', 'ExportNamedDeclaration', 'ImportDeclaration',];
var outsideCode = code.ast.body.filter(function (x) { return x !== classNode && !ignoredOutsideTypes.includes(x.type); });
if (outsideCode === null || outsideCode === void 0 ? void 0 : outsideCode.length) {
try {
for (var outsideCode_1 = __values(outsideCode), outsideCode_1_1 = outsideCode_1.next(); !outsideCode_1_1.done; outsideCode_1_1 = outsideCode_1.next()) {
var c = outsideCode_1_1.value;
emitComments(c);
emitLine(code.unIndent(code.getSource(c)));
emitNewLine();
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (outsideCode_1_1 && !outsideCode_1_1.done && (_a = outsideCode_1["return"])) _a.call(outsideCode_1);
}
finally { if (e_1) throw e_1.error; }
}
}
if (!classNode) {
emitSectionHeader('Transpilation failed; could not identify component class node');
return xformed;
}
emitComments(classNode);
var memberNodes = classNode.body.body;
var properties = memberNodes.filter(function (x) { return x.type === 'PropertyDefinition'; });
// Static non-reactive data (static properties)
var staticMembers = properties.filter(function (x) { return x.static; }).map(code.deconstructProperty);
if (staticMembers === null || staticMembers === void 0 ? void 0 : staticMembers.length) {
emitSectionHeader('Static shared data (move to separate script section?)');
try {
for (var staticMembers_1 = __values(staticMembers), staticMembers_1_1 = staticMembers_1.next(); !staticMembers_1_1.done; staticMembers_1_1 = staticMembers_1.next()) {
var _p = staticMembers_1_1.value, id = _p.id, typeStr = _p.typeStr, node = _p.node;
emitComments(node);
var initializer = node.value != null ? ' = ' + code.unIndent(code.getSource(node.value)) : '';
emitLine("const ".concat(id).concat(typeStr ? ': ' + typeStr : '').concat(initializer, ";"));
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (staticMembers_1_1 && !staticMembers_1_1.done && (_b = staticMembers_1["return"])) _b.call(staticMembers_1);
}
finally { if (e_2) throw e_2.error; }
}
emitNewLine();
}
// Static non-reactive data (uninitialized instance properties)
var nonReactiveMembers = properties.filter(function (x) { return !x.static && !(0, astTools_1.isDecorated)(x) && x.value == null; }).map(code.deconstructProperty);
if (nonReactiveMembers === null || nonReactiveMembers === void 0 ? void 0 : nonReactiveMembers.length) {
emitSectionHeader('Non-reactive data');
try {
for (var nonReactiveMembers_1 = __values(nonReactiveMembers), nonReactiveMembers_1_1 = nonReactiveMembers_1.next(); !nonReactiveMembers_1_1.done; nonReactiveMembers_1_1 = nonReactiveMembers_1.next()) {
var _q = nonReactiveMembers_1_1.value, id = _q.id, typeStr = _q.typeStr, node = _q.node;
code.deconstructProperty(node);
emitComments(node);
emitLine("let ".concat(id).concat(typeStr ? ': ' + typeStr : '', ";"));
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (nonReactiveMembers_1_1 && !nonReactiveMembers_1_1.done && (_c = nonReactiveMembers_1["return"])) _c.call(nonReactiveMembers_1);
}
finally { if (e_3) throw e_3.error; }
}
emitNewLine();
}
// Props
var props = properties.filter(function (x) { return (0, astTools_1.isDecoratedWith)(x, 'Prop'); }).map(code.deconstructProperty);
var propIdentifiers = {};
if (props === null || props === void 0 ? void 0 : props.length) {
emitSectionHeader('Props');
emitLine('const props = defineProps<{');
try {
for (var props_1 = __values(props), props_1_1 = props_1.next(); !props_1_1.done; props_1_1 = props_1.next()) {
var _r = props_1_1.value, id = _r.id, typeStr = _r.typeStr, node = _r.node;
propIdentifiers[id] = node;
emitComments(node);
emitLine("\t".concat(id).concat(typeStr ? ': ' + typeStr : '').concat(node.value != null ? ' = ' + code.getSource(node.value) : '', ";"));
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (props_1_1 && !props_1_1.done && (_d = props_1["return"])) _d.call(props_1);
}
finally { if (e_4) throw e_4.error; }
}
emitLine('}>();');
emitNewLine();
}
// Emits - found by usage
var emits = {};
(_m = templateContext === null || templateContext === void 0 ? void 0 : templateContext.emits) === null || _m === void 0 ? void 0 : _m.forEach(function (x) { return emits[x] = null; });
(0, astTools_1.applyRecursively)(classNode.body, function (n) {
var _a;
if (n.type === 'CallExpression' && n.callee.type === 'MemberExpression') {
var name_1 = code.getSource(n.callee.property);
if (name_1 === '$emit' && ((_a = n.arguments) === null || _a === void 0 ? void 0 : _a.length) >= 1) {
var eventName = n.arguments[0].value;
if (typeof eventName === 'string' && !emits[eventName])
emits[eventName] = n;
else
issues.push({ message: 'Failed to interpret $emit call', node: n });
}
}
});
var emitNames = Object.keys(emits);
if (emitNames.length) {
emitSectionHeader('Emits');
emitLine("const emit = defineEmits(['".concat(emitNames.join('\', \''), "']);"));
emitNewLine();
}
// Refs
var refs = properties.filter(function (x) { return !x.static && !(0, astTools_1.isDecorated)(x) && x.value != null; }).map(code.deconstructProperty);
var refIdentifiers = {};
if (refs === null || refs === void 0 ? void 0 : refs.length) {
emitSectionHeader('State');
try {
for (var refs_1 = __values(refs), refs_1_1 = refs_1.next(); !refs_1_1.done; refs_1_1 = refs_1.next()) {
var _s = refs_1_1.value, id = _s.id, typeStr = _s.typeStr, node = _s.node;
refIdentifiers[id] = node;
emitComments(node);
emitLine("const ".concat(id, " = ref").concat(typeStr ? ("<".concat(typeStr, ">")) : '', "(").concat(code.getSource(node.value), ");"));
}
}
catch (e_5_1) { e_5 = { error: e_5_1 }; }
finally {
try {
if (refs_1_1 && !refs_1_1.done && (_e = refs_1["return"])) _e.call(refs_1);
}
finally { if (e_5) throw e_5.error; }
}
emitNewLine();
}
// function/lambda body transpilation
var thisDot = "([^a-zA-Z0-9]|^)this\\.";
function replaceThisExpr(code, member, prefix, newName, suffix) {
var regex = new RegExp("".concat(thisDot).concat(member, "([^a-zA-Z0-9]|$)"), 'g');
return code.replace(regex, "$1".concat(prefix !== null && prefix !== void 0 ? prefix : '').concat(newName !== null && newName !== void 0 ? newName : member).concat(suffix !== null && suffix !== void 0 ? suffix : '', "$2"));
}
var computedIdentifiers = {};
var staticRefRegexp = new RegExp("([^a-zA-Z0-9]|^)".concat(className, "\\."), 'g');
var watchRegexp = new RegExp("".concat(thisDot, "\\$watch\\s?\\(\\s?['\"]([^'\"]+)['\"]"), 'g');
var otherMemberRegexp = new RegExp("".concat(thisDot), 'g');
function transpiledText(node, unIndent) {
var e_11, _a, e_12, _b, e_13, _c;
var bodyText;
if (typeof node == 'string')
bodyText = node;
else if (node.type === 'MethodDefinition')
bodyText = code.asLambda(node);
else
bodyText = code.getSource(node);
// this.$watch(...) -> watch(...) (keep `this.` to apply observables etc below)
bodyText = bodyText.replace(watchRegexp, '$1watch(() => this.$2');
if (typeof node !== 'string')
reportShadowedProps(node, issues);
try {
// this.[prop] -> props.[prop]
for (var _d = __values(Object.keys(propIdentifiers)), _e = _d.next(); !_e.done; _e = _d.next()) {
var prop = _e.value;
bodyText = replaceThisExpr(bodyText, prop, 'props.');
}
}
catch (e_11_1) { e_11 = { error: e_11_1 }; }
finally {
try {
if (_e && !_e.done && (_a = _d["return"])) _a.call(_d);
}
finally { if (e_11) throw e_11.error; }
}
try {
// this.[observable] -> [observable].value
for (var _f = __values(Object.keys(refIdentifiers)), _g = _f.next(); !_g.done; _g = _f.next()) {
var prop = _g.value;
bodyText = replaceThisExpr(bodyText, prop, '', null, '.value');
}
}
catch (e_12_1) { e_12 = { error: e_12_1 }; }
finally {
try {
if (_g && !_g.done && (_b = _f["return"])) _b.call(_f);
}
finally { if (e_12) throw e_12.error; }
}
try {
// this.[computed] -> [computed].value
for (var _h = __values(Object.keys(computedIdentifiers)), _j = _h.next(); !_j.done; _j = _h.next()) {
var prop = _j.value;
bodyText = replaceThisExpr(bodyText, prop, '', null, '.value');
}
}
catch (e_13_1) { e_13 = { error: e_13_1 }; }
finally {
try {
if (_j && !_j.done && (_c = _h["return"])) _c.call(_h);
}
finally { if (e_13) throw e_13.error; }
}
// this.$emit(ev, ...) -> emit(ev, ...)
bodyText = replaceThisExpr(bodyText, '\\$emit', '', 'emit');
// this.$nextTick(...) -> nextTick(ev, ...)
bodyText = replaceThisExpr(bodyText, '\\$nextTick', '', 'nextTick');
// <className>.method/property (static member reference)
bodyText = bodyText.replace(staticRefRegexp, '$1');
// this.[other member] -> [other member]
bodyText = bodyText.replace(otherMemberRegexp, '$1');
if (unIndent === false)
return bodyText;
return code.unIndent(bodyText);
}
var methods = memberNodes.filter(function (x) { return x.type === 'MethodDefinition'; });
// Computeds
var computeds = methods.filter(function (x) { return !(0, astTools_1.isDecorated)(x) && x.kind == 'get'; }).map(code.deconstructProperty);
var computedSetters = new Map(methods.filter(function (x) { return !(0, astTools_1.isDecorated)(x) && x.kind == 'set'; })
.map(code.deconstructProperty)
.map(function (x) { return [x.id, x.node]; }));
if (computeds === null || computeds === void 0 ? void 0 : computeds.length) {
try {
// Gather definitions
for (var computeds_1 = __values(computeds), computeds_1_1 = computeds_1.next(); !computeds_1_1.done; computeds_1_1 = computeds_1.next()) {
var _t = computeds_1_1.value, id = _t.id, node = _t.node;
computedIdentifiers[id] = node;
}
}
catch (e_6_1) { e_6 = { error: e_6_1 }; }
finally {
try {
if (computeds_1_1 && !computeds_1_1.done && (_f = computeds_1["return"])) _f.call(computeds_1);
}
finally { if (e_6) throw e_6.error; }
}
// Transpile references
emitSectionHeader('Computeds');
try {
for (var computeds_2 = __values(computeds), computeds_2_1 = computeds_2.next(); !computeds_2_1.done; computeds_2_1 = computeds_2.next()) {
var _u = computeds_2_1.value, id = _u.id, node = _u.node;
var setter = computedSetters.get(id);
if (setter) {
emitComments(node);
emitLine("const ".concat(id, " = computed({"));
emitComments(node);
emitLine("\tget: ".concat(transpiledText(node, false), ","));
emitLine("\tset: ".concat(transpiledText(setter, false)));
emitLine("});");
emitNewLine();
}
else {
emitComments(node);
emitLine("const ".concat(id, " = computed(").concat(transpiledText(node), ");"));
emitNewLine();
}
}
}
catch (e_7_1) { e_7 = { error: e_7_1 }; }
finally {
try {
if (computeds_2_1 && !computeds_2_1.done && (_g = computeds_2["return"])) _g.call(computeds_2);
}
finally { if (e_7) throw e_7.error; }
}
}
// Watches
var watches = methods.filter(function (x) { return (0, astTools_1.isDecoratedWith)(x, 'Watch'); }).map(code.deconstructProperty);
if (watches === null || watches === void 0 ? void 0 : watches.length) {
emitSectionHeader('Watches');
try {
for (var watches_1 = __values(watches), watches_1_1 = watches_1.next(); !watches_1_1.done; watches_1_1 = watches_1.next()) {
var node = watches_1_1.value.node;
var deco = node.decorators[0].expression;
var decoArg0 = deco.arguments[0].value;
var decoArg1 = (((_o = deco.arguments) === null || _o === void 0 ? void 0 : _o.length) > 1 ? deco.arguments[1] : null);
var watchedExpr = transpiledText("this.".concat(decoArg0));
var handler = transpiledText(node);
var extraArg = "".concat(decoArg1 ? (', ' + code.getSource(decoArg1)) : '');
emitComments(node);
emitLine("watch(() => ".concat(watchedExpr, ", ").concat(handler).concat(extraArg, ");"));
emitNewLine();
}
}
catch (e_8_1) { e_8 = { error: e_8_1 }; }
finally {
try {
if (watches_1_1 && !watches_1_1.done && (_h = watches_1["return"])) _h.call(watches_1);
}
finally { if (e_8) throw e_8.error; }
}
}
var plainMethods = methods.filter(function (x) { return !(0, astTools_1.isDecorated)(x) && x.kind == 'method'; }).map(code.deconstructProperty);
// Life cycle hooks
var specialMethods = ['created', 'mounted'];
var specialFunctions = plainMethods.filter(function (_a) {
var id = _a.id;
return specialMethods.includes(id);
});
if (specialFunctions === null || specialFunctions === void 0 ? void 0 : specialFunctions.length) {
emitSectionHeader('Initialization');
try {
for (var specialFunctions_1 = __values(specialFunctions), specialFunctions_1_1 = specialFunctions_1.next(); !specialFunctions_1_1.done; specialFunctions_1_1 = specialFunctions_1.next()) {
var _v = specialFunctions_1_1.value, id = _v.id, node = _v.node;
emitComments(node);
if (id == 'created')
emitLine(code.unIndent(transpiledText(node.value.body)).slice(2, -2).trim());
else if (id == 'mounted')
emitLine("onMounted(".concat(transpiledText(node), ");"));
else
continue;
emitNewLine();
}
}
catch (e_9_1) { e_9 = { error: e_9_1 }; }
finally {
try {
if (specialFunctions_1_1 && !specialFunctions_1_1.done && (_j = specialFunctions_1["return"])) _j.call(specialFunctions_1);
}
finally { if (e_9) throw e_9.error; }
}
}
function emitFunctions(functions) {
var e_14, _a;
try {
for (var functions_1 = __values(functions), functions_1_1 = functions_1.next(); !functions_1_1.done; functions_1_1 = functions_1.next()) {
var f = functions_1_1.value;
emitComments(f.node);
emitLine("".concat(f.async ? 'async ' : '', "function ").concat(f.id).concat(transpiledText(f.node.value)));
emitNewLine();
}
}
catch (e_14_1) { e_14 = { error: e_14_1 }; }
finally {
try {
if (functions_1_1 && !functions_1_1.done && (_a = functions_1["return"])) _a.call(functions_1);
}
finally { if (e_14) throw e_14.error; }
}
}
// Regular functions
var functions = plainMethods.filter(function (_a) {
var id = _a.id, node = _a.node;
return !node.static && !specialMethods.includes(id);
});
if (functions === null || functions === void 0 ? void 0 : functions.length) {
emitSectionHeader('Functions');
emitFunctions(functions);
}
// Static functions
var staticFunctions = plainMethods.filter(function (_a) {
var id = _a.id, node = _a.node;
return node.static && !specialMethods.includes(id);
});
if (staticFunctions === null || staticFunctions === void 0 ? void 0 : staticFunctions.length) {
emitSectionHeader('Static functions');
emitFunctions(staticFunctions);
}
// Exports (skip export of Vue class from vue-facing-decorator)
var exportNodes = code.ast.body.filter(function (x) { return x.type === 'ExportNamedDeclaration'; })
.filter(function (c) { return code.getSource(c.specifiers[0]) !== className; });
if (exportNodes === null || exportNodes === void 0 ? void 0 : exportNodes.length) {
emitSectionHeader('Exports');
try {
for (var exportNodes_1 = __values(exportNodes), exportNodes_1_1 = exportNodes_1.next(); !exportNodes_1_1.done; exportNodes_1_1 = exportNodes_1.next()) {
var c = exportNodes_1_1.value;
emitComments(c);
emitLine(code.unIndent(code.getSource(c)));
emitNewLine();
}
}
catch (e_10_1) { e_10 = { error: e_10_1 }; }
finally {
try {
if (exportNodes_1_1 && !exportNodes_1_1.done && (_k = exportNodes_1["return"])) _k.call(exportNodes_1);
}
finally { if (e_10) throw e_10.error; }
}
}
if (issues === null || issues === void 0 ? void 0 : issues.length) {
emitSectionHeader('Transpilation issues');
issues.forEach(function (x) { var _a, _b; return emitLine("// * ".concat(x.message, " (script section, row ").concat((_b = (_a = x.node.loc) === null || _a === void 0 ? void 0 : _a.start) === null || _b === void 0 ? void 0 : _b.line, ")")); });
}
return xformed;
}
exports.transpile = transpile;
function reportShadowedProps(node, issues) {
var e_15, _a;
var thisUses = [];
var locals = new Map();
(0, astTools_1.applyRecursively)(node, function (x) {
var e_16, _a;
var _b;
if (x.type === 'MemberExpression' && x.object.type === 'ThisExpression') {
var member = x.property.type === 'Identifier' ? x.property.name : null;
if (member)
thisUses.push(member);
}
else if (x.type === 'VariableDeclaration') {
try {
for (var _c = __values(x.declarations), _d = _c.next(); !_d.done; _d = _c.next()) {
var decl = _d.value;
if (decl.id.type === 'Identifier' && ((_b = decl.init) === null || _b === void 0 ? void 0 : _b.type) !== 'CallExpression' && !locals.has(decl.id.name))
locals.set(decl.id.name, decl);
}
}
catch (e_16_1) { e_16 = { error: e_16_1 }; }
finally {
try {
if (_d && !_d.done && (_a = _c["return"])) _a.call(_c);
}
finally { if (e_16) throw e_16.error; }
}
}
});
var shadows = new Set(thisUses.filter(function (x) { return locals.has(x); }));
try {
for (var shadows_1 = __values(shadows), shadows_1_1 = shadows_1.next(); !shadows_1_1.done; shadows_1_1 = shadows_1.next()) {
var x = shadows_1_1.value;
var node_1 = locals.get(x);
issues.push({
message: "Local '".concat(x, "' shadows use of member with the same name. Rename to avoid compilation errors."),
node: node_1
});
}
}
catch (e_15_1) { e_15 = { error: e_15_1 }; }
finally {
try {
if (shadows_1_1 && !shadows_1_1.done && (_a = shadows_1["return"])) _a.call(shadows_1);
}
finally { if (e_15) throw e_15.error; }
}
}