@simplix-react/cli
v0.2.2
Published
CLI for scaffolding and validating simplix-react projects
Readme
@simplix-react/cli
CLI for scaffolding and validating simplix-react projects.
Installation
Install via the meta package (recommended):
pnpm add simplix-reactWhen using pnpm, add this to .npmrc so @simplix-react/* packages are resolvable:
public-hoist-pattern[]=@simplix-react/*Or install the CLI only:
pnpm add -D @simplix-react/cliRequires Node.js 18 or later.
Note: Projects scaffolded with
simplix initinclude the.npmrcconfiguration automatically.
Quick Start
# Create a new project
simplix init my-app
# Add a domain package
simplix add-domain inventory
# Add an FSD module
simplix add-module editor
# Validate project structure
simplix validateCommands
simplix init
Initialize a new simplix-react project with a monorepo structure (pnpm + Turborepo).
simplix init <project-name> [options]Arguments:
| Argument | Description |
| --- | --- |
| project-name | Name of the project to create |
Options:
| Option | Description | Default |
| --- | --- | --- |
| -s, --scope <scope> | npm scope for packages | @<project-name> |
| --no-demo | Skip demo app creation | - |
| --no-i18n | Skip i18n setup | - |
| -y, --yes | Accept all defaults (non-interactive) | - |
Example:
# Interactive mode
simplix init my-app
# Non-interactive with custom scope
simplix init my-app --scope @mycompany -y
# Without demo app or i18n
simplix init my-app --no-demo --no-i18n -yGenerated structure:
my-app/
apps/my-app-demo/ # Demo app (if --no-demo not set)
packages/my-app-core/ # Core package (API, mock, react, types)
modules/ # FSD modules directory
config/typescript/ # Shared TypeScript configs
package.json
pnpm-workspace.yaml
turbo.json
tsconfig.json
.gitignore
.claude/CLAUDE.mdWhen i18n is enabled, the demo app includes locale files for en, ko, and ja.
simplix add-domain
Add a new domain package under packages/. Domain packages encapsulate API client, schemas, mock handlers, and repository logic for a specific domain.
simplix add-domain <name> [options]Arguments:
| Argument | Description |
| --- | --- |
| name | Domain name (e.g., inventory, topology) |
Options:
| Option | Description | Default |
| --- | --- | --- |
| -e, --entities <entities> | Comma-separated entity names | domain name |
| -y, --yes | Accept all defaults (non-interactive) | - |
Example:
# Interactive mode
simplix add-domain inventory
# With explicit entities
simplix add-domain inventory --entities product,category,warehouse -yGenerated structure:
packages/<project>-domain-<name>/
src/
api/
client.ts # API client functions
hooks.ts # React Query hooks
query-keys.ts # Query key factory
types.ts # API types
index.ts
schemas/
index.ts # Zod schemas
interfaces/
index.ts
mock/
handlers.ts # MSW request handlers
seed.ts # Mock seed data
repositories/
<entity>.ts # Per-entity repository
index.ts
index.ts
package.json
tsup.config.ts
tsconfig.jsonsimplix add-module
Add a new FSD (Feature-Sliced Design) module under modules/. Modules organize UI features using the FSD architecture with features/, widgets/, and shared/ layers.
simplix add-module <name> [options]Arguments:
| Argument | Description |
| --- | --- |
| name | Module name (e.g., editor, maps, monitoring) |
Options:
| Option | Description | Default |
| --- | --- | --- |
| --no-i18n | Skip i18n locales setup | - |
| -y, --yes | Accept all defaults (non-interactive) | - |
Example:
# Interactive mode
simplix add-module editor
# Without i18n
simplix add-module editor --no-i18n -yGenerated structure:
modules/<project>-<name>/
src/
features/
index.ts
widgets/
index.ts
shared/
lib/
ui/
config/
locales/ # Only if i18n enabled
en.json
ko.json
ja.json
index.ts
widgets/
features/
manifest.ts
index.ts
package.json
tsup.config.ts
tsconfig.jsonsimplix validate
Validate project structure, FSD layer rules, import boundaries, package configuration, i18n consistency, and contract completeness.
simplix validate [options]Options:
| Option | Description | Default |
| --- | --- | --- |
| --fix | Auto-fix issues where possible | false |
Example:
# Validate only
simplix validate
# Validate and auto-fix
simplix validate --fixValidation rules:
The validator applies different rule sets to packages and modules:
| Rule Set | Target | Checks |
| --- | --- | --- |
| Package | packages/, modules/ | exports field, tsup.config, React peerDependencies, "type": "module" |
| Contract | packages/ | Entity schemas completeness (schema, createSchema, updateSchema), operation input/output, mock handler config |
| FSD | modules/ | manifest.ts exists, features/ does not import from widgets/, shared/ does not import from features/ or widgets/ |
| Import | modules/ | No cross-module direct imports (must use package exports) |
| i18n | modules/ | Missing keys across locales, extra keys, empty values, interpolation variable ({{var}}) consistency |
Auto-fixable issues (with --fix):
- Missing
"type": "module"inpackage.json - Missing React
peerDependencies - Missing i18n keys (copies from reference locale)
- Extra i18n keys (removes from target locale)
Output format:
simplix validate
packages/myapp-core
✔ Has "exports" field
✔ tsup.config exists
✔ "type": "module"
modules/myapp-editor
✔ Manifest exists
✔ FSD: features/ has no widgets/ imports
✖ i18n: Missing key "title" in ko.json (src/locales)
Summary: 1 error, 0 warnings, 5 checks passedsimplix i18n-codegen
Generate TypeScript type definitions from i18n JSON files. Scans all modules under modules/ and creates keys.d.ts files containing union types of all translation keys.
simplix i18n-codegen [options]Options:
| Option | Description | Default |
| --- | --- | --- |
| --watch | Watch for file changes and regenerate | false |
Example:
# One-time generation
simplix i18n-codegen
# Watch mode
simplix i18n-codegen --watchThe codegen uses en.json as the source of truth (falls back to the first JSON file found). It generates a union type of all flattened keys:
// Auto-generated by simplix i18n-codegen
// Do not edit manually
export type LocalesKeys =
| "title"
| "description"
| "actions.save"
| "actions.cancel";simplix openapi
Generate a complete domain package from an OpenAPI specification. Supports both file paths and URLs as input. On subsequent runs, it performs incremental updates by comparing against a snapshot, regenerating only the src/generated/ directory while preserving user-modified files.
simplix openapi <spec> [options]Arguments:
| Argument | Description |
| --- | --- |
| spec | OpenAPI spec file path or URL |
Options:
| Option | Description | Default |
| --- | --- | --- |
| -d, --domain <name> | Domain name | Derived from OpenAPI info.title |
| -e, --entities <names> | Entity names to generate (comma-separated) | All entities |
| -o, --output <dir> | Output directory | packages/ |
| --dry-run | Preview files without writing | false |
| -f, --force | Force regeneration even if no changes | false |
| --no-http | Skip .http file generation | - |
| --no-mock | Skip mock layer generation | - |
| --header | Add auto-generated header comment | true |
| --no-header | Skip auto-generated header comment | - |
| -y, --yes | Auto-confirm without prompts | - |
Example:
# Generate from a local file
simplix openapi ./specs/inventory-api.yaml
# Generate from a URL with custom domain name
simplix openapi https://api.example.com/openapi.json --domain inventory
# Generate specific entities only
simplix openapi ./spec.yaml --entities product,category
# Preview without writing files
simplix openapi ./spec.yaml --dry-run
# Force regeneration, skip mocks
simplix openapi ./spec.yaml --force --no-mock -yGenerated structure (first run):
packages/<prefix>-domain-<name>/
src/
generated/ # Auto-generated (regenerated on updates)
schemas.ts # Zod schemas from OpenAPI
client.ts # API client functions
hooks.ts # React Query hooks
query-keys.ts # Query key factory
interfaces.ts # TypeScript interfaces
index.ts
mock/
generated/ # Auto-generated mock layer
handlers.ts # MSW request handlers
seed.ts # User-editable seed data
index.ts # User-editable mock entry
index.ts # User-editable package entry
http/ # HTTP client files
http-client.env.json
<entity>.http
.openapi-snapshot.json # Snapshot for incremental updates
package.json
tsup.config.ts
tsconfig.json
eslint.config.jsOn subsequent runs, only src/generated/ and src/mock/generated/ are regenerated. User-modified files (src/index.ts, src/mock/index.ts, src/mock/seed.ts, package.json, etc.) are preserved.
Multi-Domain Mode (Tag-Based Splitting)
When your OpenAPI spec covers multiple domains, you can split entities into separate packages based on operation tags. Configure openapi.domains in simplix.config.ts to map domain names to tag patterns:
// simplix.config.ts
export default {
openapi: {
domains: {
pet: ["pet"],
store: ["store"],
user: ["user"],
},
},
} satisfies SimplixConfig;Each value is an array of tag patterns. Patterns can be exact strings or regular expressions enclosed in /:
openapi: {
domains: {
iam: ["IAM", "Authentication", "/^Auth.*/"], // exact + regex
billing: ["Billing", "/^Payment.*/"],
},
}When openapi.domains is configured, running simplix openapi generates one package per domain:
simplix openapi https://petstore.swagger.io/v2/swagger.json -y
# Generates:
# packages/myapp-domain-pet/
# packages/myapp-domain-store/
# packages/myapp-domain-user/Matching rules:
| Rule | Behavior |
| --- | --- |
| First-match-wins | Each entity is assigned to the first matching domain in config order |
| Fallback domain | Entities with no matching tags go to a fallback domain (from --domain flag or spec title) |
| Empty domain skip | Domains with zero matched entities are not generated |
| Entity filter first | --entities filter is applied before domain grouping |
| Independent snapshots | Each domain package maintains its own .openapi-snapshot.json |
When openapi.domains is not configured or is an empty object, the command falls back to single-domain behavior.
Dry-run mode shows file lists grouped by domain:
simplix openapi ./spec.yaml --dry-run
# Multi-domain mode: pet(3), store(2), user(1)
# Dry run — myapp-domain-pet/
# src/generated/index.ts
# src/generated/schemas.ts
# ...
# Dry run — myapp-domain-store/
# ...simplix init-ui
Initialize @simplix-react/ui with shadcn/ui integration. Installs required shadcn components and generates a UIProvider configuration file.
simplix init-ui [-y]Options:
| Flag | Description |
| --- | --- |
| -y, --yes | Non-interactive mode |
Prerequisites: shadcn must be initialized first (npx shadcn@latest init). The command installs these shadcn components: input, textarea, select, switch, checkbox, badge, calendar, label.
simplix scaffold
Generate CRUD widgets into an FSD module's widgets/ layer. Reads entity schema definitions and generates list, form, detail, and tree page components.
simplix scaffold <entity> [options]Arguments:
| Argument | Description |
| --- | --- |
| <entity> | Entity name (e.g., product, user) |
Options:
| Flag | Description |
| --- | --- |
| --module <dir> | Target FSD module directory (relative to modules/) |
| --output <dir> | Custom output directory (overrides --module, relative to cwd) |
Example:
# Generate CRUD widgets for the "product" entity
simplix scaffold product --module storeConfiguration
The CLI reads an optional simplix.config.ts file from the project root. If the file does not exist, default values are used.
// simplix.config.ts
import type { SimplixConfig } from "@simplix-react/cli";
export default {
packages: {
prefix: "myapp", // Package name prefix (default: derived from root package.json)
},
http: {
environments: {
development: { baseUrl: "http://localhost:3000" },
staging: { baseUrl: "https://staging.example.com" },
},
},
mock: {
defaultLimit: 50, // Default pagination limit
maxLimit: 100, // Maximum pagination limit
},
codegen: {
header: true, // Add auto-generated header to generated files
},
openapi: {
domains: { // Tag-based domain splitting (optional)
iam: ["IAM", "/^Auth.*/"],
billing: ["Billing"],
},
},
} satisfies SimplixConfig;| Field | Description | Default |
| --- | --- | --- |
| packages.prefix | Short prefix for generated package names | Derived from root package.json name |
| http.environments | Named environments for .http files | { development: { baseUrl: "http://localhost:3000" } } |
| mock.defaultLimit | Default pagination limit for mock handlers | 50 |
| mock.maxLimit | Maximum pagination limit for mock handlers | 100 |
| codegen.header | Prepend auto-generated header comment to generated files | true |
| openapi.domains | Tag-based domain splitting map: domain name → tag patterns (exact or /regex/) | undefined (single domain) |
The config file is loaded using jiti, so TypeScript syntax is supported without compilation.
defineConfig
Identity function that provides type-safe autocompletion for simplix.config.ts.
import { defineConfig } from "@simplix-react/cli";
export default defineConfig({
api: { baseUrl: "/api/v1" },
packages: { prefix: "my-app" },
codegen: { header: true },
});defineCrudMap
Identity function that provides type-safe autocompletion for per-entity CRUD operation mapping. Use in a crud.config.ts file to map entity names to their operation IDs.
import { defineCrudMap } from "@simplix-react/cli";
export default defineCrudMap({
pet: {
list: "findPetsByStatus",
get: "getPetById",
create: "addPet",
update: "updatePet",
delete: "deletePet",
},
});Plugin System
The CLI provides a plugin registry for extending OpenAPI code generation with custom naming strategies, response adapters, and schema adapters.
Registration Functions
| Export | Kind | Description |
| --- | --- | --- |
| registerSpecProfile | Function | Register a named spec profile (naming + response adapter bundle) |
| registerResponseAdapterPreset | Function | Register a named response adapter preset |
| registerSchemaAdapter | Function | Register a schema adapter for unwrapping wrapper types |
| registerPlugin | Function | Register a complete plugin (bulk-registers spec profiles and response adapters) |
Retrieval Functions
| Export | Kind | Description |
| --- | --- | --- |
| getSpecProfile | Function | Get a registered spec profile by name |
| getResponseAdapterPreset | Function | Get a registered response adapter preset by name |
| getSchemaAdapters | Function | Get all registered schema adapters |
registerSpecProfile
Registers a named SpecProfile that bundles a naming strategy and response adapter configuration. Reference the profile name in simplix.config.ts via the profile field.
import { registerSpecProfile } from "@simplix-react/cli";
import type { SpecProfile } from "@simplix-react/cli";
const myProfile: SpecProfile = {
naming: {
resolveEntityName: (ctx) => ctx.tag ?? "unknown",
resolveOperation: (ctx) => ({
role: "list",
hookName: `list${ctx.entityName}`,
}),
},
responseAdapter: "raw",
};
registerSpecProfile("my-api", myProfile);Then reference it in config:
export default defineConfig({
openapi: [
{ spec: "openapi.json", profile: "my-api", domains: { main: ["*"] } },
],
});registerResponseAdapterPreset
Registers a named response adapter preset for reuse across specs.
import { registerResponseAdapterPreset } from "@simplix-react/cli";
registerResponseAdapterPreset("my-envelope", {
unwrapExpression: "data?.result",
errorAdapterImport: 'import { adaptError } from "./error-adapter"',
errorAdapterName: "adaptError",
});registerSchemaAdapter
Registers a schema adapter that can unwrap wrapper types in OpenAPI schemas (e.g., stripping generic envelope types).
import { registerSchemaAdapter } from "@simplix-react/cli";
registerSchemaAdapter({
id: "my-wrapper",
canUnwrap: (schema) => !!schema["x-wrapper"],
unwrap: (schema) => schema.properties?.data as Record<string, unknown>,
stripPrefix: (typeName) => typeName.replace(/^Wrapper/, ""),
});registerPlugin
Convenience function that bulk-registers spec profiles and response adapter presets from a single plugin object.
import { registerPlugin } from "@simplix-react/cli";
registerPlugin({
id: "my-backend",
specs: {
"my-backend": mySpecProfile,
},
responseAdapters: {
"my-envelope": myResponseAdapterPreset,
},
});Type Exports
| Export | Description |
| --- | --- |
| SimplixConfig | Project-level configuration for simplix.config.ts |
| OpenAPISpecConfig | Per-spec OpenAPI configuration within SimplixConfig.openapi |
| CrudEndpointPattern | CRUD role to HTTP method/path pattern mapping |
| CrudEntityConfig | Per-entity CRUD role to operationId mapping |
| CrudMap | Entity name to CrudEntityConfig mapping (used by defineCrudMap) |
| SpecProfile | Bundles naming strategy + response adapter as a reusable preset |
| ResponseAdapterPreset | Preset definition for a response adapter |
| ResponseAdapterConfig | Response adapter configuration (string preset or object) |
| OpenApiNamingStrategy | Strategy interface for entity/operation name derivation |
| EntityNameContext | Context provided to resolveEntityName() |
| OperationContext | Context provided to resolveOperation() |
| ResolvedOperation | Result of resolving an operation (role + hookName) |
| CliPlugin | Plugin object for registerPlugin |
| SchemaAdapter | Schema adapter interface for registerSchemaAdapter |
| I18nEntityInfo | Entity info for i18n key mapping |
| I18nDownloader | Callback for downloading i18n data from a server |
Related Packages
Install all packages at once with the meta package:
pnpm add simplix-react| Package | Description |
| --- | --- |
| simplix-react | Meta package (installs all packages below) |
| @simplix-react/contract | Zod-based type-safe API contract definitions |
| @simplix-react/react | React Query hooks derived from contracts |
| @simplix-react/form | TanStack Form hooks derived from contracts |
| @simplix-react/auth | Authentication middleware (Bearer, API Key, OAuth2) |
| @simplix-react/mock | MSW handlers + in-memory mock stores |
| @simplix-react/i18n | i18next-based internationalization framework |
| @simplix-react/testing | Test utilities (mock clients, query wrappers) |
