@forinda/kickjs-cli 5.0.2 → 5.2.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/dist/index.d.mts CHANGED
@@ -1,4 +1,435 @@
1
1
 
2
+ import { Command } from "commander";
3
+
4
+ //#region src/typegen/scanner.d.ts
5
+ /**
6
+ * Static scanner for KickJS decorated classes and DI tokens.
7
+ *
8
+ * Walks `src/**\/*.ts` (excluding tests and node_modules) and extracts:
9
+ *
10
+ * - Decorated classes (`@Service`, `@Controller`, `@Repository`, etc.)
11
+ * - `createToken<T>('name')` definitions
12
+ * - `@Inject('literal')` calls
13
+ *
14
+ * The output feeds the type generator, which emits `.kickjs/types/*.d.ts`
15
+ * files used by the user's tsc to make `container.resolve()` and module
16
+ * discovery type-safe.
17
+ *
18
+ * This is intentionally regex-based (not AST-based) to avoid the
19
+ * ts-morph / typescript compiler dependency. Pattern from
20
+ * `packages/vite/src/module-discovery.ts` which already uses regex
21
+ * to detect `*.module.ts` exports.
22
+ *
23
+ * ## Collision detection
24
+ *
25
+ * Two classes with the same name across different files is a collision.
26
+ * The scanner records all collisions in `ScanResult.collisions` so the
27
+ * caller (generator) can decide whether to hard-error or auto-namespace.
28
+ *
29
+ * @module @forinda/kickjs-cli/typegen/scanner
30
+ */
31
+ /** Decorators that mark a class as DI-managed */
32
+ declare const DECORATOR_NAMES: readonly ["Service", "Controller", "Repository", "Injectable", "Component", "Module"];
33
+ type DecoratorName = (typeof DECORATOR_NAMES)[number];
34
+ /** A single discovered decorated class */
35
+ interface DiscoveredClass {
36
+ /** Class name (e.g., 'UserService') */
37
+ className: string;
38
+ /** Decorator that marked it (e.g., 'Service') */
39
+ decorator: DecoratorName;
40
+ /** Absolute file path */
41
+ filePath: string;
42
+ /** Path relative to scan root, with forward slashes */
43
+ relativePath: string;
44
+ /** True if exported as `default` */
45
+ isDefault: boolean;
46
+ }
47
+ /** A single route handler discovered on a controller class */
48
+ interface DiscoveredRoute {
49
+ /** Owning controller class name (e.g. 'UserController') */
50
+ controller: string;
51
+ /** Handler method name on the controller (e.g. 'getUser') */
52
+ method: string;
53
+ /** HTTP verb (uppercase) */
54
+ httpMethod: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
55
+ /** Route path including parameter placeholders (e.g. '/:id/posts/:postId') */
56
+ path: string;
57
+ /** URL path parameter names extracted from `:placeholder` segments */
58
+ pathParams: string[];
59
+ /**
60
+ * Whitelisted query field names extracted from `@ApiQueryParams({...})`.
61
+ * `null` means no `@ApiQueryParams` was found on this method (so the
62
+ * generator emits an unconstrained `query` shape). An empty array means
63
+ * the decorator existed but no fields could be statically extracted
64
+ * (e.g. an opaque imported config).
65
+ */
66
+ queryFilterable: string[] | null;
67
+ querySortable: string[] | null;
68
+ querySearchable: string[] | null;
69
+ /**
70
+ * Schema identifiers referenced from the route decorator's second arg
71
+ * (e.g. `@Post('/', { body: createTaskSchema })`). `null` means no
72
+ * such reference; the value carries the identifier and the resolved
73
+ * import source (relative module path) if known.
74
+ */
75
+ bodySchema: SchemaRef | null;
76
+ querySchema: SchemaRef | null;
77
+ paramsSchema: SchemaRef | null;
78
+ /** Absolute file path of the controller */
79
+ filePath: string;
80
+ /** Path relative to scan root, with forward slashes */
81
+ relativePath: string;
82
+ }
83
+ /** A statically-resolved schema identifier reference */
84
+ interface SchemaRef {
85
+ /** The identifier as written (e.g. `createTaskSchema`) */
86
+ identifier: string;
87
+ /**
88
+ * Resolved module specifier (relative path or bare module name) where
89
+ * the identifier is defined. `null` means the source could not be
90
+ * statically determined (the generator falls back to `unknown`).
91
+ */
92
+ source: string | null;
93
+ }
94
+ /** A `createToken<T>('name')` call discovered in source */
95
+ interface DiscoveredToken {
96
+ /** The literal string passed to `createToken()` */
97
+ name: string;
98
+ /** The const variable name on the LHS, if any */
99
+ variable: string | null;
100
+ /** Absolute file path */
101
+ filePath: string;
102
+ /** Path relative to scan root, with forward slashes */
103
+ relativePath: string;
104
+ }
105
+ /** An `@Inject('literal')` call discovered in source */
106
+ interface DiscoveredInject {
107
+ /** The literal string passed to `@Inject()` */
108
+ name: string;
109
+ /** Absolute file path */
110
+ filePath: string;
111
+ /** Path relative to scan root, with forward slashes */
112
+ relativePath: string;
113
+ }
114
+ /** A name collision — same class name in two or more files */
115
+ interface ClassCollision {
116
+ /** The colliding class name */
117
+ className: string;
118
+ /** All files declaring the class */
119
+ classes: DiscoveredClass[];
120
+ }
121
+ /**
122
+ * Information about a discovered env schema file. The typegen
123
+ * generator uses this to emit a `KickEnv` + `NodeJS.ProcessEnv`
124
+ * augmentation that flows through to `@Value` and `process.env`.
125
+ *
126
+ * `null` means no env file was found at the configured location.
127
+ */
128
+ interface DiscoveredEnv {
129
+ /** Absolute path to the env schema file */
130
+ filePath: string;
131
+ /** Path relative to scan root, with forward slashes */
132
+ relativePath: string;
133
+ }
134
+ /**
135
+ * A plugin or adapter discovered in source — either via `defineAdapter({ name })`
136
+ * / `definePlugin({ name })` calls, or via a class that `implements AppAdapter`
137
+ * and declares a string-literal `name` field.
138
+ *
139
+ * The `name` here is the literal string passed to the framework (the value
140
+ * `dependsOn` references), NOT the symbol on the LHS. `defineAdapter` lets
141
+ * authors choose any name they want; the symbol is irrelevant at runtime.
142
+ */
143
+ interface DiscoveredPluginOrAdapter {
144
+ /** Whether this is a plugin (`definePlugin`) or adapter (`defineAdapter` / class) */
145
+ kind: 'plugin' | 'adapter';
146
+ /** The string literal passed as `name` (the value `dependsOn` references) */
147
+ name: string;
148
+ /** Absolute file path */
149
+ filePath: string;
150
+ /** Path relative to scan root, with forward slashes */
151
+ relativePath: string;
152
+ }
153
+ /**
154
+ * A `defineAugmentation('Name', meta)` call discovered in source. Plugins
155
+ * call this to advertise an augmentable interface so the typegen can list
156
+ * every augmentation surface in one generated file.
157
+ */
158
+ interface DiscoveredAugmentation {
159
+ /** The literal string passed as the first arg to `defineAugmentation` */
160
+ name: string;
161
+ /** Optional `description` extracted from the second-arg object literal */
162
+ description: string | null;
163
+ /** Optional `example` extracted from the second-arg object literal */
164
+ example: string | null;
165
+ /** Absolute file path */
166
+ filePath: string;
167
+ /** Path relative to scan root, with forward slashes */
168
+ relativePath: string;
169
+ }
170
+ /** Aggregated scanner output */
171
+ interface ScanResult {
172
+ classes: DiscoveredClass[];
173
+ routes: DiscoveredRoute[];
174
+ tokens: DiscoveredToken[];
175
+ injects: DiscoveredInject[];
176
+ collisions: ClassCollision[];
177
+ /** Discovered env schema file (or null if none found at the configured path) */
178
+ env: DiscoveredEnv | null;
179
+ /** Plugins/adapters discovered via `defineAdapter`/`definePlugin`/`implements AppAdapter` */
180
+ pluginsAndAdapters: DiscoveredPluginOrAdapter[];
181
+ /** Augmentation interfaces declared via `defineAugmentation('Name', meta)` */
182
+ augmentations: DiscoveredAugmentation[];
183
+ }
184
+ /** Options for the scanner */
185
+ interface ScanOptions {
186
+ /** Root directory to scan (e.g., absolute path to `src`) */
187
+ root: string;
188
+ /** Project root used to compute relative paths (e.g., process.cwd()) */
189
+ cwd: string;
190
+ /** Glob-like extensions to scan */
191
+ extensions?: string[];
192
+ /** Substrings that exclude a path (matched against relative path) */
193
+ exclude?: string[];
194
+ /**
195
+ * Path to the env schema file, relative to `cwd`. Defaults to
196
+ * `'src/env.ts'`. The file must contain a `defineEnv(...)` call
197
+ * with a default export for the typegen to emit a typed `KickEnv`
198
+ * augmentation. If the file does not exist or doesn't match the
199
+ * expected shape, env typing is skipped silently.
200
+ */
201
+ envFile?: string;
202
+ }
203
+ //#endregion
204
+ //#region src/typegen/plugin.d.ts
205
+ interface TypegenLogger {
206
+ info(msg: string): void;
207
+ warn(msg: string): void;
208
+ error(msg: string): void;
209
+ }
210
+ interface TypegenContext {
211
+ cwd: string;
212
+ config: KickConfig;
213
+ /** Dynamic-import a TS module (Node loader). Used by plugins that need to
214
+ * read the adopter's schema / route map / asset registry at generate time. */
215
+ importTs<T = unknown>(absPath: string): Promise<T>;
216
+ /** Write under `cwd`. Caller passes a relPath (e.g. `.kickjs/types/foo.d.ts`). */
217
+ writeFile(relPath: string, contents: string): Promise<void>;
218
+ /**
219
+ * Run `scanProject` once per typegen pass, memoizing the result so
220
+ * multiple plugins (`kick/routes`, `kick/env`, future adopter plugins)
221
+ * share a single fs walk + AST extraction.
222
+ *
223
+ * The runner uses an order-independent cache key derived from the
224
+ * resolved options (`root`, `cwd`, `extensions`, `exclude`, `envFile`)
225
+ * — semantically equal options hit the cache regardless of how the
226
+ * caller built the literal. (We deliberately don't `JSON.stringify`
227
+ * the options for caching since that would be sensitive to property
228
+ * insertion order.) Plugins that don't need scanner data can ignore
229
+ * this method entirely.
230
+ *
231
+ * Implementation lives in the runner so test harnesses can inject
232
+ * a stub scanner; plugins only see the function.
233
+ */
234
+ getScanResult(opts: ScanOptions): Promise<ScanResult>;
235
+ log: TypegenLogger;
236
+ }
237
+ interface TypegenPlugin {
238
+ /** Stable id — used as filename: `.kickjs/types/${id}<outExtension>` (slashes → `__`). */
239
+ id: string;
240
+ /** Glob patterns the Vite watcher subscribes to; change → re-run this plugin. */
241
+ inputs: string[];
242
+ /**
243
+ * Output filename extension. Default `.d.ts` — the right choice for
244
+ * pure module-augmentation plugins (kick/db, kick/assets) since
245
+ * declaration files don't need the runtime-import dance.
246
+ *
247
+ * `kick/routes` overrides to `.ts` because it emits hoisted
248
+ * `import type {...} from '...'` lines at the top of the file. Inline
249
+ * `import('...').X` references inside `.d.ts` silently degrade to
250
+ * `unknown` under `moduleResolution: 'bundler'`; emitting `.ts`
251
+ * sidesteps that quirk and gets full type resolution.
252
+ *
253
+ * Adopter-supplied plugins should leave this unset unless they hit
254
+ * the same hoisted-import constraint.
255
+ */
256
+ outExtension?: string;
257
+ /**
258
+ * Return the augmentation source (without banner — runner prepends).
259
+ * Return null to skip emission (e.g. no schema file present).
260
+ */
261
+ generate(ctx: TypegenContext): Promise<string | null>;
262
+ }
263
+ interface TypegenPluginResult {
264
+ id: string;
265
+ status: 'written' | 'unchanged' | 'skipped';
266
+ outFile?: string;
267
+ }
268
+ //#endregion
269
+ //#region src/generator-extension/define.d.ts
270
+ /**
271
+ * Plugin generator API per architecture.md §21.2.3 — lets first-party
272
+ * AND third-party packages ship `kick g <name>` scaffolders the same
273
+ * way the framework's built-in generators do.
274
+ *
275
+ * Plugins declare a discovery file in their `package.json`:
276
+ *
277
+ * ```json
278
+ * {
279
+ * "name": "@my-org/kickjs-cqrs",
280
+ * "kickjs": { "generators": "./dist/generators.js" }
281
+ * }
282
+ * ```
283
+ *
284
+ * The discovery file exports a typed manifest:
285
+ *
286
+ * ```ts
287
+ * import { defineGenerator } from '@forinda/kickjs-cli'
288
+ *
289
+ * export default [
290
+ * defineGenerator({
291
+ * name: 'command',
292
+ * description: 'Generate a CQRS command + handler',
293
+ * args: [{ name: 'name', required: true }],
294
+ * files: (ctx) => [
295
+ * {
296
+ * path: `src/modules/${ctx.kebab}/commands/create-${ctx.kebab}.command.ts`,
297
+ * content: `// generated command for ${ctx.pascal}`,
298
+ * },
299
+ * ],
300
+ * }),
301
+ * ]
302
+ * ```
303
+ *
304
+ * `kick g command Order` then dispatches against the registered
305
+ * generator and writes the returned files relative to `cwd`.
306
+ */
307
+ /**
308
+ * Resolved naming variants + project context handed to a generator's
309
+ * `files()` factory. Keys mirror `TemplateContext` so first-party
310
+ * generators that rely on the same shape can be migrated to plugin
311
+ * generators without rewriting their templates.
312
+ */
313
+ interface GeneratorContext {
314
+ /** Raw name passed on the command line (`kick g resolver UserPost` → `'UserPost'`). */
315
+ name: string;
316
+ /** PascalCase form (`UserPost`). */
317
+ pascal: string;
318
+ /** kebab-case form (`user-post`). */
319
+ kebab: string;
320
+ /** camelCase form (`userPost`). */
321
+ camel: string;
322
+ /** snake_case form (`user_post`). */
323
+ snake: string;
324
+ /** Pluralized PascalCase (`UserPosts`) — present when the project enables `pluralize`. */
325
+ pluralPascal?: string;
326
+ /** Pluralized kebab-case (`user-posts`). */
327
+ pluralKebab?: string;
328
+ /** Pluralized camelCase (`userPosts`). */
329
+ pluralCamel?: string;
330
+ /** Modules directory from `kick.config.ts` (default `'src/modules'`). */
331
+ modulesDir: string;
332
+ /** Working directory for the generator — usually `process.cwd()`. */
333
+ cwd: string;
334
+ /** Positional arguments passed AFTER the name (e.g. `kick g command Order extra1 extra2` → `['extra1', 'extra2']`). */
335
+ args: string[];
336
+ /** Flag values from the command line — booleans for switches, strings for `--key value`. */
337
+ flags: Record<string, string | boolean>;
338
+ }
339
+ /** A single output file the generator wants written. */
340
+ interface GeneratorFile {
341
+ /**
342
+ * Output path. Relative paths resolve against `ctx.cwd`; absolute
343
+ * paths are used as-is. Parent directories are created automatically.
344
+ */
345
+ path: string;
346
+ /** File contents written verbatim (UTF-8). */
347
+ content: string;
348
+ }
349
+ /** CLI argument descriptor surfaced in `kick g --list` help. */
350
+ interface GeneratorArg {
351
+ name: string;
352
+ required?: boolean;
353
+ description?: string;
354
+ }
355
+ /** CLI flag descriptor — boolean unless `takesValue: true`. */
356
+ interface GeneratorFlag {
357
+ name: string;
358
+ alias?: string;
359
+ description?: string;
360
+ takesValue?: boolean;
361
+ }
362
+ /**
363
+ * Spec returned by {@link defineGenerator}. Plugin discovery files
364
+ * export `GeneratorSpec[]` as their default export.
365
+ */
366
+ interface GeneratorSpec {
367
+ /**
368
+ * Dispatch name — `kick g <name>` looks for an exact match against
369
+ * this string after the built-in generators are checked.
370
+ */
371
+ name: string;
372
+ /** Description shown in `kick g --list` and `--help`. */
373
+ description: string;
374
+ /** Optional argument descriptors — informational, surfaced in help output. */
375
+ args?: readonly GeneratorArg[];
376
+ /** Optional flag descriptors — informational, surfaced in help output. */
377
+ flags?: readonly GeneratorFlag[];
378
+ /** Build the output files for one invocation. May return a Promise. */
379
+ files(ctx: GeneratorContext): GeneratorFile[] | Promise<GeneratorFile[]>;
380
+ }
381
+ /**
382
+ * Identity factory — returns the spec verbatim. Exists for type
383
+ * inference and forward-compatibility (future fields can be added with
384
+ * defaults).
385
+ *
386
+ * @example
387
+ * ```ts
388
+ * import { defineGenerator } from '@forinda/kickjs-cli'
389
+ *
390
+ * export default [
391
+ * defineGenerator({
392
+ * name: 'command',
393
+ * description: 'Generate a CQRS command + handler',
394
+ * files: (ctx) => [
395
+ * {
396
+ * path: `src/modules/${ctx.kebab}/commands/${ctx.kebab}.command.ts`,
397
+ * content: `// command for ${ctx.pascal}`,
398
+ * },
399
+ * ],
400
+ * }),
401
+ * ]
402
+ * ```
403
+ */
404
+ declare function defineGenerator(spec: GeneratorSpec): GeneratorSpec;
405
+ //#endregion
406
+ //#region src/plugin/types.d.ts
407
+ /**
408
+ * Runtime context handed to `register()` — saves callbacks from
409
+ * re-loading config or guessing cwd. Forward-compatible: future fields
410
+ * land here without changing the callback signature.
411
+ */
412
+ interface KickCliPluginContext {
413
+ cwd: string;
414
+ /** Resolved kick.config.ts (null if the project has none). */
415
+ config: KickConfig | null;
416
+ log: (msg: string) => void;
417
+ }
418
+ interface KickCliPlugin {
419
+ /** Stable identifier — used in error messages on conflict + de-dup. */
420
+ name: string;
421
+ commands?: KickCommandDefinition[];
422
+ /** Programmatic command registration. Called once at CLI startup. */
423
+ register?: (program: Command, ctx: KickCliPluginContext) => void | Promise<void>;
424
+ typegens?: TypegenPlugin[];
425
+ generators?: GeneratorSpec[];
426
+ }
427
+ /** Identity helper — exists for type inference + parity with definePlugin. */
428
+ declare function defineCliPlugin(p: KickCliPlugin): KickCliPlugin;
429
+ declare class KickPluginConflictError extends Error {
430
+ constructor(kind: 'plugin' | 'command' | 'typegen' | 'generator', id: string, owners: string[]);
431
+ }
432
+ //#endregion
2
433
  //#region src/config.d.ts
3
434
  /** A custom command that developers can register via kick.config.ts */
4
435
  interface KickCommandDefinition {
@@ -64,6 +495,28 @@ interface AssetMapEntry {
64
495
  * selective by design (unlike `copyDirs` which copies everything).
65
496
  */
66
497
  glob?: string;
498
+ /**
499
+ * How file extensions feed into manifest keys. Default `'auto'`.
500
+ *
501
+ * - `'strip'` — drop the extension. `pages/index.pug` →
502
+ * `'pages/index'`. Two siblings with the same basename collide;
503
+ * last-walk-order wins, others are silently dropped. Opt-in
504
+ * only — kept for backward compatibility with projects that
505
+ * relied on this contract.
506
+ * - `'with-extension'` — keep every extension on every key. Best
507
+ * when the namespace holds extension siblings (`index.pug` +
508
+ * `index.html` + `index.css` in `src/pages/`); every file
509
+ * reaches the manifest under its full path.
510
+ * - `'auto'` — strip when basenames are unique, keep extensions
511
+ * on collision groups. Singleton files keep their short key;
512
+ * `pages/index.{pug,html,css}` becomes
513
+ * `pages/index.pug` / `pages/index.html` / `pages/index.css`.
514
+ * No data loss; non-colliding namespaces stay on the short
515
+ * keys they had before.
516
+ *
517
+ * @default 'auto'
518
+ */
519
+ keys?: 'auto' | 'strip' | 'with-extension';
67
520
  }
68
521
  /** Typegen settings — controls .kickjs/types/* generation */
69
522
  interface TypegenConfig {
@@ -100,6 +553,24 @@ interface TypegenConfig {
100
553
  * @default 'src/env.ts'
101
554
  */
102
555
  envFile?: string | false;
556
+ /**
557
+ * Built-in or user typegen plugin ids to skip during `kick typegen`,
558
+ * `kick dev`, and `kick typegen --watch`.
559
+ *
560
+ * The plugin still loads and merge-time conflict detection still
561
+ * runs — only the `generate()` invocation is skipped — so adopters
562
+ * who want to hand-write `KickDbRegister` (manual typeof-schema
563
+ * augmentation) can disable `'kick/db'` and keep the rest:
564
+ *
565
+ * @example
566
+ * typegen: {
567
+ * disable: ['kick/db'], // hand-written register.ts owns the type
568
+ * }
569
+ *
570
+ * Unrecognised ids are ignored — the list is treated as a wishlist,
571
+ * not a strict registry.
572
+ */
573
+ disable?: string[];
103
574
  }
104
575
  /** Module generation settings — controls how `kick g module` produces code */
105
576
  interface ModuleConfig {
@@ -176,6 +647,25 @@ interface KickConfig {
176
647
  * packageManager: 'pnpm'
177
648
  */
178
649
  packageManager?: PackageManager;
650
+ /**
651
+ * DI token scope prefix used by code generators. Every scaffolded
652
+ * `createToken<T>('<scope>/<area>/<key>')` substitutes this string
653
+ * for `<scope>`. Generators emit org-scoped tokens out of the box
654
+ * so adopter projects pass `kick-lint`'s `token-reserved-prefix`
655
+ * rule (which forbids the reserved `kick/` prefix on third-party
656
+ * code) without manual rename.
657
+ *
658
+ * Resolution order (highest first):
659
+ * 1. This field, when set
660
+ * 2. `package.json` `name` field — `@scope/pkg` → `'scope'`,
661
+ * bare `pkg` → `'pkg'`
662
+ * 3. Fallback `'app'`
663
+ *
664
+ * @example
665
+ * tokenScope: 'mycorp'
666
+ * // → createToken<...>('mycorp/users/repository')
667
+ */
668
+ tokenScope?: string;
179
669
  /**
180
670
  * Directories to copy to dist/ after build.
181
671
  * Useful for EJS templates, email templates, static assets, etc.
@@ -249,6 +739,20 @@ interface KickConfig {
249
739
  typegen?: TypegenConfig;
250
740
  /** Custom commands that extend the CLI */
251
741
  commands?: KickCommandDefinition[];
742
+ /**
743
+ * CLI plugins — bundled commands + typegens contributed by external
744
+ * packages (e.g. `@forinda/kickjs-cli-drizzle`). Plugin commands
745
+ * appear first; adopter `commands` overrides plugin commands of the
746
+ * same name. Duplicate commands or typegen ids across two plugins
747
+ * fail-fast at CLI startup.
748
+ *
749
+ * @example
750
+ * import { drizzlePlugin } from '@forinda/kickjs-cli-drizzle'
751
+ * export default defineConfig({
752
+ * plugins: [drizzlePlugin({ schemaPath: 'src/db/schema' })],
753
+ * })
754
+ */
755
+ plugins?: KickCliPlugin[];
252
756
  /** Code style overrides (auto-detected from prettier when possible) */
253
757
  style?: {
254
758
  semicolons?: boolean;
@@ -279,6 +783,14 @@ interface GenerateModuleOptions {
279
783
  pluralize?: boolean;
280
784
  /** Prisma client import path (default: '@prisma/client', Prisma 7+: '@/generated/prisma/client') */
281
785
  prismaClientPath?: string;
786
+ /**
787
+ * DI-token scope prefix substituted into emitted `createToken<T>()`
788
+ * literals. Resolved by the orchestrating command from
789
+ * `kick.config.ts > tokenScope` or the project's package.json.
790
+ * Falls back to `'app'` when not set so the generator can be called
791
+ * without a config in tests/fixtures.
792
+ */
793
+ tokenScope?: string;
282
794
  }
283
795
  /**
284
796
  * Generate a module — structure depends on the project pattern.
@@ -379,143 +891,6 @@ interface InitProjectOptions {
379
891
  /** Scaffold a new KickJS project */
380
892
  declare function initProject(options: InitProjectOptions): Promise<void>;
381
893
  //#endregion
382
- //#region src/generator-extension/define.d.ts
383
- /**
384
- * Plugin generator API per architecture.md §21.2.3 — lets first-party
385
- * AND third-party packages ship `kick g <name>` scaffolders the same
386
- * way the framework's built-in generators do.
387
- *
388
- * Plugins declare a discovery file in their `package.json`:
389
- *
390
- * ```json
391
- * {
392
- * "name": "@my-org/kickjs-cqrs",
393
- * "kickjs": { "generators": "./dist/generators.js" }
394
- * }
395
- * ```
396
- *
397
- * The discovery file exports a typed manifest:
398
- *
399
- * ```ts
400
- * import { defineGenerator } from '@forinda/kickjs-cli'
401
- *
402
- * export default [
403
- * defineGenerator({
404
- * name: 'command',
405
- * description: 'Generate a CQRS command + handler',
406
- * args: [{ name: 'name', required: true }],
407
- * files: (ctx) => [
408
- * {
409
- * path: `src/modules/${ctx.kebab}/commands/create-${ctx.kebab}.command.ts`,
410
- * content: `// generated command for ${ctx.pascal}`,
411
- * },
412
- * ],
413
- * }),
414
- * ]
415
- * ```
416
- *
417
- * `kick g command Order` then dispatches against the registered
418
- * generator and writes the returned files relative to `cwd`.
419
- */
420
- /**
421
- * Resolved naming variants + project context handed to a generator's
422
- * `files()` factory. Keys mirror `TemplateContext` so first-party
423
- * generators that rely on the same shape can be migrated to plugin
424
- * generators without rewriting their templates.
425
- */
426
- interface GeneratorContext {
427
- /** Raw name passed on the command line (`kick g resolver UserPost` → `'UserPost'`). */
428
- name: string;
429
- /** PascalCase form (`UserPost`). */
430
- pascal: string;
431
- /** kebab-case form (`user-post`). */
432
- kebab: string;
433
- /** camelCase form (`userPost`). */
434
- camel: string;
435
- /** snake_case form (`user_post`). */
436
- snake: string;
437
- /** Pluralized PascalCase (`UserPosts`) — present when the project enables `pluralize`. */
438
- pluralPascal?: string;
439
- /** Pluralized kebab-case (`user-posts`). */
440
- pluralKebab?: string;
441
- /** Pluralized camelCase (`userPosts`). */
442
- pluralCamel?: string;
443
- /** Modules directory from `kick.config.ts` (default `'src/modules'`). */
444
- modulesDir: string;
445
- /** Working directory for the generator — usually `process.cwd()`. */
446
- cwd: string;
447
- /** Positional arguments passed AFTER the name (e.g. `kick g command Order extra1 extra2` → `['extra1', 'extra2']`). */
448
- args: string[];
449
- /** Flag values from the command line — booleans for switches, strings for `--key value`. */
450
- flags: Record<string, string | boolean>;
451
- }
452
- /** A single output file the generator wants written. */
453
- interface GeneratorFile {
454
- /**
455
- * Output path. Relative paths resolve against `ctx.cwd`; absolute
456
- * paths are used as-is. Parent directories are created automatically.
457
- */
458
- path: string;
459
- /** File contents written verbatim (UTF-8). */
460
- content: string;
461
- }
462
- /** CLI argument descriptor surfaced in `kick g --list` help. */
463
- interface GeneratorArg {
464
- name: string;
465
- required?: boolean;
466
- description?: string;
467
- }
468
- /** CLI flag descriptor — boolean unless `takesValue: true`. */
469
- interface GeneratorFlag {
470
- name: string;
471
- alias?: string;
472
- description?: string;
473
- takesValue?: boolean;
474
- }
475
- /**
476
- * Spec returned by {@link defineGenerator}. Plugin discovery files
477
- * export `GeneratorSpec[]` as their default export.
478
- */
479
- interface GeneratorSpec {
480
- /**
481
- * Dispatch name — `kick g <name>` looks for an exact match against
482
- * this string after the built-in generators are checked.
483
- */
484
- name: string;
485
- /** Description shown in `kick g --list` and `--help`. */
486
- description: string;
487
- /** Optional argument descriptors — informational, surfaced in help output. */
488
- args?: readonly GeneratorArg[];
489
- /** Optional flag descriptors — informational, surfaced in help output. */
490
- flags?: readonly GeneratorFlag[];
491
- /** Build the output files for one invocation. May return a Promise. */
492
- files(ctx: GeneratorContext): GeneratorFile[] | Promise<GeneratorFile[]>;
493
- }
494
- /**
495
- * Identity factory — returns the spec verbatim. Exists for type
496
- * inference and forward-compatibility (future fields can be added with
497
- * defaults).
498
- *
499
- * @example
500
- * ```ts
501
- * import { defineGenerator } from '@forinda/kickjs-cli'
502
- *
503
- * export default [
504
- * defineGenerator({
505
- * name: 'command',
506
- * description: 'Generate a CQRS command + handler',
507
- * files: (ctx) => [
508
- * {
509
- * path: `src/modules/${ctx.kebab}/commands/${ctx.kebab}.command.ts`,
510
- * content: `// command for ${ctx.pascal}`,
511
- * },
512
- * ],
513
- * }),
514
- * ]
515
- * ```
516
- */
517
- declare function defineGenerator(spec: GeneratorSpec): GeneratorSpec;
518
- //#endregion
519
894
  //#region src/generator-extension/discover.d.ts
520
895
  /**
521
896
  * One row in the discovered registry. `source` is the npm package name
@@ -575,5 +950,5 @@ declare function toKebabCase(name: string): string;
575
950
  */
576
951
  declare function pluralize(name: string): string;
577
952
  //#endregion
578
- export { type DiscoveredGenerator, type DiscoveryResult, type GeneratorArg, type GeneratorContext, type GeneratorFile, type GeneratorFlag, type GeneratorSpec, type KickCommandDefinition, type KickConfig, buildGeneratorContext, defineConfig, defineGenerator, generateAdapter, generateController, generateDto, generateGuard, generateMiddleware, generateModule, generateService, initProject, loadKickConfig, pluralize, toCamelCase, toKebabCase, toPascalCase };
953
+ export { type DiscoveredGenerator, type DiscoveryResult, type GeneratorArg, type GeneratorContext, type GeneratorFile, type GeneratorFlag, type GeneratorSpec, type KickCliPlugin, type KickCliPluginContext, type KickCommandDefinition, type KickConfig, KickPluginConflictError, type TypegenContext, type TypegenPlugin, type TypegenPluginResult, buildGeneratorContext, defineCliPlugin, defineConfig, defineGenerator, generateAdapter, generateController, generateDto, generateGuard, generateMiddleware, generateModule, generateService, initProject, loadKickConfig, pluralize, toCamelCase, toKebabCase, toPascalCase };
579
954
  //# sourceMappingURL=index.d.mts.map