@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/builtins-BW3g09hP.mjs +8538 -0
- package/dist/builtins-C_VfEGdg.mjs +4182 -0
- package/dist/builtins-C_VfEGdg.mjs.map +1 -0
- package/dist/cli.mjs +21 -9299
- package/dist/config-DDrgs-I3.mjs +171 -0
- package/dist/config-DDrgs-I3.mjs.map +1 -0
- package/dist/config-DsQe2yzy.mjs +169 -0
- package/dist/generator-extension-DRNQpoZP.mjs +4380 -0
- package/dist/generator-extension-DRNQpoZP.mjs.map +1 -0
- package/dist/index.d.mts +513 -138
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +5 -4159
- package/dist/plugin-6_YlK-JG.mjs +71 -0
- package/dist/plugin-6_YlK-JG.mjs.map +1 -0
- package/dist/plugin-CQ0yYXyr.mjs +80 -0
- package/dist/rolldown-runtime-CYBbkZNy.mjs +24 -0
- package/dist/run-plugins-B1R0HG0g.mjs +12 -0
- package/dist/typegen-CYCsmCRF.mjs +1351 -0
- package/dist/{typegen-D8MJ2hPX.mjs → typegen-DugZmi-0.mjs} +127 -224
- package/dist/typegen-DugZmi-0.mjs.map +1 -0
- package/dist/types-CGB8BiQh.mjs +25 -0
- package/dist/types-CGB8BiQh.mjs.map +1 -0
- package/package.json +9 -3
- package/dist/index.mjs.map +0 -1
- package/dist/typegen-D8MJ2hPX.mjs.map +0 -1
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
|