@forinda/kickjs-cli 5.1.0 → 5.2.1
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-caRjFvKz.mjs → builtins-B0dptoXq.mjs} +626 -241
- package/dist/builtins-B0dptoXq.mjs.map +1 -0
- package/dist/{builtins-Cb_d-b1S.mjs → builtins-N3mDa6bM.mjs} +695 -273
- package/dist/cli.mjs +9 -9
- package/dist/{config-8bAt-mLl.mjs → config-Bc6ERRTE.mjs} +35 -5
- package/dist/{config-C_LQNClP.mjs → config-CRi3zCxk.mjs} +36 -6
- package/dist/config-CRi3zCxk.mjs.map +1 -0
- package/dist/{generator-extension-CYY-RI21.mjs → generator-extension-C-HwKvFf.mjs} +76 -39
- package/dist/generator-extension-C-HwKvFf.mjs.map +1 -0
- package/dist/index.d.mts +282 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +4 -4
- package/dist/{plugin-D8K5fG-O.mjs → plugin-DfomEcef.mjs} +4 -4
- package/dist/{plugin-D8K5fG-O.mjs.map → plugin-DfomEcef.mjs.map} +1 -1
- package/dist/{plugin-Bgfg7qMk.mjs → plugin-b7ig7Uxv.mjs} +2 -2
- package/dist/{rolldown-runtime-BM29JyaJ.mjs → rolldown-runtime-CV_zlh2d.mjs} +1 -1
- package/dist/{run-plugins-BXvMFPhJ.mjs → run-plugins-D9abb5Nx.mjs} +2 -2
- package/dist/{typegen-BNz_RQTb.mjs → typegen-B9S81bOx.mjs} +48 -225
- package/dist/typegen-B9S81bOx.mjs.map +1 -0
- package/dist/{typegen-8ZeA1B-X.mjs → typegen-BKUAdp_3.mjs} +47 -228
- package/dist/{types-BBUo1vXh.mjs → types-CU89yUxU.mjs} +2 -2
- package/dist/{types-BBUo1vXh.mjs.map → types-CU89yUxU.mjs.map} +1 -1
- package/package.json +6 -4
- package/dist/builtins-caRjFvKz.mjs.map +0 -1
- package/dist/config-C_LQNClP.mjs.map +0 -1
- package/dist/generator-extension-CYY-RI21.mjs.map +0 -1
- package/dist/typegen-8ZeA1B-X.mjs.map +0 -1
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v5.1
|
|
2
|
+
* @forinda/kickjs-cli v5.2.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import { i as runShellCommand, t as builtinCliPlugins } from "./builtins-
|
|
12
|
-
import { r as loadKickConfig } from "./config-
|
|
13
|
-
import { n as mergeCliPlugins } from "./plugin-
|
|
11
|
+
import { i as runShellCommand, t as builtinCliPlugins } from "./builtins-N3mDa6bM.mjs";
|
|
12
|
+
import { r as loadKickConfig } from "./config-Bc6ERRTE.mjs";
|
|
13
|
+
import { n as mergeCliPlugins } from "./plugin-b7ig7Uxv.mjs";
|
|
14
14
|
import { Command } from "commander";
|
|
15
15
|
import { readFileSync } from "node:fs";
|
|
16
16
|
import { dirname, join } from "node:path";
|
|
@@ -92,7 +92,7 @@ function registerSingleCommand(program, def) {
|
|
|
92
92
|
console.log(` $ ${finalCmd}`);
|
|
93
93
|
try {
|
|
94
94
|
runShellCommand(finalCmd);
|
|
95
|
-
} catch
|
|
95
|
+
} catch {
|
|
96
96
|
console.error(` Command failed: ${def.name}`);
|
|
97
97
|
process.exitCode = 1;
|
|
98
98
|
return;
|
|
@@ -107,15 +107,15 @@ const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-
|
|
|
107
107
|
async function main() {
|
|
108
108
|
const program = new Command();
|
|
109
109
|
program.name("kick").description("KickJS — A production-grade, decorator-driven Node.js framework").version(pkg.version);
|
|
110
|
-
const config = await loadKickConfig(process.cwd());
|
|
111
|
-
const merged = mergeCliPlugins([...builtinCliPlugins, ...config
|
|
110
|
+
const config = await loadKickConfig(process.cwd()) ?? {};
|
|
111
|
+
const merged = mergeCliPlugins([...builtinCliPlugins, ...config.plugins ?? []], config.commands ?? []);
|
|
112
112
|
await merged.register(program, {
|
|
113
113
|
cwd: process.cwd(),
|
|
114
|
-
config
|
|
114
|
+
config,
|
|
115
115
|
log: (msg) => console.log(msg)
|
|
116
116
|
});
|
|
117
117
|
registerCustomCommands(program, {
|
|
118
|
-
...config
|
|
118
|
+
...config,
|
|
119
119
|
commands: merged.commands
|
|
120
120
|
});
|
|
121
121
|
program.showHelpAfterError();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v5.1
|
|
2
|
+
* @forinda/kickjs-cli v5.2.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import { t as __exportAll } from "./rolldown-runtime-
|
|
12
|
-
import { existsSync } from "node:fs";
|
|
11
|
+
import { t as __exportAll } from "./rolldown-runtime-CV_zlh2d.mjs";
|
|
12
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
13
13
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
14
14
|
import { access, readFile } from "node:fs/promises";
|
|
15
15
|
//#region src/config.ts
|
|
@@ -19,6 +19,7 @@ var config_exports = /* @__PURE__ */ __exportAll({
|
|
|
19
19
|
defineConfig: () => defineConfig,
|
|
20
20
|
loadKickConfig: () => loadKickConfig,
|
|
21
21
|
resolveModuleConfig: () => resolveModuleConfig,
|
|
22
|
+
resolveTokenScope: () => resolveTokenScope,
|
|
22
23
|
validateAssetMap: () => validateAssetMap
|
|
23
24
|
});
|
|
24
25
|
const PACKAGE_MANAGERS = [
|
|
@@ -37,6 +38,35 @@ function defineConfig(config) {
|
|
|
37
38
|
return config;
|
|
38
39
|
}
|
|
39
40
|
/** Resolve module config from `modules.*` block. */
|
|
41
|
+
/**
|
|
42
|
+
* Resolve the project's DI token scope for code generators.
|
|
43
|
+
* Falls back through kick.config.ts → package.json → `'app'`.
|
|
44
|
+
*
|
|
45
|
+
* @param config Loaded `kick.config.ts` (null when not present)
|
|
46
|
+
* @param cwd Project root — used to read package.json
|
|
47
|
+
*/
|
|
48
|
+
function resolveTokenScope(config, cwd) {
|
|
49
|
+
if (config?.tokenScope && typeof config.tokenScope === "string" && config.tokenScope.length > 0) {
|
|
50
|
+
const sanitised = sanitizeScope(config.tokenScope);
|
|
51
|
+
if (sanitised.length > 0) return sanitised;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const pkgPath = join(cwd, "package.json");
|
|
55
|
+
if (existsSync(pkgPath)) {
|
|
56
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
57
|
+
if (typeof pkg.name === "string" && pkg.name.length > 0) {
|
|
58
|
+
const scoped = pkg.name.match(/^@([^/]+)\//);
|
|
59
|
+
const candidate = scoped ? sanitizeScope(scoped[1]) : sanitizeScope(pkg.name);
|
|
60
|
+
if (candidate.length > 0) return candidate;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
} catch {}
|
|
64
|
+
return "app";
|
|
65
|
+
}
|
|
66
|
+
/** Lowercase + strip characters that would break a token literal. */
|
|
67
|
+
function sanitizeScope(raw) {
|
|
68
|
+
return raw.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^-+|-+$/g, "").replace(/-{2,}/g, "-");
|
|
69
|
+
}
|
|
40
70
|
function resolveModuleConfig(config) {
|
|
41
71
|
if (!config) return {};
|
|
42
72
|
const mc = {
|
|
@@ -75,7 +105,7 @@ async function loadKickConfig(cwd) {
|
|
|
75
105
|
const warnings = validateAssetMap(config, cwd);
|
|
76
106
|
for (const warning of warnings) console.warn(` Warning: ${warning}`);
|
|
77
107
|
return config;
|
|
78
|
-
} catch
|
|
108
|
+
} catch {
|
|
79
109
|
if (filename.endsWith(".ts")) console.warn(`Warning: Failed to load ${filename}. TypeScript config files require a runtime loader (e.g. tsx, ts-node) or use kick.config.js/.mjs instead.`);
|
|
80
110
|
continue;
|
|
81
111
|
}
|
|
@@ -136,4 +166,4 @@ function escapesRoot(path, root) {
|
|
|
136
166
|
return rel === "" ? false : rel.startsWith("..") || isAbsolute(rel);
|
|
137
167
|
}
|
|
138
168
|
//#endregion
|
|
139
|
-
export { resolveModuleConfig as i, config_exports as n, loadKickConfig as r, PACKAGE_MANAGERS as t };
|
|
169
|
+
export { resolveTokenScope as a, resolveModuleConfig as i, config_exports as n, loadKickConfig as r, PACKAGE_MANAGERS as t };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v5.1
|
|
2
|
+
* @forinda/kickjs-cli v5.2.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import { t as __exportAll } from "./rolldown-runtime-
|
|
11
|
+
import { t as __exportAll } from "./rolldown-runtime-CV_zlh2d.mjs";
|
|
12
12
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
13
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
13
14
|
import { access, readFile } from "node:fs/promises";
|
|
14
|
-
import { existsSync } from "node:fs";
|
|
15
15
|
//#region src/config.ts
|
|
16
16
|
var config_exports = /* @__PURE__ */ __exportAll({
|
|
17
17
|
BUILTIN_REPO_TYPES: () => BUILTIN_REPO_TYPES,
|
|
@@ -19,6 +19,7 @@ var config_exports = /* @__PURE__ */ __exportAll({
|
|
|
19
19
|
defineConfig: () => defineConfig,
|
|
20
20
|
loadKickConfig: () => loadKickConfig,
|
|
21
21
|
resolveModuleConfig: () => resolveModuleConfig,
|
|
22
|
+
resolveTokenScope: () => resolveTokenScope,
|
|
22
23
|
validateAssetMap: () => validateAssetMap
|
|
23
24
|
});
|
|
24
25
|
const PACKAGE_MANAGERS = [
|
|
@@ -37,6 +38,35 @@ function defineConfig(config) {
|
|
|
37
38
|
return config;
|
|
38
39
|
}
|
|
39
40
|
/** Resolve module config from `modules.*` block. */
|
|
41
|
+
/**
|
|
42
|
+
* Resolve the project's DI token scope for code generators.
|
|
43
|
+
* Falls back through kick.config.ts → package.json → `'app'`.
|
|
44
|
+
*
|
|
45
|
+
* @param config Loaded `kick.config.ts` (null when not present)
|
|
46
|
+
* @param cwd Project root — used to read package.json
|
|
47
|
+
*/
|
|
48
|
+
function resolveTokenScope(config, cwd) {
|
|
49
|
+
if (config?.tokenScope && typeof config.tokenScope === "string" && config.tokenScope.length > 0) {
|
|
50
|
+
const sanitised = sanitizeScope(config.tokenScope);
|
|
51
|
+
if (sanitised.length > 0) return sanitised;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const pkgPath = join(cwd, "package.json");
|
|
55
|
+
if (existsSync(pkgPath)) {
|
|
56
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
57
|
+
if (typeof pkg.name === "string" && pkg.name.length > 0) {
|
|
58
|
+
const scoped = pkg.name.match(/^@([^/]+)\//);
|
|
59
|
+
const candidate = scoped ? sanitizeScope(scoped[1]) : sanitizeScope(pkg.name);
|
|
60
|
+
if (candidate.length > 0) return candidate;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
} catch {}
|
|
64
|
+
return "app";
|
|
65
|
+
}
|
|
66
|
+
/** Lowercase + strip characters that would break a token literal. */
|
|
67
|
+
function sanitizeScope(raw) {
|
|
68
|
+
return raw.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^-+|-+$/g, "").replace(/-{2,}/g, "-");
|
|
69
|
+
}
|
|
40
70
|
function resolveModuleConfig(config) {
|
|
41
71
|
if (!config) return {};
|
|
42
72
|
const mc = {
|
|
@@ -75,7 +105,7 @@ async function loadKickConfig(cwd) {
|
|
|
75
105
|
const warnings = validateAssetMap(config, cwd);
|
|
76
106
|
for (const warning of warnings) console.warn(` Warning: ${warning}`);
|
|
77
107
|
return config;
|
|
78
|
-
} catch
|
|
108
|
+
} catch {
|
|
79
109
|
if (filename.endsWith(".ts")) console.warn(`Warning: Failed to load ${filename}. TypeScript config files require a runtime loader (e.g. tsx, ts-node) or use kick.config.js/.mjs instead.`);
|
|
80
110
|
continue;
|
|
81
111
|
}
|
|
@@ -136,6 +166,6 @@ function escapesRoot(path, root) {
|
|
|
136
166
|
return rel === "" ? false : rel.startsWith("..") || isAbsolute(rel);
|
|
137
167
|
}
|
|
138
168
|
//#endregion
|
|
139
|
-
export { resolveModuleConfig as a, loadKickConfig as i, config_exports as n, defineConfig as r, PACKAGE_MANAGERS as t };
|
|
169
|
+
export { resolveModuleConfig as a, loadKickConfig as i, config_exports as n, resolveTokenScope as o, defineConfig as r, PACKAGE_MANAGERS as t };
|
|
140
170
|
|
|
141
|
-
//# sourceMappingURL=config-
|
|
171
|
+
//# sourceMappingURL=config-CRi3zCxk.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-CRi3zCxk.mjs","names":[],"sources":["../src/config.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs'\nimport { readFile, access } from 'node:fs/promises'\nimport { isAbsolute, join, relative, resolve } from 'node:path'\n\nimport type { KickCliPlugin } from './plugin/types'\n\n/** A custom command that developers can register via kick.config.ts */\nexport interface KickCommandDefinition {\n /** The command name (e.g. 'db:migrate', 'seed', 'proto:gen') */\n name: string\n /** Description shown in --help */\n description: string\n /**\n * Shell command(s) to run. Can be a single string or an array of\n * sequential steps. Use {args} as a placeholder for CLI arguments.\n *\n * @example\n * 'npx drizzle-kit migrate'\n * ['npx drizzle-kit generate', 'npx drizzle-kit migrate']\n */\n steps: string | string[]\n /** Optional aliases (e.g. ['migrate'] for 'db:migrate') */\n aliases?: string[]\n}\n\n/** Project pattern — controls what generators produce and which deps are installed */\nexport type ProjectPattern = 'rest' | 'ddd' | 'cqrs' | 'minimal'\n\n/** Package manager used for `kick add` and other dep-installing commands */\nexport type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun'\n\nexport const PACKAGE_MANAGERS: readonly PackageManager[] = ['pnpm', 'npm', 'yarn', 'bun']\n\n/** Built-in repository types with first-class code generation support */\nexport type BuiltinRepoType = 'drizzle' | 'inmemory' | 'prisma'\n\nexport const BUILTIN_REPO_TYPES: readonly string[] = ['drizzle', 'inmemory', 'prisma']\n\n/** Custom repository type — generates a stub with TODO markers */\nexport interface CustomRepoType {\n name: string\n}\n\n/** Repository type — built-in string or custom object */\nexport type RepoTypeConfig = BuiltinRepoType | CustomRepoType\n\n/**\n * Supported schema validators for `kick typegen` body/query/params\n * type extraction. Only `'zod'` ships built-in for now; other libraries\n * (Joi, Yup, JSON Schema) will be added later as the adapter system\n * grows. Set to `false` (or omit) to disable schema-driven body typing\n * entirely (the route entries will keep `body: unknown`).\n */\nexport type SchemaValidator = 'zod' | false\n\n/**\n * One entry in the typed `assetMap` config record (`assets-plan.md`).\n * Each entry names a source directory whose files become addressable\n * via the `assets.<name>.*` typed accessor at runtime.\n */\nexport interface AssetMapEntry {\n /**\n * Source directory, relative to project root. Required. The directory\n * must exist when `kick build` runs — `loadKickConfig` warns when an\n * entry points at a missing directory but doesn't fail the load\n * (the typegen + build steps surface the error in context instead).\n */\n src: string\n /**\n * Destination directory inside `dist/`. Defaults to `dist/<name>/`\n * where `<name>` is the assetMap key. Override when the consumer of\n * the assets expects a non-standard layout (e.g. an existing\n * downstream tool reads from `dist/templates/...`).\n */\n dest?: string\n /**\n * Glob pattern for which files to include. Defaults to `**\\/*` (all\n * files). Files that don't match are NOT copied — `assetMap` is\n * selective by design (unlike `copyDirs` which copies everything).\n */\n glob?: string\n /**\n * How file extensions feed into manifest keys. Default `'auto'`.\n *\n * - `'strip'` — drop the extension. `pages/index.pug` →\n * `'pages/index'`. Two siblings with the same basename collide;\n * last-walk-order wins, others are silently dropped. Opt-in\n * only — kept for backward compatibility with projects that\n * relied on this contract.\n * - `'with-extension'` — keep every extension on every key. Best\n * when the namespace holds extension siblings (`index.pug` +\n * `index.html` + `index.css` in `src/pages/`); every file\n * reaches the manifest under its full path.\n * - `'auto'` — strip when basenames are unique, keep extensions\n * on collision groups. Singleton files keep their short key;\n * `pages/index.{pug,html,css}` becomes\n * `pages/index.pug` / `pages/index.html` / `pages/index.css`.\n * No data loss; non-colliding namespaces stay on the short\n * keys they had before.\n *\n * @default 'auto'\n */\n keys?: 'auto' | 'strip' | 'with-extension'\n}\n\n/** Typegen settings — controls .kickjs/types/* generation */\nexport interface TypegenConfig {\n /**\n * Source directory to scan for controllers and decorators.\n * Defaults to `'src'`.\n */\n srcDir?: string\n /**\n * Output directory for generated `.d.ts` files.\n * Defaults to `'.kickjs/types'`.\n */\n outDir?: string\n /**\n * Schema validator used to derive `body` types from route metadata.\n *\n * - `'zod'` — emit `z.infer<typeof <importedSchema>>` for any schema\n * referenced as a named identifier in `@Get/@Post/...({ body, query, params })`.\n * - `false` — disable schema-driven body typing.\n *\n * Future: `'joi' | 'yup' | 'json-schema'` plus a `{ name; module }`\n * escape hatch for custom adapters.\n *\n * @default 'zod'\n */\n schemaValidator?: SchemaValidator\n /**\n * Path to the project's env schema file (relative to project root).\n * Must default-export a `defineEnv(...)` schema for typegen to emit\n * the typed `KickEnv` global registry.\n *\n * Set to `false` to disable env typing entirely.\n *\n * @default 'src/env.ts'\n */\n envFile?: string | false\n /**\n * Built-in or user typegen plugin ids to skip during `kick typegen`,\n * `kick dev`, and `kick typegen --watch`.\n *\n * The plugin still loads and merge-time conflict detection still\n * runs — only the `generate()` invocation is skipped — so adopters\n * who want to hand-write `KickDbRegister` (manual typeof-schema\n * augmentation) can disable `'kick/db'` and keep the rest:\n *\n * @example\n * typegen: {\n * disable: ['kick/db'], // hand-written register.ts owns the type\n * }\n *\n * Unrecognised ids are ignored — the list is treated as a wishlist,\n * not a strict registry.\n */\n disable?: string[]\n}\n\n/** Module generation settings — controls how `kick g module` produces code */\nexport interface ModuleConfig {\n /** Where modules live (default: 'src/modules') */\n dir?: string\n /**\n * Default repository implementation for generators.\n *\n * Built-in types (string): `'drizzle'`, `'inmemory'`, `'prisma'`\n * — generate fully working repository code.\n *\n * Custom types (object): `{ name: 'typeorm' }`\n * — generate a stub repository with TODO markers.\n *\n * @example\n * repo: 'prisma' // built-in\n * repo: { name: 'typeorm' } // custom\n */\n repo?: RepoTypeConfig\n /** Schema output directory (e.g. 'src/db/schema' for Drizzle, 'prisma/' for Prisma) */\n schemaDir?: string\n /**\n * Whether to pluralize module names in generated code.\n * When true (default), `kick g module user` creates `src/modules/users/`.\n * When false, it creates `src/modules/user/` and uses singular names throughout.\n */\n pluralize?: boolean\n /**\n * Import path for the Prisma generated client in `--repo prisma` templates.\n * Must resolve within `src/` for path alias compatibility.\n *\n * @default '@prisma/client' (Prisma 5/6)\n * @example\n * prismaClientPath: '@/generated/prisma/client' // Prisma 7+\n * prismaClientPath: './generated/prisma/client' // relative\n */\n prismaClientPath?: string\n}\n\n/** Configuration for the kick.config.ts file */\nexport interface KickConfig {\n /**\n * Project pattern — controls default generator behavior.\n * - 'rest' — Express + Swagger (default)\n * - 'ddd' — Full DDD modules with use cases, entities, value objects\n * - 'cqrs' — CQRS with commands, queries, events, WebSocket + queue\n * - 'minimal' — Bare Express with no scaffolding\n */\n pattern?: ProjectPattern\n /**\n * Module generation settings — directory, repo type, pluralization, schema dir.\n *\n * @example\n * modules: {\n * dir: 'src/modules',\n * repo: 'prisma',\n * pluralize: false,\n * schemaDir: 'prisma/',\n * }\n */\n modules?: ModuleConfig\n /**\n * Package manager used by `kick add` (and any future dep-installing command)\n * to install dependencies. When set, overrides lockfile auto-detection so\n * commands always use the project's intended package manager.\n *\n * Priority (highest first):\n * 1. `--pm` flag on the CLI\n * 2. `packageManager` in kick.config\n * 3. `packageManager` field in package.json (corepack convention)\n * 4. Lockfile detection (pnpm-lock.yaml → pnpm, yarn.lock → yarn)\n * 5. `'npm'`\n *\n * @example\n * packageManager: 'pnpm'\n */\n packageManager?: PackageManager\n\n /**\n * DI token scope prefix used by code generators. Every scaffolded\n * `createToken<T>('<scope>/<area>/<key>')` substitutes this string\n * for `<scope>`. Generators emit org-scoped tokens out of the box\n * so adopter projects pass `kick-lint`'s `token-reserved-prefix`\n * rule (which forbids the reserved `kick/` prefix on third-party\n * code) without manual rename.\n *\n * Resolution order (highest first):\n * 1. This field, when set\n * 2. `package.json` `name` field — `@scope/pkg` → `'scope'`,\n * bare `pkg` → `'pkg'`\n * 3. Fallback `'app'`\n *\n * @example\n * tokenScope: 'mycorp'\n * // → createToken<...>('mycorp/users/repository')\n */\n tokenScope?: string\n\n /**\n * Directories to copy to dist/ after build.\n * Useful for EJS templates, email templates, static assets, etc.\n *\n * @example\n * ```ts\n * copyDirs: [\n * 'src/views', // copies to dist/src/views\n * { src: 'src/views', dest: 'dist/views' }, // custom dest\n * 'src/emails',\n * ]\n * ```\n */\n copyDirs?: Array<string | { src: string; dest?: string }>\n /**\n * Build output settings. The asset manager + `kick build`'s copy\n * steps honour these — adopters who use Vite's `build.outDir =\n * 'out'` (or any non-default) should mirror the value here so\n * `assets.x.y()` paths line up with where Vite actually wrote.\n *\n * @example\n * ```ts\n * build: { outDir: 'out' }\n * ```\n */\n build?: {\n /**\n * Output directory, relative to project root. Defaults to\n * `'dist'`. The asset manager emits its manifest + copies\n * assetMap entries into this directory (under a per-namespace\n * subdirectory by default; override per-entry via `dest`).\n */\n outDir?: string\n }\n /**\n * Typed, addressable assets — see `assets-plan.md`. Each entry maps\n * a logical namespace name to a source directory. The build pipeline\n * auto-derives the necessary copy step + emits a manifest at\n * `dist/.kickjs-assets.json`; the runtime exposes\n * `import { assets } from '@forinda/kickjs'` so adopters can resolve\n * paths without dev/prod branching.\n *\n * `copyDirs` is unchanged — `assetMap` is a separate, opt-in surface.\n * Adopters who want raw directory copies keep using `copyDirs`; those\n * who want typed addressable assets add `assetMap` entries.\n *\n * @example\n * ```ts\n * assetMap: {\n * mails: { src: 'src/templates/mails' },\n * reports: { src: 'src/templates/reports', glob: '**\\/*.{ejs,html}' },\n * schemas: { src: 'src/schemas', glob: '**\\/*.json' },\n * }\n * ```\n */\n assetMap?: Record<string, AssetMapEntry>\n /**\n * Typegen settings — controls `.kickjs/types/*` generation including\n * the schema validator used for body type extraction.\n *\n * @example\n * ```ts\n * typegen: {\n * schemaValidator: 'zod',\n * }\n * ```\n */\n typegen?: TypegenConfig\n /** Custom commands that extend the CLI */\n commands?: KickCommandDefinition[]\n /**\n * CLI plugins — bundled commands + typegens contributed by external\n * packages (e.g. `@forinda/kickjs-cli-drizzle`). Plugin commands\n * appear first; adopter `commands` overrides plugin commands of the\n * same name. Duplicate commands or typegen ids across two plugins\n * fail-fast at CLI startup.\n *\n * @example\n * import { drizzlePlugin } from '@forinda/kickjs-cli-drizzle'\n * export default defineConfig({\n * plugins: [drizzlePlugin({ schemaPath: 'src/db/schema' })],\n * })\n */\n plugins?: KickCliPlugin[]\n /** Code style overrides (auto-detected from prettier when possible) */\n style?: {\n semicolons?: boolean\n quotes?: 'single' | 'double'\n trailingComma?: 'all' | 'es5' | 'none'\n indent?: number\n }\n}\n\n/** Helper to define a type-safe kick.config.ts */\nexport function defineConfig(config: KickConfig): KickConfig {\n return config\n}\n\n/** Resolve module config from `modules.*` block. */\n/**\n * Resolve the project's DI token scope for code generators.\n * Falls back through kick.config.ts → package.json → `'app'`.\n *\n * @param config Loaded `kick.config.ts` (null when not present)\n * @param cwd Project root — used to read package.json\n */\nexport function resolveTokenScope(config: KickConfig | null, cwd: string): string {\n if (config?.tokenScope && typeof config.tokenScope === 'string' && config.tokenScope.length > 0) {\n const sanitised = sanitizeScope(config.tokenScope)\n // Configured tokenScope can sanitise down to an empty string (e.g.\n // '___' or '!!') — falling through to the package.json chain is\n // safer than emitting an invalid `'/users/repository'` token.\n if (sanitised.length > 0) return sanitised\n }\n\n // Read package.json synchronously — this runs once per generator\n // invocation, so a sync read is cheaper than the async dance + lets\n // the call sites (template builders) stay synchronous.\n try {\n const pkgPath = join(cwd, 'package.json')\n if (existsSync(pkgPath)) {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as { name?: unknown }\n if (typeof pkg.name === 'string' && pkg.name.length > 0) {\n const scoped = pkg.name.match(/^@([^/]+)\\//)\n const candidate = scoped ? sanitizeScope(scoped[1]) : sanitizeScope(pkg.name)\n if (candidate.length > 0) return candidate\n // Same empty-after-sanitize guard.\n }\n }\n } catch {\n // package.json missing or malformed — fall through to default\n }\n\n return 'app'\n}\n\n/** Lowercase + strip characters that would break a token literal. */\nfunction sanitizeScope(raw: string): string {\n return raw\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, '-') // collapse anything weird to a hyphen\n .replace(/^-+|-+$/g, '') // trim leading/trailing hyphens\n .replace(/-{2,}/g, '-') // collapse runs of hyphens\n}\n\nexport function resolveModuleConfig(config: KickConfig | null): ModuleConfig {\n if (!config) return {}\n const mc: ModuleConfig = {\n dir: config.modules?.dir,\n repo: config.modules?.repo,\n schemaDir: config.modules?.schemaDir,\n pluralize: config.modules?.pluralize,\n prismaClientPath: config.modules?.prismaClientPath,\n }\n\n // Warn if a string repo value isn't a known built-in\n if (mc.repo && typeof mc.repo === 'string' && !BUILTIN_REPO_TYPES.includes(mc.repo)) {\n console.warn(\n ` Warning: modules.repo '${mc.repo}' is not a built-in type (${BUILTIN_REPO_TYPES.join(', ')}).` +\n ` It will generate a stub repository. Use { name: '${mc.repo}' } to silence this warning.`,\n )\n }\n\n return mc\n}\n\nconst CONFIG_FILES = ['kick.config.ts', 'kick.config.js', 'kick.config.mjs', 'kick.config.json']\n\n/** Load kick.config.* from the project root */\nexport async function loadKickConfig(cwd: string): Promise<KickConfig | null> {\n for (const filename of CONFIG_FILES) {\n const filepath = join(cwd, filename)\n try {\n await access(filepath)\n } catch {\n continue\n }\n\n if (filename.endsWith('.json')) {\n const content = await readFile(filepath, 'utf-8')\n return JSON.parse(content)\n }\n\n // For .ts/.js/.mjs — dynamic import (use file URL for cross-platform compat)\n try {\n const { pathToFileURL } = await import('node:url')\n const mod = await import(pathToFileURL(filepath).href)\n const config = (mod.default ?? mod) as KickConfig\n // Surface assetMap mistakes at config-load time so they aren't\n // hidden inside the build pipeline. Warnings only — a typo\n // shouldn't block `kick g`, `kick typegen`, etc.\n const warnings = validateAssetMap(config, cwd)\n for (const warning of warnings) console.warn(` Warning: ${warning}`)\n return config\n } catch {\n if (filename.endsWith('.ts')) {\n console.warn(\n `Warning: Failed to load ${filename}. TypeScript config files require ` +\n 'a runtime loader (e.g. tsx, ts-node) or use kick.config.js/.mjs instead.',\n )\n }\n continue\n }\n }\n return null\n}\n\n/**\n * Validate `assetMap` entries on a loaded config. Returns a list of\n * human-readable warnings; the caller decides how to surface them\n * (typically `console.warn`). Never throws — `kick g` and other\n * unrelated commands should keep working even when the assetMap is\n * misconfigured.\n *\n * Checks:\n *\n * - Each entry's `src` is a non-empty string.\n * - The `src` directory exists on disk (otherwise the typegen + build\n * steps will fail later with cryptic errors).\n * - `dest` doesn't escape the project root (defensive — a `dest:\n * '../../etc'` typo could write files outside the workspace).\n * - The namespace key is a non-empty string and doesn't include a\n * `/` (would conflict with the `<namespace>/<key>` manifest format).\n */\nexport function validateAssetMap(config: KickConfig | null, cwd: string): string[] {\n const warnings: string[] = []\n if (!config?.assetMap) return warnings\n\n const root = resolve(cwd)\n for (const [namespace, entry] of Object.entries(config.assetMap)) {\n if (!namespace || namespace.includes('/')) {\n warnings.push(\n `assetMap key '${namespace}' is invalid — must be a non-empty string without '/'`,\n )\n continue\n }\n if (typeof entry?.src !== 'string' || entry.src.length === 0) {\n warnings.push(`assetMap.${namespace} is missing a non-empty 'src' field`)\n continue\n }\n const srcAbs = resolve(cwd, entry.src)\n if (!existsSync(srcAbs)) {\n warnings.push(\n `assetMap.${namespace}.src ('${entry.src}') does not exist — typegen + build will fail`,\n )\n }\n if (entry.dest) {\n const destAbs = resolve(cwd, entry.dest)\n // path.relative is the right primitive for \"is X inside Y?\" —\n // a raw startsWith() prefix match has two failure modes the\n // earlier version hit: (a) `/app` is a prefix of `/app2/...`\n // even though they're different directories, and (b) it's\n // case-sensitive on filesystems that aren't (macOS default,\n // Windows). path.relative handles both correctly + accounts\n // for `..` traversal in the destination.\n if (escapesRoot(destAbs, root)) {\n warnings.push(\n `assetMap.${namespace}.dest ('${entry.dest}') resolves outside the project root — refusing to copy`,\n )\n }\n }\n }\n return warnings\n}\n\n/**\n * Returns true when `path` (absolute) resolves outside of `root`\n * (also absolute). Uses `path.relative` for accuracy:\n *\n * - The result is empty when paths are identical (inside).\n * - It starts with `..` when the path traverses outside the root.\n * - It's absolute (Windows: cross-drive) when there's no relative\n * path between them.\n *\n * Avoids the prefix-match pitfalls of `startsWith` (e.g. `/app`\n * matching `/app2/...`, or case-mismatches on macOS / Windows).\n */\nfunction escapesRoot(path: string, root: string): boolean {\n const rel = relative(root, path)\n return rel === '' ? false : rel.startsWith('..') || isAbsolute(rel)\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v5.1
|
|
2
|
+
* @forinda/kickjs-cli v5.2.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { createRequire } from "node:module";
|
|
12
12
|
import { dirname, extname, join, resolve } from "node:path";
|
|
13
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
13
14
|
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
14
15
|
import * as clack from "@clack/prompts";
|
|
15
16
|
import pc from "picocolors";
|
|
16
17
|
import pkg from "pluralize";
|
|
17
18
|
import { execSync } from "node:child_process";
|
|
18
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
19
19
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
20
20
|
//#region src/utils/fs.ts
|
|
21
21
|
let _dryRun = false;
|
|
@@ -23,7 +23,7 @@ let _dryRun = false;
|
|
|
23
23
|
function setDryRun(enabled) {
|
|
24
24
|
_dryRun = enabled;
|
|
25
25
|
}
|
|
26
|
-
/** Extensions
|
|
26
|
+
/** Extensions oxfmt can format. Anything else is written verbatim. */
|
|
27
27
|
const FORMATTABLE = new Set([
|
|
28
28
|
".ts",
|
|
29
29
|
".tsx",
|
|
@@ -37,15 +37,14 @@ const FORMATTABLE = new Set([
|
|
|
37
37
|
/**
|
|
38
38
|
* Write a file, creating parent directories if needed.
|
|
39
39
|
*
|
|
40
|
-
* After write, runs
|
|
40
|
+
* After write, runs oxfmt against the file when:
|
|
41
41
|
* - format-on-write is enabled (default)
|
|
42
42
|
* - the extension is in {@link FORMATTABLE}
|
|
43
|
-
* -
|
|
43
|
+
* - oxfmt resolves from the user's project (or our own cwd)
|
|
44
44
|
*
|
|
45
|
-
* Failures (missing
|
|
45
|
+
* Failures (missing oxfmt, unparseable source, formatter crash) are
|
|
46
46
|
* swallowed silently — formatting is a polish step, not a correctness
|
|
47
|
-
* gate. The pre-
|
|
48
|
-
* couldn't format.
|
|
47
|
+
* gate. The pre-commit hook still catches anything we couldn't format.
|
|
49
48
|
*
|
|
50
49
|
* Skips writing entirely in dry run mode.
|
|
51
50
|
*/
|
|
@@ -55,28 +54,58 @@ async function writeFileSafe(filePath, content) {
|
|
|
55
54
|
await writeFile(filePath, content, "utf-8");
|
|
56
55
|
if (FORMATTABLE.has(extname(filePath))) await formatFile(filePath, content).catch(() => {});
|
|
57
56
|
}
|
|
58
|
-
let
|
|
59
|
-
/** Resolve
|
|
60
|
-
function
|
|
61
|
-
if (
|
|
57
|
+
let _oxfmt = void 0;
|
|
58
|
+
/** Resolve oxfmt from the user's project; cache the result (or null) for the process. */
|
|
59
|
+
async function resolveOxfmt(cwd) {
|
|
60
|
+
if (_oxfmt !== void 0) return _oxfmt;
|
|
62
61
|
try {
|
|
63
|
-
|
|
62
|
+
_oxfmt = await import(createRequire(join(cwd, "package.json")).resolve("oxfmt"));
|
|
64
63
|
} catch {
|
|
65
|
-
|
|
64
|
+
_oxfmt = null;
|
|
66
65
|
}
|
|
67
|
-
return
|
|
66
|
+
return _oxfmt;
|
|
68
67
|
}
|
|
69
68
|
async function formatFile(filePath, content) {
|
|
70
|
-
const
|
|
71
|
-
if (!
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
69
|
+
const oxfmt = await resolveOxfmt(process.cwd());
|
|
70
|
+
if (!oxfmt) return;
|
|
71
|
+
const options = await loadOxfmtConfig(filePath);
|
|
72
|
+
if (options === null) return;
|
|
73
|
+
const result = await oxfmt.format(filePath, content, options);
|
|
74
|
+
if (result.code === content) return;
|
|
75
|
+
await writeFile(filePath, result.code, "utf-8");
|
|
76
|
+
}
|
|
77
|
+
const _oxfmtConfigCache = /* @__PURE__ */ new Map();
|
|
78
|
+
/**
|
|
79
|
+
* Walk up from `filePath`'s directory looking for `.oxfmtrc.json`.
|
|
80
|
+
* Returns `null` when no config is found anywhere on the path —
|
|
81
|
+
* generators then leave the raw template alone (which already
|
|
82
|
+
* follows project conventions). Cached per starting directory so
|
|
83
|
+
* the walk is one-shot per generator run.
|
|
84
|
+
*/
|
|
85
|
+
async function loadOxfmtConfig(filePath) {
|
|
86
|
+
let dir = dirname(filePath);
|
|
87
|
+
const startDir = dir;
|
|
88
|
+
if (_oxfmtConfigCache.has(startDir)) return _oxfmtConfigCache.get(startDir);
|
|
89
|
+
while (true) {
|
|
90
|
+
const configPath = join(dir, ".oxfmtrc.json");
|
|
91
|
+
if (existsSync(configPath)) try {
|
|
92
|
+
const raw = await readFile(configPath, "utf-8");
|
|
93
|
+
const parsed = JSON.parse(raw);
|
|
94
|
+
delete parsed["$schema"];
|
|
95
|
+
delete parsed.ignorePatterns;
|
|
96
|
+
_oxfmtConfigCache.set(startDir, parsed);
|
|
97
|
+
return parsed;
|
|
98
|
+
} catch {
|
|
99
|
+
_oxfmtConfigCache.set(startDir, null);
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
const parent = dirname(dir);
|
|
103
|
+
if (parent === dir) {
|
|
104
|
+
_oxfmtConfigCache.set(startDir, null);
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
dir = parent;
|
|
108
|
+
}
|
|
80
109
|
}
|
|
81
110
|
/** Check if a file exists */
|
|
82
111
|
async function fileExists(filePath) {
|
|
@@ -481,7 +510,7 @@ export const ${pascal.toUpperCase()}_QUERY_CONFIG: QueryParamsConfig = {
|
|
|
481
510
|
//#endregion
|
|
482
511
|
//#region src/generators/templates/dtos.ts
|
|
483
512
|
function generateCreateDTO(ctx) {
|
|
484
|
-
const { pascal
|
|
513
|
+
const { pascal } = ctx;
|
|
485
514
|
return `import { z } from 'zod'
|
|
486
515
|
|
|
487
516
|
/**
|
|
@@ -501,7 +530,7 @@ export type Create${pascal}DTO = z.infer<typeof create${pascal}Schema>
|
|
|
501
530
|
`;
|
|
502
531
|
}
|
|
503
532
|
function generateUpdateDTO(ctx) {
|
|
504
|
-
const { pascal
|
|
533
|
+
const { pascal } = ctx;
|
|
505
534
|
return `import { z } from 'zod'
|
|
506
535
|
|
|
507
536
|
export const update${pascal}Schema = z.object({
|
|
@@ -512,7 +541,7 @@ export type Update${pascal}DTO = z.infer<typeof update${pascal}Schema>
|
|
|
512
541
|
`;
|
|
513
542
|
}
|
|
514
543
|
function generateResponseDTO(ctx) {
|
|
515
|
-
const { pascal
|
|
544
|
+
const { pascal } = ctx;
|
|
516
545
|
return `export interface ${pascal}ResponseDTO {
|
|
517
546
|
id: string
|
|
518
547
|
name: string
|
|
@@ -629,7 +658,7 @@ export class Delete${pascal}UseCase {
|
|
|
629
658
|
//#endregion
|
|
630
659
|
//#region src/generators/templates/repository.ts
|
|
631
660
|
function generateRepositoryInterface(ctx) {
|
|
632
|
-
const { pascal, kebab, dtoPrefix = "../../application/dtos" } = ctx;
|
|
661
|
+
const { pascal, kebab, dtoPrefix = "../../application/dtos", tokenScope = "app" } = ctx;
|
|
633
662
|
return `/**
|
|
634
663
|
* ${pascal} Repository Interface
|
|
635
664
|
*
|
|
@@ -659,8 +688,12 @@ export interface I${pascal}Repository {
|
|
|
659
688
|
* \`container.resolve(${pascal.toUpperCase()}_REPOSITORY)\` and
|
|
660
689
|
* \`@Inject(${pascal.toUpperCase()}_REPOSITORY)\` both return the typed
|
|
661
690
|
* interface — no manual generic, no \`any\` cast.
|
|
691
|
+
*
|
|
692
|
+
* The \`'${tokenScope}/'\` prefix matches the project scope so
|
|
693
|
+
* \`kick-lint\`'s \`token-reserved-prefix\` rule never fires —
|
|
694
|
+
* adopters must NOT use the reserved \`'kick/'\` namespace.
|
|
662
695
|
*/
|
|
663
|
-
export const ${pascal.toUpperCase()}_REPOSITORY = createToken<I${pascal}Repository>('
|
|
696
|
+
export const ${pascal.toUpperCase()}_REPOSITORY = createToken<I${pascal}Repository>('${tokenScope}/${kebab}/repository')
|
|
664
697
|
`;
|
|
665
698
|
}
|
|
666
699
|
function generateInMemoryRepository(ctx) {
|
|
@@ -904,7 +937,7 @@ export class ${pascal} {
|
|
|
904
937
|
`;
|
|
905
938
|
}
|
|
906
939
|
function generateValueObject(ctx) {
|
|
907
|
-
const { pascal
|
|
940
|
+
const { pascal } = ctx;
|
|
908
941
|
return `/**
|
|
909
942
|
* ${pascal} ID Value Object
|
|
910
943
|
*
|
|
@@ -1949,7 +1982,7 @@ export class ${pascal}Controller {
|
|
|
1949
1982
|
//#endregion
|
|
1950
1983
|
//#region src/generators/patterns/rest.ts
|
|
1951
1984
|
async function generateRestFiles(ctx) {
|
|
1952
|
-
const { pascal, kebab, plural, pluralPascal, repo, noTests, prismaClientPath, write } = ctx;
|
|
1985
|
+
const { pascal, kebab, plural, pluralPascal, repo, noTests, prismaClientPath, tokenScope, write } = ctx;
|
|
1953
1986
|
await write(`${kebab}.module.ts`, generateRestModuleIndex({
|
|
1954
1987
|
pascal,
|
|
1955
1988
|
kebab,
|
|
@@ -1985,7 +2018,8 @@ async function generateRestFiles(ctx) {
|
|
|
1985
2018
|
await write(`${kebab}.repository.ts`, generateRepositoryInterface({
|
|
1986
2019
|
pascal,
|
|
1987
2020
|
kebab,
|
|
1988
|
-
dtoPrefix: "./dtos"
|
|
2021
|
+
dtoPrefix: "./dtos",
|
|
2022
|
+
tokenScope
|
|
1989
2023
|
}));
|
|
1990
2024
|
const builtinRepoFileMap = {
|
|
1991
2025
|
inmemory: `in-memory-${kebab}`,
|
|
@@ -2045,7 +2079,7 @@ async function generateRestFiles(ctx) {
|
|
|
2045
2079
|
//#endregion
|
|
2046
2080
|
//#region src/generators/patterns/cqrs.ts
|
|
2047
2081
|
async function generateCqrsFiles(ctx) {
|
|
2048
|
-
const { pascal, kebab, plural, pluralPascal, repo, noTests, prismaClientPath, write } = ctx;
|
|
2082
|
+
const { pascal, kebab, plural, pluralPascal, repo, noTests, prismaClientPath, tokenScope, write } = ctx;
|
|
2049
2083
|
await write(`${kebab}.module.ts`, generateCqrsModuleIndex({
|
|
2050
2084
|
pascal,
|
|
2051
2085
|
kebab,
|
|
@@ -2094,7 +2128,8 @@ async function generateCqrsFiles(ctx) {
|
|
|
2094
2128
|
await write(`${kebab}.repository.ts`, generateRepositoryInterface({
|
|
2095
2129
|
pascal,
|
|
2096
2130
|
kebab,
|
|
2097
|
-
dtoPrefix: "./dtos"
|
|
2131
|
+
dtoPrefix: "./dtos",
|
|
2132
|
+
tokenScope
|
|
2098
2133
|
}));
|
|
2099
2134
|
const builtinRepoFileMap = {
|
|
2100
2135
|
inmemory: `in-memory-${kebab}`,
|
|
@@ -2154,7 +2189,7 @@ async function generateCqrsFiles(ctx) {
|
|
|
2154
2189
|
//#endregion
|
|
2155
2190
|
//#region src/generators/patterns/ddd.ts
|
|
2156
2191
|
async function generateDddFiles(ctx) {
|
|
2157
|
-
const { pascal, kebab, plural, pluralPascal, repo, noEntity, noTests, prismaClientPath, write } = ctx;
|
|
2192
|
+
const { pascal, kebab, plural, pluralPascal, repo, noEntity, noTests, prismaClientPath, tokenScope, write } = ctx;
|
|
2158
2193
|
await write(`${kebab}.module.ts`, generateModuleIndex({
|
|
2159
2194
|
pascal,
|
|
2160
2195
|
kebab,
|
|
@@ -2195,7 +2230,8 @@ async function generateDddFiles(ctx) {
|
|
|
2195
2230
|
for (const uc of useCases) await write(`application/use-cases/${uc.file}`, uc.content);
|
|
2196
2231
|
await write(`domain/repositories/${kebab}.repository.ts`, generateRepositoryInterface({
|
|
2197
2232
|
pascal,
|
|
2198
|
-
kebab
|
|
2233
|
+
kebab,
|
|
2234
|
+
tokenScope
|
|
2199
2235
|
}));
|
|
2200
2236
|
await write(`domain/services/${kebab}-domain.service.ts`, generateDomainService({
|
|
2201
2237
|
pascal,
|
|
@@ -2312,6 +2348,7 @@ async function generateModule(options) {
|
|
|
2312
2348
|
noEntity: noEntity ?? false,
|
|
2313
2349
|
noTests: noTests ?? false,
|
|
2314
2350
|
prismaClientPath: options.prismaClientPath ?? "@prisma/client",
|
|
2351
|
+
tokenScope: options.tokenScope ?? "app",
|
|
2315
2352
|
write,
|
|
2316
2353
|
files
|
|
2317
2354
|
};
|
|
@@ -4002,7 +4039,7 @@ async function initProject(options) {
|
|
|
4002
4039
|
}
|
|
4003
4040
|
}
|
|
4004
4041
|
try {
|
|
4005
|
-
const { runTypegen } = await import("./typegen-
|
|
4042
|
+
const { runTypegen } = await import("./typegen-B9S81bOx.mjs").then((n) => n.n);
|
|
4006
4043
|
await runTypegen({
|
|
4007
4044
|
cwd: dir,
|
|
4008
4045
|
allowDuplicates: true,
|
|
@@ -4340,4 +4377,4 @@ async function runGenerator(spec, source, input, cwd) {
|
|
|
4340
4377
|
//#endregion
|
|
4341
4378
|
export { httpMethodColor as A, intro as C, select as D, outro as E, writeFileSafe as F, severityColor as M, fileExists as N, spinner as O, setDryRun as P, confirm as S, multiSelect as T, pluralize as _, initProject as a, toKebabCase as b, generateKickJsSkills as c, generateService as d, generateGuard as f, resolveRepoType as g, generateModule as h, defineGenerator as i, pc as j, text as k, generateDto as l, generateAdapter as m, tryDispatchPluginGenerator as n, generateAgents as o, generateMiddleware as p, buildGeneratorContext as r, generateClaude as s, listPluginGenerators as t, generateController as u, pluralizePascal as v, log as w, toPascalCase as x, toCamelCase as y };
|
|
4342
4379
|
|
|
4343
|
-
//# sourceMappingURL=generator-extension-
|
|
4380
|
+
//# sourceMappingURL=generator-extension-C-HwKvFf.mjs.map
|