{"id":37381130,"url":"https://github.com/devwizardhq/laravel-enumify","last_synced_at":"2026-04-12T06:13:46.254Z","repository":{"id":332727481,"uuid":"1134696070","full_name":"DevWizardHQ/laravel-enumify","owner":"DevWizardHQ","description":"Auto-generate TypeScript enums and types from Laravel PHP enums with an Artisan command and Vite integration.","archived":false,"fork":false,"pushed_at":"2026-01-15T12:10:27.000Z","size":74,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-15T14:30:22.196Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DevWizardHQ.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"DevWizard"}},"created_at":"2026-01-15T04:20:46.000Z","updated_at":"2026-01-15T12:10:31.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/DevWizardHQ/laravel-enumify","commit_stats":null,"previous_names":["devwizardhq/laravel-enumify"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/DevWizardHQ/laravel-enumify","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DevWizardHQ%2Flaravel-enumify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DevWizardHQ%2Flaravel-enumify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DevWizardHQ%2Flaravel-enumify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DevWizardHQ%2Flaravel-enumify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DevWizardHQ","download_url":"https://codeload.github.com/DevWizardHQ/laravel-enumify/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DevWizardHQ%2Flaravel-enumify/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28750641,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-25T09:00:19.176Z","status":"ssl_error","status_checked_at":"2026-01-25T09:00:04.131Z","response_time":113,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-16T05:08:12.056Z","updated_at":"2026-01-25T09:02:25.849Z","avatar_url":"https://github.com/DevWizardHQ.png","language":"PHP","readme":"# Laravel Enumify\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/devwizardhq/laravel-enumify.svg?style=flat-square)](https://packagist.org/packages/devwizardhq/laravel-enumify)\n[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/devwizardhq/laravel-enumify/run-tests.yml?branch=main\u0026label=tests\u0026style=flat-square)](https://github.com/devwizardhq/laravel-enumify/actions?query=workflow%3Arun-tests+branch%3Amain)\n[![Total Downloads](https://img.shields.io/packagist/dt/devwizardhq/laravel-enumify.svg?style=flat-square)](https://packagist.org/packages/devwizardhq/laravel-enumify)\n[![NPM Version](https://img.shields.io/npm/v/@devwizard/vite-plugin-enumify.svg?style=flat-square)](https://www.npmjs.com/package/@devwizard/vite-plugin-enumify)\n[![NPM Downloads](https://img.shields.io/npm/dt/@devwizard/vite-plugin-enumify.svg?style=flat-square)](https://www.npmjs.com/package/@devwizard/vite-plugin-enumify)\n\n**Auto-generate TypeScript enums from Laravel PHP enums. Refactor hardcoded values and normalize enum keys.**\n\nLaravel Enumify keeps frontend TypeScript enums in sync with backend PHP enums automatically. It also scans your codebase for hardcoded enum values and can refactor them to use proper enum references. Includes tools for normalizing enum case names to UPPERCASE.\n\n## Features\n\n- 🔄 **Automatic Sync** – Runs during `npm run dev` and `npm run build` via the Vite plugin\n- 🧭 **Wayfinder-Level DX** – One install command to scaffold everything\n- 🏷️ **Labels Support** – `label()` or static `labels()` become TS maps\n- 🎨 **Custom Methods** – Public zero-arg scalar methods become TS maps\n- 📦 **Barrel Exports** – Optional `index.ts` for clean imports\n- ⚡ **Smart Caching** – Only regenerate changed files using hashes\n- 🔒 **Git-Friendly** – `.gitkeep` and strict `.gitignore` patterns supported\n- 🔧 **Refactor Command** – Scan and fix hardcoded enum values in your codebase\n- 🔠 **Key Normalization** – Convert enum keys to UPPERCASE and update all references\n\n## Requirements\n\n- PHP 8.2+\n- Laravel 10, 11, or 12\n- Node.js 18+\n- Vite 4, 5, 6, or 7\n\n## Package Links\n\n- [Composer](https://packagist.org/packages/devwizardhq/laravel-enumify)\n- [NPM](https://www.npmjs.com/package/@devwizard/vite-plugin-enumify)\n\n## Installation\n\n### 1) Install the Laravel package\n\n```bash\ncomposer require devwizardhq/laravel-enumify\n```\n\n### 2) Run the install command\n\n```bash\nphp artisan enumify:install\n```\n\nThis will:\n\n- Create `resources/js/enums/`\n- Create `resources/js/enums/.gitkeep`\n- Print the `.gitignore` lines to add (and offer to append them)\n- Offer to publish the config file\n\n### 3) Configure Vite\n\nIf the installer successfully installed the plugin, you just need to add it to your `vite.config.js`:\n\n```ts\nimport { defineConfig } from \"vite\";\nimport laravel from \"laravel-vite-plugin\";\nimport enumify from \"@devwizard/vite-plugin-enumify\";\n\nexport default defineConfig({\n    plugins: [\n        enumify(),\n        laravel({\n            input: [\"resources/js/app.ts\"],\n            refresh: true,\n        }),\n    ],\n});\n```\n\nIf the automatic installation skipped or failed, manually install the plugin:\n\n```bash\nnpm install @devwizard/vite-plugin-enumify --save-dev\n# or\npnpm add -D @devwizard/vite-plugin-enumify\n# or\nyarn add -D @devwizard/vite-plugin-enumify\n```\n\n## Usage\n\n### Basic Enum\n\n```php\n// app/Enums/OrderStatus.php\n\u003c?php\n\nnamespace App\\Enums;\n\nenum OrderStatus: string\n{\n    case PENDING = 'pending';\n    case PROCESSING = 'processing';\n    case SHIPPED = 'shipped';\n    case DELIVERED = 'delivered';\n}\n```\n\n**Generated TypeScript:**\n\n```ts\n// resources/js/enums/order-status.ts\nexport const OrderStatus = {\n    PENDING: \"pending\",\n    PROCESSING: \"processing\",\n    SHIPPED: \"shipped\",\n    DELIVERED: \"delivered\",\n} as const;\n\nexport type OrderStatus = (typeof OrderStatus)[keyof typeof OrderStatus];\n\nexport const OrderStatusUtils = {\n    options(): OrderStatus[] {\n        return Object.values(OrderStatus);\n    },\n};\n```\n\n### With Labels \u0026 Custom Methods\n\n```php\nenum CampusStatus: string\n{\n    case ACTIVE = 'active';\n    case SUSPENDED = 'suspended';\n    case INACTIVE = 'inactive';\n\n    public function label(): string\n    {\n        return match ($this) {\n            self::ACTIVE =\u003e 'Active',\n            self::SUSPENDED =\u003e 'Suspended',\n            self::INACTIVE =\u003e 'Inactive',\n        };\n    }\n\n    public function color(): string\n    {\n        return match ($this) {\n            self::ACTIVE =\u003e 'green',\n            self::SUSPENDED =\u003e 'red',\n            self::INACTIVE =\u003e 'gray',\n        };\n    }\n\n    public function isActive(): bool\n    {\n        return $this === self::ACTIVE;\n    }\n}\n```\n\n**Generated TypeScript:**\n\n```ts\nexport const CampusStatus = {\n    ACTIVE: \"active\",\n    SUSPENDED: \"suspended\",\n    INACTIVE: \"inactive\",\n} as const;\n\nexport type CampusStatus = (typeof CampusStatus)[keyof typeof CampusStatus];\n\nexport const CampusStatusUtils = {\n    label(status: CampusStatus): string {\n        switch (status) {\n            case CampusStatus.ACTIVE:\n                return \"Active\";\n            case CampusStatus.SUSPENDED:\n                return \"Suspended\";\n            case CampusStatus.INACTIVE:\n                return \"Inactive\";\n        }\n    },\n\n    color(status: CampusStatus): string {\n        switch (status) {\n            case CampusStatus.ACTIVE:\n                return \"green\";\n            case CampusStatus.SUSPENDED:\n                return \"red\";\n            case CampusStatus.INACTIVE:\n                return \"gray\";\n        }\n    },\n\n    isActive(status: CampusStatus): boolean {\n        return status === CampusStatus.ACTIVE;\n    },\n\n    options(): CampusStatus[] {\n        return Object.values(CampusStatus);\n    },\n};\n```\n\n### Frontend Usage\n\n```ts\nimport { CampusStatus, CampusStatusUtils } from \"@/enums/campus-status\";\n\nconst status: CampusStatus = CampusStatus.ACTIVE;\n\n// Get label\nconsole.log(CampusStatusUtils.label(status)); // 'Active'\n\n// Get custom method value\nconst badgeColor = CampusStatusUtils.color(status); // 'green'\n\n// Check state (boolean method)\nif (CampusStatusUtils.isActive(status)) {\n    // Allow access\n}\n\n// Get all options (e.g., for a dropdown)\nconst options = CampusStatusUtils.options();\n```\n\n### Localization\n\nEnumify supports automatic localization for React and Vue applications using `@devwizard/laravel-localizer-react` or `@devwizard/laravel-localizer-vue`.\n\n**Prerequisites:** Install the appropriate localization package for your framework:\n\n```bash\n# For React\nnpm install @devwizard/laravel-localizer-react\n\n# For Vue\nnpm install @devwizard/laravel-localizer-vue\n```\n\n1. **Configure the mode** in `config/enumify.php`:\n\n```php\n'localization' =\u003e [\n    'mode' =\u003e 'react', // 'react' | 'vue' | 'none'\n],\n```\n\n2. **Generated TypeScript** will export a **use{Enum}Utils** hook instead of a static object:\n\n```ts\nimport { useLocalizer } from \"@devwizard/laravel-localizer-react\";\n\nexport const CampusStatus = {\n    ACTIVE: \"active\",\n    // ...\n} as const;\n\n/**\n * CampusStatus enum methods (PHP-style)\n */\nexport function useCampusStatusUtils() {\n    const { __ } = useLocalizer();\n\n    return {\n        label(status: CampusStatus): string {\n            switch (status) {\n                case CampusStatus.ACTIVE:\n                    return __(\"Active\");\n                // ...\n                default:\n                    return status;\n            }\n        },\n\n        options(): CampusStatus[] {\n            return Object.values(CampusStatus);\n        },\n    };\n}\n```\n\n3. **Usage in Components**:\n\n```tsx\nimport { CampusStatus, useCampusStatusUtils } from \"@/enums/campus-status\";\n\nfunction MyComponent() {\n    const { label, options } = useCampusStatusUtils();\n\n    return (\n        \u003cselect\u003e\n            {options().map((status) =\u003e (\n                \u003coption value={status}\u003e{label(status)}\u003c/option\u003e\n            ))}\n        \u003c/select\u003e\n    );\n}\n```\n\nThis ensures your enums are fully localized on the frontend while respecting React's Rules of Hooks.\n\n**Note:** If you enable localization mode but disable label generation (`generate_label_maps` set to `false`), the generator will create hooks/composables without the `useLocalizer` import, since labels are the only feature that uses localization. In this case, you'll get a hook that only contains custom methods and the `options()` method.\n\n## Method Conversion Rules\n\nEnumify will convert methods into TypeScript maps when they meet these rules:\n\n- Public, non-static, zero-argument methods only\n- Return types must be `string`, `int`, `float`, `bool`, or nullable/union combinations of those\n- Methods without return types or unsupported return types are skipped\n- Map naming: `EnumName + MethodName` (pluralized for non-boolean methods)\n- Boolean methods also generate a helper function\n\nLabels are handled separately using `label()` or `labels()`.\n\n## Artisan Commands\n\n### enumify:install\n\n```bash\nphp artisan enumify:install\n```\n\n### enumify:sync\n\n```bash\n# Standard sync\nphp artisan enumify:sync\n\n# Force regenerate all files\nphp artisan enumify:sync --force\n\n# Preview changes without writing\nphp artisan enumify:sync --dry-run\n\n# Sync only one enum\nphp artisan enumify:sync --only=\"App\\Enums\\OrderStatus\"\n\n# Output as JSON\nphp artisan enumify:sync --format=json\n\n# Suppress console output (useful for Vite)\nphp artisan enumify:sync --quiet\n```\n\n### enumify:refactor\n\nScan your codebase for hardcoded enum values and refactor them to use proper enum references. Only columns with enum casts in models will be refactored. This command also supports normalizing enum case names to UPPERCASE and updating all references throughout your application.\n\n#### Available Options\n\n| Option             | Short | Description                                                      |\n| ------------------ | ----- | ---------------------------------------------------------------- |\n| `--fix`            | `-f`  | Apply refactoring changes to files                               |\n| `--dry-run`        | `-d`  | Preview changes without modifying files                          |\n| `--enum=`          | `-e`  | Target a specific enum class by short name (e.g., `OrderStatus`) |\n| `--path=`          | `-p`  | Limit scan to a specific directory (e.g., `app/Models`)          |\n| `--interactive`    | `-i`  | Run in interactive mode with guided prompts                      |\n| `--json`           | `-j`  | Output results in JSON format                                    |\n| `--backup`         |       | Create backups before applying changes                           |\n| `--include=`       |       | File patterns to include (e.g., `*.php`)                         |\n| `--exclude=`       |       | Paths or patterns to exclude from scanning                       |\n| `--report=`        |       | Export report to file (formats: `json`, `csv`, `md`)             |\n| `--detailed`       |       | Show detailed output with code context                           |\n| `--normalize-keys` |       | Convert enum keys to UPPERCASE and fix all references            |\n\n#### Scanning for Hardcoded Values\n\n```bash\n# Scan and display hardcoded enum values\nphp artisan enumify:refactor\n\n# Preview what changes would be made\nphp artisan enumify:refactor --dry-run\n\n# Apply fixes with backup\nphp artisan enumify:refactor --fix --backup\n\n# Target a specific enum\nphp artisan enumify:refactor --enum=OrderStatus\n\n# Limit scan to a directory\nphp artisan enumify:refactor --path=app/Services\n\n# Export a markdown report\nphp artisan enumify:refactor --report=refactor-report.md\n```\n\n**Note:** The refactor command only processes columns that have an enum cast defined in a model. If no cast is available for a column, it will skip refactoring for that column.\n\n#### Key Normalization (UPPERCASE)\n\nThe `--normalize-keys` flag converts enum case names from any case format to UPPERCASE and updates all references in your codebase:\n\n- `case Active` → `case ACTIVE`\n- `case pending` → `case PENDING`\n- `case InProgress` → `case IN_PROGRESS`\n\n```bash\n# Preview key normalization changes\nphp artisan enumify:refactor --normalize-keys --dry-run\n\n# Apply key normalization with backup\nphp artisan enumify:refactor --normalize-keys --fix --backup\n```\n\n#### Interactive Mode\n\nRun the command interactively with guided prompts:\n\n```bash\nphp artisan enumify:refactor --interactive\n```\n\nThis mode allows you to:\n\n- Choose between scan, preview, apply, or normalize modes\n- Select which enums to check\n- Specify the directory to scan\n- Confirm changes before applying\n\n## Configuration\n\nPublish the config file:\n\n```bash\nphp artisan vendor:publish --tag=\"enumify-config\"\n```\n\n```php\n// config/enumify.php\nreturn [\n    'paths' =\u003e [\n        'enums' =\u003e ['app/Enums'],\n        'output' =\u003e 'resources/js/enums',\n    ],\n\n    'naming' =\u003e [\n        'file_case' =\u003e 'kebab',\n    ],\n\n    'features' =\u003e [\n        'generate_union_types' =\u003e true,\n        'generate_label_maps' =\u003e true,\n        'generate_method_maps' =\u003e true,\n        'generate_index_barrel' =\u003e true,\n    ],\n\n    'runtime' =\u003e [\n        'watch' =\u003e true,\n    ],\n\n    'filters' =\u003e [\n        'include' =\u003e [],\n        'exclude' =\u003e [],\n    ],\n];\n```\n\n## Generated Output\n\n- `resources/js/enums/*.ts` – one file per enum\n- `resources/js/enums/index.ts` – barrel exports (optional)\n- `resources/js/enums/.enumify-manifest.json` – hashes, timestamps, versions\n\nThe generator uses atomic writes and skips unchanged files for speed.\n\n## Local Development (Monorepo)\n\nThis repo contains two packages:\n\n- `packages/laravel-enumify` (Composer)\n- `packages/vite-plugin-enumify` (NPM)\n\n### Composer path repository\n\n```json\n{\n    \"repositories\": [\n        {\n            \"type\": \"path\",\n            \"url\": \"./packages/laravel-enumify\",\n            \"options\": { \"symlink\": true }\n        }\n    ]\n}\n```\n\n### Vite plugin workspace\n\nYou can install the Vite plugin locally with a workspace or a file path:\n\n```bash\npnpm add -D ./packages/vite-plugin-enumify\n# or\nnpm install --save-dev ./packages/vite-plugin-enumify\n```\n\n## Git Workflow\n\nRecommended workflow for both packages:\n\n1. Create a feature branch from `main`\n2. Make changes with focused commits\n3. Run tests/builds locally\n4. Open a PR and ensure CI passes\n\nRelease tip: tag releases after merging to `main`, then publish to Packagist and NPM.\n\n## CI\n\nSuggested pipelines:\n\n- PHP: `composer test` and `composer test-coverage`\n- Node: `pnpm run build \u0026\u0026 pnpm run typecheck`\n\n## Troubleshooting\n\n- **Missing enums folder**: run `php artisan enumify:install` or ensure `resources/js/enums/.gitkeep` exists.\n- **Imports fail during build**: ensure the Vite plugin is enabled and runs before `laravel()`.\n- **Enums not discovered**: check `config/enumify.php` paths and include/exclude filters.\n\n## Changelog\n\nSee [CHANGELOG.md](./CHANGELOG.md)\n\n## License\n\nMIT. See [LICENSE.md](./LICENSE.md)\n","funding_links":["https://github.com/sponsors/DevWizard"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevwizardhq%2Flaravel-enumify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevwizardhq%2Flaravel-enumify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevwizardhq%2Flaravel-enumify/lists"}