@forinda/kickjs-cli 5.2.3 → 5.3.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-Du70nybS.mjs → builtins-B1iai4Mu.mjs} +5 -5
- package/dist/{builtins-Du70nybS.mjs.map → builtins-B1iai4Mu.mjs.map} +1 -1
- package/dist/{builtins-BdvmVAJ1.mjs → builtins-DC1UyGqc.mjs} +5 -5
- package/dist/cli.mjs +2 -2
- package/dist/{config-Dzw8Ws4d.mjs → config-B-1yY_qH.mjs} +2 -2
- package/dist/{config-lCKbrRnt.mjs → config-DdlM0SJN.mjs} +3 -3
- package/dist/{config-lCKbrRnt.mjs.map → config-DdlM0SJN.mjs.map} +1 -1
- package/dist/{generator-extension-Cp5FUUAw.mjs → generator-extension-Ba3TqDk4.mjs} +3 -3
- package/dist/{generator-extension-Cp5FUUAw.mjs.map → generator-extension-Ba3TqDk4.mjs.map} +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{plugin-VPl_QQGb.mjs → plugin-DgxIJkPU.mjs} +3 -3
- package/dist/{plugin-VPl_QQGb.mjs.map → plugin-DgxIJkPU.mjs.map} +1 -1
- package/dist/{plugin-Dv2gKsuC.mjs → plugin-Qx3Ev5pq.mjs} +2 -2
- package/dist/{rolldown-runtime-B6QC8dMY.mjs → rolldown-runtime-oa5maqtn.mjs} +1 -1
- package/dist/{run-plugins-CM1Af-4B.mjs → run-plugins-BqZ57Zcb.mjs} +2 -2
- package/dist/{typegen-C6ZfoYTC.mjs → typegen-Dnc6bshx.mjs} +3 -3
- package/dist/{typegen-CBI7dNXr.mjs → typegen-VziXMsqI.mjs} +4 -4
- package/dist/{typegen-CBI7dNXr.mjs.map → typegen-VziXMsqI.mjs.map} +1 -1
- package/dist/{types-n4LRUF_c.mjs → types-Bcro6dIS.mjs} +2 -2
- package/dist/{types-n4LRUF_c.mjs.map → types-Bcro6dIS.mjs.map} +1 -1
- package/package.json +4 -4
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v5.
|
|
2
|
+
* @forinda/kickjs-cli v5.3.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import{t as e}from"./rolldown-runtime-
|
|
11
|
+
import{t as e}from"./rolldown-runtime-oa5maqtn.mjs";import{a as t,i as n,r,t as i}from"./config-B-1yY_qH.mjs";import{n as a,r as o}from"./plugin-Qx3Ev5pq.mjs";import{a as s,i as c,o as l,r as u,s as d,t as f}from"./typegen-Dnc6bshx.mjs";import{createRequire as p}from"node:module";import{cpSync as m,existsSync as h,mkdirSync as g,readFileSync as _,readdirSync as ee,rmSync as te,statSync as ne,writeFileSync as re}from"node:fs";import v,{basename as ie,dirname as y,extname as ae,isAbsolute as oe,join as b,relative as x,resolve as S,sep as se}from"node:path";import{fileURLToPath as ce,pathToFileURL as C}from"node:url";import{execSync as w,fork as le,spawn as ue,spawnSync as de}from"node:child_process";import{access as fe,mkdir as pe,readFile as T,rm as me,writeFile as E}from"node:fs/promises";import*as D from"@clack/prompts";import O from"picocolors";import he from"pluralize";import{glob as ge}from"glob";import{groupAssetKeys as _e}from"@forinda/kickjs";import{arch as ve,platform as ye,release as be}from"node:os";import{generate as xe,migrateDown as Se,migrateLatest as Ce,migrateRollback as we,migrateStatus as Te,migrateUp as Ee,renderSchemaSource as De,resolveDbConfig as Oe}from"@forinda/kickjs-db";function ke(e,t,n){w(e,{cwd:t,stdio:`inherit`,env:n?{...process.env,...n}:process.env})}function Ae(e,t,n){let r=de(process.execPath,[e],{cwd:n,stdio:`inherit`,env:{...process.env,...t}});r.status!==0&&process.exit(r.status??1)}let je=!1;function k(e){je=e}const Me=new Set([`.ts`,`.tsx`,`.js`,`.jsx`,`.mjs`,`.cjs`,`.json`,`.md`]);async function A(e,t){je||(await pe(y(e),{recursive:!0}),await E(e,t,`utf-8`),Me.has(ae(e))&&await Pe(e,t).catch(()=>{}))}let j;async function Ne(e){if(j!==void 0)return j;try{j=await import(p(b(e,`package.json`)).resolve(`oxfmt`))}catch{j=null}return j}async function Pe(e,t){let n=await Ne(process.cwd());if(!n)return;let r=await Fe(e);if(r===null)return;let i=await n.format(e,t,r);i.code!==t&&await E(e,i.code,`utf-8`)}const M=new Map;async function Fe(e){let t=y(e),n=t;if(M.has(n))return M.get(n);for(;;){let e=b(t,`.oxfmtrc.json`);if(h(e))try{let t=await T(e,`utf-8`),r=JSON.parse(t);return delete r.$schema,delete r.ignorePatterns,M.set(n,r),r}catch{return M.set(n,null),null}let r=y(t);if(r===t)return M.set(n,null),null;t=r}}async function N(e){try{return await fe(e),!0}catch{return!1}}const Ie={auth:`@forinda/kickjs-auth`,swagger:`@forinda/kickjs-swagger`,ws:`@forinda/kickjs-ws`,queue:`@forinda/kickjs-queue`,devtools:`@forinda/kickjs-devtools`};function Le(e,t,n,r=[]){let i={"@forinda/kickjs":n,dotenv:`^17.3.1`,express:`^5.1.0`,"reflect-metadata":`^0.2.2`,zod:`^4.3.6`,pino:`^10.3.1`,"pino-pretty":`^13.1.3`};for(let e of r){let t=Ie[e];t&&!i[t]&&(i[t]=n)}return JSON.stringify({name:e,version:n.replace(`^`,``),type:`module`,scripts:{dev:`vite`,"dev:debug":`kick dev:debug`,build:`kick build`,start:`kick start`,test:`vitest run`,"test:watch":`vitest`,typecheck:`tsc --noEmit`,typegen:`kick typegen`,lint:`eslint src/`,format:`prettier --write src/`},dependencies:i,devDependencies:{"@forinda/kickjs-cli":n,"@forinda/kickjs-vite":n,"@swc/core":`^1.15.21`,"@types/express":`^5.0.6`,"@types/node":`^25.0.0`,"unplugin-swc":`^1.5.9`,vite:`^8.0.3`,vitest:`^4.1.2`,typescript:`^6.0.3`,prettier:`^3.8.1`}},null,2)}function Re(){return`import { defineConfig } from 'vite'
|
|
12
12
|
import { resolve } from 'node:path'
|
|
13
13
|
import swc from 'unplugin-swc'
|
|
14
14
|
import { kickjsVitePlugin, envWatchPlugin } from '@forinda/kickjs-vite'
|
|
@@ -1183,7 +1183,7 @@ description: Patterns to refuse outright when the user asks for them — they br
|
|
|
1183
1183
|
- [Context Decorators](https://forinda.github.io/kick-js/guide/context-decorators.html)
|
|
1184
1184
|
- [Testing](https://forinda.github.io/kick-js/api/testing.html)
|
|
1185
1185
|
`}const it=y(ce(import.meta.url)),at=JSON.parse(_(b(it,`..`,`package.json`),`utf-8`)),ot=`^${at.version}`;async function st(e){let{name:t,directory:n,packageManager:r=`pnpm`,template:i=`rest`,defaultRepo:a=`inmemory`,packages:o=[]}=e,s=n,c=e=>console.log(` ${e}`);if(console.log(`\n Creating KickJS project: ${t}\n`),await A(b(s,`package.json`),Le(t,i,ot,o)),await A(b(s,`vite.config.ts`),Re()),await A(b(s,`tsconfig.json`),ze()),await A(b(s,`.prettierrc`),Be()),await A(b(s,`.editorconfig`),Ve()),await A(b(s,`.gitignore`),He()),await A(b(s,`.gitattributes`),Ue()),await A(b(s,`.env`),We()),await A(b(s,`.env.example`),Ge()),await A(b(s,`src/config/index.ts`),Ye()),await A(b(s,`src/index.ts`),qe(t,i,at.version,o)),await A(b(s,`src/modules/index.ts`),Je()),await A(b(s,`src/modules/hello/hello.service.ts`),Xe()),await A(b(s,`src/modules/hello/hello.controller.ts`),Ze()),await A(b(s,`src/modules/hello/hello.module.ts`),Qe()),await A(b(s,`kick.config.ts`),$e(i,a,r)),await A(b(s,`vitest.config.ts`),Ke()),await A(b(s,`README.md`),et(t,i,r)),await A(b(s,`CLAUDE.md`),tt(t,i,r)),await A(b(s,`AGENTS.md`),nt(t,i,r)),await A(b(s,`kickjs-skills.md`),rt(t,i,r)),e.installDeps){console.log(`\n Installing dependencies with ${r}...\n`);try{w(`${r} install`,{cwd:s,stdio:`inherit`}),console.log(`
|
|
1186
|
-
Dependencies installed successfully!`)}catch{console.log(`\n Warning: ${r} install failed. Run it manually.`)}}try{let{runTypegen:e}=await import(`./typegen-
|
|
1186
|
+
Dependencies installed successfully!`)}catch{console.log(`\n Warning: ${r} install failed. Run it manually.`)}}try{let{runTypegen:e}=await import(`./typegen-Dnc6bshx.mjs`).then(e=>e.n);await e({cwd:s,allowDuplicates:!0,silent:!0})}catch{}if(e.initGit)try{w(`git init`,{cwd:s,stdio:`pipe`}),w(`git branch -M main`,{cwd:s,stdio:`pipe`}),w(`git add -A`,{cwd:s,stdio:`pipe`}),w(`git commit -m "chore: initial commit from kick new"`,{cwd:s,stdio:`pipe`}),c(`Git repository initialized`)}catch{c(`Warning: git init failed (git may not be installed)`)}console.log(`
|
|
1187
1187
|
Project scaffolded successfully!`),console.log();let l=s!==process.cwd();c(`Next steps:`),l&&c(` cd ${t}`),e.installDeps||c(` ${r} install`);let u={rest:`kick g module user`,ddd:`kick g module user --repo drizzle`,cqrs:`kick g module user --pattern cqrs`,minimal:`# add your routes to src/index.ts`};c(` ${u[i]??u.rest}`),c(` kick dev`),c(``),c(`Commands:`),c(` kick dev Start dev server with Vite HMR`),c(` kick build Production build via Vite`),c(` kick start Run production build`),c(``),c(`Generators:`),c(` kick g module <name> Full DDD module (controller, DTOs, use-cases, repo)`),c(` kick g scaffold <n> <f..> CRUD module from field definitions`),c(` kick g controller <name> Standalone controller`),c(` kick g service <name> @Service() class`),c(` kick g middleware <name> Express middleware`),c(` kick g guard <name> Route guard (auth, roles, etc.)`),c(` kick g adapter <name> AppAdapter with lifecycle hooks`),c(` kick g dto <name> Zod DTO schema`),i===`cqrs`&&c(` kick g job <name> Queue job processor`),c(` kick g config Generate kick.config.ts`),c(``),c(`Add packages:`),c(` kick add <pkg> Install a KickJS package + peers`),c(` kick add --list Show all available packages`),c(``),c(`Available: auth, swagger, drizzle, prisma, ws, queue, devtools, mcp, testing`),c(``)}const ct={GET:O.green,POST:O.cyan,PUT:O.yellow,PATCH:O.magenta,DELETE:O.red};function lt(e){return(ct[e]??O.dim)(e.padEnd(7))}function ut(e){let t=`[${e}]`.padEnd(10);switch(e){case`CRITICAL`:return O.red(t);case`WARNING`:return O.yellow(t);case`INFO`:return O.blue(O.dim(t));default:return t}}O.green(`✓`),O.red(`✖`),O.yellow(`⚠`),O.blue(`ℹ`);function dt(e){D.intro(O.bgCyan(O.black(` ${e} `)))}function P(e){D.outro(e)}function ft(e){D.isCancel(e)&&(D.cancel(`Operation cancelled.`),process.exit(0))}async function pt(e){let t=await D.text(e);return ft(t),t}async function mt(e){let t=await D.select(e);return ft(t),t}async function ht(e){let t=await D.multiselect(e);return ft(t),t}async function F(e){let t=await D.confirm(e);return ft(t),t}function gt(){return D.spinner()}const I=D.log,_t={kickjs:{pkg:`@forinda/kickjs`,peers:[`express`],description:`Unified framework: DI, decorators, routing, middleware`,core:!0},vite:{pkg:`@forinda/kickjs-vite`,peers:[`vite`],description:`Vite plugin: dev server, HMR, module discovery`,dev:!0,core:!0},cli:{pkg:`@forinda/kickjs-cli`,peers:[],description:`CLI tool and code generators`,dev:!0,core:!0},swagger:{pkg:`@forinda/kickjs-swagger`,peers:[],description:`OpenAPI spec + Swagger UI + ReDoc`},db:{pkg:`@forinda/kickjs-db`,peers:[],description:`kick/db core — schema DSL, migrations, KickDbClient, customType`},"db-pg":{pkg:`@forinda/kickjs-db-pg`,peers:[`pg`],description:`kick/db PostgreSQL dialect + adapter (pgDialect, pgAdapter)`},drizzle:{pkg:`@forinda/kickjs-drizzle`,peers:[`drizzle-orm`],description:`Drizzle ORM adapter + query builder`},prisma:{pkg:`@forinda/kickjs-prisma`,peers:[`@prisma/client`],description:`Prisma adapter + query builder`},ws:{pkg:`@forinda/kickjs-ws`,peers:[`socket.io`],description:`WebSocket with @WsController decorators`},devtools:{pkg:`@forinda/kickjs-devtools`,peers:[],description:`Development dashboard — routes, DI, metrics, health`,dev:!0},auth:{pkg:`@forinda/kickjs-auth`,peers:[`jsonwebtoken`],description:`Authentication — JWT, API key, and custom strategies`},queue:{pkg:`@forinda/kickjs-queue`,peers:[],description:`Queue adapter (BullMQ/RabbitMQ/Kafka)`},"queue:bullmq":{pkg:`@forinda/kickjs-queue`,peers:[`bullmq`,`ioredis`],description:`Queue with BullMQ + Redis`},"queue:rabbitmq":{pkg:`@forinda/kickjs-queue`,peers:[`amqplib`],description:`Queue with RabbitMQ`},"queue:kafka":{pkg:`@forinda/kickjs-queue`,peers:[`kafkajs`],description:`Queue with Kafka`},mcp:{pkg:`@forinda/kickjs-mcp`,peers:[`@modelcontextprotocol/sdk`],description:`Model Context Protocol server — expose @Controller endpoints as AI tools`},testing:{pkg:`@forinda/kickjs-testing`,peers:[],description:`Test utilities and TestModule builder`,dev:!0}};function L(e,t=process.cwd()){let n=t;for(;;){if(h(S(n,e)))return n;let t=y(n);if(t===n)return null;n=t}}function vt(){return L(`pnpm-lock.yaml`)?`pnpm`:L(`yarn.lock`)?`yarn`:L(`bun.lockb`)||L(`bun.lock`)?`bun`:L(`package-lock.json`)?`npm`:null}function yt(){let e=process.cwd();for(;e;){let t=S(e,`package.json`);if(h(t))try{let e=JSON.parse(_(t,`utf-8`)).packageManager;if(typeof e==`string`){let t=e.split(`@`)[0];if(i.includes(t))return t}}catch{}let n=y(e);if(n===e)return null;e=n}return null}async function bt(e){if(e&&i.includes(e))return{pm:e,source:`flag`};let t=await r(process.cwd());if(t?.packageManager&&i.includes(t.packageManager))return{pm:t.packageManager,source:`config`};let n=yt();if(n)return{pm:n,source:`package.json`};let a=vt();return a?{pm:a,source:`lockfile`}:{pm:`npm`,source:`default`}}async function xt(e){let{pm:t}=await bt(e);return t}function St(e=!1){let t=Object.entries(_t),n=Math.max(...t.map(([e])=>e.length)),r=t.filter(([,e])=>e.core),i=t.filter(([,e])=>!e.core),a=([e,t])=>{let r=e.padEnd(n+2),i=t.peers.length?` (+ ${t.peers.join(`, `)})`:``;return` ${r} ${t.description}${i}`};console.log(`
|
|
1188
1188
|
Core packages (always installed by \`kick new\`):
|
|
1189
1189
|
`);for(let e of r)console.log(a(e));if(e){console.log(`
|
|
@@ -3669,7 +3669,7 @@ server.on('exit', () => {
|
|
|
3669
3669
|
Cancelled.
|
|
3670
3670
|
`);return}await me(c,{recursive:!0,force:!0}),console.log(` Deleted: ${c}`);let l=b(n,`index.ts`);if(await N(l)){let e=await T(l,`utf-8`),t=e,n=RegExp(`^import\\s*\\{\\s*${o}Module\\s*\\}\\s*from\\s*['"][^'"]*${s}(?:/[^'"]*)?['"].*\\n?`,`gm`);e=e.replace(n,``),e=e.replace(RegExp(`\\s*,?\\s*${o}Module\\s*,?`,`g`),e=>{let t=e.trimStart().startsWith(`,`),n=e.trimEnd().endsWith(`,`);return t&&n?`,`:``}),e=e.replace(/,(\s*])/,`$1`),e=e.replace(/\n{3,}/g,`
|
|
3671
3671
|
|
|
3672
|
-
`),e!==t&&(await E(l,e,`utf-8`),console.log(` Unregistered: ${o}Module from ${l}`))}console.log(`\n Module '${s}' removed.\n`)}function pi(e){e.command(`remove`).alias(`rm`).description(`Remove generated code`).command(`module <names...>`).description(`Remove one or more modules (e.g. kick rm module user task)`).option(`--modules-dir <dir>`,`Modules directory`).option(`--no-pluralize`,`Use singular module name`).option(`-f, --force`,`Skip confirmation prompt`).action(async(e,t)=>{let i=n(await r(process.cwd())),a=t.modulesDir??i.dir??`src/modules`,o=t.pluralize===!1?!1:i.pluralize??!0;for(let n of e)await fi({name:n,modulesDir:S(a),force:t.force,pluralize:o})})}function mi(e){if(e!==void 0){if(e===`false`||e===`off`||e===`none`)return!1;if(e===`zod`)return`zod`;console.warn(` kick typegen: unknown --schema-validator '${e}' (only 'zod' and 'false' are supported). Falling back to project config.`)}}function hi(e){if(e!==void 0)return e===`false`||e===`off`||e===`none`?!1:e}function gi(e){e.command(`typegen`).description(`Generate type-safe DI registry and module types into .kickjs/types/`).option(`-w, --watch`,`Watch source files and regenerate on change`).option(`-s, --src <dir>`,`Source directory to scan`,`src`).option(`-o, --out <dir>`,`Output directory`,`.kickjs/types`).option(`--silent`,`Suppress output`).option(`--allow-duplicates`,`Auto-namespace duplicate class names instead of failing (use with caution)`).option(`--schema-validator <name>`,`Schema validator for body/query/params typing (currently 'zod' or 'false')`).option(`--env-file <path>`,`Path to env schema file for KickEnv typing (default 'src/env.ts'; pass 'false' to disable)`).option(`--check`,`CI gate: fail on plugin-typegen drift instead of writing`).option(`--list`,"List every registered typegen plugin id (use to populate `typegen.disable`)").action(async e=>{let t=process.cwd(),n=await r(t);if(e.list){let{mergeCliPlugins:e}=await import(`./plugin-
|
|
3672
|
+
`),e!==t&&(await E(l,e,`utf-8`),console.log(` Unregistered: ${o}Module from ${l}`))}console.log(`\n Module '${s}' removed.\n`)}function pi(e){e.command(`remove`).alias(`rm`).description(`Remove generated code`).command(`module <names...>`).description(`Remove one or more modules (e.g. kick rm module user task)`).option(`--modules-dir <dir>`,`Modules directory`).option(`--no-pluralize`,`Use singular module name`).option(`-f, --force`,`Skip confirmation prompt`).action(async(e,t)=>{let i=n(await r(process.cwd())),a=t.modulesDir??i.dir??`src/modules`,o=t.pluralize===!1?!1:i.pluralize??!0;for(let n of e)await fi({name:n,modulesDir:S(a),force:t.force,pluralize:o})})}function mi(e){if(e!==void 0){if(e===`false`||e===`off`||e===`none`)return!1;if(e===`zod`)return`zod`;console.warn(` kick typegen: unknown --schema-validator '${e}' (only 'zod' and 'false' are supported). Falling back to project config.`)}}function hi(e){if(e!==void 0)return e===`false`||e===`off`||e===`none`?!1:e}function gi(e){e.command(`typegen`).description(`Generate type-safe DI registry and module types into .kickjs/types/`).option(`-w, --watch`,`Watch source files and regenerate on change`).option(`-s, --src <dir>`,`Source directory to scan`,`src`).option(`-o, --out <dir>`,`Output directory`,`.kickjs/types`).option(`--silent`,`Suppress output`).option(`--allow-duplicates`,`Auto-namespace duplicate class names instead of failing (use with caution)`).option(`--schema-validator <name>`,`Schema validator for body/query/params typing (currently 'zod' or 'false')`).option(`--env-file <path>`,`Path to env schema file for KickEnv typing (default 'src/env.ts'; pass 'false' to disable)`).option(`--check`,`CI gate: fail on plugin-typegen drift instead of writing`).option(`--list`,"List every registered typegen plugin id (use to populate `typegen.disable`)").action(async e=>{let t=process.cwd(),n=await r(t);if(e.list){let{mergeCliPlugins:e}=await import(`./plugin-Qx3Ev5pq.mjs`).then(e=>e.t),{builtinCliPlugins:t}=await Promise.resolve().then(()=>Xi),r=e([...t,...n?.plugins??[]],n?.commands??[]),i=new Set(n?.typegen?.disable??[]);if(r.typegens.length===0){console.log(` No typegen plugins registered.`);return}let a=Math.max(...r.typegens.map(e=>e.id.length));console.log(`
|
|
3673
3673
|
Registered typegen plugins:
|
|
3674
3674
|
`);for(let e of r.typegens){let t=i.has(e.id)?` (disabled)`:``;console.log(` ${e.id.padEnd(a+2)}inputs: ${e.inputs.join(`, `)||`(none)`}${t}`)}console.log();return}let i=mi(e.schemaValidator)??n?.typegen?.schemaValidator??`zod`,a=hi(e.envFile)??n?.typegen?.envFile,o={cwd:t,srcDir:e.src??n?.typegen?.srcDir,outDir:e.out??n?.typegen?.outDir,silent:e.silent,allowDuplicates:e.allowDuplicates,schemaValidator:i,envFile:a,assetMap:n?.assetMap,runPlugins:!1};try{if(e.watch){let t=await u(o);e.silent||console.log(` kick typegen: watching for changes (Ctrl-C to exit)`);let n=()=>{t(),process.exit(0)};process.on(`SIGINT`,n),process.on(`SIGTERM`,n),await new Promise(()=>{})}else{await f(o);let r=await Sr({cwd:t,config:n??null,silent:e.silent,check:e.check});e.check&&r.some(e=>e.status===`written`)&&process.exit(1)}}catch(e){e instanceof c?console.error(`
|
|
3675
3675
|
`+e.message+`
|
|
@@ -3678,7 +3678,7 @@ server.on('exit', () => {
|
|
|
3678
3678
|
|
|
3679
3679
|
Available checks:
|
|
3680
3680
|
--deploy Audit for production readiness (security, config, best practices)
|
|
3681
|
-
`);return}let t=process.cwd();dt(`KickJS Deploy Check`);let n=gt();n.start(`Scanning project...`);let r=Di(t);n.stop(`Scan complete`);let i={CRITICAL:0,WARNING:1,INFO:2};r.sort((e,t)=>i[e.severity]-i[t.severity]);for(let e of r)I.message(`${ut(e.severity)} ${e.message}`);let a=r.filter(e=>e.severity===`CRITICAL`).length,o=r.filter(e=>e.severity===`WARNING`).length,s=r.filter(e=>e.severity===`INFO`).length,c=o===1?`warning`:`warnings`,l=[a>0?O.red(`${a} critical`):`${a} critical`,o>0?O.yellow(`${o} ${c}`):`${o} ${c}`,`${s} info`].join(`, `);a>0?(P(O.red(`${l} — fix critical issues before deploying`)),process.exit(1)):P(O.green(`${l} — looking good!`))})}async function Q(e){return Oe({configPath:v.resolve(process.cwd(),e.config)})}async function $(e){if(e.adapter){let t=await e.adapter();return{adapter:t,cleanup:async()=>t.close()}}if(!e.connectionString)throw Error(`kickjs-db: no adapter resolved — set db.connectionString (or DATABASE_URL) in kick.config.ts, or supply db.adapter() factory`);let t=e.dialect??`postgres`;if(t!==`postgres`)throw Error(`kickjs-db: built-in CLI adapter only supports postgres in M1 (dialect=${t}); use db.adapter() factory for other dialects`);let[{pgAdapter:n},r]=await Promise.all([import(`@forinda/kickjs-db-pg`),import(`pg`)]),i=new r.default.Pool({connectionString:e.connectionString}),a=n({pool:i});return{adapter:a,cleanup:async()=>{await a.close(),await i.end()}}}function ki(e){if(e.length===0){console.log(`No migrations.`);return}console.table(e.map(e=>({id:e.id,state:e.state,batch:e.batch??`-`,reviewed:e.reviewed,applied:e.appliedAt??`-`})))}function Ai(e){let t=e.command(`db`).description(`Database commands (kickjs-db)`);t.command(`generate <name>`).description(`Generate a new migration from schema diff`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).option(`-e, --empty`,`Skip schema diff and create an empty migration shell (data migration, seed, freeform SQL)`).action(async(e,t)=>{let n=process.cwd(),r=await xe({name:e,config:await Q(t),cwd:n,empty:t.empty});if(r.status===`no-changes`){console.log(`No schema changes detected.`);return}if(r.empty){console.log(`Created empty migration ${r.migrationDir} (author up.sql + down.sql).`);return}let i=r.changeCount===1?``:`s`;console.log(`Created migration ${r.migrationDir} (${r.changeCount} change${i}).`)});let n=t.command(`migrate`).description(`Migration runner subcommands`);n.command(`latest`).description(`Apply all pending migrations in a new batch`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let
|
|
3681
|
+
`);return}let t=process.cwd();dt(`KickJS Deploy Check`);let n=gt();n.start(`Scanning project...`);let r=Di(t);n.stop(`Scan complete`);let i={CRITICAL:0,WARNING:1,INFO:2};r.sort((e,t)=>i[e.severity]-i[t.severity]);for(let e of r)I.message(`${ut(e.severity)} ${e.message}`);let a=r.filter(e=>e.severity===`CRITICAL`).length,o=r.filter(e=>e.severity===`WARNING`).length,s=r.filter(e=>e.severity===`INFO`).length,c=o===1?`warning`:`warnings`,l=[a>0?O.red(`${a} critical`):`${a} critical`,o>0?O.yellow(`${o} ${c}`):`${o} ${c}`,`${s} info`].join(`, `);a>0?(P(O.red(`${l} — fix critical issues before deploying`)),process.exit(1)):P(O.green(`${l} — looking good!`))})}async function Q(e){return Oe({configPath:v.resolve(process.cwd(),e.config)})}async function $(e){if(e.adapter){let t=await e.adapter();return{adapter:t,cleanup:async()=>t.close()}}if(!e.connectionString)throw Error(`kickjs-db: no adapter resolved — set db.connectionString (or DATABASE_URL) in kick.config.ts, or supply db.adapter() factory`);let t=e.dialect??`postgres`;if(t!==`postgres`)throw Error(`kickjs-db: built-in CLI adapter only supports postgres in M1 (dialect=${t}); use db.adapter() factory for other dialects`);let[{pgAdapter:n},r]=await Promise.all([import(`@forinda/kickjs-db-pg`),import(`pg`)]),i=new r.default.Pool({connectionString:e.connectionString}),a=n({pool:i});return{adapter:a,cleanup:async()=>{await a.close(),await i.end()}}}function ki(e){if(e.length===0){console.log(`No migrations.`);return}console.table(e.map(e=>({id:e.id,state:e.state,batch:e.batch??`-`,reviewed:e.reviewed,applied:e.appliedAt??`-`})))}function Ai(e){let t=e.command(`db`).description(`Database commands (kickjs-db)`);t.command(`generate <name>`).description(`Generate a new migration from schema diff`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).option(`-e, --empty`,`Skip schema diff and create an empty migration shell (data migration, seed, freeform SQL)`).action(async(e,t)=>{let n=process.cwd(),r=await xe({name:e,config:await Q(t),cwd:n,empty:t.empty});if(r.status===`no-changes`){console.log(`No schema changes detected.`);return}if(r.empty){console.log(`Created empty migration ${r.migrationDir} (author up.sql + down.sql).`);return}let i=r.changeCount===1?``:`s`;console.log(`Created migration ${r.migrationDir} (${r.changeCount} change${i}).`)});let n=t.command(`migrate`).description(`Migration runner subcommands`);n.command(`latest`).description(`Apply all pending migrations in a new batch`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).option(`--confirm-enum-drop`,"Allow migrations carrying the `-- KICK ENUM REMOVE` header to apply",!1).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let r=await Ce({adapter:n,migrationsDir:t.migrationsDir,confirmEnumDrop:e.confirmEnumDrop});r.applied.length===0?console.log(`No pending migrations.`):console.log(`Applied batch ${r.batch}: ${r.applied.join(`, `)}`)}finally{await r()}}),n.command(`up`).description(`Apply the next single pending migration`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).option(`--confirm-enum-drop`,"Allow migrations carrying the `-- KICK ENUM REMOVE` header to apply",!1).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let r=await Ee({adapter:n,migrationsDir:t.migrationsDir,confirmEnumDrop:e.confirmEnumDrop});r.applied.length===0?console.log(`No pending migrations.`):console.log(`Applied ${r.applied[0]} (batch ${r.batch})`)}finally{await r()}}),n.command(`down`).description(`Reverse the most recent applied migration`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let e=await Se({adapter:n,migrationsDir:t.migrationsDir});e.reversed?console.log(`Reversed ${e.reversed}.`):console.log(`Nothing to reverse.`)}finally{await r()}}),n.command(`rollback`).description(`Reverse the entire last batch as a single unit`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let e=await we({adapter:n,migrationsDir:t.migrationsDir});e.reversed.length===0?console.log(`Nothing to roll back.`):console.log(`Rolled back batch ${e.batch}: ${e.reversed.join(`, `)}`)}finally{await r()}}),n.command(`status`).description(`Print applied + pending migrations`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{ki(await Te({adapter:n,migrationsDir:t.migrationsDir}))}finally{await r()}}),t.command(`introspect`).description(`Generate a TypeScript schema file from a live database`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).option(`--out <path>`,`Output file (defaults to db.schemaPath from config)`).option(`--json`,`Print the raw SchemaSnapshot JSON to stdout instead of writing TS source`).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let r=await n.introspect();if(e.json){console.log(JSON.stringify(r,null,2));return}let i=e.out??t.schemaPath;await E(i,De(r),`utf8`);let a=Object.keys(r.tables).length;console.log(`Wrote ${i} (${a} table${a===1?``:`s`}).`)}finally{await r()}})}const ji=[`src/db/schema.ts`,`src/db/schema/index.ts`,`src/db/schema`],Mi=()=>({id:`kick/db`,inputs:[`src/db/schema.ts`,`src/db/schema/**/*.ts`],async generate(e){let t=Ni(e.cwd);if(!t)return null;let n=v.resolve(e.cwd,`.kickjs/types`);return[`import type { SchemaToTypes, SchemaToRelationsRegister, KickDbClient } from '@forinda/kickjs-db'`,`import type * as appSchema from '${Pi(v.relative(n,t)).replace(/\.ts$/,``).replace(/\/index$/,``)}'`,``,`declare global {`,` interface KickDbSchema extends SchemaToTypes<typeof appSchema> {}`,`}`,``,`declare module '@forinda/kickjs-db' {`,` interface KickDbRegister {`,` db: KickDbClient<KickDbSchema>`,` }`,``,` interface KickDbRelationsRegister {`,` db: SchemaToRelationsRegister<typeof appSchema>`,` }`,`}`].join(`
|
|
3682
3682
|
`)}});function Ni(e){for(let t of ji){let n=v.resolve(e,t);if(t.endsWith(`.ts`)){if(h(n))return n}else{let e=v.join(n,`index.ts`);if(h(e))return e}}return null}function Pi(e){return e.replace(/\\/g,`/`)}const Fi=()=>({id:`kick/assets`,inputs:[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`],async generate(e){if(!h(v.resolve(e.cwd,`kick.config.ts`)))return null;let t=await r(e.cwd);if(!t?.assetMap)return null;let n=s(t.assetMap,e.cwd);return n.count===0?null:l(n)}}),Ii="/* eslint-disable */\n// AUTO-GENERATED by `kick typegen`. DO NOT EDIT.\n// Re-run with `kick typegen` or rely on `kick dev` to refresh.\n";function Li(e,t,n){if(e.length===0)return`${Ii}
|
|
3683
3683
|
// (no routes discovered yet — annotate a controller method with
|
|
3684
3684
|
// @Get/@Post/@Put/@Delete/@Patch and re-run \`kick typegen\`)
|
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v5.
|
|
2
|
+
* @forinda/kickjs-cli v5.3.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,4 +8,4 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import{i as e,t}from"./builtins-
|
|
11
|
+
import{i as e,t}from"./builtins-DC1UyGqc.mjs";import{r as n}from"./config-B-1yY_qH.mjs";import{n as r}from"./plugin-Qx3Ev5pq.mjs";import{Command as i}from"commander";import{readFileSync as a}from"node:fs";import{dirname as o,join as s}from"node:path";import{fileURLToPath as c}from"node:url";function l(e,t){if(!t?.commands?.length)return;let n=new Set(e.commands.map(e=>e.name()));for(let r of t.commands){if(n.has(r.name)){console.warn(` Warning: custom command '${r.name}' skipped — conflicts with a built-in command`);continue}u(e,r)}}function u(t,n){let r=t.command(n.name).description(n.description);if(n.aliases)for(let e of n.aliases)r.alias(e);r.allowUnknownOption(!0),r.argument(`[args...]`,`Additional arguments passed to the command`),r.action(t=>{let r=t.join(` `),i=Array.isArray(n.steps)?n.steps:[n.steps];for(let t of i){let i=r?`${t} ${r}`:t;console.log(` $ ${i}`);try{e(i)}catch{console.error(` Command failed: ${n.name}`),process.exitCode=1;return}}})}const d=o(c(import.meta.url)),f=JSON.parse(a(s(d,`..`,`package.json`),`utf-8`));async function p(){let e=new i;e.name(`kick`).description(`KickJS — A production-grade, decorator-driven Node.js framework`).version(f.version);let a=await n(process.cwd())??{},o=r([...t,...a.plugins??[]],a.commands??[]);await o.register(e,{cwd:process.cwd(),config:a,log:e=>console.log(e)}),l(e,{...a,commands:o.commands}),e.showHelpAfterError(),await e.parseAsync(process.argv)}p().catch(e=>{console.error(e instanceof Error?e.message:e),process.exitCode=1});export{};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v5.
|
|
2
|
+
* @forinda/kickjs-cli v5.3.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,4 +8,4 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import{t as e}from"./rolldown-runtime-
|
|
11
|
+
import{t as e}from"./rolldown-runtime-oa5maqtn.mjs";import{existsSync as t,readFileSync as n}from"node:fs";import{isAbsolute as r,join as i,relative as a,resolve as o}from"node:path";import{access as s,readFile as c}from"node:fs/promises";var l=e({BUILTIN_REPO_TYPES:()=>d,PACKAGE_MANAGERS:()=>u,defineConfig:()=>f,loadKickConfig:()=>_,resolveModuleConfig:()=>h,resolveTokenScope:()=>p,validateAssetMap:()=>v});const u=[`pnpm`,`npm`,`yarn`,`bun`],d=[`drizzle`,`inmemory`,`prisma`];function f(e){return e}function p(e,r){if(e?.tokenScope&&typeof e.tokenScope==`string`&&e.tokenScope.length>0){let t=m(e.tokenScope);if(t.length>0)return t}try{let e=i(r,`package.json`);if(t(e)){let t=JSON.parse(n(e,`utf-8`));if(typeof t.name==`string`&&t.name.length>0){let e=t.name.match(/^@([^/]+)\//),n=m(e?e[1]:t.name);if(n.length>0)return n}}}catch{}return`app`}function m(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,`-`).replace(/^-+|-+$/g,``).replace(/-{2,}/g,`-`)}function h(e){if(!e)return{};let t={dir:e.modules?.dir,repo:e.modules?.repo,schemaDir:e.modules?.schemaDir,pluralize:e.modules?.pluralize,prismaClientPath:e.modules?.prismaClientPath};return t.repo&&typeof t.repo==`string`&&!d.includes(t.repo)&&console.warn(` Warning: modules.repo '${t.repo}' is not a built-in type (${d.join(`, `)}). It will generate a stub repository. Use { name: '${t.repo}' } to silence this warning.`),t}const g=[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`,`kick.config.json`];async function _(e){for(let t of g){let n=i(e,t);try{await s(n)}catch{continue}if(t.endsWith(`.json`)){let e=await c(n,`utf-8`);return JSON.parse(e)}try{let{pathToFileURL:t}=await import(`node:url`),r=await import(t(n).href),i=r.default??r,a=v(i,e);for(let e of a)console.warn(` Warning: ${e}`);return i}catch{t.endsWith(`.ts`)&&console.warn(`Warning: Failed to load ${t}. TypeScript config files require a runtime loader (e.g. tsx, ts-node) or use kick.config.js/.mjs instead.`);continue}}return null}function v(e,n){let r=[];if(!e?.assetMap)return r;let i=o(n);for(let[a,s]of Object.entries(e.assetMap)){if(!a||a.includes(`/`)){r.push(`assetMap key '${a}' is invalid — must be a non-empty string without '/'`);continue}if(typeof s?.src!=`string`||s.src.length===0){r.push(`assetMap.${a} is missing a non-empty 'src' field`);continue}t(o(n,s.src))||r.push(`assetMap.${a}.src ('${s.src}') does not exist — typegen + build will fail`),s.dest&&y(o(n,s.dest),i)&&r.push(`assetMap.${a}.dest ('${s.dest}') resolves outside the project root — refusing to copy`)}return r}function y(e,t){let n=a(t,e);return n===``?!1:n.startsWith(`..`)||r(n)}export{p as a,h as i,l as n,_ as r,u as t};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v5.
|
|
2
|
+
* @forinda/kickjs-cli v5.3.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import{t as e}from"./rolldown-runtime-
|
|
12
|
-
//# sourceMappingURL=config-
|
|
11
|
+
import{t as e}from"./rolldown-runtime-oa5maqtn.mjs";import{isAbsolute as t,join as n,relative as r,resolve as i}from"node:path";import{existsSync as a,readFileSync as o}from"node:fs";import{access as s,readFile as c}from"node:fs/promises";var l=e({BUILTIN_REPO_TYPES:()=>d,PACKAGE_MANAGERS:()=>u,defineConfig:()=>f,loadKickConfig:()=>_,resolveModuleConfig:()=>h,resolveTokenScope:()=>p,validateAssetMap:()=>v});const u=[`pnpm`,`npm`,`yarn`,`bun`],d=[`drizzle`,`inmemory`,`prisma`];function f(e){return e}function p(e,t){if(e?.tokenScope&&typeof e.tokenScope==`string`&&e.tokenScope.length>0){let t=m(e.tokenScope);if(t.length>0)return t}try{let e=n(t,`package.json`);if(a(e)){let t=JSON.parse(o(e,`utf-8`));if(typeof t.name==`string`&&t.name.length>0){let e=t.name.match(/^@([^/]+)\//),n=m(e?e[1]:t.name);if(n.length>0)return n}}}catch{}return`app`}function m(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,`-`).replace(/^-+|-+$/g,``).replace(/-{2,}/g,`-`)}function h(e){if(!e)return{};let t={dir:e.modules?.dir,repo:e.modules?.repo,schemaDir:e.modules?.schemaDir,pluralize:e.modules?.pluralize,prismaClientPath:e.modules?.prismaClientPath};return t.repo&&typeof t.repo==`string`&&!d.includes(t.repo)&&console.warn(` Warning: modules.repo '${t.repo}' is not a built-in type (${d.join(`, `)}). It will generate a stub repository. Use { name: '${t.repo}' } to silence this warning.`),t}const g=[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`,`kick.config.json`];async function _(e){for(let t of g){let r=n(e,t);try{await s(r)}catch{continue}if(t.endsWith(`.json`)){let e=await c(r,`utf-8`);return JSON.parse(e)}try{let{pathToFileURL:t}=await import(`node:url`),n=await import(t(r).href),i=n.default??n,a=v(i,e);for(let e of a)console.warn(` Warning: ${e}`);return i}catch{t.endsWith(`.ts`)&&console.warn(`Warning: Failed to load ${t}. TypeScript config files require a runtime loader (e.g. tsx, ts-node) or use kick.config.js/.mjs instead.`);continue}}return null}function v(e,t){let n=[];if(!e?.assetMap)return n;let r=i(t);for(let[o,s]of Object.entries(e.assetMap)){if(!o||o.includes(`/`)){n.push(`assetMap key '${o}' is invalid — must be a non-empty string without '/'`);continue}if(typeof s?.src!=`string`||s.src.length===0){n.push(`assetMap.${o} is missing a non-empty 'src' field`);continue}a(i(t,s.src))||n.push(`assetMap.${o}.src ('${s.src}') does not exist — typegen + build will fail`),s.dest&&y(i(t,s.dest),r)&&n.push(`assetMap.${o}.dest ('${s.dest}') resolves outside the project root — refusing to copy`)}return n}function y(e,n){let i=r(n,e);return i===``?!1:i.startsWith(`..`)||t(i)}export{h as a,_ as i,l as n,p as o,f as r,u as t};
|
|
12
|
+
//# sourceMappingURL=config-DdlM0SJN.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-lCKbrRnt.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
|
+
{"version":3,"file":"config-DdlM0SJN.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.
|
|
2
|
+
* @forinda/kickjs-cli v5.3.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -2682,6 +2682,6 @@ description: Patterns to refuse outright when the user asks for them — they br
|
|
|
2682
2682
|
- [Context Decorators](https://forinda.github.io/kick-js/guide/context-decorators.html)
|
|
2683
2683
|
- [Testing](https://forinda.github.io/kick-js/api/testing.html)
|
|
2684
2684
|
`}const ft=t(h(import.meta.url)),X=JSON.parse(o(r(ft,`..`,`package.json`),`utf-8`)),pt=`^${X.version}`;async function mt(e){let{name:t,directory:n,packageManager:i=`pnpm`,template:a=`rest`,defaultRepo:o=`inmemory`,packages:s=[]}=e,c=n,l=e=>console.log(` ${e}`);if(console.log(`\n Creating KickJS project: ${t}\n`),await b(r(c,`package.json`),tt(t,a,pt,s)),await b(r(c,`vite.config.ts`),nt()),await b(r(c,`tsconfig.json`),rt()),await b(r(c,`.prettierrc`),it()),await b(r(c,`.editorconfig`),at()),await b(r(c,`.gitignore`),ot()),await b(r(c,`.gitattributes`),st()),await b(r(c,`.env`),ct()),await b(r(c,`.env.example`),lt()),await b(r(c,`src/config/index.ts`),Ne()),await b(r(c,`src/index.ts`),je(t,a,X.version,s)),await b(r(c,`src/modules/index.ts`),Me()),await b(r(c,`src/modules/hello/hello.service.ts`),Pe()),await b(r(c,`src/modules/hello/hello.controller.ts`),Fe()),await b(r(c,`src/modules/hello/hello.module.ts`),Ie()),await b(r(c,`kick.config.ts`),Le(a,o,i)),await b(r(c,`vitest.config.ts`),ut()),await b(r(c,`README.md`),dt(t,a,i)),await b(r(c,`CLAUDE.md`),q(t,a,i)),await b(r(c,`AGENTS.md`),J(t,a,i)),await b(r(c,`kickjs-skills.md`),Y(t,a,i)),e.installDeps){console.log(`\n Installing dependencies with ${i}...\n`);try{m(`${i} install`,{cwd:c,stdio:`inherit`}),console.log(`
|
|
2685
|
-
Dependencies installed successfully!`)}catch{console.log(`\n Warning: ${i} install failed. Run it manually.`)}}try{let{runTypegen:e}=await import(`./typegen-
|
|
2685
|
+
Dependencies installed successfully!`)}catch{console.log(`\n Warning: ${i} install failed. Run it manually.`)}}try{let{runTypegen:e}=await import(`./typegen-VziXMsqI.mjs`).then(e=>e.n);await e({cwd:c,allowDuplicates:!0,silent:!0})}catch{}if(e.initGit)try{m(`git init`,{cwd:c,stdio:`pipe`}),m(`git branch -M main`,{cwd:c,stdio:`pipe`}),m(`git add -A`,{cwd:c,stdio:`pipe`}),m(`git commit -m "chore: initial commit from kick new"`,{cwd:c,stdio:`pipe`}),l(`Git repository initialized`)}catch{l(`Warning: git init failed (git may not be installed)`)}console.log(`
|
|
2686
2686
|
Project scaffolded successfully!`),console.log();let u=c!==process.cwd();l(`Next steps:`),u&&l(` cd ${t}`),e.installDeps||l(` ${i} install`);let d={rest:`kick g module user`,ddd:`kick g module user --repo drizzle`,cqrs:`kick g module user --pattern cqrs`,minimal:`# add your routes to src/index.ts`};l(` ${d[a]??d.rest}`),l(` kick dev`),l(``),l(`Commands:`),l(` kick dev Start dev server with Vite HMR`),l(` kick build Production build via Vite`),l(` kick start Run production build`),l(``),l(`Generators:`),l(` kick g module <name> Full DDD module (controller, DTOs, use-cases, repo)`),l(` kick g scaffold <n> <f..> CRUD module from field definitions`),l(` kick g controller <name> Standalone controller`),l(` kick g service <name> @Service() class`),l(` kick g middleware <name> Express middleware`),l(` kick g guard <name> Route guard (auth, roles, etc.)`),l(` kick g adapter <name> AppAdapter with lifecycle hooks`),l(` kick g dto <name> Zod DTO schema`),a===`cqrs`&&l(` kick g job <name> Queue job processor`),l(` kick g config Generate kick.config.ts`),l(``),l(`Add packages:`),l(` kick add <pkg> Install a KickJS package + peers`),l(` kick add --list Show all available packages`),l(``),l(`Available: auth, swagger, drizzle, prisma, ws, queue, devtools, mcp, testing`),l(``)}function ht(e){return e}function gt(e){return k(e).replace(/-/g,`_`)}function Z(e){let t=e.cwd??process.cwd(),n=e.pluralize??!0,r=D(e.name),i=O(e.name),a=k(e.name),o=gt(e.name),s={name:e.name,pascal:r,camel:i,kebab:a,snake:o,modulesDir:e.modulesDir??`src/modules`,cwd:t,args:e.args??[],flags:e.flags??{}};if(n){let e=A(a);s.pluralKebab=e,s.pluralPascal=D(e),s.pluralCamel=O(e)}return s}function _t(e,t){return i(e.cwd,t)}async function vt(e){return import(g(e).href)}const Q=new Map;async function $(e){let t=Q.get(e);if(t)return t;let n=yt(e);return Q.set(e,n),n}async function yt(n){let r=i(n,`package.json`);if(!a(r))return{generators:[],loaded:[],failed:[]};let o=bt(JSON.parse(await l(r,`utf-8`))),s=e(i(n,`package.json`)),c=[],u=[],d=[];for(let e of o){let n;try{n=s.resolve(`${e}/package.json`)}catch{continue}let r;try{r=JSON.parse(await l(n,`utf-8`))}catch(t){d.push({source:e,reason:`failed to parse package.json: ${t}`});continue}if(!r.kickjs?.generators)continue;let o=r.kickjs.generators,f=i(t(n),o);if(!a(f)){d.push({source:e,reason:`kickjs.generators points to missing file: ${o}`});continue}let p;try{p=await vt(f)}catch(t){d.push({source:e,reason:`failed to import manifest: ${t}`});continue}let m=p.default;if(!Array.isArray(m)){d.push({source:e,reason:`manifest's default export is not an array of GeneratorSpec`});continue}for(let t of m){if(!xt(t)){d.push({source:e,reason:`manifest entry is not a valid GeneratorSpec (missing name/files)`});continue}c.push({source:e,spec:t})}u.push(e)}return{generators:c,loaded:u,failed:d}}function bt(e){let t=new Set;for(let n of[e.dependencies,e.devDependencies,e.peerDependencies])if(n)for(let e of Object.keys(n))t.add(e);return Array.from(t)}function xt(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.name==`string`&&typeof t.files==`function`}async function St(e,t=[]){let n=e.cwd??process.cwd(),r=t.find(t=>t.spec.name===e.generatorName);if(r)return Tt(r.spec,r.source,e,n);let i=wt(await $(n),e.generatorName);return i?Tt(i.spec,i.source,e,n):null}async function Ct(e,t=[]){let n=await $(e),r=new Set(t.map(e=>e.spec.name)),i=n.generators.filter(e=>!r.has(e.spec.name));return{generators:[...t,...i],loaded:n.loaded,failed:n.failed}}function wt(e,t){return e.generators.find(e=>e.spec.name===t)}async function Tt(e,t,n,r){let i=Z({name:n.itemName,args:n.args,flags:n.flags,modulesDir:n.modulesDir,pluralize:n.pluralize,cwd:r}),a=await e.files(i),o=[];for(let e of a){let t=_t(i,e.path);await b(t,e.content),o.push(t)}return{files:o,source:t}}export{ie as A,oe as C,le as D,se as E,b as F,ae as M,C as N,de as O,v as P,T as S,ue as T,A as _,mt as a,k as b,Y as c,Ze as d,Xe as f,He as g,Ue as h,ht as i,f as j,ce as k,$e as l,Ge as m,St as n,J as o,Ye as p,Z as r,q as s,Ct as t,Qe as u,j as v,E as w,D as x,O as y};
|
|
2687
|
-
//# sourceMappingURL=generator-extension-
|
|
2687
|
+
//# sourceMappingURL=generator-extension-Ba3TqDk4.mjs.map
|