create-taserjs 0.0.1 → 0.0.2
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/cjs/addons/arktype/index.cjs +6 -0
- package/dist/cjs/addons/arktype/index.cjs.map +1 -0
- package/dist/cjs/addons/drizzle/index.cjs +9 -2
- package/dist/cjs/addons/drizzle/index.cjs.map +1 -1
- package/dist/cjs/addons/kysely/index.cjs +9 -2
- package/dist/cjs/addons/kysely/index.cjs.map +1 -1
- package/dist/cjs/addons/registry.cjs +16 -12
- package/dist/cjs/addons/registry.cjs.map +1 -1
- package/dist/cjs/addons/valibot/index.cjs +6 -0
- package/dist/cjs/addons/valibot/index.cjs.map +1 -0
- package/dist/cjs/addons/validators.cjs +2 -2
- package/dist/cjs/addons/validators.cjs.map +1 -1
- package/dist/cjs/cli.cjs +2 -0
- package/dist/cjs/cli.cjs.map +1 -1
- package/dist/cjs/commands/create.cjs +1 -0
- package/dist/cjs/commands/create.cjs.map +1 -1
- package/dist/cjs/commands/create.d.cts +1 -0
- package/dist/cjs/core/package-manager.cjs +5 -13
- package/dist/cjs/core/package-manager.cjs.map +1 -1
- package/dist/cjs/core/package-manager.d.cts +2 -1
- package/dist/cjs/core/parse-options.cjs +10 -0
- package/dist/cjs/core/parse-options.cjs.map +1 -1
- package/dist/cjs/core/parse-options.d.cts +1 -0
- package/dist/cjs/core/project-config.cjs +1 -0
- package/dist/cjs/core/project-config.cjs.map +1 -1
- package/dist/cjs/core/scaffold-engine.cjs +4 -2
- package/dist/cjs/core/scaffold-engine.cjs.map +1 -1
- package/dist/cjs/templates/base.cjs +9 -6
- package/dist/cjs/templates/base.cjs.map +1 -1
- package/dist/esm/addons/arktype/index.js +7 -0
- package/dist/esm/addons/arktype/index.js.map +1 -0
- package/dist/esm/addons/drizzle/index.js +9 -2
- package/dist/esm/addons/drizzle/index.js.map +1 -1
- package/dist/esm/addons/kysely/index.js +9 -2
- package/dist/esm/addons/kysely/index.js.map +1 -1
- package/dist/esm/addons/registry.js +6 -2
- package/dist/esm/addons/registry.js.map +1 -1
- package/dist/esm/addons/valibot/index.js +7 -0
- package/dist/esm/addons/valibot/index.js.map +1 -0
- package/dist/esm/addons/validators.js +2 -2
- package/dist/esm/addons/validators.js.map +1 -1
- package/dist/esm/cli.js +2 -0
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/commands/create.d.ts +1 -0
- package/dist/esm/commands/create.js +2 -1
- package/dist/esm/commands/create.js.map +1 -1
- package/dist/esm/core/package-manager.d.ts +2 -1
- package/dist/esm/core/package-manager.js +5 -14
- package/dist/esm/core/package-manager.js.map +1 -1
- package/dist/esm/core/parse-options.d.ts +1 -0
- package/dist/esm/core/parse-options.js +11 -2
- package/dist/esm/core/parse-options.js.map +1 -1
- package/dist/esm/core/project-config.js +1 -0
- package/dist/esm/core/project-config.js.map +1 -1
- package/dist/esm/core/scaffold-engine.js +4 -2
- package/dist/esm/core/scaffold-engine.js.map +1 -1
- package/dist/esm/templates/base.js +9 -6
- package/dist/esm/templates/base.js.map +1 -1
- package/package.json +1 -1
- package/src/addons/drizzle/index.ts +15 -2
- package/src/addons/kysely/index.ts +15 -2
- package/src/addons/registry.ts +5 -1
- package/src/addons/validators.ts +2 -2
- package/src/cli.ts +2 -0
- package/src/commands/create.ts +6 -0
- package/src/core/package-manager.ts +7 -10
- package/src/core/parse-options.ts +17 -0
- package/src/core/project-config.ts +4 -0
- package/src/core/scaffold-engine.ts +2 -0
- package/src/templates/base.ts +9 -6
|
@@ -84,10 +84,11 @@ export const Middleware = t.middleware('/$')
|
|
|
84
84
|
`;
|
|
85
85
|
}
|
|
86
86
|
function indexRouteTemplate() {
|
|
87
|
-
return `import {
|
|
87
|
+
return `import { reply } from '@taserjs/router'
|
|
88
|
+
import { t } from '#src/taser.js'
|
|
88
89
|
|
|
89
|
-
export const Route = t.get('/').handler((
|
|
90
|
-
return
|
|
90
|
+
export const Route = t.get('/').handler(() => {
|
|
91
|
+
return reply.json({ message: 'Welcome to Taser' })
|
|
91
92
|
})
|
|
92
93
|
`;
|
|
93
94
|
}
|
|
@@ -95,10 +96,12 @@ function healthRouteTemplate(ctx) {
|
|
|
95
96
|
const lines = [];
|
|
96
97
|
if (ctx.logger) lines.push(" ctx.logger.info('health check')");
|
|
97
98
|
if (ctx.db) lines.push(" // ctx.db is available from context boot");
|
|
98
|
-
|
|
99
|
+
const body = lines.length > 0 ? `${lines.join("\n")}\n` : "";
|
|
100
|
+
return `import { reply } from '@taserjs/router'
|
|
101
|
+
import { t } from '#src/taser.js'
|
|
99
102
|
|
|
100
|
-
export const Route = t.get('/health').handler((ctx) => {
|
|
101
|
-
${
|
|
103
|
+
export const Route = t.get('/health').handler(${lines.length > 0 ? "(ctx)" : "()"} => {
|
|
104
|
+
${body} return reply.json({ ok: true })
|
|
102
105
|
})
|
|
103
106
|
`;
|
|
104
107
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.js","names":[],"sources":["../../../src/templates/base.ts"],"sourcesContent":["import type { BootBinding } from '../addons/types.js'\nimport type { ScaffoldContext } from '../core/types.js'\n\nexport function packageJsonTemplate(projectName: string, scripts: Record<string, string> = {}): string {\n const pkg = {\n name: projectName,\n version: '1.0.0',\n private: true,\n type: 'module',\n imports: {\n '#src/*': './src/*',\n },\n scripts: {\n 'dev': 'run-p dev:server dev:taser',\n 'dev:server': 'tsx watch src/index.ts',\n 'dev:taser': 'taser watch',\n 'start': 'tsx src/index.ts',\n 'generate': 'taser generate',\n 'build': 'taser generate && tsdown',\n 'serve': 'node dist/index.mjs',\n 'typecheck': 'tsc --noEmit -p tsconfig.json',\n ...scripts,\n },\n }\n\n return `${JSON.stringify(pkg, null, 2)}\\n`\n}\n\nexport function tsdownConfigTemplate(): string {\n return `import { defineConfig } from 'tsdown'\n\nexport default defineConfig({\n entry: ['./src/index.ts'],\n platform: 'node',\n outDir: 'dist',\n clean: true,\n sourcemap: true,\n})\n`\n}\n\nexport function tsconfigTemplate(): string {\n return `${JSON.stringify({\n compilerOptions: {\n target: 'ES2022',\n module: 'NodeNext',\n paths: {\n '#src/*': ['./src/*'],\n },\n strict: true,\n skipLibCheck: true,\n verbatimModuleSyntax: true,\n isolatedModules: true,\n noEmit: true,\n types: ['node'],\n },\n include: ['src'],\n }, null, 2)}\\n`\n}\n\nexport function gitignoreTemplate(): string {\n return `node_modules\ndist\n.DS_Store\n*.log\n.env\nlocal.db\ndrizzle\n`\n}\n\nexport function contextTemplate(bindings: BootBinding[]): string {\n const imports = bindings.map(\n binding => `import { ${binding.factoryName} } from '${binding.importPath}'`,\n )\n\n const bootBody = bindings.length > 0\n ? bindings.map(binding => ` ${binding.key}: ${binding.factoryName}(),`).join('\\n')\n : ''\n\n const bootBlock = bindings.length > 0\n ? ` boot: () => ({\\n${bootBody}\\n }),`\n : ''\n\n const importBlock = imports.length > 0 ? `${imports.join('\\n')}\\n\\n` : ''\n\n return `${importBlock}import { createContext } from '@taserjs/router'\n\nexport const context = createContext({\n${bootBlock}\n request: () => ({\n requestId: crypto.randomUUID(),\n }),\n})\n`\n}\n\nexport function rootLayoutTemplate(): string {\n return `import { bodyLimit } from '@taserjs/router/body-limit'\nimport { secureHeaders } from '@taserjs/router/secure-headers'\n\nimport { t } from '#src/taser.js'\n\nexport const Middleware = t.middleware('/$')\n .use(secureHeaders())\n .use(bodyLimit({ maxSize: 1_000_000 }))\n`\n}\n\nexport function indexRouteTemplate(): string {\n return `import { t } from '#src/taser.js'\n\nexport const Route = t.get('/').handler((
|
|
1
|
+
{"version":3,"file":"base.js","names":[],"sources":["../../../src/templates/base.ts"],"sourcesContent":["import type { BootBinding } from '../addons/types.js'\nimport type { ScaffoldContext } from '../core/types.js'\n\nexport function packageJsonTemplate(projectName: string, scripts: Record<string, string> = {}): string {\n const pkg = {\n name: projectName,\n version: '1.0.0',\n private: true,\n type: 'module',\n imports: {\n '#src/*': './src/*',\n },\n scripts: {\n 'dev': 'run-p dev:server dev:taser',\n 'dev:server': 'tsx watch src/index.ts',\n 'dev:taser': 'taser watch',\n 'start': 'tsx src/index.ts',\n 'generate': 'taser generate',\n 'build': 'taser generate && tsdown',\n 'serve': 'node dist/index.mjs',\n 'typecheck': 'tsc --noEmit -p tsconfig.json',\n ...scripts,\n },\n }\n\n return `${JSON.stringify(pkg, null, 2)}\\n`\n}\n\nexport function tsdownConfigTemplate(): string {\n return `import { defineConfig } from 'tsdown'\n\nexport default defineConfig({\n entry: ['./src/index.ts'],\n platform: 'node',\n outDir: 'dist',\n clean: true,\n sourcemap: true,\n})\n`\n}\n\nexport function tsconfigTemplate(): string {\n return `${JSON.stringify({\n compilerOptions: {\n target: 'ES2022',\n module: 'NodeNext',\n paths: {\n '#src/*': ['./src/*'],\n },\n strict: true,\n skipLibCheck: true,\n verbatimModuleSyntax: true,\n isolatedModules: true,\n noEmit: true,\n types: ['node'],\n },\n include: ['src'],\n }, null, 2)}\\n`\n}\n\nexport function gitignoreTemplate(): string {\n return `node_modules\ndist\n.DS_Store\n*.log\n.env\nlocal.db\ndrizzle\n`\n}\n\nexport function contextTemplate(bindings: BootBinding[]): string {\n const imports = bindings.map(\n binding => `import { ${binding.factoryName} } from '${binding.importPath}'`,\n )\n\n const bootBody = bindings.length > 0\n ? bindings.map(binding => ` ${binding.key}: ${binding.factoryName}(),`).join('\\n')\n : ''\n\n const bootBlock = bindings.length > 0\n ? ` boot: () => ({\\n${bootBody}\\n }),`\n : ''\n\n const importBlock = imports.length > 0 ? `${imports.join('\\n')}\\n\\n` : ''\n\n return `${importBlock}import { createContext } from '@taserjs/router'\n\nexport const context = createContext({\n${bootBlock}\n request: () => ({\n requestId: crypto.randomUUID(),\n }),\n})\n`\n}\n\nexport function rootLayoutTemplate(): string {\n return `import { bodyLimit } from '@taserjs/router/body-limit'\nimport { secureHeaders } from '@taserjs/router/secure-headers'\n\nimport { t } from '#src/taser.js'\n\nexport const Middleware = t.middleware('/$')\n .use(secureHeaders())\n .use(bodyLimit({ maxSize: 1_000_000 }))\n`\n}\n\nexport function indexRouteTemplate(): string {\n return `import { reply } from '@taserjs/router'\nimport { t } from '#src/taser.js'\n\nexport const Route = t.get('/').handler(() => {\n return reply.json({ message: 'Welcome to Taser' })\n})\n`\n}\n\nexport function healthRouteTemplate(ctx: ScaffoldContext): string {\n const lines: string[] = []\n\n if (ctx.logger) {\n lines.push(' ctx.logger.info(\\'health check\\')')\n }\n\n if (ctx.db) {\n lines.push(' // ctx.db is available from context boot')\n }\n\n const body = lines.length > 0 ? `${lines.join('\\n')}\\n` : ''\n const ctxArg = lines.length > 0 ? '(ctx)' : '()'\n\n return `import { reply } from '@taserjs/router'\nimport { t } from '#src/taser.js'\n\nexport const Route = t.get('/health').handler(${ctxArg} => {\n${body} return reply.json({ ok: true })\n})\n`\n}\n\n/** Minimal placeholder until `taser generate` runs. */\nexport function starterManifestTemplate(): string {\n return `/* eslint-disable */\n// Run \\`pnpm generate\\` (taser generate) to replace this file.\nimport { Middleware as RootSplatLayoutImport } from './routes/$.js'\nimport { Route as RootIndexGetRouteImport } from './routes/index.get.js'\nimport { Route as HealthGetRouteImport } from './routes/health.get.js'\n\nexport const routeManifest = {\n layouts: {\n '/$': {\n middlewares: RootSplatLayoutImport,\n },\n },\n routes: {\n '/': {\n GET: {\n layoutChain: ['/$'],\n route: RootIndexGetRouteImport,\n },\n },\n '/health': {\n GET: {\n layoutChain: ['/$'],\n route: HealthGetRouteImport,\n },\n },\n },\n} as const\n\nexport type RoutePathGen = '/' | '/health'\nexport type LayoutIdGen = '/$'\nexport type LayoutTreeGen = {\n '/$': {\n parent: null\n middlewares: typeof RootSplatLayoutImport\n }\n}\nexport type RouteByPathMethodGen = {\n '/': {\n GET: {\n parent: '/$'\n layoutChain: ['/$']\n route: typeof RootIndexGetRouteImport\n }\n }\n '/health': {\n GET: {\n parent: '/$'\n layoutChain: ['/$']\n route: typeof HealthGetRouteImport\n }\n }\n}\nexport type RouteManifest = typeof routeManifest\n\ndeclare module '@taserjs/router' {\n interface RouterRegister {\n RoutePath: RoutePathGen\n LayoutId: LayoutIdGen\n LayoutTree: LayoutTreeGen\n RouteByPathMethod: RouteByPathMethodGen\n }\n}\n`\n}\n"],"mappings":";AAGA,SAAgB,oBAAoB,aAAqB,UAAkC,CAAC,GAAW;CACrG,MAAM,MAAM;EACV,MAAM;EACN,SAAS;EACT,SAAS;EACT,MAAM;EACN,SAAS,EACP,UAAU,UACZ;EACA,SAAS;GACP,OAAO;GACP,cAAc;GACd,aAAa;GACb,SAAS;GACT,YAAY;GACZ,SAAS;GACT,SAAS;GACT,aAAa;GACb,GAAG;EACL;CACF;CAEA,OAAO,GAAG,KAAK,UAAU,KAAK,MAAM,CAAC,EAAE;AACzC;AAEA,SAAgB,uBAA+B;CAC7C,OAAO;;;;;;;;;;AAUT;AAEA,SAAgB,mBAA2B;CACzC,OAAO,GAAG,KAAK,UAAU;EACvB,iBAAiB;GACf,QAAQ;GACR,QAAQ;GACR,OAAO,EACL,UAAU,CAAC,SAAS,EACtB;GACA,QAAQ;GACR,cAAc;GACd,sBAAsB;GACtB,iBAAiB;GACjB,QAAQ;GACR,OAAO,CAAC,MAAM;EAChB;EACA,SAAS,CAAC,KAAK;CACjB,GAAG,MAAM,CAAC,EAAE;AACd;AAEA,SAAgB,oBAA4B;CAC1C,OAAO;;;;;;;;AAQT;AAEA,SAAgB,gBAAgB,UAAiC;CAC/D,MAAM,UAAU,SAAS,KACvB,YAAW,YAAY,QAAQ,YAAY,WAAW,QAAQ,WAAW,EAC3E;CAEA,MAAM,WAAW,SAAS,SAAS,IAC/B,SAAS,KAAI,YAAW,OAAO,QAAQ,IAAI,IAAI,QAAQ,YAAY,IAAI,CAAC,CAAC,KAAK,IAAI,IAClF;CAEJ,MAAM,YAAY,SAAS,SAAS,IAChC,qBAAqB,SAAS,WAC9B;CAIJ,OAAO,GAFa,QAAQ,SAAS,IAAI,GAAG,QAAQ,KAAK,IAAI,EAAE,QAAQ,GAEjD;;;EAGtB,UAAU;;;;;;AAMZ;AAEA,SAAgB,qBAA6B;CAC3C,OAAO;;;;;;;;;AAST;AAEA,SAAgB,qBAA6B;CAC3C,OAAO;;;;;;;AAOT;AAEA,SAAgB,oBAAoB,KAA8B;CAChE,MAAM,QAAkB,CAAC;CAEzB,IAAI,IAAI,QACN,MAAM,KAAK,mCAAqC;CAGlD,IAAI,IAAI,IACN,MAAM,KAAK,4CAA4C;CAGzD,MAAM,OAAO,MAAM,SAAS,IAAI,GAAG,MAAM,KAAK,IAAI,EAAE,MAAM;CAG1D,OAAO;;;gDAFQ,MAAM,SAAS,IAAI,UAAU,KAKS;EACrD,KAAK;;;AAGP;;AAGA,SAAgB,0BAAkC;CAChD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+DT"}
|
package/package.json
CHANGED
|
@@ -112,6 +112,18 @@ function driverPackages(driver: DbDriver): string[] {
|
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
function driverDevPackages(driver: DbDriver): string[] {
|
|
116
|
+
switch (driver) {
|
|
117
|
+
case 'postgres':
|
|
118
|
+
return ['@types/pg']
|
|
119
|
+
case 'sqlite':
|
|
120
|
+
return ['@types/better-sqlite3']
|
|
121
|
+
case 'mysql':
|
|
122
|
+
default:
|
|
123
|
+
return []
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
115
127
|
export const drizzleAddon: AddonDefinition = {
|
|
116
128
|
id: 'drizzle',
|
|
117
129
|
category: 'database',
|
|
@@ -119,8 +131,9 @@ export const drizzleAddon: AddonDefinition = {
|
|
|
119
131
|
const driver = ctx.driver ?? 'sqlite'
|
|
120
132
|
return ['drizzle-orm', ...driverPackages(driver)]
|
|
121
133
|
},
|
|
122
|
-
devDependencies() {
|
|
123
|
-
|
|
134
|
+
devDependencies(ctx) {
|
|
135
|
+
const driver = ctx.driver ?? 'sqlite'
|
|
136
|
+
return ['drizzle-kit', ...driverDevPackages(driver)]
|
|
124
137
|
},
|
|
125
138
|
scripts() {
|
|
126
139
|
return {
|
|
@@ -73,6 +73,18 @@ function driverPackages(driver: DbDriver): string[] {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
function driverDevPackages(driver: DbDriver): string[] {
|
|
77
|
+
switch (driver) {
|
|
78
|
+
case 'postgres':
|
|
79
|
+
return ['@types/pg']
|
|
80
|
+
case 'sqlite':
|
|
81
|
+
return ['@types/better-sqlite3']
|
|
82
|
+
case 'mysql':
|
|
83
|
+
default:
|
|
84
|
+
return []
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
76
88
|
function envExample(driver: DbDriver): string {
|
|
77
89
|
switch (driver) {
|
|
78
90
|
case 'postgres':
|
|
@@ -92,8 +104,9 @@ export const kyselyAddon: AddonDefinition = {
|
|
|
92
104
|
const driver = ctx.driver ?? 'sqlite'
|
|
93
105
|
return ['kysely', ...driverPackages(driver)]
|
|
94
106
|
},
|
|
95
|
-
devDependencies() {
|
|
96
|
-
|
|
107
|
+
devDependencies(ctx) {
|
|
108
|
+
const driver = ctx.driver ?? 'sqlite'
|
|
109
|
+
return driverDevPackages(driver)
|
|
97
110
|
},
|
|
98
111
|
bootBinding() {
|
|
99
112
|
return {
|
package/src/addons/registry.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { arktypeAddon } from './arktype/index.js'
|
|
1
2
|
import { drizzleAddon } from './drizzle/index.js'
|
|
2
3
|
import { kyselyAddon } from './kysely/index.js'
|
|
3
4
|
import { pinoAddon } from './pino/index.js'
|
|
4
5
|
import { prismaAddon } from './prisma/index.js'
|
|
6
|
+
import { valibotAddon } from './valibot/index.js'
|
|
7
|
+
import { winstonAddon } from './winston/index.js'
|
|
5
8
|
import { zodAddon } from './zod/index.js'
|
|
6
9
|
import type { AddonDefinition } from './types.js'
|
|
7
|
-
import { winstonAddon } from './winston/index.js'
|
|
8
10
|
import type { CapabilitiesCatalog, ScaffoldContext } from '../core/types.js'
|
|
9
11
|
import {
|
|
10
12
|
DB_DRIVERS,
|
|
@@ -22,6 +24,8 @@ const ALL_ADDONS: AddonDefinition[] = [
|
|
|
22
24
|
pinoAddon,
|
|
23
25
|
winstonAddon,
|
|
24
26
|
zodAddon,
|
|
27
|
+
arktypeAddon,
|
|
28
|
+
valibotAddon,
|
|
25
29
|
]
|
|
26
30
|
|
|
27
31
|
const DB_ADDONS = ALL_ADDONS.filter(addon => addon.category === 'database')
|
package/src/addons/validators.ts
CHANGED
|
@@ -19,12 +19,12 @@ export const VALIDATION_BLOCK_TEMPLATE: Record<ValidatorId, string> = {
|
|
|
19
19
|
}`,
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
const ROUTE_TEMPLATE = (validator: ValidatorId) => `
|
|
22
|
+
const ROUTE_TEMPLATE = (validator: ValidatorId) => `import { reply } from '@taserjs/router'
|
|
23
23
|
import { t } from '#src/taser.js'
|
|
24
24
|
${IMPORT_LINES[validator]}
|
|
25
25
|
|
|
26
26
|
export const Route = t.get('/'${VALIDATION_BLOCK_TEMPLATE[validator]}).handler((ctx) => {
|
|
27
|
-
return
|
|
27
|
+
return reply.json({ message: \`Hello, \${ctx.query.name}!\` })
|
|
28
28
|
})
|
|
29
29
|
`
|
|
30
30
|
|
package/src/cli.ts
CHANGED
|
@@ -14,6 +14,7 @@ async function main(): Promise<void> {
|
|
|
14
14
|
framework: { type: 'string' },
|
|
15
15
|
db: { type: 'string' },
|
|
16
16
|
logger: { type: 'string' },
|
|
17
|
+
validator: { type: 'string' },
|
|
17
18
|
y: { type: 'boolean', short: 'y' },
|
|
18
19
|
noInstall: { type: 'boolean' },
|
|
19
20
|
json: { type: 'boolean' },
|
|
@@ -26,6 +27,7 @@ async function main(): Promise<void> {
|
|
|
26
27
|
...(values.framework !== undefined ? { framework: values.framework } : {}),
|
|
27
28
|
...(values.db !== undefined ? { db: values.db } : {}),
|
|
28
29
|
...(values.logger !== undefined ? { logger: values.logger } : {}),
|
|
30
|
+
...(values.validator !== undefined ? { validator: values.validator } : {}),
|
|
29
31
|
...(values.y !== undefined ? { y: values.y } : {}),
|
|
30
32
|
...(values.noInstall !== undefined ? { noInstall: values.noInstall } : {}),
|
|
31
33
|
...(values.json !== undefined ? { json: values.json } : {}),
|
package/src/commands/create.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
parseDbFlag,
|
|
10
10
|
parseFrameworkFlag,
|
|
11
11
|
parseLoggerFlag,
|
|
12
|
+
parseValidatorFlag,
|
|
12
13
|
type ParsedCreateArgs,
|
|
13
14
|
resolveScaffoldDefaults,
|
|
14
15
|
} from '../core/parse-options.js'
|
|
@@ -245,6 +246,7 @@ export function buildParsedArgsFromCli(values: {
|
|
|
245
246
|
framework?: string
|
|
246
247
|
db?: string
|
|
247
248
|
logger?: string
|
|
249
|
+
validator?: string
|
|
248
250
|
y?: boolean
|
|
249
251
|
noInstall?: boolean
|
|
250
252
|
json?: boolean
|
|
@@ -273,5 +275,9 @@ export function buildParsedArgsFromCli(values: {
|
|
|
273
275
|
args.logger = parseLoggerFlag(values.logger)
|
|
274
276
|
}
|
|
275
277
|
|
|
278
|
+
if (values.validator) {
|
|
279
|
+
args.validator = parseValidatorFlag(values.validator)
|
|
280
|
+
}
|
|
281
|
+
|
|
276
282
|
return args
|
|
277
283
|
}
|
|
@@ -27,18 +27,15 @@ function runCommand(command: string, args: string[], cwd: string): Promise<void>
|
|
|
27
27
|
})
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return ['install', ...packages, dev ? '-D' : '']
|
|
34
|
-
},
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function resolveInstallCommand(agent: Agent, packages: string[], dev: boolean): ResolvedCommand {
|
|
38
|
-
const command = resolveCommand(agent, 'install', packages)
|
|
30
|
+
export function resolveInstallCommand(agent: Agent, packages: string[], dev: boolean): ResolvedCommand {
|
|
31
|
+
const args = dev ? ['-D', ...packages] : packages
|
|
32
|
+
const command = resolveCommand(agent, 'add', args)
|
|
39
33
|
if (command) return command
|
|
40
34
|
|
|
41
|
-
return {
|
|
35
|
+
return {
|
|
36
|
+
command: 'npm',
|
|
37
|
+
args: ['install', ...args],
|
|
38
|
+
}
|
|
42
39
|
}
|
|
43
40
|
|
|
44
41
|
export async function installPackages(
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
DEFAULT_DB_DRIVER,
|
|
5
5
|
FRAMEWORKS,
|
|
6
6
|
LOGGERS,
|
|
7
|
+
VALIDATORS,
|
|
7
8
|
type DbDriver,
|
|
8
9
|
type DbOdm,
|
|
9
10
|
type Framework,
|
|
@@ -40,6 +41,10 @@ function isLoggerId(value: string): value is LoggerId {
|
|
|
40
41
|
return (LOGGERS as readonly string[]).includes(value)
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
function isValidatorId(value: string): value is ValidatorId {
|
|
45
|
+
return (VALIDATORS as readonly string[]).includes(value)
|
|
46
|
+
}
|
|
47
|
+
|
|
43
48
|
export function parseDbFlag(value: string): { db: DbOdm, driver: DbDriver } {
|
|
44
49
|
const [odm, driver] = value.split(':')
|
|
45
50
|
if (!odm || !isDbOdm(odm)) {
|
|
@@ -61,6 +66,7 @@ export function resolveScaffoldDefaults(args: ParsedCreateArgs): ScaffoldContext
|
|
|
61
66
|
const framework = args.framework ?? 'node'
|
|
62
67
|
const db = args.db
|
|
63
68
|
const logger = args.logger
|
|
69
|
+
const validator = args.validator
|
|
64
70
|
|
|
65
71
|
if (!args.projectName) {
|
|
66
72
|
throw new Error('Project name is required')
|
|
@@ -81,6 +87,10 @@ export function resolveScaffoldDefaults(args: ParsedCreateArgs): ScaffoldContext
|
|
|
81
87
|
result.logger = logger
|
|
82
88
|
}
|
|
83
89
|
|
|
90
|
+
if (validator) {
|
|
91
|
+
result.validator = validator
|
|
92
|
+
}
|
|
93
|
+
|
|
84
94
|
return result
|
|
85
95
|
}
|
|
86
96
|
|
|
@@ -97,3 +107,10 @@ export function parseLoggerFlag(value: string): LoggerId {
|
|
|
97
107
|
}
|
|
98
108
|
return value
|
|
99
109
|
}
|
|
110
|
+
|
|
111
|
+
export function parseValidatorFlag(value: string): ValidatorId {
|
|
112
|
+
if (!isValidatorId(value)) {
|
|
113
|
+
throw new Error(`Invalid --validator "${value}". Use zod, arktype, or valibot.`)
|
|
114
|
+
}
|
|
115
|
+
return value
|
|
116
|
+
}
|
|
@@ -19,6 +19,10 @@ export async function writeProjectConfig(root: string, ctx: ScaffoldContext): Pr
|
|
|
19
19
|
config.logger = ctx.logger
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
if (ctx.validator) {
|
|
23
|
+
config.validator = ctx.validator
|
|
24
|
+
}
|
|
25
|
+
|
|
22
26
|
await writeFile(
|
|
23
27
|
path.join(root, '.taser.json'),
|
|
24
28
|
`${JSON.stringify(config, null, 2)}\n`,
|
|
@@ -64,6 +64,7 @@ export async function scaffoldProject(options: ScaffoldOptions): Promise<Scaffol
|
|
|
64
64
|
framework: ctx.framework,
|
|
65
65
|
...(ctx.db ? { db: ctx.db, driver: ctx.driver } : {}),
|
|
66
66
|
...(ctx.logger ? { logger: ctx.logger } : {}),
|
|
67
|
+
...(ctx.validator ? { validator: ctx.validator } : {}),
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
70
|
|
|
@@ -79,5 +80,6 @@ export async function scaffoldProject(options: ScaffoldOptions): Promise<Scaffol
|
|
|
79
80
|
framework: ctx.framework,
|
|
80
81
|
...(ctx.db ? { db: ctx.db, driver: ctx.driver } : {}),
|
|
81
82
|
...(ctx.logger ? { logger: ctx.logger } : {}),
|
|
83
|
+
...(ctx.validator ? { validator: ctx.validator } : {}),
|
|
82
84
|
}
|
|
83
85
|
}
|
package/src/templates/base.ts
CHANGED
|
@@ -108,10 +108,11 @@ export const Middleware = t.middleware('/$')
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
export function indexRouteTemplate(): string {
|
|
111
|
-
return `import {
|
|
111
|
+
return `import { reply } from '@taserjs/router'
|
|
112
|
+
import { t } from '#src/taser.js'
|
|
112
113
|
|
|
113
|
-
export const Route = t.get('/').handler((
|
|
114
|
-
return
|
|
114
|
+
export const Route = t.get('/').handler(() => {
|
|
115
|
+
return reply.json({ message: 'Welcome to Taser' })
|
|
115
116
|
})
|
|
116
117
|
`
|
|
117
118
|
}
|
|
@@ -128,11 +129,13 @@ export function healthRouteTemplate(ctx: ScaffoldContext): string {
|
|
|
128
129
|
}
|
|
129
130
|
|
|
130
131
|
const body = lines.length > 0 ? `${lines.join('\n')}\n` : ''
|
|
132
|
+
const ctxArg = lines.length > 0 ? '(ctx)' : '()'
|
|
131
133
|
|
|
132
|
-
return `import {
|
|
134
|
+
return `import { reply } from '@taserjs/router'
|
|
135
|
+
import { t } from '#src/taser.js'
|
|
133
136
|
|
|
134
|
-
export const Route = t.get('/health').handler(
|
|
135
|
-
${body} return
|
|
137
|
+
export const Route = t.get('/health').handler(${ctxArg} => {
|
|
138
|
+
${body} return reply.json({ ok: true })
|
|
136
139
|
})
|
|
137
140
|
`
|
|
138
141
|
}
|