@devwizard/vite-plugin-enumify 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DevWizard HQ
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,163 @@
1
+ # @devwizard/vite-plugin-enumify
2
+
3
+ [![NPM](https://img.shields.io/npm/v/@devwizard/vite-plugin-enumify.svg?style=flat-square)](https://www.npmjs.com/package/@devwizard/vite-plugin-enumify)
4
+ [![GitHub](https://img.shields.io/badge/repo-devwizardhq%2Flaravel--enumify-181717?style=flat-square&logo=github)](https://github.com/devwizardhq/laravel-enumify)
5
+
6
+ Vite plugin for [Laravel Enumify](https://github.com/devwizardhq/laravel-enumify) — automatically sync PHP enums to TypeScript during development and builds.
7
+
8
+ ## Features
9
+
10
+ - Runs `php artisan enumify:sync --force --quiet` before Vite compiles
11
+ - Watches enum directories in dev mode (debounced)
12
+ - Reads `config/enumify.php` to discover paths and watch config
13
+ - Ignores changes inside the output directory to avoid infinite loops
14
+ - Cross-platform: Windows/macOS/Linux
15
+
16
+ ## Package Links
17
+
18
+ - NPM: https://www.npmjs.com/package/@devwizard/vite-plugin-enumify
19
+ - Repository: https://github.com/devwizardhq/laravel-enumify
20
+ - Composer (Laravel package): https://packagist.org/packages/devwizardhq/laravel-enumify
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ npm install @devwizard/vite-plugin-enumify --save-dev
26
+ # or
27
+ pnpm add -D @devwizard/vite-plugin-enumify
28
+ # or
29
+ yarn add -D @devwizard/vite-plugin-enumify
30
+ ```
31
+
32
+ ## Package Manager Support
33
+
34
+ This plugin is package-manager agnostic and works with npm, pnpm, or yarn. The runtime behavior is identical regardless of how you install it.
35
+
36
+ ## Usage
37
+
38
+ Add the plugin to your `vite.config.ts`:
39
+
40
+ ```ts
41
+ import { defineConfig } from 'vite';
42
+ import laravel from 'laravel-vite-plugin';
43
+ import enumify from '@devwizard/vite-plugin-enumify';
44
+
45
+ export default defineConfig({
46
+ plugins: [
47
+ enumify(),
48
+ laravel({
49
+ input: ['resources/js/app.ts'],
50
+ refresh: true,
51
+ }),
52
+ ],
53
+ });
54
+ ```
55
+
56
+ ## How It Works
57
+
58
+ 1. **On Build Start**: runs `php artisan enumify:sync --force --quiet` before Vite compiles TypeScript.
59
+ 2. **Watch Mode**: watches the enum paths from `config/enumify.php` and re-syncs on changes.
60
+ 3. **Safe Output**: ignores changes under the output directory to avoid re-trigger loops.
61
+
62
+ ## Options
63
+
64
+ ```ts
65
+ enumify({
66
+ // PHP binary path (default: "php")
67
+ artisanBin: 'php',
68
+
69
+ // Path to the artisan file (default: "artisan")
70
+ artisanFile: 'artisan',
71
+
72
+ // Command to run (default: "enumify:sync")
73
+ syncCommand: 'enumify:sync',
74
+
75
+ // Working directory (default: process.cwd())
76
+ cwd: process.cwd(),
77
+
78
+ // Enable watch mode in development (default: runtime.watch from config/enumify.php)
79
+ watch: true,
80
+
81
+ // Additional environment variables
82
+ env: {},
83
+ });
84
+ ```
85
+
86
+ The plugin reads `config/enumify.php` to discover enum paths and output paths so it can watch the right files and avoid feedback loops.
87
+
88
+ ## Example
89
+
90
+ Given this PHP enum:
91
+
92
+ ```php
93
+ // app/Enums/OrderStatus.php
94
+ enum OrderStatus: string
95
+ {
96
+ case PENDING = 'pending';
97
+ case PROCESSING = 'processing';
98
+ case SHIPPED = 'shipped';
99
+
100
+ public function label(): string
101
+ {
102
+ return match ($this) {
103
+ self::PENDING => 'Pending',
104
+ self::PROCESSING => 'Processing',
105
+ self::SHIPPED => 'Shipped',
106
+ };
107
+ }
108
+
109
+ public function color(): string
110
+ {
111
+ return match ($this) {
112
+ self::PENDING => 'yellow',
113
+ self::PROCESSING => 'blue',
114
+ self::SHIPPED => 'green',
115
+ };
116
+ }
117
+ }
118
+ ```
119
+
120
+ The plugin generates:
121
+
122
+ ```ts
123
+ // resources/js/enums/order-status.ts
124
+ export enum OrderStatus {
125
+ Pending = 'pending',
126
+ Processing = 'processing',
127
+ Shipped = 'shipped',
128
+ }
129
+
130
+ export type OrderStatusValue = `${OrderStatus}`;
131
+
132
+ export const OrderStatusLabels: Record<OrderStatus, string> = {
133
+ [OrderStatus.Pending]: 'Pending',
134
+ [OrderStatus.Processing]: 'Processing',
135
+ [OrderStatus.Shipped]: 'Shipped',
136
+ };
137
+
138
+ export const OrderStatusColors: Record<OrderStatus, string> = {
139
+ [OrderStatus.Pending]: 'yellow',
140
+ [OrderStatus.Processing]: 'blue',
141
+ [OrderStatus.Shipped]: 'green',
142
+ };
143
+ ```
144
+
145
+ ## Git Workflow
146
+
147
+ 1. Create a feature branch from `main`
148
+ 2. Make changes with focused commits
149
+ 3. Run `npm run build` and `npm run typecheck`
150
+ 4. Open a PR and ensure CI passes
151
+
152
+ Release tip: tag releases after merging to `main`, then publish to NPM.
153
+
154
+ ## Requirements
155
+
156
+ - Node.js >= 18.0.0
157
+ - Vite >= 4.0.0 (including Vite 7)
158
+ - PHP >= 8.2
159
+ - Laravel Enumify package installed
160
+
161
+ ## License
162
+
163
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,183 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ const child_process = require('child_process');
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
10
+
11
+ const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
12
+ const path__default = /*#__PURE__*/_interopDefaultCompat(path);
13
+
14
+ const DEFAULT_ENUM_PATHS = ["app/Enums"];
15
+ const DEFAULT_OUTPUT_PATH = "resources/js/enums";
16
+ const DEFAULT_WATCH = true;
17
+ const WATCH_DEBOUNCE_MS = 250;
18
+ function resolveOptions(options = {}) {
19
+ const cwd = options.cwd ?? process.cwd();
20
+ const config = readEnumifyConfig(cwd);
21
+ return {
22
+ options: {
23
+ artisanBin: options.artisanBin ?? "php",
24
+ artisanFile: options.artisanFile ?? "artisan",
25
+ syncCommand: options.syncCommand ?? "enumify:sync",
26
+ cwd,
27
+ watch: options.watch ?? config.watch,
28
+ env: options.env ?? {}
29
+ },
30
+ config
31
+ };
32
+ }
33
+ function readEnumifyConfig(cwd) {
34
+ const defaults = {
35
+ enumPaths: DEFAULT_ENUM_PATHS,
36
+ outputPath: DEFAULT_OUTPUT_PATH,
37
+ watch: DEFAULT_WATCH
38
+ };
39
+ const configPath = path__default.join(cwd, "config", "enumify.php");
40
+ if (!fs__default.existsSync(configPath)) {
41
+ return defaults;
42
+ }
43
+ try {
44
+ const contents = fs__default.readFileSync(configPath, "utf8");
45
+ return {
46
+ enumPaths: extractStringArray(contents, "enums") ?? defaults.enumPaths,
47
+ outputPath: extractString(contents, "output") ?? defaults.outputPath,
48
+ watch: extractBoolean(contents, "watch") ?? defaults.watch
49
+ };
50
+ } catch {
51
+ return defaults;
52
+ }
53
+ }
54
+ function extractStringArray(contents, key) {
55
+ const match = new RegExp(`['"]${key}['"]\\s*=>\\s*\\[([\\s\\S]*?)\\]`, "m").exec(contents);
56
+ if (!match) {
57
+ return null;
58
+ }
59
+ const items = [];
60
+ const itemRegex = /['"]([^'"]+)['"]/g;
61
+ let itemMatch;
62
+ while ((itemMatch = itemRegex.exec(match[1])) !== null) {
63
+ items.push(itemMatch[1]);
64
+ }
65
+ return items.length > 0 ? items : null;
66
+ }
67
+ function extractString(contents, key) {
68
+ const match = new RegExp(`['"]${key}['"]\\s*=>\\s*['"]([^'"]+)['"]`, "m").exec(contents);
69
+ return match ? match[1] : null;
70
+ }
71
+ function extractBoolean(contents, key) {
72
+ const match = new RegExp(`['"]${key}['"]\\s*=>\\s*(true|false)`, "mi").exec(contents);
73
+ if (!match) {
74
+ return null;
75
+ }
76
+ return match[1].toLowerCase() === "true";
77
+ }
78
+ function toAbsolutePath(cwd, value) {
79
+ return path__default.isAbsolute(value) ? value : path__default.join(cwd, value);
80
+ }
81
+ function isPathInside(filePath, dirPath) {
82
+ const relative = path__default.relative(dirPath, filePath);
83
+ return relative !== "" && !relative.startsWith("..") && !path__default.isAbsolute(relative);
84
+ }
85
+ function debounce(fn, delay) {
86
+ let timeoutId = null;
87
+ return (...args) => {
88
+ if (timeoutId) {
89
+ clearTimeout(timeoutId);
90
+ }
91
+ timeoutId = setTimeout(() => {
92
+ fn(...args);
93
+ timeoutId = null;
94
+ }, delay);
95
+ };
96
+ }
97
+ function enumify(options = {}) {
98
+ const { options: resolved, config } = resolveOptions(options);
99
+ const enumDirs = config.enumPaths.map((enumPath) => toAbsolutePath(resolved.cwd, enumPath));
100
+ const outputDir = toAbsolutePath(resolved.cwd, config.outputPath);
101
+ let viteConfig = null;
102
+ let logger = console;
103
+ let running = false;
104
+ let rerunRequested = false;
105
+ let initialSyncDone = false;
106
+ const spawnSync = () => new Promise((resolve, reject) => {
107
+ const args = [resolved.artisanFile, resolved.syncCommand, "--force", "--quiet"];
108
+ const child = child_process.spawn(resolved.artisanBin, args, {
109
+ cwd: resolved.cwd,
110
+ env: { ...process.env, ...resolved.env },
111
+ stdio: "inherit"
112
+ });
113
+ child.on("error", (error) => reject(error));
114
+ child.on("close", (code) => {
115
+ if (code === 0) {
116
+ resolve();
117
+ return;
118
+ }
119
+ reject(new Error(`Enumify sync failed with exit code ${code}`));
120
+ });
121
+ });
122
+ const runSync = async () => {
123
+ if (running) {
124
+ rerunRequested = true;
125
+ return;
126
+ }
127
+ running = true;
128
+ do {
129
+ rerunRequested = false;
130
+ await spawnSync();
131
+ logger.info("[plugin @devwizard/vite-plugin-enumify] Enum types generated successfully");
132
+ } while (rerunRequested);
133
+ running = false;
134
+ };
135
+ const debouncedSync = debounce(() => {
136
+ runSync().catch((error) => logger.error(`[enumify] ${error.message}`));
137
+ }, WATCH_DEBOUNCE_MS);
138
+ return {
139
+ name: "@devwizard/vite-plugin-enumify",
140
+ enforce: "pre",
141
+ configResolved(resolvedConfig) {
142
+ viteConfig = resolvedConfig;
143
+ logger = resolvedConfig.logger;
144
+ },
145
+ buildStart() {
146
+ if (viteConfig?.command === "serve") {
147
+ if (initialSyncDone) {
148
+ return;
149
+ }
150
+ initialSyncDone = true;
151
+ }
152
+ return runSync().catch((error) => {
153
+ this.error(`[enumify] ${error.message}`);
154
+ });
155
+ },
156
+ configureServer(server) {
157
+ if (!resolved.watch) {
158
+ return;
159
+ }
160
+ for (const enumDir of enumDirs) {
161
+ server.watcher.add(enumDir);
162
+ }
163
+ },
164
+ handleHotUpdate({ file }) {
165
+ if (!resolved.watch) {
166
+ return;
167
+ }
168
+ const filePath = path__default.resolve(file);
169
+ if (isPathInside(filePath, outputDir)) {
170
+ return;
171
+ }
172
+ for (const enumDir of enumDirs) {
173
+ if (isPathInside(filePath, enumDir)) {
174
+ debouncedSync();
175
+ break;
176
+ }
177
+ }
178
+ }
179
+ };
180
+ }
181
+
182
+ exports.default = enumify;
183
+ exports.enumify = enumify;
@@ -0,0 +1,58 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ /**
4
+ * Configuration options for the Enumify Vite plugin.
5
+ */
6
+ interface EnumifyOptions {
7
+ /**
8
+ * PHP binary path.
9
+ * @default "php"
10
+ */
11
+ artisanBin?: string;
12
+ /**
13
+ * Path to the artisan file.
14
+ * @default "artisan"
15
+ */
16
+ artisanFile?: string;
17
+ /**
18
+ * Artisan command to run for syncing enums.
19
+ * @default "enumify:sync"
20
+ */
21
+ syncCommand?: string;
22
+ /**
23
+ * Working directory for the command.
24
+ * @default process.cwd()
25
+ */
26
+ cwd?: string;
27
+ /**
28
+ * Whether to watch for changes in development mode.
29
+ * Defaults to the Laravel enumify config runtime.watch setting.
30
+ */
31
+ watch?: boolean;
32
+ /**
33
+ * Additional environment variables for the command.
34
+ * @default {}
35
+ */
36
+ env?: Record<string, string>;
37
+ }
38
+ /**
39
+ * Resolved configuration with defaults applied.
40
+ */
41
+ interface ResolvedEnumifyOptions {
42
+ artisanBin: string;
43
+ artisanFile: string;
44
+ syncCommand: string;
45
+ cwd: string;
46
+ watch: boolean;
47
+ env: Record<string, string>;
48
+ }
49
+
50
+ /**
51
+ * Laravel Enumify Vite plugin.
52
+ */
53
+ declare function enumify(options?: EnumifyOptions): Plugin;
54
+
55
+ // @ts-ignore
56
+ export = enumify;
57
+ export { enumify };
58
+ export type { EnumifyOptions, ResolvedEnumifyOptions };
@@ -0,0 +1,56 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ /**
4
+ * Configuration options for the Enumify Vite plugin.
5
+ */
6
+ interface EnumifyOptions {
7
+ /**
8
+ * PHP binary path.
9
+ * @default "php"
10
+ */
11
+ artisanBin?: string;
12
+ /**
13
+ * Path to the artisan file.
14
+ * @default "artisan"
15
+ */
16
+ artisanFile?: string;
17
+ /**
18
+ * Artisan command to run for syncing enums.
19
+ * @default "enumify:sync"
20
+ */
21
+ syncCommand?: string;
22
+ /**
23
+ * Working directory for the command.
24
+ * @default process.cwd()
25
+ */
26
+ cwd?: string;
27
+ /**
28
+ * Whether to watch for changes in development mode.
29
+ * Defaults to the Laravel enumify config runtime.watch setting.
30
+ */
31
+ watch?: boolean;
32
+ /**
33
+ * Additional environment variables for the command.
34
+ * @default {}
35
+ */
36
+ env?: Record<string, string>;
37
+ }
38
+ /**
39
+ * Resolved configuration with defaults applied.
40
+ */
41
+ interface ResolvedEnumifyOptions {
42
+ artisanBin: string;
43
+ artisanFile: string;
44
+ syncCommand: string;
45
+ cwd: string;
46
+ watch: boolean;
47
+ env: Record<string, string>;
48
+ }
49
+
50
+ /**
51
+ * Laravel Enumify Vite plugin.
52
+ */
53
+ declare function enumify(options?: EnumifyOptions): Plugin;
54
+
55
+ export { enumify as default, enumify };
56
+ export type { EnumifyOptions, ResolvedEnumifyOptions };
@@ -0,0 +1,58 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ /**
4
+ * Configuration options for the Enumify Vite plugin.
5
+ */
6
+ interface EnumifyOptions {
7
+ /**
8
+ * PHP binary path.
9
+ * @default "php"
10
+ */
11
+ artisanBin?: string;
12
+ /**
13
+ * Path to the artisan file.
14
+ * @default "artisan"
15
+ */
16
+ artisanFile?: string;
17
+ /**
18
+ * Artisan command to run for syncing enums.
19
+ * @default "enumify:sync"
20
+ */
21
+ syncCommand?: string;
22
+ /**
23
+ * Working directory for the command.
24
+ * @default process.cwd()
25
+ */
26
+ cwd?: string;
27
+ /**
28
+ * Whether to watch for changes in development mode.
29
+ * Defaults to the Laravel enumify config runtime.watch setting.
30
+ */
31
+ watch?: boolean;
32
+ /**
33
+ * Additional environment variables for the command.
34
+ * @default {}
35
+ */
36
+ env?: Record<string, string>;
37
+ }
38
+ /**
39
+ * Resolved configuration with defaults applied.
40
+ */
41
+ interface ResolvedEnumifyOptions {
42
+ artisanBin: string;
43
+ artisanFile: string;
44
+ syncCommand: string;
45
+ cwd: string;
46
+ watch: boolean;
47
+ env: Record<string, string>;
48
+ }
49
+
50
+ /**
51
+ * Laravel Enumify Vite plugin.
52
+ */
53
+ declare function enumify(options?: EnumifyOptions): Plugin;
54
+
55
+ // @ts-ignore
56
+ export = enumify;
57
+ export { enumify };
58
+ export type { EnumifyOptions, ResolvedEnumifyOptions };
package/dist/index.mjs ADDED
@@ -0,0 +1,173 @@
1
+ import { spawn } from 'child_process';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+
5
+ const DEFAULT_ENUM_PATHS = ["app/Enums"];
6
+ const DEFAULT_OUTPUT_PATH = "resources/js/enums";
7
+ const DEFAULT_WATCH = true;
8
+ const WATCH_DEBOUNCE_MS = 250;
9
+ function resolveOptions(options = {}) {
10
+ const cwd = options.cwd ?? process.cwd();
11
+ const config = readEnumifyConfig(cwd);
12
+ return {
13
+ options: {
14
+ artisanBin: options.artisanBin ?? "php",
15
+ artisanFile: options.artisanFile ?? "artisan",
16
+ syncCommand: options.syncCommand ?? "enumify:sync",
17
+ cwd,
18
+ watch: options.watch ?? config.watch,
19
+ env: options.env ?? {}
20
+ },
21
+ config
22
+ };
23
+ }
24
+ function readEnumifyConfig(cwd) {
25
+ const defaults = {
26
+ enumPaths: DEFAULT_ENUM_PATHS,
27
+ outputPath: DEFAULT_OUTPUT_PATH,
28
+ watch: DEFAULT_WATCH
29
+ };
30
+ const configPath = path.join(cwd, "config", "enumify.php");
31
+ if (!fs.existsSync(configPath)) {
32
+ return defaults;
33
+ }
34
+ try {
35
+ const contents = fs.readFileSync(configPath, "utf8");
36
+ return {
37
+ enumPaths: extractStringArray(contents, "enums") ?? defaults.enumPaths,
38
+ outputPath: extractString(contents, "output") ?? defaults.outputPath,
39
+ watch: extractBoolean(contents, "watch") ?? defaults.watch
40
+ };
41
+ } catch {
42
+ return defaults;
43
+ }
44
+ }
45
+ function extractStringArray(contents, key) {
46
+ const match = new RegExp(`['"]${key}['"]\\s*=>\\s*\\[([\\s\\S]*?)\\]`, "m").exec(contents);
47
+ if (!match) {
48
+ return null;
49
+ }
50
+ const items = [];
51
+ const itemRegex = /['"]([^'"]+)['"]/g;
52
+ let itemMatch;
53
+ while ((itemMatch = itemRegex.exec(match[1])) !== null) {
54
+ items.push(itemMatch[1]);
55
+ }
56
+ return items.length > 0 ? items : null;
57
+ }
58
+ function extractString(contents, key) {
59
+ const match = new RegExp(`['"]${key}['"]\\s*=>\\s*['"]([^'"]+)['"]`, "m").exec(contents);
60
+ return match ? match[1] : null;
61
+ }
62
+ function extractBoolean(contents, key) {
63
+ const match = new RegExp(`['"]${key}['"]\\s*=>\\s*(true|false)`, "mi").exec(contents);
64
+ if (!match) {
65
+ return null;
66
+ }
67
+ return match[1].toLowerCase() === "true";
68
+ }
69
+ function toAbsolutePath(cwd, value) {
70
+ return path.isAbsolute(value) ? value : path.join(cwd, value);
71
+ }
72
+ function isPathInside(filePath, dirPath) {
73
+ const relative = path.relative(dirPath, filePath);
74
+ return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative);
75
+ }
76
+ function debounce(fn, delay) {
77
+ let timeoutId = null;
78
+ return (...args) => {
79
+ if (timeoutId) {
80
+ clearTimeout(timeoutId);
81
+ }
82
+ timeoutId = setTimeout(() => {
83
+ fn(...args);
84
+ timeoutId = null;
85
+ }, delay);
86
+ };
87
+ }
88
+ function enumify(options = {}) {
89
+ const { options: resolved, config } = resolveOptions(options);
90
+ const enumDirs = config.enumPaths.map((enumPath) => toAbsolutePath(resolved.cwd, enumPath));
91
+ const outputDir = toAbsolutePath(resolved.cwd, config.outputPath);
92
+ let viteConfig = null;
93
+ let logger = console;
94
+ let running = false;
95
+ let rerunRequested = false;
96
+ let initialSyncDone = false;
97
+ const spawnSync = () => new Promise((resolve, reject) => {
98
+ const args = [resolved.artisanFile, resolved.syncCommand, "--force", "--quiet"];
99
+ const child = spawn(resolved.artisanBin, args, {
100
+ cwd: resolved.cwd,
101
+ env: { ...process.env, ...resolved.env },
102
+ stdio: "inherit"
103
+ });
104
+ child.on("error", (error) => reject(error));
105
+ child.on("close", (code) => {
106
+ if (code === 0) {
107
+ resolve();
108
+ return;
109
+ }
110
+ reject(new Error(`Enumify sync failed with exit code ${code}`));
111
+ });
112
+ });
113
+ const runSync = async () => {
114
+ if (running) {
115
+ rerunRequested = true;
116
+ return;
117
+ }
118
+ running = true;
119
+ do {
120
+ rerunRequested = false;
121
+ await spawnSync();
122
+ logger.info("[plugin @devwizard/vite-plugin-enumify] Enum types generated successfully");
123
+ } while (rerunRequested);
124
+ running = false;
125
+ };
126
+ const debouncedSync = debounce(() => {
127
+ runSync().catch((error) => logger.error(`[enumify] ${error.message}`));
128
+ }, WATCH_DEBOUNCE_MS);
129
+ return {
130
+ name: "@devwizard/vite-plugin-enumify",
131
+ enforce: "pre",
132
+ configResolved(resolvedConfig) {
133
+ viteConfig = resolvedConfig;
134
+ logger = resolvedConfig.logger;
135
+ },
136
+ buildStart() {
137
+ if (viteConfig?.command === "serve") {
138
+ if (initialSyncDone) {
139
+ return;
140
+ }
141
+ initialSyncDone = true;
142
+ }
143
+ return runSync().catch((error) => {
144
+ this.error(`[enumify] ${error.message}`);
145
+ });
146
+ },
147
+ configureServer(server) {
148
+ if (!resolved.watch) {
149
+ return;
150
+ }
151
+ for (const enumDir of enumDirs) {
152
+ server.watcher.add(enumDir);
153
+ }
154
+ },
155
+ handleHotUpdate({ file }) {
156
+ if (!resolved.watch) {
157
+ return;
158
+ }
159
+ const filePath = path.resolve(file);
160
+ if (isPathInside(filePath, outputDir)) {
161
+ return;
162
+ }
163
+ for (const enumDir of enumDirs) {
164
+ if (isPathInside(filePath, enumDir)) {
165
+ debouncedSync();
166
+ break;
167
+ }
168
+ }
169
+ }
170
+ };
171
+ }
172
+
173
+ export { enumify as default, enumify };
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@devwizard/vite-plugin-enumify",
3
+ "version": "0.1.0",
4
+ "description": "Vite plugin for Laravel Enumify - auto-sync PHP enums to TypeScript",
5
+ "keywords": [
6
+ "vite",
7
+ "vite-plugin",
8
+ "laravel",
9
+ "enum",
10
+ "typescript",
11
+ "codegen"
12
+ ],
13
+ "author": {
14
+ "name": "IQBAL HASAN",
15
+ "email": "devwizard24@gmail.com",
16
+ "url": "https://github.com/DevWizardHQ"
17
+ },
18
+ "license": "MIT",
19
+ "funding": {
20
+ "type": "github",
21
+ "url": "https://github.com/sponsors/DevWizardHQ"
22
+ },
23
+ "homepage": "https://github.com/devwizardhq/vite-plugin-enumify#readme",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/devwizardhq/vite-plugin-enumify.git"
27
+ },
28
+ "bugs": {
29
+ "url": "https://github.com/devwizardhq/vite-plugin-enumify/issues"
30
+ },
31
+ "scripts": {
32
+ "prepublishOnly": "npm run build",
33
+ "dev": "unbuild --stub",
34
+ "build": "unbuild",
35
+ "test": "vitest run",
36
+ "lint": "tsc --noEmit",
37
+ "typecheck": "tsc --noEmit",
38
+ "format": "prettier --write ."
39
+ },
40
+ "main": "dist/index.cjs",
41
+ "module": "dist/index.mjs",
42
+ "types": "dist/index.d.ts",
43
+ "exports": {
44
+ ".": {
45
+ "import": "./dist/index.mjs",
46
+ "require": "./dist/index.cjs",
47
+ "types": "./dist/index.d.ts"
48
+ }
49
+ },
50
+ "files": [
51
+ "dist",
52
+ "README.md"
53
+ ],
54
+ "peerDependencies": {
55
+ "vite": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
56
+ },
57
+ "devDependencies": {
58
+ "@types/node": "^25.0.8",
59
+ "prettier": "^3.5.0",
60
+ "rollup": "^4.40.0",
61
+ "typescript": "^5.7.0",
62
+ "unbuild": "^3.5.0",
63
+ "vite": "^7.3.1",
64
+ "vitest": "^4.0.17"
65
+ },
66
+ "engines": {
67
+ "node": ">=18.0.0"
68
+ },
69
+ "publishConfig": {
70
+ "access": "public"
71
+ }
72
+ }