diff --git a/packages/installer/src/migration/index.test.ts b/packages/installer/src/migration/index.test.ts index 0b777901..6f77ee3f 100644 --- a/packages/installer/src/migration/index.test.ts +++ b/packages/installer/src/migration/index.test.ts @@ -26,6 +26,20 @@ describe("findMigrator", () => { expect(migrator.name).toBe("remix"); }); + it("should find tanstack migrator", () => { + const migrator = findMigrator({ + name: "tanstack", + dependencies: { + "@tanstack/start": "^1.95.1", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "vinxi": "0.5.1" + }, + }); + expect(migrator).not.toBe(null); + expect(migrator.name).toBe("tanstack"); + }); + it("should throw error if migrator could not be found", () => { expect(() => findMigrator({ diff --git a/packages/installer/src/migration/index.ts b/packages/installer/src/migration/index.ts index dfea14c1..af820888 100644 --- a/packages/installer/src/migration/index.ts +++ b/packages/installer/src/migration/index.ts @@ -7,11 +7,13 @@ import { migratorRemix } from "./remix.js"; import { migratorVinxi } from "./vinxi.js"; import { migratorVite } from "./vite.js"; import { migratorSvelteKit } from "./sveltekit.js"; +import { migratorTanStack } from "./tanstack.js"; const migrators = [ migratorNextJS, migratorRemix, migratorQwik, + migratorTanStack, migratorVinxi, migratorSvelteKit, migratorVite, diff --git a/packages/installer/src/migration/tanstack.test.ts b/packages/installer/src/migration/tanstack.test.ts new file mode 100644 index 00000000..633559ec --- /dev/null +++ b/packages/installer/src/migration/tanstack.test.ts @@ -0,0 +1,196 @@ +import { PackageJson } from "src/packageJson.js"; +import { describe, expect, it } from "vitest"; +import { migratorTanStack } from "./tanstack.js"; + +describe("tanstack migrator", () => { + const packageJson: PackageJson = { + name: "something", + }; + + describe("isResponsible", () => { + it("should be responsible for TanStack Start", () => { + const responsible = migratorTanStack.isResponsible({ + name: "something", + dependencies: { + "@tanstack/start": "^1.95.1" + }, + }); + expect(responsible).toBe(true); + }); + + it("should be responsible for TanStack Start in dev dependencies", () => { + const responsible = migratorTanStack.isResponsible({ + name: "something", + devDependencies: { + "@tanstack/start": "^1.95.1" + }, + }); + expect(responsible).toBe(true); + }); + + it("should not be responsible for next.js", () => { + const responsible = migratorTanStack.isResponsible({ + name: "something", + dependencies: { + next: "14.3.1", + }, + }); + expect(responsible).toBe(false); + }); + + it("should not be responsible for vinxi", () => { + const responsible = migratorTanStack.isResponsible({ + name: "something", + dependencies: { + vinxi: "0.5.1", + }, + }); + expect(responsible).toBe(false); + }); + }); + + describe("options", () => { + it("should parse options", () => { + const options = migratorTanStack.options.parse({ demoContent: "none" }); + expect(options).toEqual({ demoContent: "none" }); + }); + }); + + describe("migration", () => { + it("should return tasks without demo content", async () => { + const migration = await migratorTanStack.createMigration( + { + directory: "directory", + packageJson, + }, + { + demoContent: "none", + }, + ); + + const names = migration.map((task) => task.name); + expect(names).toEqual([ + "Install dependencies", + "Add alias to tsconfig", + "Modify vinxi configuration", + "Add .content-collections to .gitignore", + "Create configuration file", + ]); + }); + + it("should return tasks with demo content", async () => { + const migration = await migratorTanStack.createMigration( + { + directory: "directory", + packageJson, + }, + { + demoContent: "markdown", + }, + ); + + const names = migration.map((task) => task.name); + expect(names).toEqual([ + "Install dependencies", + "Add alias to tsconfig", + "Modify vinxi configuration", + "Add .content-collections to .gitignore", + "Create configuration file", + "Create demo content", + ]); + }); + + it("should add markdown package with markdown demo content", async () => { + const migration = await migratorTanStack.createMigration( + { + directory: "directory", + packageJson, + }, + { + demoContent: "markdown", + }, + ); + + const addDependenciesTask = migration.find( + (task) => task.name === "Install dependencies", + ); + if (!addDependenciesTask) { + throw new Error("Task not found"); + } + + // @ts-expect-error - we know it's there + const dependencies = addDependenciesTask.devDependencies; + expect(dependencies).toContain("@content-collections/markdown"); + }); + + it("should add mdx package with mdx demo content", async () => { + const migration = await migratorTanStack.createMigration( + { + directory: "directory", + packageJson, + }, + { + demoContent: "mdx", + }, + ); + + const addDependenciesTask = migration.find( + (task) => task.name === "Install dependencies", + ); + if (!addDependenciesTask) { + throw new Error("Task not found"); + } + + // @ts-expect-error - we know it's there + const dependencies = addDependenciesTask.devDependencies; + expect(dependencies).toContain("@content-collections/mdx"); + }); + + it("should not add markdown package without demo content", async () => { + const migration = await migratorTanStack.createMigration( + { + directory: "directory", + packageJson, + }, + { + demoContent: "none", + }, + ); + + const addDependenciesTask = migration.find( + (task) => task.name === "Install dependencies", + ); + if (!addDependenciesTask) { + throw new Error("Task not found"); + } + + // @ts-expect-error - we know it's there + const dependencies = addDependenciesTask.devDependencies; + expect(dependencies).not.toContain("@content-collections/markdown"); + }); + + it("should add core and vite packages", async () => { + const migration = await migratorTanStack.createMigration( + { + directory: "directory", + packageJson, + }, + { + demoContent: "none", + }, + ); + + const addDependenciesTask = migration.find( + (task) => task.name === "Install dependencies", + ); + if (!addDependenciesTask) { + throw new Error("Task not found"); + } + + // @ts-expect-error - we know it's there + const dependencies = addDependenciesTask.devDependencies; + expect(dependencies).toContain("@content-collections/core"); + expect(dependencies).toContain("@content-collections/vinxi"); + }); + }); +}); diff --git a/packages/installer/src/migration/tanstack.ts b/packages/installer/src/migration/tanstack.ts new file mode 100644 index 00000000..8e8e34d9 --- /dev/null +++ b/packages/installer/src/migration/tanstack.ts @@ -0,0 +1,48 @@ +import { z } from "zod"; +import { defineMigrator } from "./migrator.js"; +import { createConfiguration } from "./tasks/config.js"; +import { createDemoContent } from "./tasks/demo.js"; +import { addDependencies } from "./tasks/dependencies.js"; +import { addToGitIgnore } from "./tasks/gitignore.js"; +import { modifyVinxiConfig } from "./tasks/vinxi.js"; +import { addAliasToTsConfig } from "./tasks/tsconfig.js"; + +export const migratorTanStack = defineMigrator({ + name: "tanstack", + options: z.object({ + demoContent: z + .enum(["none", "markdown", "mdx"]) + .default("markdown") + .describe("Type of demo content"), + }), + isResponsible: (packageJson) => + Boolean(packageJson.dependencies?.["@tanstack/start"]) || + Boolean(packageJson.devDependencies?.["@tanstack/start"]), + async createMigration({ directory, packageJson }, { demoContent }) { + const packages = [ + "@content-collections/core", + "@content-collections/vinxi", + ]; + + if (demoContent === "markdown") { + packages.push("@content-collections/markdown"); + } else if (demoContent === "mdx") { + packages.push("@content-collections/mdx"); + } + + + const tasks = [ + addDependencies(directory, packageJson, [], packages), + addAliasToTsConfig(directory), + modifyVinxiConfig(directory), + addToGitIgnore(directory), + createConfiguration(directory, demoContent), + ]; + + if (demoContent !== "none") { + tasks.push(createDemoContent(directory, demoContent)); + } + + return tasks; + }, +});