diff --git a/compiler/plugins/vue.plugin.js b/compiler/plugins/vue.plugin.js index 29494f53..bd5ef2f0 100644 --- a/compiler/plugins/vue.plugin.js +++ b/compiler/plugins/vue.plugin.js @@ -5,10 +5,17 @@ */ module.exports = function vueCompilerPlugin() { return { + json: { + // Happens after getting json + post: (json) => { + json = fixCleanupRefAst(json); + return json; + }, + }, code: { // Happens before formatting pre: (codeStr) => { - return [fixCleanupRefIssues].reduce((acc, transform) => { + return [fixVueClassName].reduce((acc, transform) => { acc = transform(codeStr); return acc; }, codeStr); @@ -17,9 +24,75 @@ module.exports = function vueCompilerPlugin() { }; }; -function fixCleanupRefIssues(codeStr) { - return codeStr.replace( - /if \(typeof cleanupRef\.value === "function"\) \{\s*cleanupRef\(\);\s*\}/g, - 'if (typeof cleanupRef.value === "function") {\n cleanupRef.value();\n }', - ); +function fixCleanupRefAst(ast) { + if (ast.hooks && ast.hooks.onUnMount) { + console.log(ast.hooks); + + const onUnMountCode = ast.hooks.onUnMount.code; + + let updatedCode = onUnMountCode; + + if ( + onUnMountCode && + /if\s*\(\s*typeof\s+cleanupRef\.value\s*===\s*["']function["']\s*\)/.test( + onUnMountCode, + ) + ) { + // Case 1: With braces + const { parse } = require("@babel/parser"); + const traverse = require("@babel/traverse").default; + const generate = require("@babel/generator").default; + const t = require("@babel/types"); + + const ast = parse(onUnMountCode, { + sourceType: "module", + plugins: ["typescript"], + }); + + traverse(ast, { + IfStatement(path) { + const { test, consequent } = path.node; + if ( + t.isBinaryExpression(test) && + t.isUnaryExpression(test.left) && + t.isMemberExpression(test.left.argument) && + t.isIdentifier(test.left.argument.object) && + test.left.argument.object.name === "cleanupRef" && + t.isIdentifier(test.left.argument.property) && + test.left.argument.property.name === "value" && + t.isStringLiteral(test.right) && + test.right.value === "function" + ) { + const newConsequent = t.blockStatement([ + t.expressionStatement( + t.callExpression( + t.memberExpression( + t.identifier("cleanupRef"), + t.identifier("value"), + ), + [], + ), + ), + ]); + path.node.consequent = newConsequent; + } + }, + }); + + updatedCode = generate(ast).code; + } + + ast.hooks.onUnMount.code = updatedCode; + } + return ast; +} + +function fixVueClassName(codeStr) { + return codeStr + .replace(/\.className/g, ".class") + .replace(/\bclassName\b/g, "class") + .replace( + /:class="boxStyles\.class"/g, + ':class="clsx(boxStyles.class, class)"', + ); } diff --git a/package.json b/package.json index b3291eb4..a596ff5a 100644 --- a/package.json +++ b/package.json @@ -36,10 +36,14 @@ }, "devDependencies": { "@babel/core": "^7.24.7", + "@babel/generator": "^7.25.6", + "@babel/parser": "^7.25.6", "@babel/plugin-proposal-decorators": "^7.24.7", "@babel/preset-env": "^7.24.7", "@babel/preset-react": "^7.24.7", "@babel/preset-typescript": "^7.24.7", + "@babel/traverse": "^7.25.6", + "@babel/types": "^7.25.6", "@builder.io/eslint-plugin-mitosis": "^0.0.16", "@builder.io/mitosis": "0.3.11", "@builder.io/mitosis-cli": "0.3.11", diff --git a/packages/vue/stories/Button.stories.ts b/packages/vue/stories/Button.stories.ts deleted file mode 100644 index a69991a5..00000000 --- a/packages/vue/stories/Button.stories.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/vue3'; -import { fn } from '@storybook/test'; -import Button from './Button.vue'; - -// More on how to set up stories at: https://storybook.js.org/docs/writing-stories -const meta = { - title: 'Example/Button', - component: Button, - // This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/writing-docs/autodocs - tags: ['autodocs'], - argTypes: { - size: { control: 'select', options: ['small', 'medium', 'large'] }, - backgroundColor: { control: 'color' }, - }, - args: { - primary: false, - // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args - onClick: fn(), - }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; -/* - *👇 Render functions are a framework specific feature to allow you control on how the component renders. - * See https://storybook.js.org/docs/api/csf - * to learn how to use render functions. - */ -export const Primary: Story = { - args: { - primary: true, - label: 'Button', - }, -}; - -export const Secondary: Story = { - args: { - primary: false, - label: 'Button', - }, -}; - -export const Large: Story = { - args: { - label: 'Button', - size: 'large', - }, -}; - -export const Small: Story = { - args: { - label: 'Button', - size: 'small', - }, -}; diff --git a/packages/vue/stories/Button.vue b/packages/vue/stories/Button.vue deleted file mode 100644 index 2e1ee0ee..00000000 --- a/packages/vue/stories/Button.vue +++ /dev/null @@ -1,48 +0,0 @@ - - - \ No newline at end of file diff --git a/packages/vue/stories/Header.vue b/packages/vue/stories/Header.vue index b716db02..e5c3ae1b 100644 --- a/packages/vue/stories/Header.vue +++ b/packages/vue/stories/Header.vue @@ -13,9 +13,6 @@
Welcome, {{ user.name }}! - - -
@@ -23,7 +20,6 @@