diff --git a/.typos.toml b/.typos.toml index 28c7a0f9ea..afff8e2a2e 100644 --- a/.typos.toml +++ b/.typos.toml @@ -9,12 +9,15 @@ PUNICODE = "PUNICODE" Jod = "Jod" # Node.js v22 LTS codename flate = "flate" # flate2 crate name (gzip/deflate compression) fpr = "fpr" # GPG colon-format record name for a key fingerprint +sigle = "sigle" # Ecosystem repository name used in migration regression fixtures [default.extend-identifiers] # Yarn Plug'n'Play — tokenizer splits `PnP` into the word `Pn`, which typos # otherwise wants to autocorrect to `On`. Whitelist the full identifier so # the parts aren't tokenized. PnP = "PnP" +# Tests pass an attached config path: `-c` followed by `custom.json`. +ccustom = "ccustom" [files] extend-exclude = [ diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_monorepo_local_template_shorthand/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_monorepo_local_template_shorthand/snapshots.toml index defdfb38b6..12703b557e 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_monorepo_local_template_shorthand/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_monorepo_local_template_shorthand/snapshots.toml @@ -4,6 +4,6 @@ vp = "local" steps = [ { argv = ["vp", "create", "starter", "--no-interactive", "--no-agent", "--", "--directory", "my-app"], comment = "run the local create.templates entry; generated pkg declares fmt/lint via shorthand", continue-on-failure = true }, { argv = ["vpt", "print-file", "packages/my-app/vite.config.ts"], comment = "fmt/lint stay shorthand only, no injected duplicate inline fmt:/lint: blocks (#1836)", continue-on-failure = true }, - { argv = ["vpt", "stat-file", "packages/my-app/.oxlintrc.json", "--assert-not", "file"], comment = "standalone lint config merge-skipped and removed", continue-on-failure = true }, - { argv = ["vpt", "stat-file", "packages/my-app/.oxfmtrc.json", "--assert-not", "file"], comment = "standalone fmt config merge-skipped and removed", continue-on-failure = true }, + { argv = ["vpt", "stat-file", "packages/my-app/.oxlintrc.json", "--assert", "file"], comment = "standalone lint config preserved", continue-on-failure = true }, + { argv = ["vpt", "stat-file", "packages/my-app/.oxfmtrc.json", "--assert", "file"], comment = "standalone fmt config preserved", continue-on-failure = true }, ] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_monorepo_local_template_shorthand/snapshots/create_monorepo_local_template_shorthand.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_monorepo_local_template_shorthand/snapshots/create_monorepo_local_template_shorthand.md index 4d7d3ba9c2..44501b71ab 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_monorepo_local_template_shorthand/snapshots/create_monorepo_local_template_shorthand.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_monorepo_local_template_shorthand/snapshots/create_monorepo_local_template_shorthand.md @@ -9,8 +9,6 @@ run the local create.templates entry; generated pkg declares fmt/lint via shorth ● Running: node /packages/starter-template/bin/index.mjs --directory my-app cloned starter-template to my-app ◇ Monorepo integration... -● lint config already present in packages/my-app/vite.config.ts — removed redundant packages/my-app/.oxlintrc.json -● fmt config already present in packages/my-app/vite.config.ts — removed redundant packages/my-app/.oxfmtrc.json ● Formatting code... ● Code formatted ◇ Scaffolded packages/my-app @@ -37,18 +35,18 @@ export default defineConfig(({ mode }) => { }); ``` -## `vpt stat-file packages/my-app/.oxlintrc.json --assert-not file` +## `vpt stat-file packages/my-app/.oxlintrc.json --assert file` -standalone lint config merge-skipped and removed +standalone lint config preserved ``` -packages/my-app/.oxlintrc.json: missing +packages/my-app/.oxlintrc.json: file ``` -## `vpt stat-file packages/my-app/.oxfmtrc.json --assert-not file` +## `vpt stat-file packages/my-app/.oxfmtrc.json --assert file` -standalone fmt config merge-skipped and removed +standalone fmt config preserved ``` -packages/my-app/.oxfmtrc.json: missing +packages/my-app/.oxfmtrc.json: file ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/.oxfmtrc.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/.oxfmtrc.json new file mode 100644 index 0000000000..fd496a820e --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/.oxfmtrc.json @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "semi": false +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/package.json new file mode 100644 index 0000000000..cdaf891df3 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/package.json @@ -0,0 +1,9 @@ +{ + "name": "migration-existing-oxc-configs", + "private": true, + "type": "module", + "packageManager": "pnpm@12.3.4", + "devDependencies": { + "vite-plus": "latest" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots.toml new file mode 100644 index 0000000000..d28db5bcbe --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots.toml @@ -0,0 +1,97 @@ +[[case]] +name = "migration_existing_oxc_configs" +vp = "global" +steps = [ + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "finish a leftover Oxfmt config even when Vite+ is already installed" }, + ["vpt", "print-file", "vite.config.ts"], + ["vpt", "stat-file", ".oxfmtrc.json", "--assert-not", "file"], + { argv = ["vp", "fmt", "src/index.ts"], comment = "the migrated options must affect formatting" }, + ["vpt", "print-file", "src/index.ts"], + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "a completed migration should be a no-op on retry" }, + ["vpt", "print-file", "vite.config.ts"], + ["vpt", "stat-file", "AGENTS.md", "--assert-not", "file"], + ["vpt", "stat-file", ".vite-hooks", "--assert-not", "dir"], + ["vpt", "stat-file", ".vscode", "--assert-not", "dir"], +] + +[[case]] +name = "migration_existing_oxc_configs_unreferenced_lint" +vp = "global" +steps = [ + { argv = ["vpt", "write-file", ".oxlintrc.json", "{\"rules\":{\"no-console\":\"error\"},\"options\":{\"typeAware\":false,\"typeCheck\":false}}\n"], snapshot = false }, + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "finish both unreferenced Oxc configs in a project that already uses Vite+" }, + ["vpt", "stat-file", ".oxlintrc.json", "--assert-not", "file"], + ["vpt", "stat-file", ".oxfmtrc.json", "--assert-not", "file"], + ["vpt", "print-file", "vite.config.ts"], + ["vp", "fmt", "src/index.ts"], + ["vpt", "print-file", "src/index.ts"], + ["vp", "lint", "src/index.ts"], + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "the restored finalization must remain a no-op on retry" }, + ["vpt", "print-file", "vite.config.ts"], + ["vp", "fmt", "--check", "src/index.ts"], + { argv = ["vpt", "write-file", "src/index.ts", "console.log('hello')\n"], snapshot = false }, + { argv = ["vp", "lint", "src/index.ts"], comment = "the merged lint rule must apply after the JSON config is removed", continue-on-failure = true }, +] + +[[case]] +name = "migration_existing_oxc_configs_inline_fmt" +vp = "global" +steps = [ + { argv = ["vpt", "write-file", "vite.config.ts", "export default { fmt: { singleQuote: false, semi: false } };\n"], snapshot = false }, + { argv = ["vp", "fmt", "src/index.ts"], comment = "the existing inline fmt config takes precedence over the standalone config" }, + ["vpt", "print-file", "src/index.ts"], + { argv = ["vpt", "write-file", "src/index.ts", "export const message = \"preserved\";\n"], snapshot = false }, + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "keep the standalone config when fmt is already configured" }, + ["vpt", "print-file", "vite.config.ts"], + ["vpt", "stat-file", ".oxfmtrc.json", "--assert", "file"], + { argv = ["vp", "fmt", "src/index.ts"], comment = "formatting must still use the existing inline options after migration" }, + ["vpt", "print-file", "src/index.ts"], + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "retrying the completed migration should be a no-op" }, + ["vpt", "print-file", "vite.config.ts"], +] + +[[case]] +name = "migration_existing_oxc_configs_imported" +vp = "global" +steps = [ + { argv = ["vpt", "write-file", "vite.config.ts", "import fmt from './.oxfmtrc.json' with { type: 'json' };\nimport { readFileSync } from 'node:fs';\nconst lint = JSON.parse(readFileSync(new URL('./.oxlintrc.json', import.meta.url), 'utf8'));\nexport default { fmt, lint };\n"], snapshot = false }, + { argv = ["vpt", "write-file", ".oxlintrc.json", "{\"rules\":{\"no-debugger\":\"error\"}}\n"], snapshot = false }, + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "preserve JSON configs loaded with imports and readFileSync" }, + ["vpt", "print-file", ".oxfmtrc.json"], + ["vpt", "print-file", ".oxlintrc.json"], + ["vp", "fmt", "src/index.ts"], + ["vpt", "print-file", "src/index.ts"], + ["vp", "lint", "src/index.ts"], + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "retry preserves both imported configs" }, + ["vp", "fmt", "--check", "src/index.ts"], + ["vp", "lint", "src/index.ts"], +] + +[[case]] +name = "migration_existing_oxc_configs_script" +vp = "global" +steps = [ + { argv = ["vpt", "json-edit", "package.json", "scripts.fmt", "vp fmt -c .oxfmtrc.json src/index.ts"], snapshot = false }, + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "preserve the config passed explicitly by a package script" }, + ["vpt", "stat-file", ".oxfmtrc.json", "--assert", "file"], + ["vpt", "print-file", "vite.config.ts"], + ["vp", "run", "fmt"], + ["vpt", "print-file", "src/index.ts"], +] + +[[case]] +name = "migration_existing_oxc_configs_extends" +vp = ["global", "local"] +steps = [ + { argv = ["vpt", "write-file", ".oxlintrc.json", '{"extends":["./lint-base.json"]}'], snapshot = false }, + { argv = ["vpt", "write-file", "lint-base.json", '{"rules":{"no-console":"error"},"options":{"typeAware":false,"typeCheck":false}}'], snapshot = false }, + { argv = ["vpt", "write-file", "src/index.ts", "console.log('hello');\n"], snapshot = false }, + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "recover an interrupted inheritance migration using shared TypeScript configs" }, + ["vpt", "stat-file", ".oxlintrc.json", "--assert", "missing"], + ["vpt", "print-file", "vite.config.ts"], + ["vpt", "print-file", "lint-base.ts"], + { argv = ["vp", "lint", "src/index.ts"], comment = "plain lint must enforce the inherited no-console error", continue-on-failure = true }, + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], continue-on-failure = true }, + ["vpt", "print-file", "vite.config.ts"], + { argv = ["vp", "lint", "src/index.ts"], comment = "a second migration must preserve the inherited error", continue-on-failure = true }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs.md new file mode 100644 index 0000000000..d124881fe9 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs.md @@ -0,0 +1,91 @@ +# migration_existing_oxc_configs + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +finish a leftover Oxfmt config even when Vite+ is already installed + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Updated . to Vite+ +• Node pnpm +• Dependencies: + vite-plus latest → + vite → +• 1 config update applied +• Package manager settings configured +``` + +## `vpt print-file vite.config.ts` + +``` +export default { + fmt: { + "singleQuote": true, + "semi": false + }, + +} +``` + +## `vpt stat-file .oxfmtrc.json --assert-not file` + +``` +.oxfmtrc.json: missing +``` + +## `vp fmt src/index.ts` + +the migrated options must affect formatting + +``` +VITE+ - The Unified Toolchain for the Web + +Finished in on 1 files using threads. +``` + +## `vpt print-file src/index.ts` + +``` +export const message = 'preserved' +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +a completed migration should be a no-op on retry + +``` +VITE+ - The Unified Toolchain for the Web + +This project is already using Vite+! Happy coding! +``` + +## `vpt print-file vite.config.ts` + +``` +export default { + fmt: { + "singleQuote": true, + "semi": false + }, + +} +``` + +## `vpt stat-file AGENTS.md --assert-not file` + +``` +AGENTS.md: missing +``` + +## `vpt stat-file .vite-hooks --assert-not dir` + +``` +.vite-hooks: missing +``` + +## `vpt stat-file .vscode --assert-not dir` + +``` +.vscode: missing +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs_extends.global.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs_extends.global.md new file mode 100644 index 0000000000..a9e66dec92 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs_extends.global.md @@ -0,0 +1,140 @@ +# migration_existing_oxc_configs_extends + +## `vpt write-file .oxlintrc.json '{"extends":["./lint-base.json"]}'` + + +## `vpt write-file lint-base.json '{"rules":{"no-console":"error"},"options":{"typeAware":false,"typeCheck":false}}'` + + +## `vpt write-file src/index.ts 'console.log('\''hello'\''); +'` + + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +recover an interrupted inheritance migration using shared TypeScript configs + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Updated . to Vite+ +• Node pnpm +• Dependencies: + vite-plus latest → + vite → +• 2 config updates applied +• Package manager settings configured +``` + +## `vpt stat-file .oxlintrc.json --assert missing` + +``` +.oxlintrc.json: missing +``` + +## `vpt print-file vite.config.ts` + +``` +// vp migrate: merged .oxlintrc.json (09d7752c6f5506f21cb975ff7f8df4f0). +import oxlintConfig1 from "./lint-base.js"; +export default { + fmt: { + "singleQuote": true, + "semi": false + }, + lint: { + "extends": [oxlintConfig1], + "options": {}, + "jsPlugins": [{ "name": "vite-plus", "specifier": "vite-plus/oxlint-plugin" }], + "rules": { + "vite-plus/prefer-vite-plus-imports": "error" + } + }, +} +``` + +## `vpt print-file lint-base.ts` + +``` +// Generated by vp migrate from lint-base.json. +import type { OxlintConfig } from "vite-plus/lint"; + +export default { + "rules": { + "no-console": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + } +} satisfies OxlintConfig; +``` + +## `vp lint src/index.ts` + +plain lint must enforce the inherited no-console error + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + + × eslint(no-console): Unexpected console statement. + ╭─[src/index.ts:1:1] + 1 │ console.log('hello'); + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +This project is already using Vite+! Happy coding! +``` + +## `vpt print-file vite.config.ts` + +``` +// vp migrate: merged .oxlintrc.json (09d7752c6f5506f21cb975ff7f8df4f0). +import oxlintConfig1 from "./lint-base.js"; +export default { + fmt: { + "singleQuote": true, + "semi": false + }, + lint: { + "extends": [oxlintConfig1], + "options": {}, + "jsPlugins": [{ "name": "vite-plus", "specifier": "vite-plus/oxlint-plugin" }], + "rules": { + "vite-plus/prefer-vite-plus-imports": "error" + } + }, +} +``` + +## `vp lint src/index.ts` + +a second migration must preserve the inherited error + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + + × eslint(no-console): Unexpected console statement. + ╭─[src/index.ts:1:1] + 1 │ console.log('hello'); + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs_extends.local.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs_extends.local.md new file mode 100644 index 0000000000..c15985e257 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs_extends.local.md @@ -0,0 +1,138 @@ +# migration_existing_oxc_configs_extends + +## `vpt write-file .oxlintrc.json '{"extends":["./lint-base.json"]}'` + + +## `vpt write-file lint-base.json '{"rules":{"no-console":"error"},"options":{"typeAware":false,"typeCheck":false}}'` + + +## `vpt write-file src/index.ts 'console.log('\''hello'\''); +'` + + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +recover an interrupted inheritance migration using shared TypeScript configs + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Updated . to Vite+ +• Node pnpm +• Dependencies: + vite-plus latest → + vite → +• 2 config updates applied +• Package manager settings configured +``` + +## `vpt stat-file .oxlintrc.json --assert missing` + +``` +.oxlintrc.json: missing +``` + +## `vpt print-file vite.config.ts` + +``` +// vp migrate: merged .oxlintrc.json (09d7752c6f5506f21cb975ff7f8df4f0). +import oxlintConfig1 from "./lint-base.js"; +export default { + fmt: { + "singleQuote": true, + "semi": false + }, + lint: { + "extends": [oxlintConfig1], + "options": {}, + "jsPlugins": [{ "name": "vite-plus", "specifier": "vite-plus/oxlint-plugin" }], + "rules": { + "vite-plus/prefer-vite-plus-imports": "error" + } + }, +} +``` + +## `vpt print-file lint-base.ts` + +``` +// Generated by vp migrate from lint-base.json. +import type { OxlintConfig } from "vite-plus/lint"; + +export default { + "rules": { + "no-console": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + } +} satisfies OxlintConfig; +``` + +## `vp lint src/index.ts` + +plain lint must enforce the inherited no-console error + +**Exit code:** 1 + +``` + + × eslint(no-console): Unexpected console statement. + ╭─[src/index.ts:1:1] + 1 │ console.log('hello'); + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +This project is already using Vite+! Happy coding! +``` + +## `vpt print-file vite.config.ts` + +``` +// vp migrate: merged .oxlintrc.json (09d7752c6f5506f21cb975ff7f8df4f0). +import oxlintConfig1 from "./lint-base.js"; +export default { + fmt: { + "singleQuote": true, + "semi": false + }, + lint: { + "extends": [oxlintConfig1], + "options": {}, + "jsPlugins": [{ "name": "vite-plus", "specifier": "vite-plus/oxlint-plugin" }], + "rules": { + "vite-plus/prefer-vite-plus-imports": "error" + } + }, +} +``` + +## `vp lint src/index.ts` + +a second migration must preserve the inherited error + +**Exit code:** 1 + +``` + + × eslint(no-console): Unexpected console statement. + ╭─[src/index.ts:1:1] + 1 │ console.log('hello'); + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs_imported.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs_imported.md new file mode 100644 index 0000000000..80af79fd40 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs_imported.md @@ -0,0 +1,95 @@ +# migration_existing_oxc_configs_imported + +## `vpt write-file vite.config.ts 'import fmt from '\''./.oxfmtrc.json'\'' with { type: '\''json'\'' }; +import { readFileSync } from '\''node:fs'\''; +const lint = JSON.parse(readFileSync(new URL('\''./.oxlintrc.json'\'', import.meta.url), '\''utf8'\'')); +export default { fmt, lint }; +'` + + +## `vpt write-file .oxlintrc.json '{"rules":{"no-debugger":"error"}} +'` + + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +preserve JSON configs loaded with imports and readFileSync + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Updated . to Vite+ +• Node pnpm +• Dependencies: + vite-plus latest → + vite → +• Package manager settings configured +``` + +## `vpt print-file .oxfmtrc.json` + +``` +{ + "singleQuote": true, + "semi": false +} +``` + +## `vpt print-file .oxlintrc.json` + +``` +{"rules":{"no-debugger":"error"}} +``` + +## `vp fmt src/index.ts` + +``` +VITE+ - The Unified Toolchain for the Web + +Finished in on 1 files using threads. +``` + +## `vpt print-file src/index.ts` + +``` +export const message = 'preserved' +``` + +## `vp lint src/index.ts` + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +retry preserves both imported configs + +``` +VITE+ - The Unified Toolchain for the Web + +This project is already using Vite+! Happy coding! +``` + +## `vp fmt --check src/index.ts` + +``` +VITE+ - The Unified Toolchain for the Web + +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vp lint src/index.ts` + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs_inline_fmt.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs_inline_fmt.md new file mode 100644 index 0000000000..88b5781e23 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs_inline_fmt.md @@ -0,0 +1,84 @@ +# migration_existing_oxc_configs_inline_fmt + +## `vpt write-file vite.config.ts 'export default { fmt: { singleQuote: false, semi: false } }; +'` + + +## `vp fmt src/index.ts` + +the existing inline fmt config takes precedence over the standalone config + +``` +VITE+ - The Unified Toolchain for the Web + +Finished in on 1 files using threads. +``` + +## `vpt print-file src/index.ts` + +``` +export const message = "preserved" +``` + +## `vpt write-file src/index.ts 'export const message = "preserved"; +'` + + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +keep the standalone config when fmt is already configured + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Updated . to Vite+ +• Node pnpm +• Dependencies: + vite-plus latest → + vite → +• Package manager settings configured +``` + +## `vpt print-file vite.config.ts` + +``` +export default { fmt: { singleQuote: false, semi: false } }; +``` + +## `vpt stat-file .oxfmtrc.json --assert file` + +``` +.oxfmtrc.json: file +``` + +## `vp fmt src/index.ts` + +formatting must still use the existing inline options after migration + +``` +VITE+ - The Unified Toolchain for the Web + +Finished in on 1 files using threads. +``` + +## `vpt print-file src/index.ts` + +``` +export const message = "preserved" +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +retrying the completed migration should be a no-op + +``` +VITE+ - The Unified Toolchain for the Web + +This project is already using Vite+! Happy coding! +``` + +## `vpt print-file vite.config.ts` + +``` +export default { fmt: { singleQuote: false, semi: false } }; +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs_script.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs_script.md new file mode 100644 index 0000000000..716dae4e09 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs_script.md @@ -0,0 +1,46 @@ +# migration_existing_oxc_configs_script + +## `vpt json-edit package.json scripts.fmt 'vp fmt -c .oxfmtrc.json src/index.ts'` + + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +preserve the config passed explicitly by a package script + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Updated . to Vite+ +• Node pnpm +• Dependencies: + vite-plus latest → + vite → +• Package manager settings configured +``` + +## `vpt stat-file .oxfmtrc.json --assert file` + +``` +.oxfmtrc.json: file +``` + +## `vpt print-file vite.config.ts` + +``` +export default {}; +``` + +## `vp run fmt` + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp fmt -c .oxfmtrc.json src/index.ts ⊘ cache disabled +Finished in on 1 files using threads. +``` + +## `vpt print-file src/index.ts` + +``` +export const message = 'preserved' +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs_unreferenced_lint.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs_unreferenced_lint.md new file mode 100644 index 0000000000..0b447cabad --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/snapshots/migration_existing_oxc_configs_unreferenced_lint.md @@ -0,0 +1,157 @@ +# migration_existing_oxc_configs_unreferenced_lint + +## `vpt write-file .oxlintrc.json '{"rules":{"no-console":"error"},"options":{"typeAware":false,"typeCheck":false}} +'` + + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +finish both unreferenced Oxc configs in a project that already uses Vite+ + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Updated . to Vite+ +• Node pnpm +• Dependencies: + vite-plus latest → + vite → +• 2 config updates applied +• Package manager settings configured +``` + +## `vpt stat-file .oxlintrc.json --assert-not file` + +``` +.oxlintrc.json: missing +``` + +## `vpt stat-file .oxfmtrc.json --assert-not file` + +``` +.oxfmtrc.json: missing +``` + +## `vpt print-file vite.config.ts` + +``` +// vp migrate: merged .oxlintrc.json (4f1106d1e5daf0701ef5d9536d92669d). +export default { + fmt: { + "singleQuote": true, + "semi": false + }, + lint: { + "rules": { + "no-console": "error", + "vite-plus/prefer-vite-plus-imports": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + }, + "jsPlugins": [ + { + "name": "vite-plus", + "specifier": "vite-plus/oxlint-plugin" + } + ] + }, +} +``` + +## `vp fmt src/index.ts` + +``` +VITE+ - The Unified Toolchain for the Web + +Finished in on 1 files using threads. +``` + +## `vpt print-file src/index.ts` + +``` +export const message = 'preserved' +``` + +## `vp lint src/index.ts` + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +the restored finalization must remain a no-op on retry + +``` +VITE+ - The Unified Toolchain for the Web + +This project is already using Vite+! Happy coding! +``` + +## `vpt print-file vite.config.ts` + +``` +// vp migrate: merged .oxlintrc.json (4f1106d1e5daf0701ef5d9536d92669d). +export default { + fmt: { + "singleQuote": true, + "semi": false + }, + lint: { + "rules": { + "no-console": "error", + "vite-plus/prefer-vite-plus-imports": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + }, + "jsPlugins": [ + { + "name": "vite-plus", + "specifier": "vite-plus/oxlint-plugin" + } + ] + }, +} +``` + +## `vp fmt --check src/index.ts` + +``` +VITE+ - The Unified Toolchain for the Web + +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vpt write-file src/index.ts 'console.log('\''hello'\'') +'` + + +## `vp lint src/index.ts` + +the merged lint rule must apply after the JSON config is removed + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + + × eslint(no-console): Unexpected console statement. + ╭─[src/index.ts:1:1] + 1 │ console.log('hello') + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/src/index.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/src/index.ts new file mode 100644 index 0000000000..38b0fa8a2f --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/src/index.ts @@ -0,0 +1 @@ +export const message = "preserved"; diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/vite.config.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/vite.config.ts new file mode 100644 index 0000000000..ff8b4c5632 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_oxc_configs/vite.config.ts @@ -0,0 +1 @@ +export default {}; diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/.oxlintrc.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/.oxlintrc.json new file mode 100644 index 0000000000..e54ba4dbb0 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/.oxlintrc.json @@ -0,0 +1,4 @@ +{ + "rules": { "no-debugger": "error" }, + "options": { "typeAware": false, "typeCheck": false } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/package.json new file mode 100644 index 0000000000..3bb6286751 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/package.json @@ -0,0 +1,14 @@ +{ + "name": "migration-independent-workspace-oxc-configs", + "private": true, + "type": "module", + "packageManager": "npm@11.8.0", + "workspaces": ["packages/*"], + "scripts": { + "lint": "oxlint -c .oxlintrc.json root.js" + }, + "devDependencies": { + "vite": "^8.3.4", + "oxlint": "^1.88.0" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/packages/app/.oxlintrc.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/packages/app/.oxlintrc.json new file mode 100644 index 0000000000..d6537e8361 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/packages/app/.oxlintrc.json @@ -0,0 +1,4 @@ +{ + "rules": { "no-console": "error" }, + "options": { "typeAware": false, "typeCheck": false } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/packages/app/index.js b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/packages/app/index.js new file mode 100644 index 0000000000..14c198cadb --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/packages/app/index.js @@ -0,0 +1 @@ +console.log("test"); diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/packages/app/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/packages/app/package.json new file mode 100644 index 0000000000..a070ce87e7 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/packages/app/package.json @@ -0,0 +1,12 @@ +{ + "name": "app", + "private": true, + "type": "module", + "scripts": { + "lint": "oxlint index.js" + }, + "devDependencies": { + "vite": "^8.3.4", + "oxlint": "^1.88.0" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/packages/app/vite.config.mjs b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/packages/app/vite.config.mjs new file mode 100644 index 0000000000..ff8b4c5632 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/packages/app/vite.config.mjs @@ -0,0 +1 @@ +export default {}; diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/root.js b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/root.js new file mode 100644 index 0000000000..efeee5db16 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/root.js @@ -0,0 +1 @@ +export const value = 1; diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/snapshots.toml new file mode 100644 index 0000000000..b96252c6b8 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/snapshots.toml @@ -0,0 +1,36 @@ +[[case]] +name = "migration_independent_workspace_oxc_configs" +vp = ["global", "local"] +comment = "A reference to the root config must not prevent merging an independent package config with the same filename." +steps = [ + ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], + ["vpt", "print-file", ".oxlintrc.json"], + ["vpt", "print-file", "packages/app/package.json"], + ["vpt", "print-file", "packages/app/vite.config.mjs"], + ["vpt", "stat-file", "packages/app/.oxlintrc.json", "--assert", "missing"], + ["vp", "lint", "-c", ".oxlintrc.json", "root.js"], + { argv = ["vp", "lint", "index.js"], cwd = "packages/app", comment = "plain lint must report no-console as an error", continue-on-failure = true }, + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], continue-on-failure = true }, + ["vpt", "print-file", ".oxlintrc.json"], + ["vpt", "print-file", "packages/app/vite.config.mjs"], + { argv = ["vp", "lint", "index.js"], cwd = "packages/app", comment = "a second migration must preserve the error and nonzero exit status", continue-on-failure = true }, +] + +[[case]] +name = "migration_referenced_oxc_config_converted_consumer" +vp = ["global", "local"] +comment = "Converting a package's inheritance must not remove JSON still used by the root script." +steps = [ + { argv = ["vpt", "write-file", "packages/app/.oxlintrc.json", '{"extends":["../../.oxlintrc.json"],"rules":{"no-console":"error"}}'], snapshot = false }, + { argv = ["vpt", "write-file", "packages/app/index.js", "debugger;\nconsole.log('test');\n"], snapshot = false }, + ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], + ["vpt", "print-file", ".oxlintrc.json"], + ["vpt", "print-file", ".oxlintrc.ts"], + ["vpt", "print-file", "packages/app/vite.config.mjs"], + ["vpt", "stat-file", "packages/app/.oxlintrc.json", "--assert", "missing"], + ["vp", "lint", "-c", ".oxlintrc.json", "root.js"], + { argv = ["vp", "lint", "index.js"], cwd = "packages/app", comment = "plain lint enforces both the inherited and local rules", continue-on-failure = true }, + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], continue-on-failure = true }, + ["vpt", "stat-file", ".oxlintrc.json", "--assert", "file"], + { argv = ["vp", "lint", "index.js"], cwd = "packages/app", comment = "the conversion and reference protection remain intact on retry", continue-on-failure = true }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/snapshots/migration_independent_workspace_oxc_configs.global.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/snapshots/migration_independent_workspace_oxc_configs.global.md new file mode 100644 index 0000000000..a5f2acb056 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/snapshots/migration_independent_workspace_oxc_configs.global.md @@ -0,0 +1,166 @@ +# migration_independent_workspace_oxc_configs + +A reference to the root config must not prevent merging an independent package config with the same filename. + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Migrated . to Vite+ +• Node npm +• 1 config update applied +``` + +## `vpt print-file .oxlintrc.json` + +``` +{ + "rules": { "no-debugger": "error" }, + "options": { "typeAware": false, "typeCheck": false } +} +``` + +## `vpt print-file packages/app/package.json` + +``` +{ + "name": "app", + "private": true, + "type": "module", + "scripts": { + "lint": "vp lint index.js" + }, + "devDependencies": { + "vite": "npm:@voidzero-dev/vite-plus-core@", + "vite-plus": "" + } +} +``` + +## `vpt print-file packages/app/vite.config.mjs` + +``` +// vp migrate: merged packages%2Fapp%2F.oxlintrc.json (c22a5fff1bbaa26c1877cded5b947cf8). +export default { + lint: { + "rules": { + "no-console": "error", + "vite-plus/prefer-vite-plus-imports": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + }, + "jsPlugins": [ + { + "name": "vite-plus", + "specifier": "vite-plus/oxlint-plugin" + } + ] + }, + +} +``` + +## `vpt stat-file packages/app/.oxlintrc.json --assert missing` + +``` +packages/app/.oxlintrc.json: missing +``` + +## `vp lint -c .oxlintrc.json root.js` + +``` +VITE+ - The Unified Toolchain for the Web + +note: You are running `vp lint` as a Vite+ built-in command. If you meant to run the lint npm script, use `vpr lint` instead. +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `cd packages/app && vp lint index.js` + +plain lint must report no-console as an error + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + +note: You are running `vp lint` as a Vite+ built-in command. If you meant to run the lint npm script, use `vpr lint` instead. + + × eslint(no-console): Unexpected console statement. + ╭─[index.js:1:1] + 1 │ console.log("test"); + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +This project is already using Vite+! Happy coding! +``` + +## `vpt print-file .oxlintrc.json` + +``` +{ + "rules": { "no-debugger": "error" }, + "options": { "typeAware": false, "typeCheck": false } +} +``` + +## `vpt print-file packages/app/vite.config.mjs` + +``` +// vp migrate: merged packages%2Fapp%2F.oxlintrc.json (c22a5fff1bbaa26c1877cded5b947cf8). +export default { + lint: { + "rules": { + "no-console": "error", + "vite-plus/prefer-vite-plus-imports": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + }, + "jsPlugins": [ + { + "name": "vite-plus", + "specifier": "vite-plus/oxlint-plugin" + } + ] + }, + +} +``` + +## `cd packages/app && vp lint index.js` + +a second migration must preserve the error and nonzero exit status + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + +note: You are running `vp lint` as a Vite+ built-in command. If you meant to run the lint npm script, use `vpr lint` instead. + + × eslint(no-console): Unexpected console statement. + ╭─[index.js:1:1] + 1 │ console.log("test"); + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/snapshots/migration_independent_workspace_oxc_configs.local.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/snapshots/migration_independent_workspace_oxc_configs.local.md new file mode 100644 index 0000000000..5a74d8cbb1 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/snapshots/migration_independent_workspace_oxc_configs.local.md @@ -0,0 +1,160 @@ +# migration_independent_workspace_oxc_configs + +A reference to the root config must not prevent merging an independent package config with the same filename. + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Migrated . to Vite+ +• Node npm +• 1 config update applied +``` + +## `vpt print-file .oxlintrc.json` + +``` +{ + "rules": { "no-debugger": "error" }, + "options": { "typeAware": false, "typeCheck": false } +} +``` + +## `vpt print-file packages/app/package.json` + +``` +{ + "name": "app", + "private": true, + "type": "module", + "scripts": { + "lint": "vp lint index.js" + }, + "devDependencies": { + "vite": "npm:@voidzero-dev/vite-plus-core@", + "vite-plus": "" + } +} +``` + +## `vpt print-file packages/app/vite.config.mjs` + +``` +// vp migrate: merged packages%2Fapp%2F.oxlintrc.json (c22a5fff1bbaa26c1877cded5b947cf8). +export default { + lint: { + "rules": { + "no-console": "error", + "vite-plus/prefer-vite-plus-imports": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + }, + "jsPlugins": [ + { + "name": "vite-plus", + "specifier": "vite-plus/oxlint-plugin" + } + ] + }, + +} +``` + +## `vpt stat-file packages/app/.oxlintrc.json --assert missing` + +``` +packages/app/.oxlintrc.json: missing +``` + +## `vp lint -c .oxlintrc.json root.js` + +``` +note: You are running `vp lint` as a Vite+ built-in command. If you meant to run the lint npm script, use `vpr lint` instead. +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `cd packages/app && vp lint index.js` + +plain lint must report no-console as an error + +**Exit code:** 1 + +``` +note: You are running `vp lint` as a Vite+ built-in command. If you meant to run the lint npm script, use `vpr lint` instead. + + × eslint(no-console): Unexpected console statement. + ╭─[index.js:1:1] + 1 │ console.log("test"); + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +This project is already using Vite+! Happy coding! +``` + +## `vpt print-file .oxlintrc.json` + +``` +{ + "rules": { "no-debugger": "error" }, + "options": { "typeAware": false, "typeCheck": false } +} +``` + +## `vpt print-file packages/app/vite.config.mjs` + +``` +// vp migrate: merged packages%2Fapp%2F.oxlintrc.json (c22a5fff1bbaa26c1877cded5b947cf8). +export default { + lint: { + "rules": { + "no-console": "error", + "vite-plus/prefer-vite-plus-imports": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + }, + "jsPlugins": [ + { + "name": "vite-plus", + "specifier": "vite-plus/oxlint-plugin" + } + ] + }, + +} +``` + +## `cd packages/app && vp lint index.js` + +a second migration must preserve the error and nonzero exit status + +**Exit code:** 1 + +``` +note: You are running `vp lint` as a Vite+ built-in command. If you meant to run the lint npm script, use `vpr lint` instead. + + × eslint(no-console): Unexpected console statement. + ╭─[index.js:1:1] + 1 │ console.log("test"); + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/snapshots/migration_referenced_oxc_config_converted_consumer.global.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/snapshots/migration_referenced_oxc_config_converted_consumer.global.md new file mode 100644 index 0000000000..63a2e0eb63 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/snapshots/migration_referenced_oxc_config_converted_consumer.global.md @@ -0,0 +1,158 @@ +# migration_referenced_oxc_config_converted_consumer + +Converting a package's inheritance must not remove JSON still used by the root script. + +## `vpt write-file packages/app/.oxlintrc.json '{"extends":["../../.oxlintrc.json"],"rules":{"no-console":"error"}}'` + + +## `vpt write-file packages/app/index.js 'debugger; +console.log('\''test'\''); +'` + + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Migrated . to Vite+ +• Node npm +• 1 config update applied +``` + +## `vpt print-file .oxlintrc.json` + +``` +{ + "rules": { "no-debugger": "error" }, + "options": { "typeAware": false, "typeCheck": false } +} +``` + +## `vpt print-file .oxlintrc.ts` + +``` +// Generated by vp migrate from .oxlintrc.json. +import type { OxlintConfig } from "vite-plus/lint"; + +export default { + "rules": { + "no-debugger": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + } +} satisfies OxlintConfig; +``` + +## `vpt print-file packages/app/vite.config.mjs` + +``` +// vp migrate: merged packages%2Fapp%2F.oxlintrc.json (f41297efef6313aa5180c2fdec748c48). +import oxlintConfig1 from "../../.oxlintrc.js"; +export default { + lint: { + "extends": [oxlintConfig1], + "rules": { + "no-console": "error", + "vite-plus/prefer-vite-plus-imports": "error" + }, + "options": {}, + "jsPlugins": [{ "name": "vite-plus", "specifier": "vite-plus/oxlint-plugin" }] + }, + +} +``` + +## `vpt stat-file packages/app/.oxlintrc.json --assert missing` + +``` +packages/app/.oxlintrc.json: missing +``` + +## `vp lint -c .oxlintrc.json root.js` + +``` +VITE+ - The Unified Toolchain for the Web + +note: You are running `vp lint` as a Vite+ built-in command. If you meant to run the lint npm script, use `vpr lint` instead. +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `cd packages/app && vp lint index.js` + +plain lint enforces both the inherited and local rules + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + +note: You are running `vp lint` as a Vite+ built-in command. If you meant to run the lint npm script, use `vpr lint` instead. + + × eslint(no-debugger): `debugger` statement is not allowed + ╭─[index.js:1:1] + 1 │ debugger; + · ───────── + 2 │ console.log('test'); + ╰──── + help: Remove the debugger statement + + × eslint(no-console): Unexpected console statement. + ╭─[index.js:2:1] + 1 │ debugger; + 2 │ console.log('test'); + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 2 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +This project is already using Vite+! Happy coding! +``` + +## `vpt stat-file .oxlintrc.json --assert file` + +``` +.oxlintrc.json: file +``` + +## `cd packages/app && vp lint index.js` + +the conversion and reference protection remain intact on retry + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + +note: You are running `vp lint` as a Vite+ built-in command. If you meant to run the lint npm script, use `vpr lint` instead. + + × eslint(no-debugger): `debugger` statement is not allowed + ╭─[index.js:1:1] + 1 │ debugger; + · ───────── + 2 │ console.log('test'); + ╰──── + help: Remove the debugger statement + + × eslint(no-console): Unexpected console statement. + ╭─[index.js:2:1] + 1 │ debugger; + 2 │ console.log('test'); + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 2 errors. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/snapshots/migration_referenced_oxc_config_converted_consumer.local.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/snapshots/migration_referenced_oxc_config_converted_consumer.local.md new file mode 100644 index 0000000000..ea4a9f7c1e --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/snapshots/migration_referenced_oxc_config_converted_consumer.local.md @@ -0,0 +1,152 @@ +# migration_referenced_oxc_config_converted_consumer + +Converting a package's inheritance must not remove JSON still used by the root script. + +## `vpt write-file packages/app/.oxlintrc.json '{"extends":["../../.oxlintrc.json"],"rules":{"no-console":"error"}}'` + + +## `vpt write-file packages/app/index.js 'debugger; +console.log('\''test'\''); +'` + + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Migrated . to Vite+ +• Node npm +• 1 config update applied +``` + +## `vpt print-file .oxlintrc.json` + +``` +{ + "rules": { "no-debugger": "error" }, + "options": { "typeAware": false, "typeCheck": false } +} +``` + +## `vpt print-file .oxlintrc.ts` + +``` +// Generated by vp migrate from .oxlintrc.json. +import type { OxlintConfig } from "vite-plus/lint"; + +export default { + "rules": { + "no-debugger": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + } +} satisfies OxlintConfig; +``` + +## `vpt print-file packages/app/vite.config.mjs` + +``` +// vp migrate: merged packages%2Fapp%2F.oxlintrc.json (f41297efef6313aa5180c2fdec748c48). +import oxlintConfig1 from "../../.oxlintrc.js"; +export default { + lint: { + "extends": [oxlintConfig1], + "rules": { + "no-console": "error", + "vite-plus/prefer-vite-plus-imports": "error" + }, + "options": {}, + "jsPlugins": [{ "name": "vite-plus", "specifier": "vite-plus/oxlint-plugin" }] + }, + +} +``` + +## `vpt stat-file packages/app/.oxlintrc.json --assert missing` + +``` +packages/app/.oxlintrc.json: missing +``` + +## `vp lint -c .oxlintrc.json root.js` + +``` +note: You are running `vp lint` as a Vite+ built-in command. If you meant to run the lint npm script, use `vpr lint` instead. +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `cd packages/app && vp lint index.js` + +plain lint enforces both the inherited and local rules + +**Exit code:** 1 + +``` +note: You are running `vp lint` as a Vite+ built-in command. If you meant to run the lint npm script, use `vpr lint` instead. + + × eslint(no-debugger): `debugger` statement is not allowed + ╭─[index.js:1:1] + 1 │ debugger; + · ───────── + 2 │ console.log('test'); + ╰──── + help: Remove the debugger statement + + × eslint(no-console): Unexpected console statement. + ╭─[index.js:2:1] + 1 │ debugger; + 2 │ console.log('test'); + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 2 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +This project is already using Vite+! Happy coding! +``` + +## `vpt stat-file .oxlintrc.json --assert file` + +``` +.oxlintrc.json: file +``` + +## `cd packages/app && vp lint index.js` + +the conversion and reference protection remain intact on retry + +**Exit code:** 1 + +``` +note: You are running `vp lint` as a Vite+ built-in command. If you meant to run the lint npm script, use `vpr lint` instead. + + × eslint(no-debugger): `debugger` statement is not allowed + ╭─[index.js:1:1] + 1 │ debugger; + · ───────── + 2 │ console.log('test'); + ╰──── + help: Remove the debugger statement + + × eslint(no-console): Unexpected console statement. + ╭─[index.js:2:1] + 1 │ debugger; + 2 │ console.log('test'); + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 2 errors. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/vite.config.mjs b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/vite.config.mjs new file mode 100644 index 0000000000..ff8b4c5632 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_independent_workspace_oxc_configs/vite.config.mjs @@ -0,0 +1 @@ +export default {}; diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/.oxfmtrc.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/.oxfmtrc.json new file mode 100644 index 0000000000..fd496a820e --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/.oxfmtrc.json @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "semi": false +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/.oxlintrc.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/.oxlintrc.json new file mode 100644 index 0000000000..3a438765d5 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/.oxlintrc.json @@ -0,0 +1,9 @@ +{ + "rules": { + "no-console": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/config/lint.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/config/lint.json new file mode 100644 index 0000000000..d4ac61eb93 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/config/lint.json @@ -0,0 +1,3 @@ +{ + "extends": ["../.oxlintrc.json"] +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/config/shared.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/config/shared.ts new file mode 100644 index 0000000000..33d9f7c0fd --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/config/shared.ts @@ -0,0 +1,4 @@ +import fmt from '../.oxfmtrc.json' with { type: 'json' }; +import lint from '../.oxlintrc.json' with { type: 'json' }; + +export default { fmt, lint }; diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/config/unused.cjs b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/config/unused.cjs new file mode 100644 index 0000000000..f053ebf797 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/config/unused.cjs @@ -0,0 +1 @@ +module.exports = {}; diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/package.json new file mode 100644 index 0000000000..fd4957a38c --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/package.json @@ -0,0 +1,9 @@ +{ + "name": "migration-indirect-oxc-configs", + "devDependencies": { + "vite-plus": "latest" + }, + "scripts": { + "lint:custom": "vp lint --config config/lint.json src" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/snapshots.toml new file mode 100644 index 0000000000..be11ffdecc --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/snapshots.toml @@ -0,0 +1,77 @@ +[[case]] +name = "migration_custom_lint_config_root" +vp = "global" +steps = [ + ["vp", "run", "lint:custom"], + ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], + ["vpt", "print-file", ".oxlintrc.json"], + ["vpt", "print-file", "config/lint.json"], + { argv = ["vpt", "stat-file", ".oxfmtrc.json", "--assert-not", "file"], comment = "the unrelated formatter config still merges" }, + { argv = ["vp", "run", "lint:custom"], comment = "the custom entrypoint must still load its inherited JSON config" }, + ["vp", "fmt", "--check", "src/index.js"], + ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], + ["vp", "run", "lint:custom"], + { argv = ["vpt", "write-file", "src/index.js", "console.log('hello')\n"], snapshot = false }, + { argv = ["vp", "run", "lint:custom"], comment = "the inherited no-console rule remains active after two migrations", continue-on-failure = true }, +] + +[[case]] +name = "migration_shared_vite_config_module" +vp = "global" +steps = [ + { argv = ["vpt", "write-file", "package.json", "{\"name\":\"migration-shared-vite-config\",\"devDependencies\":{\"vite-plus\":\"latest\"}}\n"], snapshot = false }, + { argv = ["vpt", "write-file", "vite.config.ts", "import shared from './config/shared.js';\nexport default { ...shared };\n"], snapshot = false }, + ["vp", "fmt", "--check", "src/index.js"], + ["vp", "lint", "src/index.js"], + ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], + ["vpt", "print-file", ".oxfmtrc.json"], + ["vpt", "print-file", ".oxlintrc.json"], + ["vpt", "print-file", "vite.config.ts"], + { argv = ["vp", "fmt", "--check", "src/index.js"], comment = "the shared TypeScript module must still import its JSON configs" }, + ["vp", "lint", "src/index.js"], + ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], + ["vp", "fmt", "--check", "src/index.js"], + { argv = ["vpt", "write-file", "src/index.js", "console.log('hello')\n"], snapshot = false }, + { argv = ["vp", "lint", "src/index.js"], comment = "the indirectly imported lint rule remains active after two migrations", continue-on-failure = true }, +] + +[[case]] +name = "migration_package_import_alias" +vp = "global" +steps = [ + { argv = ["vpt", "write-file", "package.json", "{\"name\":\"migration-shared-vite-config\",\"type\":\"module\",\"imports\":{\"#shared\":{\"import\":\"./config/shared.ts\",\"require\":\"./config/unused.cjs\"}},\"devDependencies\":{\"vite-plus\":\"latest\"}}\n"], snapshot = false }, + { argv = ["vpt", "write-file", "vite.config.ts", "import shared from '#shared';\nexport default { ...shared };\n"], snapshot = false }, + ["vp", "fmt", "--check", "src/index.js"], + ["vp", "lint", "src/index.js"], + ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], + ["vpt", "print-file", ".oxfmtrc.json"], + ["vpt", "print-file", ".oxlintrc.json"], + ["vpt", "print-file", "vite.config.ts"], + { argv = ["vp", "fmt", "--check", "src/index.js"], comment = "the package import alias must still load its JSON configs" }, + ["vp", "lint", "src/index.js"], + ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], + ["vp", "fmt", "--check", "src/index.js"], + { argv = ["vpt", "write-file", "src/index.js", "console.log('hello')\n"], snapshot = false }, + { argv = ["vp", "lint", "src/index.js"], comment = "the indirectly imported lint rule remains active after two migrations", continue-on-failure = true }, +] + +[[case]] +name = "migration_directory_package_import" +vp = "global" +steps = [ + { argv = ["vpt", "write-file", "package.json", "{\"name\":\"migration-shared-vite-config\",\"devDependencies\":{\"vite-plus\":\"latest\"}}\n"], snapshot = false }, + { argv = ["vpt", "write-file", "vite.config.ts", "import shared from './config';\nexport default { ...shared };\n"], snapshot = false }, + { argv = ["vpt", "write-file", "config/package.json", "{\"type\":\"module\",\"main\":\"./shared.ts\"}\n"], snapshot = false }, + ["vp", "fmt", "--check", "src/index.js"], + ["vp", "lint", "src/index.js"], + ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], + ["vpt", "print-file", ".oxfmtrc.json"], + ["vpt", "print-file", ".oxlintrc.json"], + ["vpt", "print-file", "vite.config.ts"], + { argv = ["vp", "fmt", "--check", "src/index.js"], comment = "the directory package entry must still load its JSON configs" }, + ["vp", "lint", "src/index.js"], + ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], + ["vp", "fmt", "--check", "src/index.js"], + { argv = ["vpt", "write-file", "src/index.js", "console.log('hello')\n"], snapshot = false }, + { argv = ["vp", "lint", "src/index.js"], comment = "the indirectly imported lint rule remains active after two migrations", continue-on-failure = true }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/snapshots/migration_custom_lint_config_root.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/snapshots/migration_custom_lint_config_root.md new file mode 100644 index 0000000000..1c916ff393 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/snapshots/migration_custom_lint_config_root.md @@ -0,0 +1,123 @@ +# migration_custom_lint_config_root + +## `vp run lint:custom` + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp lint --config config/lint.json src ⊘ cache disabled +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Updated . to Vite+ +• Node pnpm +• Dependencies: + vite-plus latest → + vite → +• 1 config update applied +• Package manager settings configured +``` + +## `vpt print-file .oxlintrc.json` + +``` +{ + "rules": { + "no-console": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + } +} +``` + +## `vpt print-file config/lint.json` + +``` +{ + "extends": ["../.oxlintrc.json"] +} +``` + +## `vpt stat-file .oxfmtrc.json --assert-not file` + +the unrelated formatter config still merges + +``` +.oxfmtrc.json: missing +``` + +## `vp run lint:custom` + +the custom entrypoint must still load its inherited JSON config + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp lint --config config/lint.json src ⊘ cache disabled +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp fmt --check src/index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +▲ No package manager is declared in package.json; using pnpm for this migration without adding a pin. Run `vp env pin` to declare it explicitly. +This project is already using Vite+! Happy coding! +``` + +## `vp run lint:custom` + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp lint --config config/lint.json src ⊘ cache disabled +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vpt write-file src/index.js 'console.log('\''hello'\'') +'` + + +## `vp run lint:custom` + +the inherited no-console rule remains active after two migrations + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp lint --config config/lint.json src ⊘ cache disabled + + × eslint(no-console): Unexpected console statement. + ╭─[src/index.js:1:1] + 1 │ console.log('hello') + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/snapshots/migration_directory_package_import.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/snapshots/migration_directory_package_import.md new file mode 100644 index 0000000000..4a00043732 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/snapshots/migration_directory_package_import.md @@ -0,0 +1,143 @@ +# migration_directory_package_import + +## `vpt write-file package.json '{"name":"migration-shared-vite-config","devDependencies":{"vite-plus":"latest"}} +'` + + +## `vpt write-file vite.config.ts 'import shared from '\''./config'\''; +export default { ...shared }; +'` + + +## `vpt write-file config/package.json '{"type":"module","main":"./shared.ts"} +'` + + +## `vp fmt --check src/index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vp lint src/index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Updated . to Vite+ +• Node pnpm +• Dependencies: + vite-plus latest → + vite → +• Package manager settings configured +``` + +## `vpt print-file .oxfmtrc.json` + +``` +{ + "singleQuote": true, + "semi": false +} +``` + +## `vpt print-file .oxlintrc.json` + +``` +{ + "rules": { + "no-console": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + } +} +``` + +## `vpt print-file vite.config.ts` + +``` +import shared from './config'; +export default { ...shared }; +``` + +## `vp fmt --check src/index.js` + +the directory package entry must still load its JSON configs + +``` +VITE+ - The Unified Toolchain for the Web + +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vp lint src/index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +▲ No package manager is declared in package.json; using pnpm for this migration without adding a pin. Run `vp env pin` to declare it explicitly. +This project is already using Vite+! Happy coding! +``` + +## `vp fmt --check src/index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vpt write-file src/index.js 'console.log('\''hello'\'') +'` + + +## `vp lint src/index.js` + +the indirectly imported lint rule remains active after two migrations + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + + × eslint(no-console): Unexpected console statement. + ╭─[src/index.js:1:1] + 1 │ console.log('hello') + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/snapshots/migration_package_import_alias.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/snapshots/migration_package_import_alias.md new file mode 100644 index 0000000000..b9aaf596a5 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/snapshots/migration_package_import_alias.md @@ -0,0 +1,139 @@ +# migration_package_import_alias + +## `vpt write-file package.json '{"name":"migration-shared-vite-config","type":"module","imports":{"#shared":{"import":"./config/shared.ts","require":"./config/unused.cjs"}},"devDependencies":{"vite-plus":"latest"}} +'` + + +## `vpt write-file vite.config.ts 'import shared from '\''#shared'\''; +export default { ...shared }; +'` + + +## `vp fmt --check src/index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vp lint src/index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Updated . to Vite+ +• Node pnpm +• Dependencies: + vite-plus latest → + vite → +• Package manager settings configured +``` + +## `vpt print-file .oxfmtrc.json` + +``` +{ + "singleQuote": true, + "semi": false +} +``` + +## `vpt print-file .oxlintrc.json` + +``` +{ + "rules": { + "no-console": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + } +} +``` + +## `vpt print-file vite.config.ts` + +``` +import shared from '#shared'; +export default { ...shared }; +``` + +## `vp fmt --check src/index.js` + +the package import alias must still load its JSON configs + +``` +VITE+ - The Unified Toolchain for the Web + +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vp lint src/index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +▲ No package manager is declared in package.json; using pnpm for this migration without adding a pin. Run `vp env pin` to declare it explicitly. +This project is already using Vite+! Happy coding! +``` + +## `vp fmt --check src/index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vpt write-file src/index.js 'console.log('\''hello'\'') +'` + + +## `vp lint src/index.js` + +the indirectly imported lint rule remains active after two migrations + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + + × eslint(no-console): Unexpected console statement. + ╭─[src/index.js:1:1] + 1 │ console.log('hello') + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/snapshots/migration_shared_vite_config_module.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/snapshots/migration_shared_vite_config_module.md new file mode 100644 index 0000000000..52e0de1dfe --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/snapshots/migration_shared_vite_config_module.md @@ -0,0 +1,139 @@ +# migration_shared_vite_config_module + +## `vpt write-file package.json '{"name":"migration-shared-vite-config","devDependencies":{"vite-plus":"latest"}} +'` + + +## `vpt write-file vite.config.ts 'import shared from '\''./config/shared.js'\''; +export default { ...shared }; +'` + + +## `vp fmt --check src/index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vp lint src/index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Updated . to Vite+ +• Node pnpm +• Dependencies: + vite-plus latest → + vite → +• Package manager settings configured +``` + +## `vpt print-file .oxfmtrc.json` + +``` +{ + "singleQuote": true, + "semi": false +} +``` + +## `vpt print-file .oxlintrc.json` + +``` +{ + "rules": { + "no-console": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + } +} +``` + +## `vpt print-file vite.config.ts` + +``` +import shared from './config/shared.js'; +export default { ...shared }; +``` + +## `vp fmt --check src/index.js` + +the shared TypeScript module must still import its JSON configs + +``` +VITE+ - The Unified Toolchain for the Web + +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vp lint src/index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +▲ No package manager is declared in package.json; using pnpm for this migration without adding a pin. Run `vp env pin` to declare it explicitly. +This project is already using Vite+! Happy coding! +``` + +## `vp fmt --check src/index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vpt write-file src/index.js 'console.log('\''hello'\'') +'` + + +## `vp lint src/index.js` + +the indirectly imported lint rule remains active after two migrations + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + + × eslint(no-console): Unexpected console statement. + ╭─[src/index.js:1:1] + 1 │ console.log('hello') + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/src/index.js b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/src/index.js new file mode 100644 index 0000000000..854ef01aa3 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/src/index.js @@ -0,0 +1 @@ +export const message = 'preserved' diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/vite.config.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/vite.config.ts new file mode 100644 index 0000000000..ff8b4c5632 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_indirect_oxc_configs/vite.config.ts @@ -0,0 +1 @@ +export default {}; diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/.oxfmtrc.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/.oxfmtrc.json new file mode 100644 index 0000000000..fd496a820e --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/.oxfmtrc.json @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "semi": false +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/.oxlintrc.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/.oxlintrc.json new file mode 100644 index 0000000000..3a438765d5 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/.oxlintrc.json @@ -0,0 +1,9 @@ +{ + "rules": { + "no-console": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/package.json new file mode 100644 index 0000000000..75aeb4229e --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/package.json @@ -0,0 +1,12 @@ +{ + "name": "migration-oxc-ecosystem-delta-comic", + "private": true, + "type": "module", + "packageManager": "pnpm@12.3.4", + "devDependencies": { + "vite-plus": "latest" + }, + "scripts": { + "check": "vp check packages/app/src" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/packages/app/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/packages/app/package.json new file mode 100644 index 0000000000..33f2660adc --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/packages/app/package.json @@ -0,0 +1,5 @@ +{ + "name": "app", + "private": true, + "type": "module" +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/packages/app/src/index.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/packages/app/src/index.ts new file mode 100644 index 0000000000..38b0fa8a2f --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/packages/app/src/index.ts @@ -0,0 +1 @@ +export const message = "preserved"; diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/pnpm-workspace.yaml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/pnpm-workspace.yaml new file mode 100644 index 0000000000..924b55f42e --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - packages/* diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/snapshots.toml new file mode 100644 index 0000000000..051946a49b --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/snapshots.toml @@ -0,0 +1,16 @@ +[[case]] +name = "migration_oxc_ecosystem_delta_comic" +vp = "global" +comment = "Reproduces the typed JSON imports in https://github.com/vite-plus-ecosystem-ci/delta-comic/pull/9." +steps = [ + ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], + ["vpt", "print-file", ".oxlintrc.json"], + ["vpt", "print-file", ".oxfmtrc.json"], + ["vp", "fmt", "packages/app/src"], + ["vpt", "print-file", "packages/app/src/index.ts"], + ["vp", "run", "check"], + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "repeat migration without invalidating either JSON import" }, + ["vp", "run", "check"], + { argv = ["vpt", "write-file", "packages/app/src/index.ts", "console.log('hello')\n"], snapshot = false }, + { argv = ["vp", "run", "check"], comment = "vp check must still apply the imported lint rule", continue-on-failure = true }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/snapshots/migration_oxc_ecosystem_delta_comic.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/snapshots/migration_oxc_ecosystem_delta_comic.md new file mode 100644 index 0000000000..9cf7709794 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/snapshots/migration_oxc_ecosystem_delta_comic.md @@ -0,0 +1,115 @@ +# migration_oxc_ecosystem_delta_comic + +Reproduces the typed JSON imports in https://github.com/vite-plus-ecosystem-ci/delta-comic/pull/9. + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Updated . to Vite+ +• Node pnpm +• Dependencies: + vite-plus latest → + vite → +• Package manager settings configured +``` + +## `vpt print-file .oxlintrc.json` + +``` +{ + "rules": { + "no-console": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + } +} +``` + +## `vpt print-file .oxfmtrc.json` + +``` +{ + "singleQuote": true, + "semi": false +} +``` + +## `vp fmt packages/app/src` + +``` +VITE+ - The Unified Toolchain for the Web + +Finished in on 1 files using threads. +``` + +## `vpt print-file packages/app/src/index.ts` + +``` +export const message = 'preserved' +``` + +## `vp run check` + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp check packages/app/src ⊘ cache disabled +VITE+ - The Unified Toolchain for the Web + +pass: All 1 file are correctly formatted (, threads) +pass: Found no warnings or lint errors in 1 file (, threads) +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +repeat migration without invalidating either JSON import + +``` +VITE+ - The Unified Toolchain for the Web + +This project is already using Vite+! Happy coding! +``` + +## `vp run check` + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp check packages/app/src ⊘ cache disabled +VITE+ - The Unified Toolchain for the Web + +pass: All 1 file are correctly formatted (, threads) +pass: Found no warnings or lint errors in 1 file (, threads) +``` + +## `vpt write-file packages/app/src/index.ts 'console.log('\''hello'\'') +'` + + +## `vp run check` + +vp check must still apply the imported lint rule + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp check packages/app/src ⊘ cache disabled +VITE+ - The Unified Toolchain for the Web + +pass: All 1 file are correctly formatted (, threads) +error: Lint issues found +× eslint(no-console): Unexpected console statement. + ╭─[packages/app/src/index.ts:1:1] + 1 │ console.log('hello') + · ─────────── + ╰──── + help: Delete this console statement. + +Found 1 error and 0 warnings in 1 file (, threads) +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/vite.config.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/vite.config.ts new file mode 100644 index 0000000000..c2e9c9eec2 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_delta_comic/vite.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'vite-plus'; +import type { OxfmtConfig } from 'vite-plus/fmt'; +import type { OxlintConfig } from 'vite-plus/lint'; + +import fmt from './.oxfmtrc.json' with { type: 'json' }; +import lint from './.oxlintrc.json' with { type: 'json' }; + +export default defineConfig({ + fmt: fmt as OxfmtConfig, + lint: lint as OxlintConfig, +}); diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/.oxfmtrc.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/.oxfmtrc.json new file mode 100644 index 0000000000..fd496a820e --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/.oxfmtrc.json @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "semi": false +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/.oxlintrc.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/.oxlintrc.json new file mode 100644 index 0000000000..3a438765d5 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/.oxlintrc.json @@ -0,0 +1,9 @@ +{ + "rules": { + "no-console": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/package.json new file mode 100644 index 0000000000..b8383e58a3 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/package.json @@ -0,0 +1,14 @@ +{ + "name": "migration-oxc-ecosystem-freecut", + "private": true, + "type": "module", + "packageManager": "npm@11.16.0", + "devDependencies": { + "vite-plus": "latest" + }, + "scripts": { + "lint": "vp lint src", + "format": "vp fmt src .oxlintrc.json .oxfmtrc.json", + "format:check": "vp fmt src .oxlintrc.json .oxfmtrc.json --check" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/snapshots.toml new file mode 100644 index 0000000000..b4611bbb48 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/snapshots.toml @@ -0,0 +1,17 @@ +[[case]] +name = "migration_oxc_ecosystem_freecut" +vp = "global" +comment = "Reproduces the config file reads and script inputs in https://github.com/vite-plus-ecosystem-ci/freecut/pull/9." +steps = [ + ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], + ["vpt", "print-file", ".oxlintrc.json"], + ["vpt", "print-file", ".oxfmtrc.json"], + ["vp", "run", "format"], + ["vpt", "print-file", "src/index.ts"], + ["vp", "run", "lint"], + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "repeat migration without deleting either file read by vite.config.ts" }, + ["vp", "run", "format:check"], + ["vp", "run", "lint"], + { argv = ["vpt", "write-file", "src/index.ts", "console.log('hello')\n"], snapshot = false }, + { argv = ["vp", "run", "lint"], comment = "the rules read from the retained JSON must still apply", continue-on-failure = true }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/snapshots/migration_oxc_ecosystem_freecut.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/snapshots/migration_oxc_ecosystem_freecut.md new file mode 100644 index 0000000000..77b1cbed9f --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/snapshots/migration_oxc_ecosystem_freecut.md @@ -0,0 +1,122 @@ +# migration_oxc_ecosystem_freecut + +Reproduces the config file reads and script inputs in https://github.com/vite-plus-ecosystem-ci/freecut/pull/9. + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Updated . to Vite+ +• Node npm +• Dependencies: + vite-plus latest → + vite → +• Package manager settings configured +``` + +## `vpt print-file .oxlintrc.json` + +``` +{ + "rules": { + "no-console": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + } +} +``` + +## `vpt print-file .oxfmtrc.json` + +``` +{ + "singleQuote": true, + "semi": false +} +``` + +## `vp run format` + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp fmt src .oxlintrc.json .oxfmtrc.json ⊘ cache disabled +Finished in on 3 files using threads. +``` + +## `vpt print-file src/index.ts` + +``` +export const message = 'preserved' +``` + +## `vp run lint` + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp lint src ⊘ cache disabled +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +repeat migration without deleting either file read by vite.config.ts + +``` +VITE+ - The Unified Toolchain for the Web + +This project is already using Vite+! Happy coding! +``` + +## `vp run format:check` + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp fmt src .oxlintrc.json .oxfmtrc.json --check ⊘ cache disabled +Checking formatting... + +All matched files use the correct format. +Finished in on 3 files using threads. +``` + +## `vp run lint` + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp lint src ⊘ cache disabled +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vpt write-file src/index.ts 'console.log('\''hello'\'') +'` + + +## `vp run lint` + +the rules read from the retained JSON must still apply + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp lint src ⊘ cache disabled + + × eslint(no-console): Unexpected console statement. + ╭─[src/index.ts:1:1] + 1 │ console.log('hello') + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/src/index.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/src/index.ts new file mode 100644 index 0000000000..38b0fa8a2f --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/src/index.ts @@ -0,0 +1 @@ +export const message = "preserved"; diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/vite.config.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/vite.config.ts new file mode 100644 index 0000000000..4473993950 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_freecut/vite.config.ts @@ -0,0 +1,16 @@ +import { readFileSync } from 'node:fs'; +import { defineConfig } from 'vite-plus'; + +const oxlintConfig = JSON.parse(readFileSync(new URL('./.oxlintrc.json', import.meta.url), 'utf8')); +const oxfmtConfig = JSON.parse(readFileSync(new URL('./.oxfmtrc.json', import.meta.url), 'utf8')); + +export default defineConfig({ + lint: { + ...oxlintConfig, + ignorePatterns: ['dist/**'], + }, + fmt: { + ...oxfmtConfig, + ignorePatterns: ['dist/**'], + }, +}); diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/.oxfmtrc.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/.oxfmtrc.json new file mode 100644 index 0000000000..fd496a820e --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/.oxfmtrc.json @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "semi": false +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/.oxlintrc.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/.oxlintrc.json new file mode 100644 index 0000000000..3a438765d5 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/.oxlintrc.json @@ -0,0 +1,9 @@ +{ + "rules": { + "no-console": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/package.json new file mode 100644 index 0000000000..be73e816c3 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/package.json @@ -0,0 +1,18 @@ +{ + "name": "migration-oxc-ecosystem-pdfme", + "private": true, + "type": "module", + "packageManager": "npm@11.16.0", + "workspaces": [ + "packages/*" + ], + "devDependencies": { + "vite-plus": "latest" + }, + "scripts": { + "lint": "vp run --filter '@pdfme/*' lint", + "lint:root": "vp lint --config .oxlintrc.json packages/common/src", + "fmt": "vp run --filter '@pdfme/*' fmt", + "fmt:check": "vp fmt -c .oxfmtrc.json packages/common/src --check" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/packages/common/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/packages/common/package.json new file mode 100644 index 0000000000..ccc47b9cb6 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/packages/common/package.json @@ -0,0 +1,9 @@ +{ + "name": "@pdfme/common", + "private": true, + "type": "module", + "scripts": { + "lint": "vp lint -c ../../.oxlintrc.json src", + "fmt": "vp fmt -c ../../.oxfmtrc.json src --write" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/packages/common/src/index.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/packages/common/src/index.ts new file mode 100644 index 0000000000..38b0fa8a2f --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/packages/common/src/index.ts @@ -0,0 +1 @@ +export const message = "preserved"; diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/playground/.oxlintrc.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/playground/.oxlintrc.json new file mode 100644 index 0000000000..4c4b01a512 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/playground/.oxlintrc.json @@ -0,0 +1,11 @@ +{ + "extends": ["../.oxlintrc.json"], + "overrides": [ + { + "files": ["e2e/**/*.ts"], + "rules": { + "no-console": "off" + } + } + ] +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/playground/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/playground/package.json new file mode 100644 index 0000000000..b25713e9bc --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/playground/package.json @@ -0,0 +1,5 @@ +{ + "name": "playground", + "private": true, + "type": "module" +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/playground/src/index.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/playground/src/index.ts new file mode 100644 index 0000000000..d6e8d0722e --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/playground/src/index.ts @@ -0,0 +1 @@ +export const message = 'playground'; diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/snapshots.toml new file mode 100644 index 0000000000..efa53dbe35 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/snapshots.toml @@ -0,0 +1,45 @@ +[[case]] +name = "migration_oxc_ecosystem_pdfme" +vp = "global" +comment = "Reproduces the root and workspace config flags and playground inheritance in https://github.com/vite-plus-ecosystem-ci/pdfme/pull/7." +steps = [ + ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], + ["vpt", "print-file", ".oxlintrc.json"], + ["vpt", "print-file", ".oxfmtrc.json"], + ["vpt", "print-file", "playground/.oxlintrc.json"], + ["vp", "run", "fmt"], + ["vpt", "print-file", "packages/common/src/index.ts"], + ["vp", "run", "fmt:check"], + ["vp", "run", "lint"], + ["vp", "run", "lint:root"], + { argv = ["vp", "lint", "-c", ".oxlintrc.json", "src"], cwd = "playground" }, + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "repeat migration and rerun scripts from both the root and a workspace" }, + ["vp", "run", "fmt:check"], + { argv = ["vp", "run", "fmt"], cwd = "packages/common" }, + { argv = ["vp", "run", "lint"], cwd = "packages/common" }, + { argv = ["vpt", "write-file", "packages/common/src/index.ts", "console.log('hello')\n"], snapshot = false }, + { argv = ["vpt", "write-file", "playground/src/index.ts", "console.log('hello')\n"], snapshot = false }, + { argv = ["vp", "run", "lint"], comment = "the workspace script must still use the root JSON rules", continue-on-failure = true }, + { argv = ["vp", "lint", "-c", ".oxlintrc.json", "src"], cwd = "playground", comment = "the playground must still inherit the root JSON rules", continue-on-failure = true }, +] + +[[case]] +name = "migration_oxc_ecosystem_pdfme_inline_config" +vp = ["local", "global"] +comment = "Explicit config paths in pdfme-style scripts must also work when inline lint and fmt options exist." +steps = [ + { argv = ["vpt", "write-file", "vite.config.mts", "export default { lint: { rules: { 'no-console': 'off' } }, fmt: { singleQuote: false, semi: true } };\n"], snapshot = false }, + ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], + ["vpt", "print-file", ".oxlintrc.json"], + ["vpt", "print-file", ".oxfmtrc.json"], + ["vp", "run", "fmt"], + ["vpt", "print-file", "packages/common/src/index.ts"], + ["vp", "run", "fmt:check"], + ["vp", "run", "lint"], + ["vp", "run", "lint:root"], + ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], + ["vp", "run", "fmt:check"], + { argv = ["vpt", "write-file", "packages/common/src/index.ts", "console.log('hello')\n"], snapshot = false }, + { argv = ["vp", "run", "lint"], comment = "the explicit JSON rule must override the inline no-console setting", continue-on-failure = true }, + { argv = ["vp", "run", "lint:root"], comment = "the root --config script must also use the explicit JSON rule", continue-on-failure = true }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/snapshots/migration_oxc_ecosystem_pdfme.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/snapshots/migration_oxc_ecosystem_pdfme.md new file mode 100644 index 0000000000..af300fde79 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/snapshots/migration_oxc_ecosystem_pdfme.md @@ -0,0 +1,202 @@ +# migration_oxc_ecosystem_pdfme + +Reproduces the root and workspace config flags and playground inheritance in https://github.com/vite-plus-ecosystem-ci/pdfme/pull/7. + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Updated . to Vite+ +• Node npm +• Dependencies: + vite-plus latest → + vite → +• Package manager settings configured +``` + +## `vpt print-file .oxlintrc.json` + +``` +{ + "rules": { + "no-console": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + } +} +``` + +## `vpt print-file .oxfmtrc.json` + +``` +{ + "singleQuote": true, + "semi": false +} +``` + +## `vpt print-file playground/.oxlintrc.json` + +``` +{ + "extends": ["../.oxlintrc.json"], + "overrides": [ + { + "files": ["e2e/**/*.ts"], + "rules": { + "no-console": "off" + } + } + ] +} +``` + +## `vp run fmt` + +``` +VITE+ - The Unified Toolchain for the Web + +~/packages/common$ vp fmt -c ../../.oxfmtrc.json src --write ⊘ cache disabled +Finished in on 1 files using threads. +``` + +## `vpt print-file packages/common/src/index.ts` + +``` +export const message = 'preserved' +``` + +## `vp run fmt:check` + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp fmt -c .oxfmtrc.json packages/common/src --check ⊘ cache disabled +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vp run lint` + +``` +VITE+ - The Unified Toolchain for the Web + +~/packages/common$ vp lint -c ../../.oxlintrc.json src ⊘ cache disabled +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp run lint:root` + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp lint --config .oxlintrc.json packages/common/src ⊘ cache disabled +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `cd playground && vp lint -c .oxlintrc.json src` + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +repeat migration and rerun scripts from both the root and a workspace + +``` +VITE+ - The Unified Toolchain for the Web + +This project is already using Vite+! Happy coding! +``` + +## `vp run fmt:check` + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp fmt -c .oxfmtrc.json packages/common/src --check ⊘ cache disabled +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `cd packages/common && vp run fmt` + +``` +VITE+ - The Unified Toolchain for the Web + +~/packages/common$ vp fmt -c ../../.oxfmtrc.json src --write ⊘ cache disabled +Finished in on 1 files using threads. +``` + +## `cd packages/common && vp run lint` + +``` +VITE+ - The Unified Toolchain for the Web + +~/packages/common$ vp lint -c ../../.oxlintrc.json src ⊘ cache disabled +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vpt write-file packages/common/src/index.ts 'console.log('\''hello'\'') +'` + + +## `vpt write-file playground/src/index.ts 'console.log('\''hello'\'') +'` + + +## `vp run lint` + +the workspace script must still use the root JSON rules + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + +~/packages/common$ vp lint -c ../../.oxlintrc.json src ⊘ cache disabled + + × eslint(no-console): Unexpected console statement. + ╭─[src/index.ts:1:1] + 1 │ console.log('hello') + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` + +## `cd playground && vp lint -c .oxlintrc.json src` + +the playground must still inherit the root JSON rules + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + + × eslint(no-console): Unexpected console statement. + ╭─[src/index.ts:1:1] + 1 │ console.log('hello') + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/snapshots/migration_oxc_ecosystem_pdfme_inline_config.global.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/snapshots/migration_oxc_ecosystem_pdfme_inline_config.global.md new file mode 100644 index 0000000000..7766dd70b6 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/snapshots/migration_oxc_ecosystem_pdfme_inline_config.global.md @@ -0,0 +1,158 @@ +# migration_oxc_ecosystem_pdfme_inline_config + +Explicit config paths in pdfme-style scripts must also work when inline lint and fmt options exist. + +## `vpt write-file vite.config.mts 'export default { lint: { rules: { '\''no-console'\'': '\''off'\'' } }, fmt: { singleQuote: false, semi: true } }; +'` + + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Updated . to Vite+ +• Node npm +• Dependencies: + vite-plus latest → + vite → +• Package manager settings configured +``` + +## `vpt print-file .oxlintrc.json` + +``` +{ + "rules": { + "no-console": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + } +} +``` + +## `vpt print-file .oxfmtrc.json` + +``` +{ + "singleQuote": true, + "semi": false +} +``` + +## `vp run fmt` + +``` +VITE+ - The Unified Toolchain for the Web + +~/packages/common$ vp fmt -c ../../.oxfmtrc.json src --write ⊘ cache disabled +Finished in on 1 files using threads. +``` + +## `vpt print-file packages/common/src/index.ts` + +``` +export const message = 'preserved' +``` + +## `vp run fmt:check` + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp fmt -c .oxfmtrc.json packages/common/src --check ⊘ cache disabled +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vp run lint` + +``` +VITE+ - The Unified Toolchain for the Web + +~/packages/common$ vp lint -c ../../.oxlintrc.json src ⊘ cache disabled +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp run lint:root` + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp lint --config .oxlintrc.json packages/common/src ⊘ cache disabled +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +This project is already using Vite+! Happy coding! +``` + +## `vp run fmt:check` + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp fmt -c .oxfmtrc.json packages/common/src --check ⊘ cache disabled +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vpt write-file packages/common/src/index.ts 'console.log('\''hello'\'') +'` + + +## `vp run lint` + +the explicit JSON rule must override the inline no-console setting + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + +~/packages/common$ vp lint -c ../../.oxlintrc.json src ⊘ cache disabled + + × eslint(no-console): Unexpected console statement. + ╭─[src/index.ts:1:1] + 1 │ console.log('hello') + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` + +## `vp run lint:root` + +the root --config script must also use the explicit JSON rule + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp lint --config .oxlintrc.json packages/common/src ⊘ cache disabled + + × eslint(no-console): Unexpected console statement. + ╭─[packages/common/src/index.ts:1:1] + 1 │ console.log('hello') + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/snapshots/migration_oxc_ecosystem_pdfme_inline_config.local.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/snapshots/migration_oxc_ecosystem_pdfme_inline_config.local.md new file mode 100644 index 0000000000..e34ebfe7ef --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/snapshots/migration_oxc_ecosystem_pdfme_inline_config.local.md @@ -0,0 +1,144 @@ +# migration_oxc_ecosystem_pdfme_inline_config + +Explicit config paths in pdfme-style scripts must also work when inline lint and fmt options exist. + +## `vpt write-file vite.config.mts 'export default { lint: { rules: { '\''no-console'\'': '\''off'\'' } }, fmt: { singleQuote: false, semi: true } }; +'` + + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Updated . to Vite+ +• Node npm +• Dependencies: + vite-plus latest → + vite → +• Package manager settings configured +``` + +## `vpt print-file .oxlintrc.json` + +``` +{ + "rules": { + "no-console": "error" + }, + "options": { + "typeAware": false, + "typeCheck": false + } +} +``` + +## `vpt print-file .oxfmtrc.json` + +``` +{ + "singleQuote": true, + "semi": false +} +``` + +## `vp run fmt` + +``` +~/packages/common$ vp fmt -c ../../.oxfmtrc.json src --write ⊘ cache disabled +Finished in on 1 files using threads. +``` + +## `vpt print-file packages/common/src/index.ts` + +``` +export const message = 'preserved' +``` + +## `vp run fmt:check` + +``` +$ vp fmt -c .oxfmtrc.json packages/common/src --check ⊘ cache disabled +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vp run lint` + +``` +~/packages/common$ vp lint -c ../../.oxlintrc.json src ⊘ cache disabled +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp run lint:root` + +``` +$ vp lint --config .oxlintrc.json packages/common/src ⊘ cache disabled +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +This project is already using Vite+! Happy coding! +``` + +## `vp run fmt:check` + +``` +$ vp fmt -c .oxfmtrc.json packages/common/src --check ⊘ cache disabled +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vpt write-file packages/common/src/index.ts 'console.log('\''hello'\'') +'` + + +## `vp run lint` + +the explicit JSON rule must override the inline no-console setting + +**Exit code:** 1 + +``` +~/packages/common$ vp lint -c ../../.oxlintrc.json src ⊘ cache disabled + + × eslint(no-console): Unexpected console statement. + ╭─[src/index.ts:1:1] + 1 │ console.log('hello') + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` + +## `vp run lint:root` + +the root --config script must also use the explicit JSON rule + +**Exit code:** 1 + +``` +$ vp lint --config .oxlintrc.json packages/common/src ⊘ cache disabled + + × eslint(no-console): Unexpected console statement. + ╭─[packages/common/src/index.ts:1:1] + 1 │ console.log('hello') + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/vite.config.mts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/vite.config.mts new file mode 100644 index 0000000000..c62e7a59fe --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_pdfme/vite.config.mts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite-plus'; + +export default defineConfig({ + run: { + enablePrePostScripts: true, + }, +}); diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/.oxlintrc.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/.oxlintrc.json new file mode 100644 index 0000000000..2ff50f91ec --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/.oxlintrc.json @@ -0,0 +1,5 @@ +{ + "rules": { + "no-console": "error" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/custom-domain/.oxlintrc.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/custom-domain/.oxlintrc.json new file mode 100644 index 0000000000..8e2ab53210 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/custom-domain/.oxlintrc.json @@ -0,0 +1,6 @@ +{ + "extends": ["../../.oxlintrc.json"], + "rules": { + "no-alert": "off" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/custom-domain/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/custom-domain/package.json new file mode 100644 index 0000000000..701939fcf2 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/custom-domain/package.json @@ -0,0 +1,5 @@ +{ + "name": "custom-domain", + "private": true, + "type": "module" +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/custom-domain/src/index.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/custom-domain/src/index.ts new file mode 100644 index 0000000000..42838525f1 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/custom-domain/src/index.ts @@ -0,0 +1 @@ +export const message = 'custom domain'; diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/sigle/.oxlintrc.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/sigle/.oxlintrc.json new file mode 100644 index 0000000000..8e2ab53210 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/sigle/.oxlintrc.json @@ -0,0 +1,6 @@ +{ + "extends": ["../../.oxlintrc.json"], + "rules": { + "no-alert": "off" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/sigle/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/sigle/package.json new file mode 100644 index 0000000000..7e69add5a4 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/sigle/package.json @@ -0,0 +1,5 @@ +{ + "name": "sigle", + "private": true, + "type": "module" +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/sigle/src/index.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/sigle/src/index.ts new file mode 100644 index 0000000000..1e96b75ca7 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/sigle/src/index.ts @@ -0,0 +1 @@ +export const message = 'sigle'; diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/sigle/vite.config.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/sigle/vite.config.ts new file mode 100644 index 0000000000..8abe24a2a4 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/apps/sigle/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite-plus'; + +export default defineConfig({ + resolve: { + tsconfigPaths: true, + }, +}); diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/package.json new file mode 100644 index 0000000000..9d4e608c4c --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/package.json @@ -0,0 +1,9 @@ +{ + "name": "migration-oxc-ecosystem-sigle", + "private": true, + "type": "module", + "packageManager": "pnpm@12.3.4", + "devDependencies": { + "vite-plus": "latest" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/pnpm-workspace.yaml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/pnpm-workspace.yaml new file mode 100644 index 0000000000..852bf6b8f9 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - apps/* diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/snapshots.toml new file mode 100644 index 0000000000..54eed080fd --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/snapshots.toml @@ -0,0 +1,21 @@ +[[case]] +name = "migration_oxc_ecosystem_sigle" +vp = "global" +comment = "Reproduces the two app-level JSON extends configs in https://github.com/vite-plus-ecosystem-ci/sigle/pull/8, with a shared base to verify inherited rules." +steps = [ + ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], + ["vpt", "print-file", ".oxlintrc.ts"], + ["vpt", "stat-file", "apps/sigle/.oxlintrc.json", "--assert", "missing"], + ["vpt", "stat-file", "apps/custom-domain/.oxlintrc.json", "--assert", "missing"], + { argv = ["vpt", "print-file", "apps/sigle/vite.config.ts"], comment = "the existing Vite config must import the shared TypeScript rules" }, + { argv = ["vpt", "print-file", "apps/custom-domain/vite.config.ts"], comment = "create a Vite config for the migrated inherited rules" }, + { argv = ["vp", "lint", "src"], cwd = "apps/sigle" }, + { argv = ["vp", "lint", "src"], cwd = "apps/custom-domain" }, + ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], + ["vpt", "print-file", "apps/sigle/vite.config.ts"], + ["vpt", "print-file", "apps/custom-domain/vite.config.ts"], + { argv = ["vpt", "write-file", "apps/sigle/src/index.ts", "console.log('hello');\n"], snapshot = false }, + { argv = ["vpt", "write-file", "apps/custom-domain/src/index.ts", "console.log('hello');\n"], snapshot = false }, + { argv = ["vp", "lint", "src"], cwd = "apps/sigle", comment = "the app must still apply its inherited rule without -c", continue-on-failure = true }, + { argv = ["vp", "lint", "src"], cwd = "apps/custom-domain", comment = "the app without vite.config.ts must also apply its inherited rule without -c", continue-on-failure = true }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/snapshots/migration_oxc_ecosystem_sigle.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/snapshots/migration_oxc_ecosystem_sigle.md new file mode 100644 index 0000000000..8e7a4ae0cb --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/snapshots/migration_oxc_ecosystem_sigle.md @@ -0,0 +1,222 @@ +# migration_oxc_ecosystem_sigle + +Reproduces the two app-level JSON extends configs in https://github.com/vite-plus-ecosystem-ci/sigle/pull/8, with a shared base to verify inherited rules. + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Updated . to Vite+ +• Node pnpm +• Dependencies: + vite-plus latest → + vite → +• 3 config updates applied +• Package manager settings configured +! Warnings: + - Preserved .oxlintrc.json because vite.config.ts already has a lint config. Merge its inherited rules manually. +``` + +## `vpt print-file .oxlintrc.ts` + +``` +// Generated by vp migrate from .oxlintrc.json. +import type { OxlintConfig } from "vite-plus/lint"; + +export default { + "rules": { + "no-console": "error" + } +} satisfies OxlintConfig; +``` + +## `vpt stat-file apps/sigle/.oxlintrc.json --assert missing` + +``` +apps/sigle/.oxlintrc.json: missing +``` + +## `vpt stat-file apps/custom-domain/.oxlintrc.json --assert missing` + +``` +apps/custom-domain/.oxlintrc.json: missing +``` + +## `vpt print-file apps/sigle/vite.config.ts` + +the existing Vite config must import the shared TypeScript rules + +``` +// vp migrate: merged apps%2Fsigle%2F.oxlintrc.json (37ebf49fc5fb9b317632070f58d36ce2). +import oxlintConfig1 from "../../.oxlintrc.js"; +import { defineConfig } from 'vite-plus'; + +export default defineConfig({ + lint: { + "extends": [oxlintConfig1], + "rules": { + "no-alert": "off", + "vite-plus/prefer-vite-plus-imports": "error" + }, + "options": { + "typeAware": true, + "typeCheck": true + }, + "jsPlugins": [{ "name": "vite-plus", "specifier": "vite-plus/oxlint-plugin" }] + }, + resolve: { + tsconfigPaths: true, + }, +}); +``` + +## `vpt print-file apps/custom-domain/vite.config.ts` + +create a Vite config for the migrated inherited rules + +``` +// vp migrate: merged apps%2Fcustom-domain%2F.oxlintrc.json (1be7219bedd302f07470f23cd73129b0). +import oxlintConfig1 from "../../.oxlintrc.js"; +import { defineConfig } from 'vite-plus'; + +export default defineConfig({ + lint: { + "extends": [oxlintConfig1], + "rules": { + "no-alert": "off", + "vite-plus/prefer-vite-plus-imports": "error" + }, + "options": { + "typeAware": true, + "typeCheck": true + }, + "jsPlugins": [{ "name": "vite-plus", "specifier": "vite-plus/oxlint-plugin" }] + }, + +}); +``` + +## `cd apps/sigle && vp lint src` + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `cd apps/custom-domain && vp lint src` + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +``` +VITE+ - The Unified Toolchain for the Web + +This project is already using Vite+! Happy coding! +``` + +## `vpt print-file apps/sigle/vite.config.ts` + +``` +// vp migrate: merged apps%2Fsigle%2F.oxlintrc.json (37ebf49fc5fb9b317632070f58d36ce2). +import oxlintConfig1 from "../../.oxlintrc.js"; +import { defineConfig } from 'vite-plus'; + +export default defineConfig({ + lint: { + "extends": [oxlintConfig1], + "rules": { + "no-alert": "off", + "vite-plus/prefer-vite-plus-imports": "error" + }, + "options": { + "typeAware": true, + "typeCheck": true + }, + "jsPlugins": [{ "name": "vite-plus", "specifier": "vite-plus/oxlint-plugin" }] + }, + resolve: { + tsconfigPaths: true, + }, +}); +``` + +## `vpt print-file apps/custom-domain/vite.config.ts` + +``` +// vp migrate: merged apps%2Fcustom-domain%2F.oxlintrc.json (1be7219bedd302f07470f23cd73129b0). +import oxlintConfig1 from "../../.oxlintrc.js"; +import { defineConfig } from 'vite-plus'; + +export default defineConfig({ + lint: { + "extends": [oxlintConfig1], + "rules": { + "no-alert": "off", + "vite-plus/prefer-vite-plus-imports": "error" + }, + "options": { + "typeAware": true, + "typeCheck": true + }, + "jsPlugins": [{ "name": "vite-plus", "specifier": "vite-plus/oxlint-plugin" }] + }, + +}); +``` + +## `vpt write-file apps/sigle/src/index.ts 'console.log('\''hello'\''); +'` + + +## `vpt write-file apps/custom-domain/src/index.ts 'console.log('\''hello'\''); +'` + + +## `cd apps/sigle && vp lint src` + +the app must still apply its inherited rule without -c + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + + × eslint(no-console): Unexpected console statement. + ╭─[src/index.ts:1:1] + 1 │ console.log('hello'); + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` + +## `cd apps/custom-domain && vp lint src` + +the app without vite.config.ts must also apply its inherited rule without -c + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + + × eslint(no-console): Unexpected console statement. + ╭─[src/index.ts:1:1] + 1 │ console.log('hello'); + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/vite.config.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/vite.config.ts new file mode 100644 index 0000000000..a21ea9b063 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxc_ecosystem_sigle/vite.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite-plus'; + +export default defineConfig({ + lint: { + rules: { + 'no-console': 'off', + }, + }, + fmt: { + singleQuote: true, + }, +}); diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlint_extends_workspace/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlint_extends_workspace/snapshots.toml index f814be252f..f8c4b44833 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlint_extends_workspace/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlint_extends_workspace/snapshots.toml @@ -308,10 +308,10 @@ steps = [ { argv = ["vpt", "write-file", "packages/c/.oxlintrc.json", '{"extends":["../../shared/base.json"]}'], snapshot = false }, { argv = ["vpt", "write-file", "packages/c/index.js", 'console.log("hello");'], snapshot = false }, { argv = ["vp", "lint", "--threads=1", "-c", ".oxlintrc.json", "index.js"], cwd = "packages/c", comment = "A new workspace uses the retained shared JSON", continue-on-failure = true }, - { argv = ["vp", "migrate", "--no-interactive", "--no-agent", "--no-editor", "--no-hooks"], comment = "An upgrade does not treat shared modules as a pending migration for the new workspace" }, - { argv = ["vpt", "print-file", "packages/c/vite.config.mjs"], comment = "The unmarked workspace keeps its original Vite config" }, - { argv = ["vpt", "print-file", "packages/c/.oxlintrc.json"], comment = "Its newly authored JSON config remains intact" }, - { argv = ["vp", "lint", "--threads=1", "-c", ".oxlintrc.json", "index.js"], cwd = "packages/c", comment = "The JSON config retains the same lint output", continue-on-failure = true }, + { argv = ["vp", "migrate", "--no-interactive", "--no-agent", "--no-editor", "--no-hooks"], comment = "Recover the unreferenced workspace config even without a pending marker" }, + { argv = ["vpt", "print-file", "packages/c/vite.config.mjs"], comment = "The workspace imports the existing shared module" }, + { argv = ["vpt", "stat-file", "packages/c/.oxlintrc.json", "--assert", "missing"], comment = "The recovered config no longer needs its standalone JSON" }, + { argv = ["vp", "lint", "--threads=1", "index.js"], cwd = "packages/c", comment = "Plain lint retains the same diagnostic and exit status", continue-on-failure = true }, ] [[case]] @@ -323,11 +323,39 @@ steps = [ { argv = ["vp", "add", "-D", "vite-plus", "prettier@3.6.2"], snapshot = false }, { argv = ["vpt", "write-file", ".prettierrc.json", '{"singleQuote":true}'], snapshot = false }, { argv = ["vp", "lint", "--threads=1", "-c", ".oxlintrc.json", "index.js"], cwd = "packages/a", comment = "The existing workspace consumer inherits the root JSON rule" }, - { argv = ["vp", "migrate", "--full", "--no-interactive", "--no-agent", "--no-editor", "--no-hooks"], comment = "Prettier migration merges the root configs without migrating package configs" }, + { argv = ["vp", "migrate", "--full", "--no-interactive", "--no-agent", "--no-editor", "--no-hooks"], comment = "Recover workspace configs and merge the migrated Prettier config" }, { argv = ["vpt", "print-file", "vite.config.mjs"], comment = "The root uses its shared module" }, - { argv = ["vpt", "stat-file", ".oxlintrc.json", "--assert", "file"], comment = "The root JSON remains available to untouched consumers" }, + { argv = ["vpt", "stat-file", ".oxlintrc.json", "--assert", "file"], comment = "The root JSON remains available to package b while its output conflict remains" }, { argv = ["vpt", "stat-file", ".oxlintrc.ts", "--assert", "file"] }, - { argv = ["vpt", "print-file", "packages/a/vite.config.mjs"], comment = "The package Vite config remains unchanged" }, - { argv = ["vp", "lint", "--threads=1", "-c", ".oxlintrc.json", "index.js"], cwd = "packages/a", comment = "The preserved package JSON still reports the same diagnostic" }, + { argv = ["vpt", "print-file", "packages/a/vite.config.mjs"], comment = "The recovered package uses the shared module" }, + { argv = ["vpt", "stat-file", "packages/a/.oxlintrc.json", "--assert", "file"] }, + { argv = ["vp", "lint", "--threads=1", "index.js"], cwd = "packages/a", comment = "The recovered package reports the same diagnostic" }, { argv = ["vp", "lint", "--threads=1", "index.js"], comment = "The migrated root enforces the same rule" }, ] + + +[[case]] +name = "migration_oxc_reference_retry" +vp = ["global", "local"] +local-registry = true +unset-env = ["VP_SKIP_INSTALL"] +steps = [ + { argv = ["vpt", "json-edit", ".oxlintrc.json", "rules.no-debugger", '"error"'], snapshot = false }, + { argv = ["vp", "migrate", "--no-interactive", "--no-agent", "--no-editor", "--no-hooks"], comment = "Package b cannot merge while extra.ts conflicts with its config" }, + { argv = ["vpt", "json-edit", "package.json", "scripts.lint:a", '"vp lint -c packages/a/.oxlintrc.json packages/a/index.js"'], snapshot = false }, + { argv = ["vpt", "json-edit", "package.json", "scripts.lint:b", '"vp lint -c packages/b/.oxlintrc.json packages/b/index.js"'], snapshot = false }, + { argv = ["vpt", "rm", "packages/b/extra.ts"], snapshot = false }, + { argv = ["vp", "migrate", "--no-interactive", "--no-agent", "--no-editor", "--no-hooks"], comment = "New script references protect both completed and pending JSON configs on retry" }, + ["vpt", "stat-file", ".oxlintrc.json", "--assert", "file"], + ["vpt", "stat-file", "packages/a/.oxlintrc.json", "--assert", "file"], + ["vpt", "stat-file", "packages/b/.oxlintrc.json", "--assert", "file"], + ["vpt", "print-file", "packages/b/vite.config.mjs"], + { argv = ["vp", "run", "lint:a"], comment = "The completed config remains usable as JSON", continue-on-failure = true }, + { argv = ["vp", "run", "lint:b"], comment = "The pending config retains its complete inheritance chain", continue-on-failure = true }, + { argv = ["vpt", "json-edit", "package.json", "scripts", '{}'], continue-on-failure = true }, + { argv = ["vp", "migrate", "--no-interactive", "--no-agent", "--no-editor", "--no-hooks"], comment = "Removing the references allows migration and deferred cleanup to finish" }, + ["vpt", "stat-file", ".oxlintrc.json", "--assert", "missing"], + ["vpt", "stat-file", "packages/a/.oxlintrc.json", "--assert", "missing"], + ["vpt", "stat-file", "packages/b/.oxlintrc.json", "--assert", "missing"], + { argv = ["vp", "lint", "--threads=1", "index.js"], cwd = "packages/b", comment = "Plain lint enforces the inherited error after recovery", continue-on-failure = true }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlint_extends_workspace/snapshots/migration_oxc_reference_retry.global.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlint_extends_workspace/snapshots/migration_oxc_reference_retry.global.md new file mode 100644 index 0000000000..02b66cda7f --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlint_extends_workspace/snapshots/migration_oxc_reference_retry.global.md @@ -0,0 +1,172 @@ +# migration_oxc_reference_retry + +## `vpt json-edit .oxlintrc.json rules.no-debugger '"error"'` + + +## `vp migrate --no-interactive --no-agent --no-editor --no-hooks` + +Package b cannot merge while extra.ts conflicts with its config + +``` +VITE+ - The Unified Toolchain for the Web + +▲ No package manager is declared in package.json; using pnpm for this migration without adding a pin. Run `vp env pin` to declare it explicitly. +◆ ✔ Merged .oxlintrc.json into vite.config.mjs +● Formatting code... +● Code formatted +◇ Migrated . to Vite+ +• Node pnpm +✓ Dependencies installed in +• 1 config update applied +! Warnings: + - Could not migrate packages/b/.oxlintrc.json: Error: Cannot create shared Oxlint config because /packages/b/extra.ts or /packages/b/extra.js already exists. The original config was preserved; use vp lint -c packages/b/.oxlintrc.json until it is migrated manually. +``` + +## `vpt json-edit package.json scripts.lint:a '"vp lint -c packages/a/.oxlintrc.json packages/a/index.js"'` + + +## `vpt json-edit package.json scripts.lint:b '"vp lint -c packages/b/.oxlintrc.json packages/b/index.js"'` + + +## `vpt rm packages/b/extra.ts` + + +## `vp migrate --no-interactive --no-agent --no-editor --no-hooks` + +New script references protect both completed and pending JSON configs on retry + +``` +VITE+ - The Unified Toolchain for the Web + +▲ No package manager is declared in package.json; using pnpm for this migration without adding a pin. Run `vp env pin` to declare it explicitly. +This project is already using Vite+! Happy coding! +``` + +## `vpt stat-file .oxlintrc.json --assert file` + +``` +.oxlintrc.json: file +``` + +## `vpt stat-file packages/a/.oxlintrc.json --assert file` + +``` +packages/a/.oxlintrc.json: file +``` + +## `vpt stat-file packages/b/.oxlintrc.json --assert file` + +``` +packages/b/.oxlintrc.json: file +``` + +## `vpt print-file packages/b/vite.config.mjs` + +``` +export default {}; +// vp migrate: pending .oxlintrc.json. +``` + +## `vp run lint:a` + +The completed config remains usable as JSON + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp lint -c packages/a/.oxlintrc.json packages/a/index.js ⊘ cache disabled + + × eslint(no-debugger): `debugger` statement is not allowed + ╭─[packages/a/index.js:1:1] + 1 │ debugger; + · ───────── + ╰──── + help: Remove the debugger statement + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` + +## `vp run lint:b` + +The pending config retains its complete inheritance chain + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp lint -c packages/b/.oxlintrc.json packages/b/index.js ⊘ cache disabled + + × eslint(no-debugger): `debugger` statement is not allowed + ╭─[packages/b/index.js:1:1] + 1 │ debugger; + · ───────── + ╰──── + help: Remove the debugger statement + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` + +## `vpt json-edit package.json scripts {}` + +``` +``` + +## `vp migrate --no-interactive --no-agent --no-editor --no-hooks` + +Removing the references allows migration and deferred cleanup to finish + +``` +VITE+ - The Unified Toolchain for the Web + +▲ No package manager is declared in package.json; using pnpm for this migration without adding a pin. Run `vp env pin` to declare it explicitly. +● Formatting code... +● Code formatted +◇ Updated . to Vite+ +• Node pnpm +• Dependencies: + vite → +• 1 config update applied +``` + +## `vpt stat-file .oxlintrc.json --assert missing` + +``` +.oxlintrc.json: missing +``` + +## `vpt stat-file packages/a/.oxlintrc.json --assert missing` + +``` +packages/a/.oxlintrc.json: missing +``` + +## `vpt stat-file packages/b/.oxlintrc.json --assert missing` + +``` +packages/b/.oxlintrc.json: missing +``` + +## `cd packages/b && vp lint --threads=1 index.js` + +Plain lint enforces the inherited error after recovery + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + + × eslint(no-debugger): `debugger` statement is not allowed + ╭─[index.js:1:1] + 1 │ debugger; + · ───────── + ╰──── + help: Remove the debugger statement + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlint_extends_workspace/snapshots/migration_oxc_reference_retry.local.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlint_extends_workspace/snapshots/migration_oxc_reference_retry.local.md new file mode 100644 index 0000000000..692b340575 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlint_extends_workspace/snapshots/migration_oxc_reference_retry.local.md @@ -0,0 +1,167 @@ +# migration_oxc_reference_retry + +## `vpt json-edit .oxlintrc.json rules.no-debugger '"error"'` + + +## `vp migrate --no-interactive --no-agent --no-editor --no-hooks` + +Package b cannot merge while extra.ts conflicts with its config + +``` +VITE+ - The Unified Toolchain for the Web + +▲ No package manager is declared in package.json; using pnpm for this migration without adding a pin. Run `vp env pin` to declare it explicitly. +◆ ✔ Merged .oxlintrc.json into vite.config.mjs +● Formatting code... +● Code formatted +◇ Migrated . to Vite+ +• Node pnpm +✓ Dependencies installed in +• 1 config update applied +! Warnings: + - Could not migrate packages/b/.oxlintrc.json: Error: Cannot create shared Oxlint config because /packages/b/extra.ts or /packages/b/extra.js already exists. The original config was preserved; use vp lint -c packages/b/.oxlintrc.json until it is migrated manually. +``` + +## `vpt json-edit package.json scripts.lint:a '"vp lint -c packages/a/.oxlintrc.json packages/a/index.js"'` + + +## `vpt json-edit package.json scripts.lint:b '"vp lint -c packages/b/.oxlintrc.json packages/b/index.js"'` + + +## `vpt rm packages/b/extra.ts` + + +## `vp migrate --no-interactive --no-agent --no-editor --no-hooks` + +New script references protect both completed and pending JSON configs on retry + +``` +VITE+ - The Unified Toolchain for the Web + +▲ No package manager is declared in package.json; using pnpm for this migration without adding a pin. Run `vp env pin` to declare it explicitly. +This project is already using Vite+! Happy coding! +``` + +## `vpt stat-file .oxlintrc.json --assert file` + +``` +.oxlintrc.json: file +``` + +## `vpt stat-file packages/a/.oxlintrc.json --assert file` + +``` +packages/a/.oxlintrc.json: file +``` + +## `vpt stat-file packages/b/.oxlintrc.json --assert file` + +``` +packages/b/.oxlintrc.json: file +``` + +## `vpt print-file packages/b/vite.config.mjs` + +``` +export default {}; +// vp migrate: pending .oxlintrc.json. +``` + +## `vp run lint:a` + +The completed config remains usable as JSON + +**Exit code:** 1 + +``` +$ vp lint -c packages/a/.oxlintrc.json packages/a/index.js ⊘ cache disabled + + × eslint(no-debugger): `debugger` statement is not allowed + ╭─[packages/a/index.js:1:1] + 1 │ debugger; + · ───────── + ╰──── + help: Remove the debugger statement + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` + +## `vp run lint:b` + +The pending config retains its complete inheritance chain + +**Exit code:** 1 + +``` +$ vp lint -c packages/b/.oxlintrc.json packages/b/index.js ⊘ cache disabled + + × eslint(no-debugger): `debugger` statement is not allowed + ╭─[packages/b/index.js:1:1] + 1 │ debugger; + · ───────── + ╰──── + help: Remove the debugger statement + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` + +## `vpt json-edit package.json scripts {}` + +``` +``` + +## `vp migrate --no-interactive --no-agent --no-editor --no-hooks` + +Removing the references allows migration and deferred cleanup to finish + +``` +VITE+ - The Unified Toolchain for the Web + +▲ No package manager is declared in package.json; using pnpm for this migration without adding a pin. Run `vp env pin` to declare it explicitly. +● Formatting code... +● Code formatted +◇ Updated . to Vite+ +• Node pnpm +• Dependencies: + vite → +• 1 config update applied +``` + +## `vpt stat-file .oxlintrc.json --assert missing` + +``` +.oxlintrc.json: missing +``` + +## `vpt stat-file packages/a/.oxlintrc.json --assert missing` + +``` +packages/a/.oxlintrc.json: missing +``` + +## `vpt stat-file packages/b/.oxlintrc.json --assert missing` + +``` +packages/b/.oxlintrc.json: missing +``` + +## `cd packages/b && vp lint --threads=1 index.js` + +Plain lint enforces the inherited error after recovery + +**Exit code:** 1 + +``` + + × eslint(no-debugger): `debugger` statement is not allowed + ╭─[index.js:1:1] + 1 │ debugger; + · ───────── + ╰──── + help: Remove the debugger statement + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlint_extends_workspace/snapshots/migration_oxlint_extends_workspace_full_setup.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlint_extends_workspace/snapshots/migration_oxlint_extends_workspace_full_setup.md index 8ce5b6ecc2..fb7e528d8b 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlint_extends_workspace/snapshots/migration_oxlint_extends_workspace_full_setup.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlint_extends_workspace/snapshots/migration_oxlint_extends_workspace_full_setup.md @@ -25,7 +25,7 @@ Finished in on 1 file with rules using threads. ## `vp migrate --full --no-interactive --no-agent --no-editor --no-hooks` -Prettier migration merges the root configs without migrating package configs +Recover workspace configs and merge the migrated Prettier config ``` VITE+ - The Unified Toolchain for the Web @@ -39,9 +39,11 @@ VITE+ - The Unified Toolchain for the Web • Dependencies: vite → ✓ Dependencies installed in -• 2 config updates applied +• 3 config updates applied • Prettier migrated to Oxfmt • Package manager settings configured +! Warnings: + - Could not migrate packages/b/.oxlintrc.json: Error: Cannot create shared Oxlint config because /packages/b/extra.ts or /packages/b/extra.js already exists. The original config was preserved; use vp lint -c packages/b/.oxlintrc.json until it is migrated manually. ``` ## `vpt print-file vite.config.mjs` @@ -52,6 +54,12 @@ The root uses its shared module // vp migrate: merged .oxlintrc.json (cca48660331feaa20cf74e4f147c8e10). import oxlintConfig1 from './.oxlintrc.js'; export default { + fmt: { + singleQuote: true, + printWidth: 80, + sortPackageJson: false, + ignorePatterns: [], + }, lint: { extends: [oxlintConfig1], options: {}, @@ -60,18 +68,12 @@ export default { 'vite-plus/prefer-vite-plus-imports': 'error', }, }, - fmt: { - singleQuote: true, - printWidth: 80, - sortPackageJson: false, - ignorePatterns: [], - }, }; ``` ## `vpt stat-file .oxlintrc.json --assert file` -The root JSON remains available to untouched consumers +The root JSON remains available to package b while its output conflict remains ``` .oxlintrc.json: file @@ -85,15 +87,32 @@ The root JSON remains available to untouched consumers ## `vpt print-file packages/a/vite.config.mjs` -The package Vite config remains unchanged +The recovered package uses the shared module + +``` +// vp migrate: merged packages%2Fa%2F.oxlintrc.json (e93b0fadd405db856ff1b8847eb5f2c3). +import oxlintConfig1 from './.oxlintrc.js'; +export default { + lint: { + extends: [oxlintConfig1], + options: {}, + jsPlugins: [{ name: 'vite-plus', specifier: 'vite-plus/oxlint-plugin' }], + rules: { + 'vite-plus/prefer-vite-plus-imports': 'error', + }, + }, +}; +``` + +## `vpt stat-file packages/a/.oxlintrc.json --assert file` ``` -export default {}; +packages/a/.oxlintrc.json: file ``` -## `cd packages/a && vp lint --threads=1 -c .oxlintrc.json index.js` +## `cd packages/a && vp lint --threads=1 index.js` -The preserved package JSON still reports the same diagnostic +The recovered package reports the same diagnostic ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlint_extends_workspace/snapshots/migration_oxlint_extends_workspace_new_consumer.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlint_extends_workspace/snapshots/migration_oxlint_extends_workspace_new_consumer.md index 0fd8c5438f..3716ab20bb 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlint_extends_workspace/snapshots/migration_oxlint_extends_workspace_new_consumer.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlint_extends_workspace/snapshots/migration_oxlint_extends_workspace_new_consumer.md @@ -64,34 +64,51 @@ Finished in on 1 file with rules using threads. ## `vp migrate --no-interactive --no-agent --no-editor --no-hooks` -An upgrade does not treat shared modules as a pending migration for the new workspace +Recover the unreferenced workspace config even without a pending marker ``` VITE+ - The Unified Toolchain for the Web ▲ No package manager is declared in package.json; using pnpm for this migration without adding a pin. Run `vp env pin` to declare it explicitly. -This project is already using Vite+! Happy coding! +● Formatting code... +● Code formatted +◇ Updated . to Vite+ +• Node pnpm +• Dependencies: + vite → +• 1 config update applied ``` ## `vpt print-file packages/c/vite.config.mjs` -The unmarked workspace keeps its original Vite config +The workspace imports the existing shared module ``` -export default {}; +// vp migrate: merged packages%2Fc%2F.oxlintrc.json (f042a7ee2bd1c045ffb01c004fc0106b). +import oxlintConfig1 from "../../shared/base.js"; +export default { + lint: { + extends: [oxlintConfig1], + options: {}, + jsPlugins: [{ name: "vite-plus", specifier: "vite-plus/oxlint-plugin" }], + rules: { + "vite-plus/prefer-vite-plus-imports": "error", + }, + }, +}; ``` -## `vpt print-file packages/c/.oxlintrc.json` +## `vpt stat-file packages/c/.oxlintrc.json --assert missing` -Its newly authored JSON config remains intact +The recovered config no longer needs its standalone JSON ``` -{"extends":["../../shared/base.json"]} +packages/c/.oxlintrc.json: missing ``` -## `cd packages/c && vp lint --threads=1 -c .oxlintrc.json index.js` +## `cd packages/c && vp lint --threads=1 index.js` -The JSON config retains the same lint output +Plain lint retains the same diagnostic and exit status **Exit code:** 1 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_preserves_existing_fmt_and_lint/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_preserves_existing_fmt_and_lint/snapshots.toml index 6a6506ca09..0e82facdb9 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_preserves_existing_fmt_and_lint/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_preserves_existing_fmt_and_lint/snapshots.toml @@ -4,6 +4,6 @@ vp = "global" steps = [ { argv = ["vp", "migrate", "--no-interactive"], comment = "should NOT duplicate fmt/lint blocks already in vite.config.ts (regression for vp create fate)", continue-on-failure = true }, { argv = ["vpt", "print-file", "vite.config.ts"], comment = "exactly one fmt: and one lint: block, preserving template values", continue-on-failure = true }, - { argv = ["vpt", "stat-file", ".oxfmtrc.jsonc", "--assert-not", "file"], comment = "redundant standalone file removed", continue-on-failure = true }, - { argv = ["vpt", "stat-file", ".oxlintrc.json", "--assert-not", "file"], comment = "redundant standalone file removed", continue-on-failure = true }, + { argv = ["vpt", "stat-file", ".oxfmtrc.jsonc", "--assert", "file"], comment = "standalone config preserved", continue-on-failure = true }, + { argv = ["vpt", "stat-file", ".oxlintrc.json", "--assert", "file"], comment = "standalone config preserved", continue-on-failure = true }, ] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_preserves_existing_fmt_and_lint/snapshots/migration_preserves_existing_fmt_and_lint.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_preserves_existing_fmt_and_lint/snapshots/migration_preserves_existing_fmt_and_lint.md index 2061ff6df2..3d358547c4 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_preserves_existing_fmt_and_lint/snapshots/migration_preserves_existing_fmt_and_lint.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_preserves_existing_fmt_and_lint/snapshots/migration_preserves_existing_fmt_and_lint.md @@ -70,18 +70,18 @@ export default defineConfig({ }); ``` -## `vpt stat-file .oxfmtrc.jsonc --assert-not file` +## `vpt stat-file .oxfmtrc.jsonc --assert file` -redundant standalone file removed +standalone config preserved ``` -.oxfmtrc.jsonc: missing +.oxfmtrc.jsonc: file ``` -## `vpt stat-file .oxlintrc.json --assert-not file` +## `vpt stat-file .oxlintrc.json --assert file` -redundant standalone file removed +standalone config preserved ``` -.oxlintrc.json: missing +.oxlintrc.json: file ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/.oxfmtrc.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/.oxfmtrc.json new file mode 100644 index 0000000000..544138be45 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "singleQuote": true +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/.oxlintrc.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/.oxlintrc.json new file mode 100644 index 0000000000..2ff50f91ec --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/.oxlintrc.json @@ -0,0 +1,5 @@ +{ + "rules": { + "no-console": "error" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/package.json new file mode 100644 index 0000000000..6f52fa50d1 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/package.json @@ -0,0 +1,9 @@ +{ + "name": "migration-referenced-workspace-oxc-configs", + "private": true, + "type": "module", + "packageManager": "pnpm@12.3.4", + "devDependencies": { + "vite-plus": "latest" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/packages/app/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/packages/app/package.json new file mode 100644 index 0000000000..33f2660adc --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/packages/app/package.json @@ -0,0 +1,5 @@ +{ + "name": "app", + "private": true, + "type": "module" +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/packages/app/src/index.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/packages/app/src/index.ts new file mode 100644 index 0000000000..38b0fa8a2f --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/packages/app/src/index.ts @@ -0,0 +1 @@ +export const message = "preserved"; diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/pnpm-workspace.yaml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/pnpm-workspace.yaml new file mode 100644 index 0000000000..924b55f42e --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - packages/* diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/snapshots.toml new file mode 100644 index 0000000000..610d01f953 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/snapshots.toml @@ -0,0 +1,32 @@ +[[case]] +name = "migration_referenced_workspace_oxc_configs_imported" +vp = "global" +steps = [ + { argv = ["vpt", "write-file", "packages/app/vite.config.ts", "import fmt from '../../.oxfmtrc.json' with { type: 'json' };\nimport { readFileSync } from 'node:fs';\nconst lint = JSON.parse(readFileSync(new URL('../../.oxlintrc.json', import.meta.url), 'utf8'));\nexport default { fmt, lint };\n"], snapshot = false }, + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "preserve root configs loaded by a workspace Vite config" }, + ["vpt", "print-file", ".oxfmtrc.json"], + ["vpt", "print-file", ".oxlintrc.json"], + { argv = ["vp", "fmt", "src/index.ts"], cwd = "packages/app" }, + ["vpt", "print-file", "packages/app/src/index.ts"], + { argv = ["vp", "lint", "src/index.ts"], cwd = "packages/app" }, + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "repeated migration keeps the workspace imports usable" }, + { argv = ["vp", "fmt", "--check", "src/index.ts"], cwd = "packages/app" }, + { argv = ["vp", "lint", "src/index.ts"], cwd = "packages/app" }, +] + +[[case]] +name = "migration_referenced_workspace_oxc_configs_extends" +vp = "global" +steps = [ + { argv = ["vpt", "write-file", "packages/app/.oxlintrc.json", "{\"extends\":[\"./config/lint-base.jsonc\"]}\n"], snapshot = false }, + { argv = ["vpt", "write-file", "packages/app/config/lint-base.jsonc", "// Shared lint rules\n{\"extends\":[\"../../../.oxlintrc.json\"]}\n"], snapshot = false }, + { argv = ["vpt", "write-file", "packages/app/src/index.ts", "console.log('hello');\n"], snapshot = false }, + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "recover a transitive inheritance chain while retaining shared JSON consumers" }, + ["vpt", "print-file", ".oxlintrc.json"], + ["vpt", "stat-file", "packages/app/.oxlintrc.json", "--assert", "missing"], + ["vpt", "print-file", "packages/app/vite.config.ts"], + ["vpt", "print-file", "packages/app/config/lint-base.ts"], + ["vpt", "print-file", "packages/app/config/lint-base.jsonc"], + { argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "repeated migration keeps inherited rules usable" }, + { argv = ["vp", "lint", "src/index.ts"], cwd = "packages/app", comment = "the inherited no-console rule must still report the console call", continue-on-failure = true }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/snapshots/migration_referenced_workspace_oxc_configs_extends.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/snapshots/migration_referenced_workspace_oxc_configs_extends.md new file mode 100644 index 0000000000..4bb80c27a0 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/snapshots/migration_referenced_workspace_oxc_configs_extends.md @@ -0,0 +1,118 @@ +# migration_referenced_workspace_oxc_configs_extends + +## `vpt write-file packages/app/.oxlintrc.json '{"extends":["./config/lint-base.jsonc"]} +'` + + +## `vpt write-file packages/app/config/lint-base.jsonc '// Shared lint rules +{"extends":["../../../.oxlintrc.json"]} +'` + + +## `vpt write-file packages/app/src/index.ts 'console.log('\''hello'\''); +'` + + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +recover a transitive inheritance chain while retaining shared JSON consumers + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Updated . to Vite+ +• Node pnpm +• Dependencies: + vite-plus latest → + vite → +• 5 config updates applied +• Package manager settings configured +``` + +## `vpt print-file .oxlintrc.json` + +``` +{ + "rules": { + "no-console": "error" + } +} +``` + +## `vpt stat-file packages/app/.oxlintrc.json --assert missing` + +``` +packages/app/.oxlintrc.json: missing +``` + +## `vpt print-file packages/app/vite.config.ts` + +``` +// vp migrate: merged packages%2Fapp%2F.oxlintrc.json (b0b82d2e920b90c0ee84812a3a015741). +import oxlintConfig1 from "./config/lint-base.js"; +import { defineConfig } from 'vite-plus'; + +export default defineConfig({ + lint: { + "extends": [oxlintConfig1], + "options": { + "typeAware": true, + "typeCheck": true + }, + "jsPlugins": [{ "name": "vite-plus", "specifier": "vite-plus/oxlint-plugin" }], + "rules": { + "vite-plus/prefer-vite-plus-imports": "error" + } + }, + +}); +``` + +## `vpt print-file packages/app/config/lint-base.ts` + +``` +// Generated by vp migrate from lint-base.jsonc. +import type { OxlintConfig } from "vite-plus/lint"; +import oxlintConfig1 from "../../../.oxlintrc.js"; + +export default { + "extends": [oxlintConfig1] +} satisfies OxlintConfig; +``` + +## `vpt print-file packages/app/config/lint-base.jsonc` + +``` +// Shared lint rules +{"extends":["../../../.oxlintrc.json"]} +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +repeated migration keeps inherited rules usable + +``` +VITE+ - The Unified Toolchain for the Web + +This project is already using Vite+! Happy coding! +``` + +## `cd packages/app && vp lint src/index.ts` + +the inherited no-console rule must still report the console call + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + + × eslint(no-console): Unexpected console statement. + ╭─[src/index.ts:1:1] + 1 │ console.log('hello'); + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/snapshots/migration_referenced_workspace_oxc_configs_imported.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/snapshots/migration_referenced_workspace_oxc_configs_imported.md new file mode 100644 index 0000000000..f0c634544e --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_referenced_workspace_oxc_configs/snapshots/migration_referenced_workspace_oxc_configs_imported.md @@ -0,0 +1,94 @@ +# migration_referenced_workspace_oxc_configs_imported + +## `vpt write-file packages/app/vite.config.ts 'import fmt from '\''../../.oxfmtrc.json'\'' with { type: '\''json'\'' }; +import { readFileSync } from '\''node:fs'\''; +const lint = JSON.parse(readFileSync(new URL('\''../../.oxlintrc.json'\'', import.meta.url), '\''utf8'\'')); +export default { fmt, lint }; +'` + + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +preserve root configs loaded by a workspace Vite config + +``` +VITE+ - The Unified Toolchain for the Web + +◇ Updated . to Vite+ +• Node pnpm +• Dependencies: + vite-plus latest → + vite → +• Package manager settings configured +``` + +## `vpt print-file .oxfmtrc.json` + +``` +{ + "singleQuote": true +} +``` + +## `vpt print-file .oxlintrc.json` + +``` +{ + "rules": { + "no-console": "error" + } +} +``` + +## `cd packages/app && vp fmt src/index.ts` + +``` +VITE+ - The Unified Toolchain for the Web + +Finished in on 1 files using threads. +``` + +## `vpt print-file packages/app/src/index.ts` + +``` +export const message = 'preserved'; +``` + +## `cd packages/app && vp lint src/index.ts` + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp migrate --no-interactive --no-hooks --no-agent --no-editor` + +repeated migration keeps the workspace imports usable + +``` +VITE+ - The Unified Toolchain for the Web + +This project is already using Vite+! Happy coding! +``` + +## `cd packages/app && vp fmt --check src/index.ts` + +``` +VITE+ - The Unified Toolchain for the Web + +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `cd packages/app && vp lint src/index.ts` + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/custom-fmt.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/custom-fmt.json new file mode 100644 index 0000000000..544138be45 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/custom-fmt.json @@ -0,0 +1,3 @@ +{ + "singleQuote": true +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/custom-lint.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/custom-lint.json new file mode 100644 index 0000000000..d5ba8f9d9c --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/custom-lint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "no-console": "off" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/index.js b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/index.js new file mode 100644 index 0000000000..702f4280ce --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/index.js @@ -0,0 +1 @@ +console.log("hello"); diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/package.json new file mode 100644 index 0000000000..bb883e47c4 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/package.json @@ -0,0 +1,9 @@ +{ + "name": "@test/oxc-explicit-config", + "version": "1.0.0", + "private": true, + "type": "module", + "scripts": { + "lint:custom": "vp lint --config custom-lint.json index.js" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/snapshots.toml new file mode 100644 index 0000000000..3f192e38e4 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/snapshots.toml @@ -0,0 +1,31 @@ +[[case]] +name = "lint_explicit_config" +vp = ["local", "global"] +steps = [ + { argv = ["vp", "lint", "index.js"], comment = "use inline lint rules when no config flag is supplied", continue-on-failure = true }, + { argv = ["vp", "lint", "--config", "custom-lint.json", "index.js"], comment = "an explicit config overrides the inline lint rules", continue-on-failure = true }, + ["vp", "lint", "-c", "custom-lint.json", "index.js"], + ["vp", "lint", "--config=custom-lint.json", "index.js"], + ["vp", "lint", "-c=custom-lint.json", "index.js"], + ["vp", "lint", "-ccustom-lint.json", "index.js"], + ["vp", "run", "lint:custom"], + { argv = ["vpt", "write-file", "vite.config.ts", "throw new Error('Vite config must not be loaded');\n"], snapshot = false }, + { argv = ["vp", "lint", "--config", "custom-lint.json", "index.js"], comment = "explicit lint configs do not require a working Vite config" }, +] + +[[case]] +name = "fmt_explicit_config" +vp = ["local", "global"] +steps = [ + { argv = ["vp", "fmt", "--config", "custom-fmt.json", "index.js"], comment = "an explicit config overrides the inline format options" }, + ["vpt", "print-file", "index.js"], + ["vp", "fmt", "--check", "-c", "custom-fmt.json", "index.js"], + ["vp", "fmt", "--check", "--config=custom-fmt.json", "index.js"], + ["vp", "fmt", "--check", "-c=custom-fmt.json", "index.js"], + ["vp", "fmt", "--check", "-ccustom-fmt.json", "index.js"], + { argv = ["vp", "fmt", "index.js"], comment = "use inline format options when no config flag is supplied" }, + ["vpt", "print-file", "index.js"], + { argv = ["vpt", "write-file", "vite.config.ts", "throw new Error('Vite config must not be loaded');\n"], snapshot = false }, + { argv = ["vp", "fmt", "--config", "custom-fmt.json", "index.js"], comment = "explicit format configs do not require a working Vite config" }, + ["vpt", "print-file", "index.js"], +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/snapshots/fmt_explicit_config.global.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/snapshots/fmt_explicit_config.global.md new file mode 100644 index 0000000000..81f07874e4 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/snapshots/fmt_explicit_config.global.md @@ -0,0 +1,97 @@ +# fmt_explicit_config + +## `vp fmt --config custom-fmt.json index.js` + +an explicit config overrides the inline format options + +``` +VITE+ - The Unified Toolchain for the Web + +Finished in on 1 files using threads. +``` + +## `vpt print-file index.js` + +``` +console.log('hello'); +``` + +## `vp fmt --check -c custom-fmt.json index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vp fmt --check --config=custom-fmt.json index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vp fmt --check -c=custom-fmt.json index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vp fmt --check -ccustom-fmt.json index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vp fmt index.js` + +use inline format options when no config flag is supplied + +``` +VITE+ - The Unified Toolchain for the Web + +Finished in on 1 files using threads. +``` + +## `vpt print-file index.js` + +``` +console.log("hello"); +``` + +## `vpt write-file vite.config.ts 'throw new Error('\''Vite config must not be loaded'\''); +'` + + +## `vp fmt --config custom-fmt.json index.js` + +explicit format configs do not require a working Vite config + +``` +VITE+ - The Unified Toolchain for the Web + +Finished in on 1 files using threads. +``` + +## `vpt print-file index.js` + +``` +console.log('hello'); +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/snapshots/fmt_explicit_config.local.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/snapshots/fmt_explicit_config.local.md new file mode 100644 index 0000000000..8803e19a95 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/snapshots/fmt_explicit_config.local.md @@ -0,0 +1,83 @@ +# fmt_explicit_config + +## `vp fmt --config custom-fmt.json index.js` + +an explicit config overrides the inline format options + +``` +Finished in on 1 files using threads. +``` + +## `vpt print-file index.js` + +``` +console.log('hello'); +``` + +## `vp fmt --check -c custom-fmt.json index.js` + +``` +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vp fmt --check --config=custom-fmt.json index.js` + +``` +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vp fmt --check -c=custom-fmt.json index.js` + +``` +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vp fmt --check -ccustom-fmt.json index.js` + +``` +Checking formatting... + +All matched files use the correct format. +Finished in on 1 files using threads. +``` + +## `vp fmt index.js` + +use inline format options when no config flag is supplied + +``` +Finished in on 1 files using threads. +``` + +## `vpt print-file index.js` + +``` +console.log("hello"); +``` + +## `vpt write-file vite.config.ts 'throw new Error('\''Vite config must not be loaded'\''); +'` + + +## `vp fmt --config custom-fmt.json index.js` + +explicit format configs do not require a working Vite config + +``` +Finished in on 1 files using threads. +``` + +## `vpt print-file index.js` + +``` +console.log('hello'); +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/snapshots/lint_explicit_config.global.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/snapshots/lint_explicit_config.global.md new file mode 100644 index 0000000000..25bf0a48e6 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/snapshots/lint_explicit_config.global.md @@ -0,0 +1,93 @@ +# lint_explicit_config + +## `vp lint index.js` + +use inline lint rules when no config flag is supplied + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + + × eslint(no-console): Unexpected console statement. + ╭─[index.js:1:1] + 1 │ console.log("hello"); + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` + +## `vp lint --config custom-lint.json index.js` + +an explicit config overrides the inline lint rules + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp lint -c custom-lint.json index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp lint --config=custom-lint.json index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp lint -c=custom-lint.json index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp lint -ccustom-lint.json index.js` + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp run lint:custom` + +``` +VITE+ - The Unified Toolchain for the Web + +$ vp lint --config custom-lint.json index.js ⊘ cache disabled +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vpt write-file vite.config.ts 'throw new Error('\''Vite config must not be loaded'\''); +'` + + +## `vp lint --config custom-lint.json index.js` + +explicit lint configs do not require a working Vite config + +``` +VITE+ - The Unified Toolchain for the Web + +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/snapshots/lint_explicit_config.local.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/snapshots/lint_explicit_config.local.md new file mode 100644 index 0000000000..3e8924c393 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/snapshots/lint_explicit_config.local.md @@ -0,0 +1,78 @@ +# lint_explicit_config + +## `vp lint index.js` + +use inline lint rules when no config flag is supplied + +**Exit code:** 1 + +``` + + × eslint(no-console): Unexpected console statement. + ╭─[index.js:1:1] + 1 │ console.log("hello"); + · ─────────── + ╰──── + help: Delete this console statement. + +Found 0 warnings and 1 error. +Finished in on 1 file with rules using threads. +``` + +## `vp lint --config custom-lint.json index.js` + +an explicit config overrides the inline lint rules + +``` +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp lint -c custom-lint.json index.js` + +``` +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp lint --config=custom-lint.json index.js` + +``` +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp lint -c=custom-lint.json index.js` + +``` +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp lint -ccustom-lint.json index.js` + +``` +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vp run lint:custom` + +``` +$ vp lint --config custom-lint.json index.js ⊘ cache disabled +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` + +## `vpt write-file vite.config.ts 'throw new Error('\''Vite config must not be loaded'\''); +'` + + +## `vp lint --config custom-lint.json index.js` + +explicit lint configs do not require a working Vite config + +``` +Found 0 warnings and 0 errors. +Finished in on 1 file with rules using threads. +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/vite.config.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/vite.config.ts new file mode 100644 index 0000000000..39d832bfa9 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/oxc_explicit_config/vite.config.ts @@ -0,0 +1,10 @@ +export default { + lint: { + rules: { + 'no-console': 'error', + }, + }, + fmt: { + singleQuote: false, + }, +}; diff --git a/packages/cli/src/migration/__tests__/migrator.spec.ts b/packages/cli/src/migration/__tests__/migrator.spec.ts index c1bcb66131..108d8776f7 100644 --- a/packages/cli/src/migration/__tests__/migrator.spec.ts +++ b/packages/cli/src/migration/__tests__/migrator.spec.ts @@ -8662,6 +8662,7 @@ describe('existing Vite+ core migration finalization', () => { scripts: true, tsconfigTypes: true, imports: true, + oxcConfigs: false, tsdownConfig: false, taskCacheConfig: false, taskCacheWarnings: [], @@ -8695,6 +8696,608 @@ describe('existing Vite+ core migration finalization', () => { }); }); + it.each(['.oxfmtrc.json', '.oxfmtrc.jsonc'])( + 'finishes a leftover %s config and remains idempotent', + (configFile) => { + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ name: 'test', devDependencies: { 'vite-plus': 'latest' } }), + ); + fs.writeFileSync(path.join(tmpDir, 'vite.config.ts'), 'export default {};\n'); + fs.writeFileSync(path.join(tmpDir, configFile), '{"singleQuote":true,"semi":false}\n'); + const workspaceInfo = makeWorkspaceInfo(tmpDir, PackageManager.npm); + const report = createMigrationReport(); + + expect(finalizeCoreMigrationForExistingVitePlus(workspaceInfo, true, report).oxcConfigs).toBe( + true, + ); + const config = fs.readFileSync(path.join(tmpDir, 'vite.config.ts'), 'utf8'); + expect(config).toContain('fmt:'); + expect(config).toContain('"singleQuote":true'); + expect(config).toContain('"semi":false'); + expect(fs.existsSync(path.join(tmpDir, configFile))).toBe(false); + expect(report.mergedConfigCount).toBe(1); + expect(finalizeCoreMigrationForExistingVitePlus(workspaceInfo, true).oxcConfigs).toBe(false); + expect(fs.readFileSync(path.join(tmpDir, 'vite.config.ts'), 'utf8')).toBe(config); + }, + ); + + it('finishes leftover lint and format configs in workspace packages', () => { + const appDir = path.join(tmpDir, 'packages', 'app'); + fs.mkdirSync(appDir, { recursive: true }); + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ name: 'root', devDependencies: { 'vite-plus': 'latest' } }), + ); + fs.writeFileSync(path.join(appDir, 'package.json'), JSON.stringify({ name: 'app' })); + fs.writeFileSync(path.join(appDir, '.oxfmtrc.json'), '{"singleQuote":true}\n'); + fs.writeFileSync(path.join(appDir, '.oxlintrc.json'), '{"rules":{"no-console":"error"}}\n'); + const workspaceInfo = { + ...makeWorkspaceInfo(tmpDir, PackageManager.pnpm), + isMonorepo: true, + packages: [{ name: 'app', path: 'packages/app' }], + }; + + expect(finalizeCoreMigrationForExistingVitePlus(workspaceInfo, true).oxcConfigs).toBe(true); + const config = fs.readFileSync(path.join(appDir, 'vite.config.ts'), 'utf8'); + expect(config).toContain('fmt:'); + expect(config).toContain('lint:'); + expect(config).toMatch(/"no-console":\s*"error"/); + expect(fs.existsSync(path.join(appDir, '.oxfmtrc.json'))).toBe(false); + expect(fs.existsSync(path.join(appDir, '.oxlintrc.json'))).toBe(false); + expect(finalizeCoreMigrationForExistingVitePlus(workspaceInfo, true).oxcConfigs).toBe(false); + }); + + it('preserves standalone configs when the tool already has an inline config', () => { + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ name: 'test', devDependencies: { 'vite-plus': 'latest' } }), + ); + const config = 'export default { fmt: { singleQuote: false } };\n'; + fs.writeFileSync(path.join(tmpDir, 'vite.config.ts'), config); + fs.writeFileSync(path.join(tmpDir, '.oxfmtrc.json'), '{"singleQuote":true}\n'); + const workspaceInfo = makeWorkspaceInfo(tmpDir, PackageManager.npm); + + expect(finalizeCoreMigrationForExistingVitePlus(workspaceInfo, true).oxcConfigs).toBe(false); + expect(fs.readFileSync(path.join(tmpDir, 'vite.config.ts'), 'utf8')).toBe(config); + expect(fs.readFileSync(path.join(tmpDir, '.oxfmtrc.json'), 'utf8')).toBe( + '{"singleQuote":true}\n', + ); + expect(finalizeCoreMigrationForExistingVitePlus(workspaceInfo, true).oxcConfigs).toBe(false); + }); + + it.each([ + `import fmt from './.oxfmtrc.json' with { type: 'json' }; +import lint from './.oxlintrc.json' with { type: 'json' }; +export default { fmt, lint }; +`, + `import { readFileSync } from 'node:fs'; +const fmt = JSON.parse(readFileSync(new URL('./.oxfmtrc.json', import.meta.url), 'utf8')); +const lint = JSON.parse(readFileSync(new URL('./.oxlintrc.json', import.meta.url), 'utf8')); +export default { fmt, lint }; +`, + `import config from './.oxfmtrc.json' with { type: 'json' }; +export default { define: { config: JSON.stringify(config) } }; +`, + ])('preserves config files loaded by vite.config.ts (%#)', (config) => { + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ name: 'test', devDependencies: { 'vite-plus': 'latest' } }), + ); + fs.writeFileSync(path.join(tmpDir, 'vite.config.ts'), config); + fs.writeFileSync(path.join(tmpDir, '.oxfmtrc.json'), '{"singleQuote":true}\n'); + if (config.includes('.oxlintrc.json')) { + fs.writeFileSync(path.join(tmpDir, '.oxlintrc.json'), '{"rules":{"no-console":"error"}}\n'); + } + const workspaceInfo = makeWorkspaceInfo(tmpDir, PackageManager.npm); + + for (let run = 0; run < 2; run++) { + expect(finalizeCoreMigrationForExistingVitePlus(workspaceInfo, true).oxcConfigs).toBe(false); + expect(fs.readFileSync(path.join(tmpDir, 'vite.config.ts'), 'utf8')).toBe(config); + expect(fs.readFileSync(path.join(tmpDir, '.oxfmtrc.json'), 'utf8')).toBe( + '{"singleQuote":true}\n', + ); + if (config.includes('.oxlintrc.json')) { + expect(fs.readFileSync(path.join(tmpDir, '.oxlintrc.json'), 'utf8')).toBe( + '{"rules":{"no-console":"error"}}\n', + ); + } + } + }); + + it.each([ + ['.', 'packages/app'], + ['packages/shared', 'packages/app'], + ['packages/app', '.'], + ])('preserves configs in %s loaded by the Vite config in %s', (configDir, consumerDir) => { + const workspaceInfo = { + ...makeWorkspaceInfo(tmpDir, PackageManager.pnpm), + packages: [ + { name: 'app', path: 'packages/app' }, + { name: 'shared', path: 'packages/shared' }, + ], + }; + for (const dir of ['.', ...workspaceInfo.packages.map((pkg) => pkg.path)]) { + fs.mkdirSync(path.join(tmpDir, dir), { recursive: true }); + fs.writeFileSync(path.join(tmpDir, dir, 'package.json'), JSON.stringify({ name: dir })); + } + const configPath = path.join(tmpDir, configDir); + const consumerPath = path.join(tmpDir, consumerDir); + const relativePath = path.relative(consumerPath, configPath).replaceAll('\\', '/'); + const config = `import fmt from './${relativePath}/.oxfmtrc.json' with { type: 'json' }; +import { readFileSync } from 'node:fs'; +const lint = JSON.parse(readFileSync(new URL('./${relativePath}/.oxlintrc.json', import.meta.url), 'utf8')); +export default { fmt, lint }; +`; + fs.writeFileSync(path.join(consumerPath, 'vite.config.mts'), config); + fs.writeFileSync(path.join(configPath, '.oxfmtrc.json'), '{"singleQuote":true}\n'); + fs.writeFileSync(path.join(configPath, '.oxlintrc.json'), '{"rules":{"no-console":"error"}}\n'); + + for (let run = 0; run < 2; run++) { + expect(finalizeCoreMigrationForExistingVitePlus(workspaceInfo, true).oxcConfigs).toBe(false); + expect(fs.readFileSync(path.join(consumerPath, 'vite.config.mts'), 'utf8')).toBe(config); + expect(fs.readFileSync(path.join(configPath, '.oxfmtrc.json'), 'utf8')).toBe( + '{"singleQuote":true}\n', + ); + expect(fs.readFileSync(path.join(configPath, '.oxlintrc.json'), 'utf8')).toBe( + '{"rules":{"no-console":"error"}}\n', + ); + expect(fs.existsSync(path.join(configPath, 'vite.config.ts'))).toBe(false); + } + }); + + it.each(['.', 'packages/app'])( + 'preserves configs used by scripts in %s without an inline tool config', + (packagePath) => { + const appDir = path.join(tmpDir, packagePath); + fs.mkdirSync(appDir, { recursive: true }); + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ name: 'root', devDependencies: { 'vite-plus': 'latest' } }), + ); + const prefix = packagePath === '.' ? './' : '../../'; + fs.writeFileSync( + path.join(appDir, 'package.json'), + JSON.stringify({ + name: 'app', + devDependencies: { 'vite-plus': 'latest' }, + scripts: { + fmt: `vp fmt -c ${prefix}.oxfmtrc.json src --write`, + lint: `vp lint --config=${prefix}.oxlintrc.json src`, + }, + }), + ); + fs.writeFileSync(path.join(tmpDir, 'vite.config.ts'), 'export default {};\n'); + fs.writeFileSync(path.join(tmpDir, '.oxfmtrc.json'), '{"singleQuote":true}\n'); + fs.writeFileSync(path.join(tmpDir, '.oxlintrc.json'), '{"rules":{"no-console":"error"}}\n'); + const workspaceInfo = { + ...makeWorkspaceInfo(tmpDir, PackageManager.pnpm), + packages: packagePath === '.' ? [] : [{ name: 'app', path: packagePath }], + }; + + for (let run = 0; run < 2; run++) { + expect(finalizeCoreMigrationForExistingVitePlus(workspaceInfo, true).oxcConfigs).toBe( + false, + ); + expect(fs.readFileSync(path.join(tmpDir, 'vite.config.ts'), 'utf8')).toBe( + 'export default {};\n', + ); + expect(fs.readFileSync(path.join(tmpDir, '.oxfmtrc.json'), 'utf8')).toBe( + '{"singleQuote":true}\n', + ); + expect(fs.readFileSync(path.join(tmpDir, '.oxlintrc.json'), 'utf8')).toBe( + '{"rules":{"no-console":"error"}}\n', + ); + } + }, + ); + + it.each([ + ['.', '.', 'script'], + ['packages/app', '.', 'script'], + ['.', 'packages/app', 'script'], + ['.', '.', 'module'], + ['packages/app', '.', 'module'], + ['.', 'packages/app', 'module'], + ])('merges independent configs when %s references %s via %s', (consumer, target, kind) => { + const appDir = path.join(tmpDir, 'packages/app'); + fs.mkdirSync(appDir, { recursive: true }); + const consumerDir = path.join(tmpDir, consumer); + const targetDir = path.join(tmpDir, target); + const independentDir = target === '.' ? appDir : tmpDir; + const relativePath = path.relative(consumerDir, targetDir).replaceAll('\\', '/'); + const prefix = relativePath ? `./${relativePath}/` : './'; + for (const dir of [tmpDir, appDir]) { + fs.writeFileSync( + path.join(dir, 'package.json'), + JSON.stringify({ + name: dir === tmpDir ? 'root' : 'app', + devDependencies: { vite: '^8.0.0', oxlint: '^1.0.0', oxfmt: '^0.40.0' }, + scripts: { + lint: + kind === 'script' && dir === consumerDir + ? `oxlint -c ${prefix}.oxlintrc.json index.js` + : 'oxlint index.js', + fmt: + kind === 'script' && dir === consumerDir + ? `oxfmt --config=${prefix}.oxfmtrc.json index.js` + : 'oxfmt index.js', + }, + }), + ); + fs.writeFileSync(path.join(dir, 'vite.config.mjs'), 'export default {};\n'); + fs.writeFileSync(path.join(dir, '.oxfmtrc.json'), '{"singleQuote":true}\n'); + fs.writeFileSync( + path.join(dir, '.oxlintrc.json'), + JSON.stringify({ rules: { [dir === targetDir ? 'no-debugger' : 'no-console']: 'error' } }), + ); + } + if (kind === 'module') { + fs.writeFileSync( + path.join(consumerDir, 'vite.config.mjs'), + `import lintRules from '${prefix}.oxlintrc.json' with { type: 'json' };\n` + + `import fmtRules from '${prefix}.oxfmtrc.json' with { type: 'json' };\n` + + 'export default { define: { rules: JSON.stringify({ lintRules, fmtRules }) } };\n', + ); + } + const workspaceInfo = { + ...makeWorkspaceInfo(tmpDir, PackageManager.npm), + isMonorepo: true, + packages: [{ name: 'app', path: 'packages/app' }], + }; + rewriteMonorepo(workspaceInfo, true, true); + + const config = fs.readFileSync(path.join(independentDir, 'vite.config.mjs'), 'utf8'); + expect(config).toMatch(/"no-console":\s*"error"/); + expect(config).toContain('fmt:'); + expect(config).toContain('"singleQuote":true'); + for (const filename of ['.oxlintrc.json', '.oxfmtrc.json']) { + expect(fs.existsSync(path.join(independentDir, filename))).toBe(false); + expect(fs.existsSync(path.join(targetDir, filename))).toBe(true); + } + expect(readJson(path.join(appDir, 'package.json')).scripts).toMatchObject({ + lint: + kind === 'script' && consumer === 'packages/app' + ? `vp lint -c ${prefix}.oxlintrc.json index.js` + : 'vp lint index.js', + }); + expect(finalizeCoreMigrationForExistingVitePlus(workspaceInfo, true).oxcConfigs).toBe(false); + expect(fs.readFileSync(path.join(independentDir, 'vite.config.mjs'), 'utf8')).toBe(config); + }); + + it.each([ + ['script', 'vp lint --config "$LINT_CONFIG"'], + ['script', 'node check-config.js .oxlintrc.json'], + ['module', "import shared from '#shared'; export default shared;"], + ['module', "const filename = '.oxlintrc.json'; export default { define: { filename } };"], + ])('scopes uncertain %s references to their package: %s', (kind, reference) => { + const appDir = path.join(tmpDir, 'packages/app'); + fs.mkdirSync(appDir, { recursive: true }); + for (const dir of [tmpDir, appDir]) { + fs.writeFileSync( + path.join(dir, 'package.json'), + JSON.stringify({ + name: 'test', + scripts: kind === 'script' && dir === tmpDir ? { lint: reference } : {}, + }), + ); + fs.writeFileSync(path.join(dir, '.oxlintrc.json'), '{"rules":{"no-console":"error"}}\n'); + fs.writeFileSync( + path.join(dir, 'vite.config.ts'), + kind === 'module' && dir === tmpDir ? reference : 'export default {};\n', + ); + } + const workspaceInfo = { + ...makeWorkspaceInfo(tmpDir, PackageManager.pnpm), + packages: [{ name: 'app', path: 'packages/app' }], + }; + expect(finalizeCoreMigrationForExistingVitePlus(workspaceInfo, true).oxcConfigs).toBe(true); + expect(fs.existsSync(path.join(tmpDir, '.oxlintrc.json'))).toBe(true); + expect(fs.existsSync(path.join(appDir, '.oxlintrc.json'))).toBe(false); + expect(fs.readFileSync(path.join(appDir, 'vite.config.ts'), 'utf8')).toMatch( + /"no-console":\s*"error"/, + ); + }); + + it.each([ + '--config "config files/lint.jsonc"', + "-c 'config files/lint.jsonc'", + '--config="config files/lint.jsonc"', + '-c="config files/lint.jsonc"', + '-c"config files/lint.jsonc"', + '"--config" "config files/lint.jsonc"', + '"--config=config files/lint.jsonc"', + ])('preserves inheritance rooted at a custom script config: %s', (args) => { + const appDir = path.join(tmpDir, 'packages/app'); + fs.mkdirSync(path.join(appDir, 'config files'), { recursive: true }); + fs.writeFileSync(path.join(tmpDir, 'package.json'), JSON.stringify({ name: 'root' })); + fs.writeFileSync( + path.join(appDir, 'package.json'), + JSON.stringify({ name: 'app', scripts: { lint: `vp lint ${args} src` } }), + ); + const rootConfig = '{"rules":{"no-console":"error"}}\n'; + const customConfig = '// Shared lint rules\n{"extends":["../../../.oxlintrc.json"]}\n'; + fs.writeFileSync(path.join(tmpDir, '.oxlintrc.json'), rootConfig); + fs.writeFileSync(path.join(appDir, 'config files/lint.jsonc'), customConfig); + fs.writeFileSync(path.join(tmpDir, 'vite.config.ts'), 'export default {};\n'); + const workspaceInfo = { + ...makeWorkspaceInfo(tmpDir, PackageManager.pnpm), + packages: [{ name: 'app', path: 'packages/app' }], + }; + + for (let run = 0; run < 2; run++) { + expect(finalizeCoreMigrationForExistingVitePlus(workspaceInfo, true).oxcConfigs).toBe(false); + expect(fs.readFileSync(path.join(tmpDir, '.oxlintrc.json'), 'utf8')).toBe(rootConfig); + expect(fs.readFileSync(path.join(appDir, 'config files/lint.jsonc'), 'utf8')).toBe( + customConfig, + ); + expect(fs.readFileSync(path.join(tmpDir, 'vite.config.ts'), 'utf8')).toBe( + 'export default {};\n', + ); + } + }); + + it.each(['vp lint --config "$LINT_CONFIG"', 'cd config && vp lint -c lint.json'])( + 'preserves configs when a script config path is uncertain: %s', + (lint) => { + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ name: 'root', scripts: { lint } }), + ); + const config = '{"rules":{"no-console":"error"}}\n'; + fs.writeFileSync(path.join(tmpDir, '.oxlintrc.json'), config); + expect( + finalizeCoreMigrationForExistingVitePlus( + makeWorkspaceInfo(tmpDir, PackageManager.npm), + true, + ).oxcConfigs, + ).toBe(false); + expect(fs.readFileSync(path.join(tmpDir, '.oxlintrc.json'), 'utf8')).toBe(config); + expect(fs.existsSync(path.join(tmpDir, 'vite.config.ts'))).toBe(false); + }, + ); + + it.each([ + ['./config/shared.ts', 'shared.ts'], + ['./config/shared', 'shared.ts'], + ['./config/shared.base', 'shared.base.ts'], + ['./config/shared.js', 'shared.ts'], + ['./config/shared.mjs', 'shared.mts'], + ['./config/shared.cjs', 'shared.cts'], + ['./config', 'index.ts'], + ])('preserves configs imported through the shared Vite module %s', (specifier, filename) => { + fs.mkdirSync(path.join(tmpDir, 'config')); + fs.writeFileSync(path.join(tmpDir, 'package.json'), JSON.stringify({ name: 'root' })); + const config = `import shared from '${specifier}';\nexport default { ...shared };\n`; + fs.writeFileSync(path.join(tmpDir, 'vite.config.ts'), config); + // Follow a re-export, a readFileSync path, and a cycle without evaluating code. + fs.writeFileSync( + path.join(tmpDir, 'config', filename), + "export { default } from './tools.ts';\nthrow new Error('must not execute shared config');\n", + ); + // A competing source must not hide references under another config loader. + if (specifier.endsWith('.js')) { + fs.writeFileSync(path.join(tmpDir, specifier), 'export default {};\n'); + } + fs.writeFileSync( + path.join(tmpDir, 'config/tools.ts'), + `import './${filename}'; +import { readFileSync } from 'node:fs'; +import lint from '../.oxlintrc.json' with { type: 'json' }; +const fmt = JSON.parse(readFileSync(new URL('../.oxfmtrc.json', import.meta.url), 'utf8')); +export default { fmt, lint }; +`, + ); + const lint = '{"rules":{"no-console":"error"}}\n'; + const fmt = '{"singleQuote":true}\n'; + fs.writeFileSync(path.join(tmpDir, '.oxlintrc.json'), lint); + fs.writeFileSync(path.join(tmpDir, '.oxfmtrc.json'), fmt); + const workspaceInfo = makeWorkspaceInfo(tmpDir, PackageManager.npm); + + for (let run = 0; run < 2; run++) { + expect(finalizeCoreMigrationForExistingVitePlus(workspaceInfo, true).oxcConfigs).toBe(false); + expect(fs.readFileSync(path.join(tmpDir, '.oxlintrc.json'), 'utf8')).toBe(lint); + expect(fs.readFileSync(path.join(tmpDir, '.oxfmtrc.json'), 'utf8')).toBe(fmt); + expect(fs.readFileSync(path.join(tmpDir, 'vite.config.ts'), 'utf8')).toBe(config); + } + }); + + it.each([ + "import shared from '#shared'; export default shared;", + "import shared from /* shared config */ '#shared'; export default shared;", + "export { default } from '#shared';", + "const shared = require('#shared'); export default shared;", + "const shared = await import(/* shared config */ '#shared'); export default shared.default;", + ])('preserves configs behind a package alias: %s', (entry) => { + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ + name: 'root', + imports: { '#shared': { import: './shared.ts', require: './unused.cjs' } }, + }), + ); + fs.writeFileSync(path.join(tmpDir, 'unused.cjs'), 'module.exports = {};\n'); + fs.writeFileSync(path.join(tmpDir, 'entry.ts'), entry); + const config = "import shared from './entry.ts';\nexport default { ...shared };\n"; + fs.writeFileSync(path.join(tmpDir, 'vite.config.ts'), config); + fs.writeFileSync( + path.join(tmpDir, 'shared.ts'), + "import fmt from './.oxfmtrc.json'; import lint from './.oxlintrc.json'; export default { fmt, lint };\n", + ); + const lint = '{"rules":{"no-console":"error"}}\n'; + const fmt = '{"singleQuote":true}\n'; + fs.writeFileSync(path.join(tmpDir, '.oxlintrc.json'), lint); + fs.writeFileSync(path.join(tmpDir, '.oxfmtrc.json'), fmt); + + for (let run = 0; run < 2; run++) { + expect( + finalizeCoreMigrationForExistingVitePlus( + makeWorkspaceInfo(tmpDir, PackageManager.npm), + true, + ).oxcConfigs, + ).toBe(false); + expect(fs.readFileSync(path.join(tmpDir, '.oxlintrc.json'), 'utf8')).toBe(lint); + expect(fs.readFileSync(path.join(tmpDir, '.oxfmtrc.json'), 'utf8')).toBe(fmt); + expect(fs.readFileSync(path.join(tmpDir, 'vite.config.ts'), 'utf8')).toBe(config); + } + }); + + it.each(['main', 'module', 'exports'])( + 'preserves configs behind a directory package with a %s entry', + (field) => { + fs.mkdirSync(path.join(tmpDir, 'config')); + fs.writeFileSync(path.join(tmpDir, 'package.json'), '{"name":"root"}\n'); + fs.writeFileSync( + path.join(tmpDir, 'config/package.json'), + JSON.stringify({ [field]: './shared.ts' }), + ); + // Finding an index is not enough: package metadata can select another file. + fs.writeFileSync(path.join(tmpDir, 'config/index.ts'), 'export default {};\n'); + fs.writeFileSync( + path.join(tmpDir, 'config/shared.ts'), + "import fmt from '../.oxfmtrc.json'; export default { fmt };\n", + ); + const config = "import shared from './config';\nexport default { ...shared };\n"; + const fmt = '{"singleQuote":true}\n'; + fs.writeFileSync(path.join(tmpDir, 'vite.config.ts'), config); + fs.writeFileSync(path.join(tmpDir, '.oxfmtrc.json'), fmt); + + for (let run = 0; run < 2; run++) { + expect( + finalizeCoreMigrationForExistingVitePlus( + makeWorkspaceInfo(tmpDir, PackageManager.npm), + true, + ).oxcConfigs, + ).toBe(false); + expect(fs.readFileSync(path.join(tmpDir, '.oxfmtrc.json'), 'utf8')).toBe(fmt); + expect(fs.readFileSync(path.join(tmpDir, 'vite.config.ts'), 'utf8')).toBe(config); + } + }, + ); + + it('still merges unreferenced configs alongside custom config arguments and local imports', () => { + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ name: 'root', scripts: { lint: 'vp lint --config custom.json src' } }), + ); + fs.writeFileSync(path.join(tmpDir, 'custom.json'), '{"rules":{"no-debugger":"error"}}\n'); + fs.writeFileSync(path.join(tmpDir, 'shared.ts'), 'export default { define: {} };\n'); + fs.writeFileSync( + path.join(tmpDir, 'vite.config.ts'), + "import shared from './shared';\nexport default { ...shared };\n", + ); + fs.writeFileSync(path.join(tmpDir, '.oxfmtrc.json'), '{"singleQuote":true}\n'); + fs.writeFileSync(path.join(tmpDir, '.oxlintrc.json'), '{"rules":{"no-console":"error"}}\n'); + + expect( + finalizeCoreMigrationForExistingVitePlus(makeWorkspaceInfo(tmpDir, PackageManager.npm), true) + .oxcConfigs, + ).toBe(true); + expect(fs.existsSync(path.join(tmpDir, '.oxfmtrc.json'))).toBe(false); + expect(fs.existsSync(path.join(tmpDir, '.oxlintrc.json'))).toBe(false); + expect(fs.readFileSync(path.join(tmpDir, 'custom.json'), 'utf8')).toBe( + '{"rules":{"no-debugger":"error"}}\n', + ); + }); + + it('keeps an unmergeable config and reports the incomplete migration', () => { + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ name: 'test', devDependencies: { 'vite-plus': 'latest' } }), + ); + fs.writeFileSync( + path.join(tmpDir, 'vite.config.ts'), + 'const config = {}; export default config;\n', + ); + fs.writeFileSync(path.join(tmpDir, '.oxfmtrc.json'), '{"singleQuote":true}\n'); + const report = createMigrationReport(); + + const result = finalizeCoreMigrationForExistingVitePlus( + makeWorkspaceInfo(tmpDir, PackageManager.npm), + true, + report, + ); + expect(result.oxcConfigs).toBe(false); + expect(fs.existsSync(path.join(tmpDir, '.oxfmtrc.json'))).toBe(true); + expect(report.warnings.some((warning) => warning.includes('Failed to merge'))).toBe(true); + }); + + it('recovers workspace inheritance with shared TS configs before removing JSON sources', () => { + const appDir = path.join(tmpDir, 'packages/app'); + fs.mkdirSync(appDir, { recursive: true }); + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ name: 'root', devDependencies: { 'vite-plus': 'latest' } }), + ); + fs.writeFileSync(path.join(appDir, 'package.json'), JSON.stringify({ name: 'app' })); + const rootConfig = '{"rules":{"no-console":"error"}}\n'; + const appConfig = '{"extends":["../../.oxlintrc.json"],"rules":{"no-debugger":"error"}}\n'; + fs.writeFileSync(path.join(tmpDir, '.oxlintrc.json'), rootConfig); + fs.writeFileSync(path.join(appDir, '.oxlintrc.json'), appConfig); + const workspaceInfo = { + ...makeWorkspaceInfo(tmpDir, PackageManager.pnpm), + packages: [{ name: 'app', path: 'packages/app' }], + }; + + expect(finalizeCoreMigrationForExistingVitePlus(workspaceInfo, true).oxcConfigs).toBe(true); + const rootViteConfig = fs.readFileSync(path.join(tmpDir, 'vite.config.ts'), 'utf8'); + const appViteConfig = fs.readFileSync(path.join(appDir, 'vite.config.ts'), 'utf8'); + expect(rootViteConfig).toContain('from "./.oxlintrc.js"'); + expect(appViteConfig).toContain('from "../../.oxlintrc.js"'); + expect(fs.readFileSync(path.join(tmpDir, '.oxlintrc.ts'), 'utf8')).toContain( + '"no-console": "error"', + ); + expect(fs.existsSync(path.join(tmpDir, '.oxlintrc.json'))).toBe(false); + expect(fs.existsSync(path.join(appDir, '.oxlintrc.json'))).toBe(false); + expect(finalizeCoreMigrationForExistingVitePlus(workspaceInfo, true).oxcConfigs).toBe(false); + expect(fs.readFileSync(path.join(tmpDir, 'vite.config.ts'), 'utf8')).toBe(rootViteConfig); + expect(fs.readFileSync(path.join(appDir, 'vite.config.ts'), 'utf8')).toBe(appViteConfig); + }); + + it.each(['leaf', 'cycle', 'missing'])( + 'preserves transitive lint inheritance through custom JSON files with a %s target', + (target) => { + const appDir = path.join(tmpDir, 'packages/app'); + fs.mkdirSync(path.join(appDir, 'config'), { recursive: true }); + fs.writeFileSync(path.join(tmpDir, 'package.json'), JSON.stringify({ name: 'root' })); + fs.writeFileSync(path.join(appDir, 'package.json'), JSON.stringify({ name: 'app' })); + const rootConfig = '{"rules":{"no-console":"error"}}\n'; + const appConfig = '{"extends":["./config/lint-base.jsonc"]}\n'; + const targets = ['../../../.oxlintrc.json']; + if (target !== 'leaf') { + targets.push(target === 'cycle' ? '../.oxlintrc.json' : './missing.json'); + } + const baseConfig = `// Shared lint rules\n${JSON.stringify({ extends: targets })}\n`; + fs.writeFileSync(path.join(tmpDir, '.oxlintrc.json'), rootConfig); + fs.writeFileSync(path.join(appDir, '.oxlintrc.json'), appConfig); + fs.writeFileSync(path.join(appDir, 'config/lint-base.jsonc'), baseConfig); + const workspaceInfo = { + ...makeWorkspaceInfo(tmpDir, PackageManager.pnpm), + packages: [{ name: 'app', path: 'packages/app' }], + }; + + const report = createMigrationReport(); + expect(finalizeCoreMigrationForExistingVitePlus(workspaceInfo, true, report).oxcConfigs).toBe( + true, + ); + // The custom JSON file stays available, so its root dependency must remain. + expect(fs.readFileSync(path.join(tmpDir, '.oxlintrc.json'), 'utf8')).toBe(rootConfig); + expect(fs.readFileSync(path.join(appDir, 'config/lint-base.jsonc'), 'utf8')).toBe(baseConfig); + if (target === 'leaf') { + expect(fs.existsSync(path.join(appDir, '.oxlintrc.json'))).toBe(false); + expect(fs.readFileSync(path.join(appDir, 'vite.config.ts'), 'utf8')).toContain( + 'from "./config/lint-base.js"', + ); + expect(report.warnings).toEqual([]); + } else { + expect(fs.readFileSync(path.join(appDir, '.oxlintrc.json'), 'utf8')).toBe(appConfig); + expect(report.warnings).toEqual([expect.stringContaining('Could not migrate')]); + } + expect(finalizeCoreMigrationForExistingVitePlus(workspaceInfo, true).oxcConfigs).toBe(false); + expect(fs.readFileSync(path.join(tmpDir, '.oxlintrc.json'), 'utf8')).toBe(rootConfig); + }, + ); + it('detects package-level legacy signals in workspaces', () => { const appDir = path.join(tmpDir, 'packages', 'app'); fs.mkdirSync(appDir, { recursive: true }); @@ -8741,6 +9344,7 @@ export default defineConfig({ scripts: false, tsconfigTypes: false, imports: true, + oxcConfigs: false, tsdownConfig: true, taskCacheConfig: false, taskCacheWarnings: [], @@ -8760,6 +9364,7 @@ export default defineConfig({ scripts: false, tsconfigTypes: false, imports: false, + oxcConfigs: false, tsdownConfig: false, taskCacheConfig: false, taskCacheWarnings: [], @@ -8799,6 +9404,7 @@ export default defineConfig({ entry: 'src/index.ts' }); scripts: false, tsconfigTypes: false, imports: true, + oxcConfigs: false, tsdownConfig: false, taskCacheConfig: false, taskCacheWarnings: [], @@ -9023,11 +9629,81 @@ export default defineConfig({ const viteConfig = fs.readFileSync(path.join(tmpDir, 'vite.config.ts'), 'utf8'); expect(viteConfig.match(/\bfmt\s*:/g)?.length).toBe(1); - // Template-authored value wins (singleQuote: true) — standalone config dropped. + // Template-authored value wins (singleQuote: true). expect(viteConfig).toContain('singleQuote: true'); expect(viteConfig).not.toContain('singleQuote: false'); - // Redundant standalone file removed. - expect(fs.existsSync(path.join(tmpDir, '.oxfmtrc.jsonc'))).toBe(false); + // The standalone file can still be used outside this config. + expect(fs.existsSync(path.join(tmpDir, '.oxfmtrc.jsonc'))).toBe(true); + }); + + it.each(['.oxlintrc.json', '.oxlintrc.jsonc'])( + 'converts unreferenced JSON extends during a fresh migration and retry (%s)', + (filename) => { + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ + name: 'test', + scripts: { lint: 'oxlint' }, + devDependencies: { oxlint: '^1.88.0', vite: '^8.3.4' }, + }), + ); + fs.writeFileSync( + path.join(tmpDir, 'vite.config.ts'), + "import { defineConfig } from 'vite';\nexport default defineConfig({});\n", + ); + fs.mkdirSync(path.join(tmpDir, 'shared')); + const lint = '{"extends":["./shared/oxlint-config.json"]}\n'; + const shared = '{"rules":{"no-debugger":"error"}}\n'; + fs.writeFileSync(path.join(tmpDir, filename), lint); + fs.writeFileSync(path.join(tmpDir, 'shared/oxlint-config.json'), shared); + const workspaceInfo = makeWorkspaceInfo(tmpDir, PackageManager.npm); + const report = createMigrationReport(); + + rewriteStandaloneProject(tmpDir, workspaceInfo, true, true, report); + + const config = fs.readFileSync(path.join(tmpDir, 'vite.config.ts'), 'utf8'); + expect(config).toContain("from 'vite-plus'"); + expect(config).toMatch(/\blint\s*:/); + expect(config).toContain('from "./shared/oxlint-config.js"'); + expect(fs.existsSync(path.join(tmpDir, filename))).toBe(false); + expect(fs.readFileSync(path.join(tmpDir, 'shared/oxlint-config.ts'), 'utf8')).toContain( + '"no-debugger": "error"', + ); + expect(fs.readFileSync(path.join(tmpDir, 'shared/oxlint-config.json'), 'utf8')).toBe(shared); + expect( + (readJson(path.join(tmpDir, 'package.json')).scripts as Record).lint, + ).toBe('vp lint'); + expect(report.warnings).toEqual([]); + expect(finalizeCoreMigrationForExistingVitePlus(workspaceInfo, true, report).oxcConfigs).toBe( + false, + ); + expect(fs.readFileSync(path.join(tmpDir, 'vite.config.ts'), 'utf8')).toBe(config); + expect(fs.existsSync(path.join(tmpDir, filename))).toBe(false); + expect(report.warnings).toEqual([]); + }, + ); + + it('does not inject defaults over configs retained for explicit script arguments', () => { + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ + name: 'test', + devDependencies: { vite: '^7.0.0' }, + scripts: { fmt: 'oxfmt -c .oxfmtrc.json src', lint: 'oxlint -c .oxlintrc.json src' }, + }), + ); + fs.writeFileSync(path.join(tmpDir, '.oxfmtrc.json'), '{"singleQuote":true}\n'); + fs.writeFileSync(path.join(tmpDir, '.oxlintrc.json'), '{"rules":{"no-console":"error"}}\n'); + + rewriteStandaloneProject(tmpDir, makeWorkspaceInfo(tmpDir, PackageManager.pnpm), true, true); + + expect(fs.existsSync(path.join(tmpDir, 'vite.config.ts'))).toBe(false); + expect(fs.readFileSync(path.join(tmpDir, '.oxfmtrc.json'), 'utf8')).toBe( + '{"singleQuote":true}\n', + ); + expect(fs.readFileSync(path.join(tmpDir, '.oxlintrc.json'), 'utf8')).toBe( + '{"rules":{"no-console":"error"}}\n', + ); }); }); diff --git a/packages/cli/src/migration/__tests__/oxlint-extends.spec.ts b/packages/cli/src/migration/__tests__/oxlint-extends.spec.ts index bdaaedab20..fd68eeb803 100644 --- a/packages/cli/src/migration/__tests__/oxlint-extends.spec.ts +++ b/packages/cli/src/migration/__tests__/oxlint-extends.spec.ts @@ -7,11 +7,12 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { PackageManager } from '../../types/index.ts'; import { + finalizeCoreMigrationForExistingVitePlus, injectLintTypeCheckDefaults, mergeViteConfigFiles, prepareOxlintConfigs, resolveOxlintConfigExtends, - retryPreservedOxlintConfigs, + finalizeOxcConfigMigration, rewriteMonorepo, } from '../migrator.ts'; import { createMigrationReport } from '../report.ts'; @@ -87,6 +88,155 @@ describe('Oxlint JSON extends migration', () => { fs.rmSync(project, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }); + it.each([ + ['fresh', 'script'], + ['fresh', 'module'], + ['fresh', 'custom config'], + ['recovery', 'script'], + ['recovery', 'module'], + ['recovery', 'custom config'], + ])( + 'keeps referenced JSON after a sibling converts its inheritance (%s, %s)', + async (mode, reference) => { + createWorkspace(['a']); + const source = write('.oxlintrc.json', { + rules: { 'no-debugger': 'error' }, + options: { typeAware: false, typeCheck: false }, + }); + const original = fs.readFileSync(source, 'utf8'); + if (reference === 'module') { + write( + 'vite.config.mjs', + 'import rules from "./.oxlintrc.json" with { type: "json" }; export default { define: { rules: JSON.stringify(rules) } };', + ); + } else { + const pkg = JSON.parse(fs.readFileSync(path.join(project, 'package.json'), 'utf8')); + pkg.scripts = { + lint: `oxlint -c ${reference === 'script' ? '.oxlintrc.json' : 'custom.json'} index.js`, + }; + write('package.json', pkg); + if (reference === 'custom config') { + write('custom.json', { extends: ['./.oxlintrc.json'] }); + } + } + write('packages/a/.oxlintrc.json', { + extends: ['../../.oxlintrc.json'], + rules: { 'no-console': 'error' }, + }); + const workspace = { rootDir: project, packages: [{ name: 'a', path: 'packages/a' }] }; + const report = createMigrationReport(); + if (mode === 'fresh') { + expect(migrateWorkspace(['a']).warnings).toEqual([]); + } else { + expect(finalizeCoreMigrationForExistingVitePlus(workspace, true, report).oxcConfigs).toBe( + true, + ); + expect(report.warnings).toEqual([]); + } + expect(fs.readFileSync(source, 'utf8')).toBe(original); + expect((await loadConfig()).lint).toBeUndefined(); + expect((await loadConfig(path.join(project, 'packages/a'))).lint).toMatchObject({ + extends: [{ rules: { 'no-debugger': 'error' } }], + rules: { 'no-console': 'error' }, + }); + expect(fs.existsSync(path.join(project, 'packages/a/.oxlintrc.json'))).toBe(false); + expect(fs.existsSync(path.join(project, '.oxlintrc.ts'))).toBe(true); + expect(finalizeCoreMigrationForExistingVitePlus(workspace, true).oxcConfigs).toBe(false); + expect(fs.readFileSync(source, 'utf8')).toBe(original); + }, + ); + + it.each([ + ['retry', 'pending', 'script'], + ['retry', 'pending', 'module'], + ['retry', 'completed', 'script'], + ['retry', 'completed', 'module'], + ['recovery', 'pending', 'script'], + ['recovery', 'pending', 'module'], + ['recovery', 'completed', 'script'], + ['recovery', 'completed', 'module'], + ])('protects a %s config with a %s marker and a new %s reference', (mode, state, reference) => { + createWorkspace(); + write('.oxlintrc.json', { rules: { 'no-debugger': 'error' } }); + write('packages/a/.oxlintrc.json', { extends: ['../../.oxlintrc.json'] }); + write('packages/b/.oxlintrc.json', { extends: ['../a/.oxlintrc.json'] }); + const unsupported = "export { default } from './other.mjs';"; + const pendingViteConfig = write('packages/b/vite.config.mjs', unsupported); + expect(migrateWorkspace().warnings).toHaveLength(1); + fs.writeFileSync( + pendingViteConfig, + fs.readFileSync(pendingViteConfig, 'utf8').replace(unsupported, 'export default {};'), + ); + const target = state === 'pending' ? 'b' : 'a'; + const source = path.join(project, `packages/${target}/.oxlintrc.json`); + const original = fs.readFileSync(source, 'utf8'); + const viteConfig = path.join(project, `packages/${target}/vite.config.mjs`); + const originalViteConfig = fs.readFileSync(viteConfig, 'utf8'); + if (reference === 'script') { + write('package.json', { + name: 'root', + type: 'module', + scripts: { lint: `vp lint -c packages/${target}/.oxlintrc.json` }, + }); + } else { + fs.appendFileSync( + path.join(project, 'vite.config.mjs'), + `\nimport config from './packages/${target}/.oxlintrc.json' with { type: 'json' };\n`, + ); + } + const packages = ['a', 'b'].map((name) => ({ name, path: `packages/${name}` })); + const report = createMigrationReport(); + const resume = () => + mode === 'retry' + ? finalizeOxcConfigMigration(project, true, report, packages) + : finalizeCoreMigrationForExistingVitePlus({ rootDir: project, packages }, true, report) + .oxcConfigs; + + expect(resume()).toBe(state === 'completed'); + expect(report.warnings).toEqual([]); + expect(fs.readFileSync(source, 'utf8')).toBe(original); + expect(fs.readFileSync(viteConfig, 'utf8')).toBe(originalViteConfig); + expect(fs.existsSync(path.join(project, '.oxlintrc.json'))).toBe(true); + expect(resume()).toBe(false); + }); + + it.each(['script', 'module'])( + 'keeps dependencies relative to each JSON alias referenced by a %s', + (reference) => { + createWorkspace(); + write('shared/lint.json', { extends: ['./.oxlintrc.json'] }); + for (const name of ['a', 'b']) { + write(`packages/${name}/.oxlintrc.json`, { rules: { 'no-debugger': 'error' } }); + fs.symlinkSync('../../shared/lint.json', path.join(project, `packages/${name}/alias.json`)); + } + if (reference === 'script') { + write('package.json', { + name: 'root', + type: 'module', + scripts: { + lint: 'oxlint -c packages/a/alias.json && oxlint -c packages/b/alias.json', + }, + }); + } else { + write( + 'vite.config.mjs', + `import a from './packages/a/alias.json' with { type: 'json' }; +import b from './packages/b/alias.json' with { type: 'json' }; +export default { define: { configs: JSON.stringify([a, b]) } };`, + ); + } + expect(migrateWorkspace().warnings).toEqual([]); + for (const name of ['a', 'b']) { + expect( + resolveOxlintConfigExtends(path.join(project, `packages/${name}/alias.json`)).config, + ).toMatchObject({ extends: [{ rules: { 'no-debugger': 'error' } }] }); + expect( + fs.readFileSync(path.join(project, `packages/${name}/vite.config.mjs`), 'utf8'), + ).toBe('export default {};'); + } + }, + ); + it('resolves nested JSONC paths relative to each declaring file and retains inheritance order', async () => { const base = write( 'shared/base.jsonc', @@ -493,7 +643,7 @@ describe('Oxlint JSON extends migration', () => { ); const retryReport = createMigrationReport(); expect( - retryPreservedOxlintConfigs( + finalizeOxcConfigMigration( project, true, retryReport, @@ -711,7 +861,7 @@ describe('Oxlint JSON extends migration', () => { const report = createMigrationReport(); expect( - retryPreservedOxlintConfigs( + finalizeOxcConfigMigration( project, true, report, @@ -743,43 +893,41 @@ describe('Oxlint JSON extends migration', () => { write('.oxlintrc.json', { rules: { 'no-debugger': 'error' } }); } - expect(retryPreservedOxlintConfigs(project, true)).toBe(false); + expect(finalizeOxcConfigMigration(project, true)).toBe(false); expect(fs.existsSync(path.join(project, '.oxlintrc.json'))).toBe(true); }, ); - it('does not retry unrelated JSON configs in an existing Vite+ project', () => { + it('recovers unreferenced JSON configs without a pending marker in an existing Vite+ project', () => { write('base.json', { rules: { 'no-debugger': 'error' } }); write('.oxlintrc.json', { extends: ['./base.json'] }); const report = createMigrationReport(); - expect(retryPreservedOxlintConfigs(project, true, report)).toBe(false); + expect(finalizeOxcConfigMigration(project, true, report)).toBe(true); expect(report.warnings).toEqual([]); - expect(fs.existsSync(path.join(project, '.oxlintrc.json'))).toBe(true); - expect(fs.existsSync(path.join(project, 'base.ts'))).toBe(false); - expect(fs.readFileSync(path.join(project, 'vite.config.mjs'), 'utf8')).toBe( - 'export default {};', - ); + expect(fs.existsSync(path.join(project, '.oxlintrc.json'))).toBe(false); + expect(fs.existsSync(path.join(project, 'base.ts'))).toBe(true); + expect(fs.readFileSync(path.join(project, 'vite.config.mjs'), 'utf8')).toContain('lint:'); + expect(finalizeOxcConfigMigration(project, true, report)).toBe(false); }); - it('does not retry a new workspace config that references a previously generated module', () => { + it('recovers an unmarked workspace config with a previously generated shared module', () => { write('base.json', { rules: { 'no-debugger': 'error' } }); write('.oxlintrc.json', { extends: ['./base.json'] }); mergeViteConfigFiles(project, true); createWorkspace(['a']); const source = write('packages/a/.oxlintrc.json', { extends: ['../../base.json'] }); - const original = fs.readFileSync(source, 'utf8'); const report = createMigrationReport(); expect( - retryPreservedOxlintConfigs(project, true, report, [{ name: 'a', path: 'packages/a' }]), - ).toBe(false); + finalizeOxcConfigMigration(project, true, report, [{ name: 'a', path: 'packages/a' }]), + ).toBe(true); expect(report.warnings).toEqual([]); - expect(fs.readFileSync(source, 'utf8')).toBe(original); - expect(fs.readFileSync(path.join(project, 'packages/a/vite.config.mjs'), 'utf8')).toBe( - 'export default {};', + expect(fs.existsSync(source)).toBe(false); + expect(fs.readFileSync(path.join(project, 'packages/a/vite.config.mjs'), 'utf8')).toContain( + 'lint:', ); expect(fs.existsSync(path.join(project, 'base.ts'))).toBe(true); }); @@ -795,7 +943,7 @@ describe('Oxlint JSON extends migration', () => { const report = createMigrationReport(); expect( - retryPreservedOxlintConfigs( + finalizeOxcConfigMigration( project, true, report, @@ -828,7 +976,7 @@ describe('Oxlint JSON extends migration', () => { expect(firstReport.warnings).toHaveLength(1); if (failure === 'missing source') { const pendingReport = createMigrationReport(); - expect(retryPreservedOxlintConfigs(project, true, pendingReport)).toBe(false); + expect(finalizeOxcConfigMigration(project, true, pendingReport)).toBe(false); expect(pendingReport.warnings).toHaveLength(1); write('base.json', { rules: { 'no-debugger': 'error' } }); } else { @@ -836,7 +984,7 @@ describe('Oxlint JSON extends migration', () => { } const report = createMigrationReport(); - expect(retryPreservedOxlintConfigs(project, true, report)).toBe(true); + expect(finalizeOxcConfigMigration(project, true, report)).toBe(true); expect(report.warnings).toEqual([]); expect(fs.existsSync(path.join(project, '.oxlintrc.json'))).toBe(false); @@ -856,7 +1004,7 @@ describe('Oxlint JSON extends migration', () => { const report = createMigrationReport(); expect( - retryPreservedOxlintConfigs(project, true, report, [{ name: 'a', path: 'packages/a' }]), + finalizeOxcConfigMigration(project, true, report, [{ name: 'a', path: 'packages/a' }]), ).toBe(true); expect(report.warnings).toEqual([]); const modulePath = path.join(project, '.oxlintrc.ts'); @@ -1111,7 +1259,7 @@ describe('Oxlint JSON extends migration', () => { fs.readFileSync(configPath, 'utf8').replace(viteConfig, 'export default {};'), ); const retryReport = createMigrationReport(); - expect(retryPreservedOxlintConfigs(project, true, retryReport)).toBe(true); + expect(finalizeOxcConfigMigration(project, true, retryReport)).toBe(true); expect(retryReport.warnings).toEqual([]); expect(fs.existsSync(source)).toBe(false); expect((await loadConfig()).lint!.extends![0].rules!['no-debugger']).toBe('error'); diff --git a/packages/cli/src/migration/bin.ts b/packages/cli/src/migration/bin.ts index d374bb2b52..96987f8b48 100644 --- a/packages/cli/src/migration/bin.ts +++ b/packages/cli/src/migration/bin.ts @@ -77,7 +77,6 @@ import { rewriteStandaloneProject, planVitestV5Migration, refreshVitestV5Migration, - retryPreservedOxlintConfigs, prepareOxlintConfigs, removeMigratedOxlintConfigs, shouldSkipStagedMigrationForHooks, @@ -1162,23 +1161,13 @@ async function main() { coreMigrationResult.scripts || coreMigrationResult.tsconfigTypes || coreMigrationResult.imports || + coreMigrationResult.oxcConfigs || coreMigrationResult.tsdownConfig || coreMigrationResult.taskCacheConfig ) { didMigrate = true; } - if ( - retryPreservedOxlintConfigs( - workspaceInfoOptional.rootDir, - true, - report, - workspaceInfoOptional.packages, - ) - ) { - didMigrate = true; - } - // finalizeCore has finished; stop the spinner before the interactive setup // prompts below (collectMigrationSetupPlan / framework shims, in --full mode) // so they don't render on top of the still-running progress line. diff --git a/packages/cli/src/migration/migrator.ts b/packages/cli/src/migration/migrator.ts index 4433d1d157..49f3989adc 100644 --- a/packages/cli/src/migration/migrator.ts +++ b/packages/cli/src/migration/migrator.ts @@ -13,6 +13,7 @@ export * from './migrator/vite-plus-bootstrap.ts'; export * from './migrator/package-json.ts'; export * from './migrator/vite-config.ts'; export * from './migrator/oxlint-config.ts'; +export * from './migrator/oxc-references.ts'; export * from './migrator/git-hooks.ts'; export * from './migrator/setup.ts'; export * from './migrator/core-finalization.ts'; diff --git a/packages/cli/src/migration/migrator/README.md b/packages/cli/src/migration/migrator/README.md index b93087cfde..dfdaa62353 100644 --- a/packages/cli/src/migration/migrator/README.md +++ b/packages/cli/src/migration/migrator/README.md @@ -31,6 +31,7 @@ Pick the file by what a function _does_, not by where it happens to be called. | `source-scan.ts` | Scanning a project's source tree for signals (browser-mode, opt-in providers, `@nuxt/test-utils`, retained upstream-vitest references). | | `vite-config.ts` | `vite.config.ts` merging, default-config injection, staged-config merge, lazy-plugin wrapping, import rewriting (`rewriteAllImports`), migrated-oxlint-config sanitization, lint-staged removal. | | `oxlint-config.ts` | Oxlint JSON inheritance graphs and shared TypeScript config generation. | +| `oxc-references.ts` | References from scripts and modules that protect Oxc JSON configs during migration. | | `eslint.ts` | ESLint → Oxlint migration, oxlint JS-plugin namespace handling, ESLint prompts/warnings. | | `prettier.ts` | Prettier → Oxfmt migration and its prompts/warnings. | | `tsup.ts` | tsup → tsdown (`vp pack`) migration via `tsdown-migrate` and its prompts/warnings. | diff --git a/packages/cli/src/migration/migrator/catalog.ts b/packages/cli/src/migration/migrator/catalog.ts index cd6b13e998..e1a986413b 100644 --- a/packages/cli/src/migration/migrator/catalog.ts +++ b/packages/cli/src/migration/migrator/catalog.ts @@ -1153,6 +1153,7 @@ export function rewriteRootWorkspacePackageJson( // When false, the root `vite-plus` edge and the direct `vite` edge are concrete. supportCatalog = true, preparedOxlintConfigs?: PreparedOxlintConfigs, + preparedReferences?: ReadonlySet, ): void { const packageJsonPath = path.join(projectPath, 'package.json'); if (!fs.existsSync(packageJsonPath)) { @@ -1293,7 +1294,14 @@ export function rewriteRootWorkspacePackageJson( undefined, undefined, catalogDependencyResolver, - packages ? { rootDir: projectPath, packages, oxlintConfigs: preparedOxlintConfigs } : undefined, + packages + ? { + rootDir: projectPath, + packages, + oxlintConfigs: preparedOxlintConfigs, + oxcReferences: preparedReferences, + } + : undefined, true, supportCatalog, ); diff --git a/packages/cli/src/migration/migrator/core-finalization.ts b/packages/cli/src/migration/migrator/core-finalization.ts index d57f2b556a..231bc37982 100644 --- a/packages/cli/src/migration/migrator/core-finalization.ts +++ b/packages/cli/src/migration/migrator/core-finalization.ts @@ -7,6 +7,7 @@ import { editJsonFile, readJsonFile } from '../../utils/json.ts'; import { rulesDir } from '../../utils/path.ts'; import { dropDeadOxlintPluginsDependency, + finalizeOxcConfigMigration, hasTsconfigTypesToRewrite, mergeTsdownConfigFile, migrateTaskCacheConfigInViteConfig, @@ -84,6 +85,7 @@ export type CoreMigrationFinalizationResult = { scripts: boolean; tsconfigTypes: boolean; imports: boolean; + oxcConfigs: boolean; tsdownConfig: boolean; taskCacheConfig: boolean; // Kept out of the report so that review items alone do not make an @@ -154,6 +156,7 @@ export function finalizeCoreMigrationForExistingVitePlus( scripts: false, tsconfigTypes: false, imports: false, + oxcConfigs: false, tsdownConfig: false, taskCacheConfig: false, taskCacheWarnings: [], @@ -191,5 +194,14 @@ export function finalizeCoreMigrationForExistingVitePlus( result.taskCacheConfig; } + // A failed migration may have installed Vite+ before merging these files. + // Finish that core work without opting into unrelated first-time setup. + result.oxcConfigs = finalizeOxcConfigMigration( + workspaceInfo.rootDir, + silent, + report, + workspaceInfo.packages, + ); + return result; } diff --git a/packages/cli/src/migration/migrator/orchestrators.ts b/packages/cli/src/migration/migrator/orchestrators.ts index dc4a2c5550..21b762b277 100644 --- a/packages/cli/src/migration/migrator/orchestrators.ts +++ b/packages/cli/src/migration/migrator/orchestrators.ts @@ -33,6 +33,7 @@ import { migrateTaskCacheConfigInViteConfig, pnpmSupportsWorkspaceSettings, prepareOxlintConfigs, + findReferencedOxcConfigs, supportsCatalog, projectListsRequiredVitestPeer, projectUsesVitestDirectly, @@ -402,13 +403,15 @@ export function rewriteMonorepo( workspaceInfo.downloadPackageManager.version, true, ); + const projectPaths = [ + workspaceInfo.rootDir, + ...workspaceInfo.packages.map((pkg) => path.join(workspaceInfo.rootDir, pkg.path)), + ]; const workspaceContext = { rootDir: workspaceInfo.rootDir, packages: workspaceInfo.packages, - oxlintConfigs: prepareOxlintConfigs([ - workspaceInfo.rootDir, - ...workspaceInfo.packages.map((pkg) => path.join(workspaceInfo.rootDir, pkg.path)), - ]), + oxlintConfigs: prepareOxlintConfigs(projectPaths), + oxcReferences: findReferencedOxcConfigs(projectPaths), }; // rewrite root workspace if (workspaceInfo.packageManager === PackageManager.yarn) { @@ -439,6 +442,7 @@ export function rewriteMonorepo( workspaceUsesVitest, supportCatalog, workspaceContext.oxlintConfigs, + workspaceContext.oxcReferences, ); if (workspaceInfo.packageManager === PackageManager.pnpm) { rewritePnpmWorkspaceYaml( @@ -496,6 +500,7 @@ export function rewriteMonorepo( workspaceInfo.packages, workspaceInfo.rootDir, workspaceContext.oxlintConfigs, + workspaceContext.oxcReferences, ); removeMigratedOxlintConfigs(workspaceContext.oxlintConfigs); injectLintTypeCheckDefaults(workspaceInfo.rootDir, silent, report); @@ -537,6 +542,7 @@ export function rewriteMonorepoProject( rootDir: string; packages: WorkspacePackage[]; oxlintConfigs?: PreparedOxlintConfigs; + oxcReferences?: ReadonlySet; }, deferLazyPluginWrapping = false, // Whether this workspace's edges use catalog references. Yarn catalogs require @@ -557,6 +563,7 @@ export function rewriteMonorepoProject( workspaceContext?.packages, workspaceContext?.rootDir, workspaceContext?.oxlintConfigs, + workspaceContext?.oxcReferences, ); mergeTsdownConfigFile(projectPath, silent, report); diff --git a/packages/cli/src/migration/migrator/oxc-references.ts b/packages/cli/src/migration/migrator/oxc-references.ts new file mode 100644 index 0000000000..8fe08fab5e --- /dev/null +++ b/packages/cli/src/migration/migrator/oxc-references.ts @@ -0,0 +1,209 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +import { readJsonFile } from '../../utils/json.ts'; +import { detectConfigs } from '../detector.ts'; + +const CONFIG_MODULE_EXTENSIONS = ['.ts', '.mts', '.cts', '.tsx', '.js', '.mjs', '.cjs', '.jsx']; +const CONFIG_SOURCE_EXTENSIONS: Record = { + '.js': ['.ts', '.tsx'], + '.mjs': ['.mts'], + '.cjs': ['.cts'], + '.jsx': ['.tsx'], +}; + +function resolveConfigReferences(directory: string, reference: string): string[] | undefined { + // Package imports can select different modules for different loaders or + // conditions. An unresolved reference must never authorize deleting a config. + if (reference.startsWith('#')) { + return undefined; + } + if (!reference) { + return []; + } + const filename = path.resolve(directory, reference); + const extension = path.extname(filename); + const candidates = [filename]; + // Vite resolves .js imports to TypeScript sources, as well as extensionless + // imports and directory indexes. Inspect those sources before deleting JSON. + for (const suffix of CONFIG_SOURCE_EXTENSIONS[extension] ?? []) { + candidates.push(filename.slice(0, -extension.length) + suffix); + } + for (const suffix of CONFIG_MODULE_EXTENSIONS) { + candidates.push(filename + suffix, path.join(filename, `index${suffix}`)); + } + // Preserve references from all matching sources instead of relying on one + // config loader's extension precedence when multiple candidates exist. + const resolved = new Set(); + for (const candidate of candidates) { + if (fs.existsSync(candidate)) { + if (fs.statSync(candidate).isFile()) { + resolved.add(candidate); + } else if (fs.existsSync(path.join(candidate, 'package.json'))) { + // A directory's main/module/exports fields can supersede its index. + // Keep the configs even if another candidate above was found. + return undefined; + } + } + } + return [...resolved]; +} + +/** Find JSON files still needed by scripts, modules, or retained tool configs. */ +export function findReferencedOxcConfigs(projectPaths: string[]): Set { + const projectDirectories = [...projectPaths] + .filter((directory) => fs.existsSync(directory)) + .map((directory) => fs.realpathSync(directory)) + .toSorted((left, right) => right.length - left.length); + // A helper module belongs to its nearest workspace package. Uncertain paths + // there must not prevent unrelated packages from migrating their own configs. + const referenceDirectory = (directory: string): string => + projectDirectories.find( + (project) => directory === project || directory.startsWith(project + path.sep), + ) ?? directory; + const configReferences: { directory: string; content: string }[] = []; + const lintConfigPaths = new Set(); + const preservedConfigs = new Set(); + function preserveJsonConfig(filename: string): void { + preservedConfigs.add(fs.realpathSync(filename)); + // Match sources by identity, but resolve extends from the declaring alias. + lintConfigPaths.add( + path.join(fs.realpathSync(path.dirname(filename)), path.basename(filename)), + ); + } + const modulePaths = new Set(); + const unresolvedConfigDirectories = new Set(); + const migrationCandidates = new Set(); + for (const directory of projectDirectories) { + const packageJsonPath = path.join(directory, 'package.json'); + if (fs.existsSync(packageJsonPath)) { + const pkg = readJsonFile(packageJsonPath) as { scripts?: Record }; + for (const script of Object.values(pkg.scripts ?? {})) { + // Inspect config arguments without executing shell commands. An unknown + // path (for example an environment variable or a preceding `cd`) means + // we cannot safely decide that a standalone config is unused. + const words = (script.match(/(?:[^\s"';&|]+|"[^"]*"|'[^']*')+/g) ?? []).map((word) => + word.replace(/(["'])(.*?)\1/g, '$2'), + ); + const changesDirectory = words.includes('cd'); + for (let index = 0; index < words.length; index++) { + const word = words[index]; + let reference: string; + if (word === '--config' || word === '-c') { + reference = words[++index] ?? ''; + } else if (word.startsWith('--config=')) { + reference = word.slice('--config='.length); + } else if (word.startsWith('-c')) { + reference = word.slice(2).replace(/^=/, ''); + } else { + continue; + } + const filenames = resolveConfigReferences(directory, reference); + if (!filenames?.length || changesDirectory) { + unresolvedConfigDirectories.add(directory); + } else { + // Known references are matched by file identity below. Do not let + // their basenames also preserve a different config in this package. + words[index] = ''; + } + for (const filename of filenames ?? []) { + if (/\.jsonc?$/.test(filename)) { + preserveJsonConfig(filename); + } else if (CONFIG_MODULE_EXTENSIONS.includes(path.extname(filename))) { + modulePaths.add(fs.realpathSync(filename)); + } else { + unresolvedConfigDirectories.add(directory); + } + } + } + configReferences.push({ directory, content: words.join(' ') }); + } + } + const projectConfigs = detectConfigs(directory); + if (projectConfigs.oxlintConfig) { + migrationCandidates.add(path.join(directory, projectConfigs.oxlintConfig)); + } + if (projectConfigs.viteConfig) { + modulePaths.add(fs.realpathSync(path.join(directory, projectConfigs.viteConfig))); + } + } + for (const modulePath of modulePaths) { + const source = fs.readFileSync(modulePath, 'utf8'); + const provenance = source.match(/^\/\/ Generated by vp migrate from (\S+)\.\r?(?:\n|$)/); + if (provenance) { + // Custom JSON sources remain on disk after conversion. On a retry their + // workspace consumer may be gone, but their inherited sources are still needed. + try { + const filename = path.resolve(path.dirname(modulePath), decodeURIComponent(provenance[1])); + if (fs.existsSync(filename) && !migrationCandidates.has(filename)) { + preserveJsonConfig(filename); + } + } catch { + // A user-edited provenance comment is not a resolvable source reference. + } + } + const content = source + // Migration bookkeeping names a source without consuming it at runtime. + .replace(/^\/\/ vp migrate: (?:pending \S+\.|merged \S+ \([a-f0-9]{32}\)\.)\r?$/gm, '') + .replace(/^\/\/ Generated by vp migrate from \S+\.\r?$/gm, ''); + const directory = referenceDirectory(path.dirname(modulePath)); + // Quoted paths and package aliases cover imports, re-exports, require(), + // dynamic import(), and readFileSync/new URL calls, including comments + // between tokens. Extra matches only preserve more configs. + // Canonical paths keep cycles, including symlink cycles, finite. + const unresolvedContent = content.replace( + /(["'`])((?:\.{1,2}\/|\/|#)[^"'`\r\n]+)\1/g, + (match, _quote, reference: string) => { + const filenames = resolveConfigReferences(path.dirname(modulePath), reference); + if (!filenames) { + unresolvedConfigDirectories.add(directory); + } + for (const filename of filenames ?? []) { + if (/\.jsonc?$/.test(filename)) { + preserveJsonConfig(filename); + } else if (CONFIG_MODULE_EXTENSIONS.includes(path.extname(filename))) { + modulePaths.add(fs.realpathSync(filename)); + } + } + return filenames?.length ? '' : match; + }, + ); + configReferences.push({ directory, content: unresolvedContent }); + } + for (const directory of projectDirectories) { + const configs = detectConfigs(directory); + for (const filename of [configs.oxlintConfig, configs.oxfmtConfig]) { + if (!filename) { + continue; + } + if ( + unresolvedConfigDirectories.has(directory) || + configReferences.some( + (reference) => reference.directory === directory && reference.content.includes(filename), + ) + ) { + preserveJsonConfig(path.join(directory, filename)); + } + } + } + // Set iteration also visits newly discovered targets, once each, including + // custom filenames. This follows transitive extends without looping on cycles. + for (const lintConfigPath of lintConfigPaths) { + if (!fs.existsSync(lintConfigPath)) { + continue; + } + const json = readJsonFile(lintConfigPath, true) as { extends?: unknown } | null | undefined; + if (Array.isArray(json?.extends) && json.extends.length > 0) { + // A retained JSON consumer still needs its complete inheritance chain. + for (const extendedConfig of json.extends) { + if (typeof extendedConfig === 'string') { + const resolvedPath = path.resolve(path.dirname(lintConfigPath), extendedConfig); + if (fs.existsSync(resolvedPath)) { + preserveJsonConfig(resolvedPath); + } + } + } + } + } + return preservedConfigs; +} diff --git a/packages/cli/src/migration/migrator/vite-config.ts b/packages/cli/src/migration/migrator/vite-config.ts index 96e6e6d46f..263e026db6 100644 --- a/packages/cli/src/migration/migrator/vite-config.ts +++ b/packages/cli/src/migration/migrator/vite-config.ts @@ -32,6 +32,7 @@ import { collectInstalledPackageNames, oxlintMigrationMarker, prepareOxlintConfigs, + findReferencedOxcConfigs, readRulesYaml, removeMigratedOxlintConfigs, resolveOxlintConfigExtends, @@ -39,7 +40,7 @@ import { sanitizeMigratedOxlintConfig, sanitizeInheritedJsPlugins, } from '../migrator.ts'; -import { type MigrationReport } from '../report.ts'; +import { createMigrationReport, type MigrationReport } from '../report.ts'; import { type OxlintConfigMigration, type OxlintModulePlan, @@ -269,11 +270,38 @@ export function mergeViteConfigFiles( // projectPath IS the workspace root). workspaceRoot?: string, preparedOxlintConfigs?: PreparedOxlintConfigs, + preparedReferences?: ReadonlySet, ): void { const configs = detectConfigs(projectPath); if (!configs.oxfmtConfig && !configs.oxlintConfig) { return; } + const rootDir = workspaceRoot ?? projectPath; + const referencedConfigs = + preparedReferences ?? + findReferencedOxcConfigs([ + ...new Set([ + rootDir, + projectPath, + ...(packages ?? []).map((pkg) => path.join(rootDir, pkg.path)), + ]), + ]); + // Check references before conversion, default injection, or source removal. + if ( + configs.oxlintConfig && + referencedConfigs.has(fs.realpathSync(path.join(projectPath, configs.oxlintConfig))) + ) { + configs.oxlintConfig = undefined; + } + if ( + configs.oxfmtConfig && + referencedConfigs.has(fs.realpathSync(path.join(projectPath, configs.oxfmtConfig))) + ) { + configs.oxfmtConfig = undefined; + } + if (!configs.oxfmtConfig && !configs.oxlintConfig) { + return; + } const viteConfig = ensureViteConfig(projectPath, configs, silent, report); if (configs.oxlintConfig) { mergeOxlintConfigFile( @@ -297,48 +325,33 @@ function pendingOxlintMigrationMarker(filename: string): string { return `// vp migrate: pending ${encodeURIComponent(path.basename(filename))}.`; } -/** Resume partial migrations without applying lint setup to other existing Vite+ projects. */ -export function retryPreservedOxlintConfigs( +/** Finish remaining Oxc merges and deferred cleanup in an existing Vite+ workspace. */ +export function finalizeOxcConfigMigration( workspaceRoot: string, silent = false, - report?: MigrationReport, + report: MigrationReport = createMigrationReport(), packages?: WorkspacePackage[], ): boolean { - const prepared = prepareOxlintConfigs([ + const projectPaths = [ workspaceRoot, ...(packages ?? []).map((pkg) => path.join(workspaceRoot, pkg.path)), - ]); - let updated = false; - for (const [filename, migration] of prepared) { - const projectPath = path.dirname(filename); - const configs = detectConfigs(projectPath); - const existingViteConfig = configs.viteConfig && path.join(projectPath, configs.viteConfig); - const source = existingViteConfig ? fs.readFileSync(existingViteConfig, 'utf8') : ''; - const lines = source.split(/\r?\n/); - if (existingViteConfig && hasConfigKey(existingViteConfig, 'lint')) { - if (!(migration instanceof Error)) { - const marker = oxlintMigrationMarker(filename, migration.file, workspaceRoot); - migration.migrated = lines.includes(marker); - } - continue; - } - if (!lines.includes(pendingOxlintMigrationMarker(filename))) { - continue; - } - const viteConfig = ensureViteConfig(projectPath, configs, silent, report); - mergeOxlintConfigFile( + ]; + // Resolve every graph and reference before any workspace removes a source. + const prepared = prepareOxlintConfigs(projectPaths); + const referencedConfigs = findReferencedOxcConfigs(projectPaths); + const mergedConfigCount = report.mergedConfigCount; + for (const projectPath of projectPaths) { + mergeViteConfigFiles( projectPath, - viteConfig, - path.basename(filename), silent, report, packages, workspaceRoot, prepared, + referencedConfigs, ); - updated ||= !(migration instanceof Error) && migration.migrated === true; } - return removeMigratedOxlintConfigs(prepared) || updated; + return removeMigratedOxlintConfigs(prepared) || report.mergedConfigCount > mergedConfigCount; } function mergeOxlintConfigFile( @@ -389,6 +402,16 @@ function mergeOxlintConfigFile( return; } const { file } = migration; + const fullViteConfigPath = path.join(projectPath, viteConfig); + const hasLintConfig = hasConfigKey(fullViteConfigPath, 'lint'); + if (hasLintConfig && preparedOxlintConfigs) { + const marker = oxlintMigrationMarker(fullOxlintPath, file, workspaceRoot ?? projectPath); + if (fs.readFileSync(fullViteConfigPath, 'utf8').split(/\r?\n/).includes(marker)) { + // A completed merge can retain its source until another workspace is repaired. + migration.migrated = true; + return; + } + } // Keep shared rules in one module, including for the workspace that owns it. // Fields that Oxlint does not inherit must also remain in the owner's local block. const sourceConfig: OxlintConfig = structuredClone(file.config); @@ -404,12 +427,14 @@ function mergeOxlintConfigFile( }; } // Never discard an inheritance tree when a lint block already exists. - if (oxlintJson.extends?.length && hasConfigKey(path.join(projectPath, viteConfig), 'lint')) { - recordPendingMigration(); - warnMigration( - `Preserved ${displayRelative(fullOxlintPath)} because ${viteConfig} already has a lint config. Merge its inherited rules manually.`, - report, - ); + if (hasLintConfig) { + if (oxlintJson.extends?.length) { + recordPendingMigration(); + warnMigration( + `Preserved ${displayRelative(fullOxlintPath)} because ${viteConfig} already has a lint config. Merge its inherited rules manually.`, + report, + ); + } return; } const layers = oxlintConfigLayers(oxlintJson); @@ -587,6 +612,12 @@ function injectConfigDefaults( report?: MigrationReport, ): void { const configs = detectConfigs(projectPath); + if ( + (configKey === 'lint' && configs.oxlintConfig) || + (configKey === 'fmt' && configs.oxfmtConfig) + ) { + return; + } if (configs.viteConfig && hasConfigKey(path.join(projectPath, configs.viteConfig), configKey)) { return; } @@ -654,15 +685,8 @@ function mergeAndRemoveJsonConfig( // AST-based check ignores comments, string-literal occurrences, and nested // keys (e.g. `plugins: [{ fmt: ... }]`). if (hasConfigKey(fullViteConfigPath, configKey)) { - if (!deferRemoval) { - fs.unlinkSync(fullJsonConfigPath); - } - if (!silent) { - prompts.log.info( - `${configKey} config already present in ${displayRelative(fullViteConfigPath)} — ${deferRemoval ? 'deferred removal of' : 'removed redundant'} ${displayRelative(fullJsonConfigPath)}`, - ); - } - return true; + // An existing block does not prove that this file has already been merged. + return false; } // Only delete the original JSON after a successful merge. Resolved lint // configs contain object extends, which JSON Oxlint configs do not accept.