vite-plus 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -2,43 +2,62 @@
2
2
 
3
3
  # Using Vite+, the Unified Toolchain for the Web
4
4
 
5
- This project is using Vite+, a modern toolchain built on top of Vite, Rolldown, Vitest, tsdown, Oxlint, and Oxfmt. Vite+ wraps these tools and package manager commands in a single, global CLI called `vp`. Vite+ is distinct from Vite, but it invokes Vite through `vp dev` and `vp build`.
5
+ This project is using Vite+, a unified toolchain built on top of Vite, Rolldown, Vitest, tsdown, Oxlint, Oxfmt, and Vite Task. Vite+ wraps runtime management, package management, and frontend tooling in a single global CLI called `vp`. Vite+ is distinct from Vite, but it invokes Vite through `vp dev` and `vp build`.
6
6
 
7
7
  ## Vite+ Workflow
8
8
 
9
9
  `vp` is a global binary that handles the full development lifecycle. Run `vp help` to print a list of commands and `vp <command> --help` for information about a specific command.
10
10
 
11
- ### Vite+ Commands
11
+ ### Start
12
+
13
+ - create - Create a new project from a template
14
+ - migrate - Migrate an existing project to Vite+
15
+ - config - Configure hooks and agent integration
16
+ - staged - Run linters on staged files
17
+ - install (`i`) - Install dependencies
18
+ - env - Manage Node.js versions
19
+
20
+ ### Develop
12
21
 
13
22
  - dev - Run the development server
14
- - build - Build for production
23
+ - check - Run format, lint, and TypeScript type checks
15
24
  - lint - Lint code
16
- - test - Run tests
17
25
  - fmt - Format code
18
- - check - Run format, lint, and type checks
19
- - lib - Build library
20
- - migrate - Migrate an existing project to Vite+
21
- - create - Create a new monorepo package (in-project) or a new project (global)
22
- - exec - Execute a command in workspace packages (supports `--filter`, `-r`, `--parallel`)
23
- - run - Run tasks from `package.json` scripts
26
+ - test - Run tests
24
27
 
25
- These commands map to their corresponding tools. For example, `vp dev --port 3000` runs Vite's dev server and works the same as Vite. `vp test` runs JavaScript tests through the bundled Vitest. The version of all tools can be checked using `vp --version`. This is useful when researching documentation, features, and bugs.
28
+ ### Execute
29
+
30
+ - run - Run monorepo tasks
31
+ - exec - Execute a command from local `node_modules/.bin`
32
+ - dlx - Execute a package binary without installing it as a dependency
33
+ - cache - Manage the task cache
34
+
35
+ ### Build
26
36
 
27
- ### Package Manager Commands
37
+ - build - Build for production
38
+ - pack - Build libraries
39
+ - preview - Preview production build
40
+
41
+ ### Manage Dependencies
28
42
 
29
43
  Vite+ automatically detects and wraps the underlying package manager such as pnpm, npm, or Yarn through the `packageManager` field in `package.json` or package manager-specific lockfiles.
30
44
 
31
- - install - Install all dependencies, or add packages if package names are provided
32
45
  - add - Add packages to dependencies
33
- - remove - Remove packages from dependencies
34
- - dlx - Execute a package binary without installing it as a dependency
35
- - info - View package information from the registry, including latest versions
36
- - link - Link packages for local development
46
+ - remove (`rm`, `un`, `uninstall`) - Remove packages from dependencies
47
+ - update (`up`) - Update packages to latest versions
48
+ - dedupe - Deduplicate dependencies
37
49
  - outdated - Check for outdated packages
50
+ - list (`ls`) - List installed packages
51
+ - why (`explain`) - Show why a package is installed
52
+ - info (`view`, `show`) - View package information from the registry
53
+ - link (`ln`) / unlink - Manage local package links
38
54
  - pm - Forward a command to the package manager
39
- - unlink - Unlink packages
40
- - update - Update packages to their latest versions
41
- - why - Show why a package is installed
55
+
56
+ ### Maintain
57
+
58
+ - upgrade - Update `vp` itself to the latest version
59
+
60
+ These commands map to their corresponding tools. For example, `vp dev --port 3000` runs Vite's dev server and works the same as Vite. `vp test` runs JavaScript tests through the bundled Vitest. The version of all tools can be checked using `vp --version`. This is useful when researching documentation, features, and bugs.
42
61
 
43
62
  ## Common Pitfalls
44
63
 
@@ -46,11 +65,12 @@ Vite+ automatically detects and wraps the underlying package manager such as pnp
46
65
  - **Always use Vite commands to run tools:** Don't attempt to run `vp vitest` or `vp oxlint`. They do not exist. Use `vp test` and `vp lint` instead.
47
66
  - **Running scripts:** Vite+ commands take precedence over `package.json` scripts. If there is a `test` script defined in `scripts` that conflicts with the built-in `vp test` command, run it using `vp run test`.
48
67
  - **Do not install Vitest, Oxlint, Oxfmt, or tsdown directly:** Vite+ wraps these tools. They must not be installed directly. You cannot upgrade these tools by installing their latest versions. Always use Vite+ commands.
68
+ - **Use Vite+ wrappers for one-off binaries:** Use `vp dlx` instead of package-manager-specific `dlx`/`npx` commands.
49
69
  - **Import JavaScript modules from `vite-plus`:** Instead of importing from `vite` or `vitest`, all modules should be imported from the project's `vite-plus` dependency. For example, `import { defineConfig } from 'vite-plus';` or `import { expect, test, vi } from 'vite-plus/test';`. You must not install `vitest` to import test utilities.
50
70
  - **Type-Aware Linting:** There is no need to install `oxlint-tsgolint`, `vp lint --type-aware` works out of the box.
51
71
 
52
72
  ## Review Checklist for Agents
53
73
 
54
74
  - [ ] Run `vp install` after pulling remote changes and before getting started.
55
- - [ ] Run `vp lint`, `vp fmt`, and `vp test` to validate changes.
75
+ - [ ] Run `vp check` and `vp test` to validate changes.
56
76
  <!--VITE PLUS END-->
package/README.md CHANGED
@@ -1,22 +1,26 @@
1
1
  # VITE+(⚡︎) Local CLI
2
2
 
3
3
  **The Unified Toolchain for the Web**
4
- _dev, build, test, lint, format, monorepo caching & more in a single dependency, built for scale, speed, and sanity_
4
+ _runtime and package management, create, dev, check, test, build, pack, and monorepo task caching in a single dependency_
5
5
 
6
6
  This package provides the project-local version of Vite+. The global `vite` command automatically delegates to this package for all project-specific tasks.
7
7
 
8
8
  ---
9
9
 
10
- Vite+ combines [Vite](https://vite.dev/), [Vitest](https://vitest.dev/), [Oxlint](https://oxc.rs/docs/guide/usage/linter.html), [Oxfmt](https://oxc.rs/docs/guide/usage/formatter.html), [tsdown](https://tsdown.dev/) and [Rolldown](https://rolldown.rs/) as a single zero-config toolchain:
10
+ Vite+ is the unified entry point for local web development. It combines [Vite](https://vite.dev/), [Vitest](https://vitest.dev/), [Oxlint](https://oxc.rs/docs/guide/usage/linter.html), [Oxfmt](https://oxc.rs/docs/guide/usage/formatter.html), [Rolldown](https://rolldown.rs/), [tsdown](https://tsdown.dev/), and [Vite Task](https://github.com/voidzero-dev/vite-task) into one zero-config toolchain that also manages runtime and package manager workflows:
11
11
 
12
- - **Dev Server:** Powered by Vite's fast development experience with native ES modules and instant HMR
13
- - **Build Tool:** Optimized production builds using Rolldown and Oxc
14
- - **Testing:** Seamless Vitest integration with fast feedback loops
15
- - **Linting:** Ships with Oxlint for quick code quality checks
16
- - **Task Runner:** Monorepo task execution with automated caching and dependency resolution
17
- - **Package Management:** Vite+ wraps package managers to provide a unified interface
12
+ - **`vp env`:** Manage Node.js globally and per project
13
+ - **`vp install`:** Install dependencies with automatic package manager detection
14
+ - **`vp dev`:** Run Vite's fast native ESM dev server with instant HMR
15
+ - **`vp check`:** Run formatting, linting, and type checks in one command
16
+ - **`vp test`:** Run tests through bundled Vitest
17
+ - **`vp build`:** Build applications for production with Vite + Rolldown
18
+ - **`vp run`:** Execute monorepo tasks with caching and dependency-aware scheduling
19
+ - **`vp pack`:** Build libraries for npm publishing or standalone app binaries
20
+ - **`vp create` / `vp migrate`:** Scaffold new projects and migrate existing ones
18
21
 
19
- Vite+ is built to scale with your codebase while reducing your devtools to a single dependency.
22
+ All of this is configured from your project root and works across Vite's framework ecosystem.
23
+ Vite+ is fully open-source under the MIT license.
20
24
 
21
25
  ## Getting Started
22
26
 
@@ -25,44 +29,115 @@ Install Vite+ globally as `vp`:
25
29
  For Linux or macOS:
26
30
 
27
31
  ```bash
28
- curl -fsSL https://staging.viteplus.dev/install.sh | bash
32
+ curl -fsSL https://viteplus.dev/install.sh | bash
29
33
  ```
30
34
 
31
35
  For Windows:
32
36
 
33
37
  ```bash
34
- irm https://staging.viteplus.dev/install.ps1 | iex
38
+ irm https://viteplus.dev/install.ps1 | iex
35
39
  ```
36
40
 
37
41
  `vp` handles the full development lifecycle such as package management, development servers, linting, formatting, testing and building for production.
38
42
 
39
- ### Vite+ Commands
43
+ ## Configuring Vite+
44
+
45
+ Vite+ can be configured using a single `vite.config.ts` at the root of your project:
46
+
47
+ ```ts
48
+ import { defineConfig } from 'vite-plus';
49
+
50
+ export default defineConfig({
51
+ // Standard Vite configuration for dev/build/preview.
52
+ plugins: [],
53
+
54
+ // Vitest configuration.
55
+ test: {
56
+ include: ['src/**/*.test.ts'],
57
+ },
58
+
59
+ // Oxlint configuration.
60
+ lint: {
61
+ ignorePatterns: ['dist/**'],
62
+ },
63
+
64
+ // Oxfmt configuration.
65
+ fmt: {
66
+ semi: true,
67
+ singleQuote: true,
68
+ },
69
+
70
+ // Vite Task configuration.
71
+ run: {
72
+ tasks: {
73
+ 'generate:icons': {
74
+ command: 'node scripts/generate-icons.js',
75
+ envs: ['ICON_THEME'],
76
+ },
77
+ },
78
+ },
79
+
80
+ // `vp staged` configuration.
81
+ staged: {
82
+ '*': 'vp check --fix',
83
+ },
84
+ });
85
+ ```
86
+
87
+ This lets you keep the configuration for your development server, build, test, lint, format, task runner, and staged-file workflow in one place with type-safe config and shared defaults.
88
+
89
+ Use `vp migrate` to migrate to Vite+. It merges tool-specific config files such as `.oxlintrc*`, `.oxfmtrc*`, and lint-staged config into `vite.config.ts`.
90
+
91
+ ### CLI Workflows (`vp help`)
92
+
93
+ #### Start
94
+
95
+ - **create** - Create a new project from a template
96
+ - **migrate** - Migrate an existing project to Vite+
97
+ - **config** - Configure hooks and agent integration
98
+ - **staged** - Run linters on staged files
99
+ - **install** (`i`) - Install dependencies
100
+ - **env** - Manage Node.js versions
101
+
102
+ #### Develop
40
103
 
41
104
  - **dev** - Run the development server
42
- - **build** - Build for production
105
+ - **check** - Run format, lint, and type checks
43
106
  - **lint** - Lint code
44
- - **test** - Run tests
45
107
  - **fmt** - Format code
46
- - **lib** - Build library
47
- - **migrate** - Migrate an existing project to Vite+
48
- - **create** - Create a new monorepo package (in-project) or a new project (global)
49
- - **run** - Run tasks from `package.json` scripts
108
+ - **test** - Run tests
109
+
110
+ #### Execute
111
+
112
+ - **run** - Run monorepo tasks
113
+ - **exec** - Execute a command from local `node_modules/.bin`
114
+ - **dlx** - Execute a package binary without installing it as a dependency
115
+ - **cache** - Manage the task cache
116
+
117
+ #### Build
50
118
 
51
- ### Package Manager Commands
119
+ - **build** - Build for production
120
+ - **pack** - Build libraries
121
+ - **preview** - Preview production build
122
+
123
+ #### Manage Dependencies
52
124
 
53
- Vite+ automatically detects and wraps the underlying package manager such as pnpm, npm, or Yarn through the `packageManager` field in `package.json` or package manager-specific lockfiles.
125
+ Vite+ automatically wraps your package manager (pnpm, npm, or Yarn) based on `packageManager` and lockfiles:
54
126
 
55
- - **install** - Install all dependencies, or add packages if package names are provided
56
127
  - **add** - Add packages to dependencies
57
- - **remove** - Remove packages from dependencies
58
- - **dlx** - Execute a package binary without installing it as a dependency
59
- - **info** - View package information from the registry, including latest versions
60
- - **link** - Link packages for local development
61
- - **outdated** - Check for outdated packages
128
+ - **remove** (`rm`, `un`, `uninstall`) - Remove packages from dependencies
129
+ - **update** (`up`) - Update packages to latest versions
130
+ - **dedupe** - Deduplicate dependencies
131
+ - **outdated** - Check outdated packages
132
+ - **list** (`ls`) - List installed packages
133
+ - **why** (`explain`) - Show why a package is installed
134
+ - **info** (`view`, `show`) - View package metadata from the registry
135
+ - **link** (`ln`) / **unlink** - Manage local package links
62
136
  - **pm** - Forward a command to the package manager
63
- - **unlink** - Unlink packages
64
- - **update** - Update packages to their latest versions
65
- - **why** - Show why a package is installed
137
+
138
+ #### Maintain
139
+
140
+ - **upgrade** - Update `vp` itself to the latest version
66
141
 
67
142
  ### Scaffolding your first Vite+ project
68
143
 
package/dist/bin.js CHANGED
@@ -9,7 +9,9 @@
9
9
  * vite-plus installation using oxc_resolver and runs its dist/bin.js directly.
10
10
  * If no local installation is found, this global dist/bin.js is used as fallback.
11
11
  */
12
+ import path from 'node:path';
12
13
  import { run } from '../binding/index.js';
14
+ import { applyToolInitConfigToViteConfig, inspectInitCommand } from './init-config.js';
13
15
  import { doc } from './resolve-doc.js';
14
16
  import { fmt } from './resolve-fmt.js';
15
17
  import { lint } from './resolve-lint.js';
@@ -17,6 +19,7 @@ import { pack } from './resolve-pack.js';
17
19
  import { test } from './resolve-test.js';
18
20
  import { resolveUniversalViteConfig } from './resolve-vite-config.js';
19
21
  import { vite } from './resolve-vite.js';
22
+ import { accent, log } from './utils/terminal.js';
20
23
  // Parse command line arguments
21
24
  let args = process.argv.slice(2);
22
25
  // Transform `vp help [command]` into `vp [command] --help`
@@ -53,21 +56,51 @@ else if (command === 'staged') {
53
56
  }
54
57
  else {
55
58
  // All other commands — delegate to Rust core via NAPI binding
56
- run({
57
- lint,
58
- pack,
59
- fmt,
60
- vite,
61
- test,
62
- doc,
63
- resolveUniversalViteConfig,
64
- args: process.argv.slice(2),
65
- })
66
- .then((exitCode) => {
67
- process.exit(exitCode);
68
- })
69
- .catch((err) => {
59
+ try {
60
+ const initInspection = inspectInitCommand(command, args.slice(1));
61
+ if (initInspection.handled &&
62
+ initInspection.configKey &&
63
+ initInspection.hasExistingConfigKey &&
64
+ initInspection.existingViteConfigPath) {
65
+ log(`Skipped initialization: '${accent(initInspection.configKey)}' already exists in '${accent(path.basename(initInspection.existingViteConfigPath))}'.`);
66
+ process.exit(0);
67
+ }
68
+ const exitCode = await run({
69
+ lint,
70
+ pack,
71
+ fmt,
72
+ vite,
73
+ test,
74
+ doc,
75
+ resolveUniversalViteConfig,
76
+ args: process.argv.slice(2),
77
+ });
78
+ let finalExitCode = exitCode;
79
+ if (exitCode === 0) {
80
+ try {
81
+ const result = await applyToolInitConfigToViteConfig(command, args.slice(1));
82
+ if (result.handled &&
83
+ result.action === 'added' &&
84
+ result.configKey &&
85
+ result.viteConfigPath) {
86
+ log(`Added '${accent(result.configKey)}' to '${accent(path.basename(result.viteConfigPath))}'.`);
87
+ }
88
+ if (result.handled &&
89
+ result.action === 'skipped-existing' &&
90
+ result.configKey &&
91
+ result.viteConfigPath) {
92
+ log(`Skipped initialization: '${accent(result.configKey)}' already exists in '${accent(path.basename(result.viteConfigPath))}'.`);
93
+ }
94
+ }
95
+ catch (err) {
96
+ console.error('[Vite+] Failed to initialize config in vite.config.ts:', err);
97
+ finalExitCode = 1;
98
+ }
99
+ }
100
+ process.exit(finalExitCode);
101
+ }
102
+ catch (err) {
70
103
  console.error('[Vite+] run error:', err);
71
104
  process.exit(1);
72
- });
105
+ }
73
106
  }
@@ -135,6 +135,17 @@ async function main() {
135
135
  }
136
136
  }
137
137
  const packageManager = workspaceInfoOptional.packageManager ?? await selectPackageManager(options.interactive);
138
+ let shouldSetupHooks = await promptGitHooks(options);
139
+ const selectedAgentTargetPaths = await selectAgentTargetPaths({
140
+ interactive: options.interactive,
141
+ agent: options.agent,
142
+ onCancel: () => cancelAndExit()
143
+ });
144
+ const selectedEditor = await selectEditor({
145
+ interactive: options.interactive,
146
+ editor: options.editor,
147
+ onCancel: () => cancelAndExit()
148
+ });
138
149
  const downloadResult = await downloadPackageManager$1(packageManager, workspaceInfoOptional.packageManagerVersion, options.interactive);
139
150
  const workspaceInfo = {
140
151
  ...workspaceInfoOptional,
@@ -156,7 +167,6 @@ async function main() {
156
167
  if (!isViteSupported || !isVitestSupported) {
157
168
  cancelAndExit("Vite+ cannot automatically migrate this project yet.", 1);
158
169
  }
159
- let shouldSetupHooks = await promptGitHooks(options);
160
170
  if (shouldSetupHooks) {
161
171
  const reason = preflightGitHooksSetup(workspaceInfo.rootDir);
162
172
  if (reason) {
@@ -173,21 +183,11 @@ async function main() {
173
183
  if (shouldSetupHooks) {
174
184
  installGitHooks(workspaceInfo.rootDir);
175
185
  }
176
- const selectedAgentTargetPaths = await selectAgentTargetPaths({
177
- interactive: options.interactive,
178
- agent: options.agent,
179
- onCancel: () => cancelAndExit()
180
- });
181
186
  await writeAgentInstructions({
182
187
  projectRoot: workspaceInfo.rootDir,
183
188
  targetPaths: selectedAgentTargetPaths,
184
189
  interactive: options.interactive
185
190
  });
186
- const selectedEditor = await selectEditor({
187
- interactive: options.interactive,
188
- editor: options.editor,
189
- onCancel: () => cancelAndExit()
190
- });
191
191
  await writeEditorConfigs({
192
192
  projectRoot: workspaceInfo.rootDir,
193
193
  editorId: selectedEditor,
@@ -1,5 +1,5 @@
1
1
  import { o as VITE_PLUS_NAME } from "./json-Bfvtp2rL.js";
2
- import { t as detectPackageMetadata } from "./package-Pq2biU7_.js";
2
+ import { r as hasVitePlusDependency, t as detectPackageMetadata } from "./package-Pq2biU7_.js";
3
3
  import { a as renderCliDoc, n as log, t as accent } from "./terminal-Cb-NuRkb.js";
4
4
  import path from "node:path";
5
5
  import fs from "node:fs";
@@ -16,8 +16,27 @@ function getCliVersion() {
16
16
  return pkg?.version ?? null;
17
17
  }
18
18
  function getLocalMetadata(cwd) {
19
+ if (!isVitePlusDeclaredInAncestors(cwd)) {
20
+ return null;
21
+ }
19
22
  return detectPackageMetadata(cwd, VITE_PLUS_NAME) ?? null;
20
23
  }
24
+ function isVitePlusDeclaredInAncestors(cwd) {
25
+ let currentDir = path.resolve(cwd);
26
+ while (true) {
27
+ const packageJsonPath = path.join(currentDir, "package.json");
28
+ const pkg = readPackageJsonFromPath(packageJsonPath);
29
+ if (pkg && hasVitePlusDependency(pkg)) {
30
+ return true;
31
+ }
32
+ const parentDir = path.dirname(currentDir);
33
+ if (parentDir === currentDir) {
34
+ break;
35
+ }
36
+ currentDir = parentDir;
37
+ }
38
+ return false;
39
+ }
21
40
  function readPackageJsonFromPath(packageJsonPath) {
22
41
  try {
23
42
  return JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
@@ -114,17 +133,19 @@ async function printVersion(cwd) {
114
133
  bundledVersionKey: "tsdown"
115
134
  }
116
135
  ];
117
- const resolvedTools = tools.map((tool) => ({
118
- tool,
119
- version: localMetadata ? resolveToolVersion(tool, localMetadata.path) : null
120
- }));
121
- sections.push({
122
- title: "Tools",
123
- rows: resolvedTools.map(({ tool, version }) => ({
124
- label: accent(tool.displayName),
125
- description: version ? `v${version}` : "Not found"
126
- }))
127
- });
136
+ if (localMetadata) {
137
+ const resolvedTools = tools.map((tool) => ({
138
+ tool,
139
+ version: resolveToolVersion(tool, localMetadata.path)
140
+ }));
141
+ sections.push({
142
+ title: "Tools",
143
+ rows: resolvedTools.map(({ tool, version }) => ({
144
+ label: accent(tool.displayName),
145
+ description: version ? `v${version}` : "Not found"
146
+ }))
147
+ });
148
+ }
128
149
  log(renderCliDoc({ sections }));
129
150
  }
130
151
  await printVersion(process.cwd());
@@ -0,0 +1,20 @@
1
+ export interface InitCommandInspection {
2
+ handled: boolean;
3
+ configKey?: 'lint' | 'fmt';
4
+ existingViteConfigPath?: string;
5
+ hasExistingConfigKey?: boolean;
6
+ }
7
+ export interface ApplyToolInitResult {
8
+ handled: boolean;
9
+ action?: 'added' | 'skipped-existing' | 'no-generated-config';
10
+ configKey?: 'lint' | 'fmt';
11
+ viteConfigPath?: string;
12
+ }
13
+ export declare function inspectInitCommand(command: string | undefined, args: string[], projectPath?: string): InitCommandInspection;
14
+ /**
15
+ * Merge generated tool config from `vp lint/fmt --init` (and fmt --migrate)
16
+ * into the project's vite config, then remove the generated standalone file.
17
+ *
18
+ * Returns true when the command was an init/migrate command (handled), false otherwise.
19
+ */
20
+ export declare function applyToolInitConfigToViteConfig(command: string | undefined, args: string[], projectPath?: string): Promise<ApplyToolInitResult>;
@@ -0,0 +1,210 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { mergeJsonConfig } from '../binding/index.js';
4
+ import { fmt as resolveFmt } from './resolve-fmt.js';
5
+ import { runCommandSilently } from './utils/command.js';
6
+ import { VITE_PLUS_NAME } from './utils/constants.js';
7
+ const INIT_COMMAND_SPECS = {
8
+ lint: {
9
+ configKey: 'lint',
10
+ triggerFlags: ['--init'],
11
+ defaultConfigFiles: ['.oxlintrc.json'],
12
+ },
13
+ fmt: {
14
+ configKey: 'fmt',
15
+ triggerFlags: ['--init', '--migrate'],
16
+ defaultConfigFiles: ['.oxfmtrc.json', '.oxfmtrc.jsonc'],
17
+ },
18
+ };
19
+ const VITE_CONFIG_FILES = [
20
+ 'vite.config.ts',
21
+ 'vite.config.mts',
22
+ 'vite.config.cts',
23
+ 'vite.config.js',
24
+ 'vite.config.mjs',
25
+ 'vite.config.cjs',
26
+ ];
27
+ function optionTerminatorIndex(args) {
28
+ const index = args.indexOf('--');
29
+ return index === -1 ? args.length : index;
30
+ }
31
+ function hasTriggerFlag(args, triggerFlags) {
32
+ const limit = optionTerminatorIndex(args);
33
+ for (let i = 0; i < limit; i++) {
34
+ const arg = args[i];
35
+ if (triggerFlags.some((flag) => arg === flag || arg.startsWith(`${flag}=`))) {
36
+ return true;
37
+ }
38
+ }
39
+ return false;
40
+ }
41
+ function extractConfigPathArg(args) {
42
+ const limit = optionTerminatorIndex(args);
43
+ for (let i = 0; i < limit; i++) {
44
+ const arg = args[i];
45
+ if (arg === '-c' || arg === '--config') {
46
+ const value = args[i + 1];
47
+ return value ? value : null;
48
+ }
49
+ if (arg.startsWith('--config=')) {
50
+ return arg.slice('--config='.length);
51
+ }
52
+ if (arg.startsWith('-c=')) {
53
+ return arg.slice('-c='.length);
54
+ }
55
+ }
56
+ return null;
57
+ }
58
+ function resolveGeneratedConfigPath(projectPath, args, defaultConfigFiles) {
59
+ const configArg = extractConfigPathArg(args);
60
+ if (configArg) {
61
+ const resolved = path.isAbsolute(configArg) ? configArg : path.join(projectPath, configArg);
62
+ if (fs.existsSync(resolved)) {
63
+ return resolved;
64
+ }
65
+ }
66
+ for (const filename of defaultConfigFiles) {
67
+ const fullPath = path.join(projectPath, filename);
68
+ if (fs.existsSync(fullPath)) {
69
+ return fullPath;
70
+ }
71
+ }
72
+ return null;
73
+ }
74
+ function findViteConfigPath(projectPath) {
75
+ for (const filename of VITE_CONFIG_FILES) {
76
+ const fullPath = path.join(projectPath, filename);
77
+ if (fs.existsSync(fullPath)) {
78
+ return fullPath;
79
+ }
80
+ }
81
+ return null;
82
+ }
83
+ function ensureViteConfigPath(projectPath) {
84
+ const existing = findViteConfigPath(projectPath);
85
+ if (existing) {
86
+ return existing;
87
+ }
88
+ const viteConfigPath = path.join(projectPath, 'vite.config.ts');
89
+ fs.writeFileSync(viteConfigPath, `import { defineConfig } from '${VITE_PLUS_NAME}';
90
+
91
+ export default defineConfig({});
92
+ `);
93
+ return viteConfigPath;
94
+ }
95
+ function hasConfigKey(viteConfigPath, configKey) {
96
+ const viteConfig = fs.readFileSync(viteConfigPath, 'utf8');
97
+ return new RegExp(`\\b${configKey}\\s*:`).test(viteConfig);
98
+ }
99
+ async function vpFmt(cwd, filePath) {
100
+ const { binPath, envs } = await resolveFmt();
101
+ const result = await runCommandSilently({
102
+ command: binPath,
103
+ args: ['--write', filePath],
104
+ cwd,
105
+ envs: {
106
+ ...process.env,
107
+ ...envs,
108
+ },
109
+ });
110
+ if (result.exitCode !== 0) {
111
+ throw new Error(`Failed to format ${filePath} with vp fmt:\n${result.stdout.toString()}${result.stderr.toString()}`);
112
+ }
113
+ }
114
+ function resolveInitSpec(command, args) {
115
+ if (!command) {
116
+ return null;
117
+ }
118
+ const spec = INIT_COMMAND_SPECS[command];
119
+ if (!spec || !hasTriggerFlag(args, spec.triggerFlags)) {
120
+ return null;
121
+ }
122
+ return spec;
123
+ }
124
+ export function inspectInitCommand(command, args, projectPath = process.cwd()) {
125
+ const spec = resolveInitSpec(command, args);
126
+ if (!spec) {
127
+ return { handled: false };
128
+ }
129
+ const viteConfigPath = findViteConfigPath(projectPath);
130
+ if (!viteConfigPath) {
131
+ return {
132
+ handled: true,
133
+ configKey: spec.configKey,
134
+ hasExistingConfigKey: false,
135
+ };
136
+ }
137
+ return {
138
+ handled: true,
139
+ configKey: spec.configKey,
140
+ existingViteConfigPath: viteConfigPath,
141
+ hasExistingConfigKey: hasConfigKey(viteConfigPath, spec.configKey),
142
+ };
143
+ }
144
+ /**
145
+ * Merge generated tool config from `vp lint/fmt --init` (and fmt --migrate)
146
+ * into the project's vite config, then remove the generated standalone file.
147
+ *
148
+ * Returns true when the command was an init/migrate command (handled), false otherwise.
149
+ */
150
+ export async function applyToolInitConfigToViteConfig(command, args, projectPath = process.cwd()) {
151
+ const inspection = inspectInitCommand(command, args, projectPath);
152
+ if (!inspection.handled || !inspection.configKey) {
153
+ return { handled: false };
154
+ }
155
+ const spec = INIT_COMMAND_SPECS[command];
156
+ const viteConfigPath = ensureViteConfigPath(projectPath);
157
+ const generatedConfigPath = resolveGeneratedConfigPath(projectPath, args, spec.defaultConfigFiles);
158
+ if (hasConfigKey(viteConfigPath, spec.configKey)) {
159
+ if (generatedConfigPath) {
160
+ fs.rmSync(generatedConfigPath, { force: true });
161
+ }
162
+ return {
163
+ handled: true,
164
+ action: 'skipped-existing',
165
+ configKey: spec.configKey,
166
+ viteConfigPath,
167
+ };
168
+ }
169
+ if (spec.configKey === 'lint' && hasTriggerFlag(args, ['--init'])) {
170
+ const lintInitConfigPath = path.join(projectPath, '.vite-plus-lint-init.oxlintrc.json');
171
+ fs.writeFileSync(lintInitConfigPath, '{}');
172
+ const mergeResult = mergeJsonConfig(viteConfigPath, lintInitConfigPath, spec.configKey);
173
+ if (!mergeResult.updated) {
174
+ throw new Error(`Failed to initialize lint config in ${path.basename(viteConfigPath)}`);
175
+ }
176
+ fs.writeFileSync(viteConfigPath, mergeResult.content);
177
+ fs.rmSync(lintInitConfigPath, { force: true });
178
+ if (generatedConfigPath) {
179
+ fs.rmSync(generatedConfigPath, { force: true });
180
+ }
181
+ await vpFmt(projectPath, path.relative(projectPath, viteConfigPath));
182
+ return {
183
+ handled: true,
184
+ action: 'added',
185
+ configKey: spec.configKey,
186
+ viteConfigPath,
187
+ };
188
+ }
189
+ if (!generatedConfigPath) {
190
+ return {
191
+ handled: true,
192
+ action: 'no-generated-config',
193
+ configKey: inspection.configKey,
194
+ viteConfigPath,
195
+ };
196
+ }
197
+ const mergeResult = mergeJsonConfig(viteConfigPath, generatedConfigPath, spec.configKey);
198
+ if (!mergeResult.updated) {
199
+ throw new Error(`Failed to merge ${path.basename(generatedConfigPath)} into ${path.basename(viteConfigPath)}`);
200
+ }
201
+ fs.writeFileSync(viteConfigPath, mergeResult.content);
202
+ fs.rmSync(generatedConfigPath, { force: true });
203
+ await vpFmt(projectPath, path.relative(projectPath, viteConfigPath));
204
+ return {
205
+ handled: true,
206
+ action: 'added',
207
+ configKey: spec.configKey,
208
+ viteConfigPath,
209
+ };
210
+ }
package/dist/lint.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { type AllowWarnDeny, type DummyRule, type DummyRuleMap, type ExternalPluginEntry, type ExternalPluginsConfig, type OxlintConfig, type OxlintEnv, type OxlintGlobals, type OxlintOverride, type RuleCategories, defineConfig, } from 'oxlint';
package/dist/lint.js ADDED
@@ -0,0 +1 @@
1
+ export { defineConfig, } from 'oxlint';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plus",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "license": "MIT",
5
5
  "bin": {
6
6
  "oxfmt": "./bin/oxfmt",
@@ -55,6 +55,10 @@
55
55
  "import": "./binding/index.cjs",
56
56
  "require": "./binding/index.cjs"
57
57
  },
58
+ "./lint": {
59
+ "types": "./dist/lint.d.ts",
60
+ "import": "./dist/lint.js"
61
+ },
58
62
  "./package.json": "./package.json",
59
63
  "./pack": {
60
64
  "types": "./dist/pack.d.ts",
@@ -297,8 +301,8 @@
297
301
  "oxlint": "^1.51.0",
298
302
  "oxlint-tsgolint": "^0.15.0",
299
303
  "picocolors": "^1.1.1",
300
- "@voidzero-dev/vite-plus-core": "0.1.0",
301
- "@voidzero-dev/vite-plus-test": "0.1.0"
304
+ "@voidzero-dev/vite-plus-core": "0.1.1",
305
+ "@voidzero-dev/vite-plus-test": "0.1.1"
302
306
  },
303
307
  "devDependencies": {
304
308
  "@napi-rs/cli": "^3.4.1",
@@ -321,7 +325,7 @@
321
325
  "yaml": "^2.8.1",
322
326
  "@voidzero-dev/vite-plus-prompts": "0.0.0",
323
327
  "rolldown": "1.0.0-rc.6",
324
- "vite": "npm:@voidzero-dev/vite-plus-core@0.1.0"
328
+ "vite": "npm:@voidzero-dev/vite-plus-core@0.1.1"
325
329
  },
326
330
  "napi": {
327
331
  "binaryName": "vite-plus",
@@ -339,12 +343,12 @@
339
343
  "node": "^20.19.0 || >=22.12.0"
340
344
  },
341
345
  "optionalDependencies": {
342
- "@voidzero-dev/vite-plus-darwin-arm64": "0.1.0",
343
- "@voidzero-dev/vite-plus-darwin-x64": "0.1.0",
344
- "@voidzero-dev/vite-plus-linux-arm64-gnu": "0.1.0",
345
- "@voidzero-dev/vite-plus-linux-x64-gnu": "0.1.0",
346
- "@voidzero-dev/vite-plus-win32-x64-msvc": "0.1.0",
347
- "@voidzero-dev/vite-plus-win32-arm64-msvc": "0.1.0"
346
+ "@voidzero-dev/vite-plus-darwin-arm64": "0.1.1",
347
+ "@voidzero-dev/vite-plus-darwin-x64": "0.1.1",
348
+ "@voidzero-dev/vite-plus-linux-arm64-gnu": "0.1.1",
349
+ "@voidzero-dev/vite-plus-linux-x64-gnu": "0.1.1",
350
+ "@voidzero-dev/vite-plus-win32-x64-msvc": "0.1.1",
351
+ "@voidzero-dev/vite-plus-win32-arm64-msvc": "0.1.1"
348
352
  },
349
353
  "scripts": {
350
354
  "build": "oxnode -C dev ./build.ts",