Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(vue-script-setup-converter): Remove defineComponent from import declaration #53

Merged
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`snapshot > defineNuxtComponent 1`] = `
"import { defineNuxtComponent, useNuxtApp } from '#imports';
"import { useNuxtApp } from '#imports';
definePageMeta({
name: 'HelloWorld', layout: 'test-layout', middleware: 'test-middleware'
});
Expand All @@ -15,7 +15,7 @@ const onSubmit = () => {
`;

exports[`snapshot > lang=js 1`] = `
"import { defineComponent, toRefs, computed, ref } from 'vue';
"import { toRefs, computed, ref } from 'vue';
const props = defineProps({
msg: {
type: String,
Expand All @@ -35,7 +35,7 @@ const count = ref(0);
`;

exports[`snapshot > lang=ts 1`] = `
"import { defineComponent, toRefs, computed, ref } from 'vue';
"import { toRefs, computed, ref } from 'vue';
type Props = {
msg?: string;
foo: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export default defineComponent({
</script>`);
expect(output).toMatchInlineSnapshot(
`
"import { defineComponent, toRefs, computed } from 'vue';
"import { toRefs, computed } from 'vue';
type Props = { msg?: string; }; const props = withDefaults(defineProps<Props>(), { msg: 'HelloWorld' });

const { msg } = toRefs(props);
Expand Down Expand Up @@ -157,7 +157,7 @@ export default defineComponent({
expect(output).toMatchInlineSnapshot(
`
"import type { PropType } from 'vue';
import { defineComponent, computed } from 'vue';
import { computed } from 'vue';
type Props = { msg?: string; }; const props = withDefaults(defineProps<Props>(), { msg: 'HelloWorld' });

const newMsg = computed(() => props.msg + '- HelloWorld');
Expand Down
21 changes: 19 additions & 2 deletions packages/vue-script-setup-converter/src/lib/convertSrc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {
} from "ts-morph";
import { parse } from "@vue/compiler-sfc";
import { getNodeByKind } from "./helper";
import { hasNamedImportIdentifier } from "./helpers/module";
import { convertDefineComponentImport } from "./converter/defineComponentImportConverter";
import { convertPageMeta } from "./converter/pageMetaConverter";
import { convertProps } from "./converter/propsConverter";
import { convertSetup } from "./converter/setupConverter";
Expand Down Expand Up @@ -41,6 +43,7 @@ export const convertSrc = (input: string) => {
throw new Error("defineComponent is not found.");
}

const defineComponentImport = convertDefineComponentImport(sourceFile) ?? "";
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking here, convertDefineComponentImport looks good. I prefer converterImportDeclaration to defineComponentImport.

const pageMeta = convertPageMeta(callexpression, lang) ?? "";
const props = convertProps(callexpression, lang) ?? "";
const emits = convertEmits(callexpression, lang) ?? "";
Expand All @@ -51,10 +54,24 @@ export const convertSrc = (input: string) => {
statements.addStatements(
sourceFile
.getStatements()
.filter((state) => !Node.isExportAssignment(state))
.map((x) => x.getText())
.filter((state) => {
if (Node.isExportAssignment(state)) return false;
if (
Node.isImportDeclaration(state) &&
(hasNamedImportIdentifier(state, "defineComponent") ||
hasNamedImportIdentifier(state, "defineNuxtComponent"))
)
return false;

return true;
})
.map((x) => {
return x.getText();
})
);

statements.addStatements(defineComponentImport);

if (isDefineNuxtComponent(callexpression)) {
statements.addStatements(pageMeta);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { expect, describe, it } from "vitest";
import { ScriptTarget, Project } from "ts-morph";
import { parse } from "@vue/compiler-sfc";
import prettier from "prettier";
import parserTypeScript from "prettier/parser-typescript";
import { convertDefineComponentImport } from "./defineComponentImportConverter";

const parseScript = (input: string, lang: "js" | "ts" = "js") => {
const {
descriptor: { script },
} = parse(input);

const project = new Project({
tsConfigFilePath: "tsconfig.json",
compilerOptions: {
target: ScriptTarget.Latest,
},
});

const sourceFile = project.createSourceFile("s.tsx", script?.content ?? "");
const convertedImportDeclarationText =
convertDefineComponentImport(sourceFile);

const formatedText = prettier.format(convertedImportDeclarationText, {
parser: "typescript",
plugins: [parserTypeScript],
});

return formatedText;
};

describe("convertDefineComponentImport", () => {
describe("when defineComponent is imported", () => {
const source = `<script>
import { defineComponent, ref } from 'vue';

export default defineComponent({
name: 'HelloWorld',
})
</script>`;

it("returns import declaration text removed defineComponent", () => {
const output = parseScript(source);
const expected = 'import { ref } from "vue";\n';

expect(output).toBe(expected);
});
});

describe("when only defineComponent is imported", () => {
const source = `<script>
import { defineComponent } from 'vue';

export default defineComponent({
name: 'HelloWorld',
})
</script>`;

it("returns blank", () => {
const output = parseScript(source);
const expected = "";

expect(output).toBe(expected);
});
});

describe("when defineNuxtComponent is imported", () => {
const source = `<script>
import { defineNuxtComponent, ref } from '#imports';

export default defineNuxtComponent({
name: 'HelloWorld',
})
</script>`;

it("returns import declaration text removed defineNuxtComponent", () => {
const output = parseScript(source);
const expected = 'import { ref } from "#imports";\n';

expect(output).toBe(expected);
});
});

describe("when only defineNuxtComponent is imported", () => {
const source = `<script>
import { defineNuxtComponent } from '#imports';

export default defineNuxtComponent({
name: 'HelloWorld',
})
</script>`;

it("returns blank", () => {
const output = parseScript(source);
const expected = "";

expect(output).toBe(expected);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { ImportDeclaration, SourceFile } from "ts-morph";
import { hasNamedImportIdentifier } from "../helpers/module";

export const convertDefineComponentImport = (sourceFile: SourceFile) => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it is a convert to defineComponent.

Suggested change
export const convertDefineComponentImport = (sourceFile: SourceFile) => {
export const convertImportDeclaration = (sourceFile: SourceFile) => {

let importDeclarationText = "";

sourceFile.getImportDeclarations().forEach((importDeclaration) => {
if (hasNamedImportIdentifier(importDeclaration, "defineComponent")) {
importDeclarationText = convertToImportDeclarationText(
importDeclaration,
"defineComponent"
);
}
if (hasNamedImportIdentifier(importDeclaration, "defineNuxtComponent")) {
importDeclarationText = convertToImportDeclarationText(
importDeclaration,
"defineNuxtComponent"
);
}
});

return importDeclarationText;
};

const convertToImportDeclarationText = (
importDeclaration: ImportDeclaration,
identifier: string
) => {
const filteredNamedImports = importDeclaration
.getNamedImports()
.map((namedImport) => namedImport.getText())
.filter((text) => text !== identifier);

if (filteredNamedImports.length === 0) return "";

return `import { ${filteredNamedImports.join(
","
)} } from '${importDeclaration.getModuleSpecifierValue()}';`;
};
1 change: 1 addition & 0 deletions packages/vue-script-setup-converter/src/lib/helper.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// TODO: Move to helpers/node.ts
Copy link
Contributor Author

@inouetakuya inouetakuya May 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will handle this in another Pull Request 🙏

import { SyntaxKind, Node, PropertyAssignment, CallExpression } from "ts-morph";

export const getNodeByKind = (
Expand Down
53 changes: 53 additions & 0 deletions packages/vue-script-setup-converter/src/lib/helpers/module.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { expect, describe, it } from "vitest";
import { ScriptTarget, Project, ImportDeclaration } from "ts-morph";
import { parse } from "@vue/compiler-sfc";
import { hasNamedImportIdentifier } from "./module";

const getSourceFile = (input: string, lang: "js" | "ts" = "js") => {
const {
descriptor: { script },
} = parse(input);

const project = new Project({
tsConfigFilePath: "tsconfig.json",
compilerOptions: {
target: ScriptTarget.Latest,
},
});

return project.createSourceFile("s.tsx", script?.content ?? "");
};

describe("helpers/module", () => {
describe("hasNamedImportIdentifier", () => {
describe("when importDeclaration includes target namedImport", () => {
const source = `<script>import { defineComponent, ref } from 'vue';</script>`;

it("returns true", () => {
const sourceFile = getSourceFile(source);
const importDeclaration = sourceFile.getImportDeclaration("vue");
const result = hasNamedImportIdentifier(
importDeclaration as ImportDeclaration,
"defineComponent"
);

expect(result).toBe(true);
});
});

describe("when importDeclaration does not include target namedImport", () => {
const source = `<script>import { ref } from 'vue';</script>`;

it("returns true", () => {
const sourceFile = getSourceFile(source);
const importDeclaration = sourceFile.getImportDeclaration("vue");
const result = hasNamedImportIdentifier(
importDeclaration as ImportDeclaration,
"defineComponent"
);

expect(result).toBe(false);
});
});
});
});
12 changes: 12 additions & 0 deletions packages/vue-script-setup-converter/src/lib/helpers/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { ImportDeclaration } from "ts-morph";

export const hasNamedImportIdentifier = (
importDeclaration: ImportDeclaration,
identifier: string
): boolean => {
return Boolean(
importDeclaration.getNamedImports().find((namedImport) => {
return namedImport.getName() === identifier;
})
);
};
Loading