create-taserjs 0.0.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/LICENSE +15 -0
- package/README.md +22 -0
- package/dist/cjs/_virtual/_rolldown/runtime.cjs +23 -0
- package/dist/cjs/addons/drizzle/index.cjs +124 -0
- package/dist/cjs/addons/drizzle/index.cjs.map +1 -0
- package/dist/cjs/addons/drizzle/index.d.cts +2 -0
- package/dist/cjs/addons/kysely/index.cjs +96 -0
- package/dist/cjs/addons/kysely/index.cjs.map +1 -0
- package/dist/cjs/addons/kysely/index.d.cts +2 -0
- package/dist/cjs/addons/pino/index.cjs +30 -0
- package/dist/cjs/addons/pino/index.cjs.map +1 -0
- package/dist/cjs/addons/pino/index.d.cts +2 -0
- package/dist/cjs/addons/prisma/index.cjs +66 -0
- package/dist/cjs/addons/prisma/index.cjs.map +1 -0
- package/dist/cjs/addons/prisma/index.d.cts +2 -0
- package/dist/cjs/addons/registry.cjs +52 -0
- package/dist/cjs/addons/registry.cjs.map +1 -0
- package/dist/cjs/addons/registry.d.cts +5 -0
- package/dist/cjs/addons/types.d.cts +16 -0
- package/dist/cjs/addons/winston/index.cjs +34 -0
- package/dist/cjs/addons/winston/index.cjs.map +1 -0
- package/dist/cjs/addons/winston/index.d.cts +2 -0
- package/dist/cjs/cli.cjs +56 -0
- package/dist/cjs/cli.cjs.map +1 -0
- package/dist/cjs/cli.d.cts +2 -0
- package/dist/cjs/commands/create.cjs +243 -0
- package/dist/cjs/commands/create.cjs.map +1 -0
- package/dist/cjs/commands/create.d.cts +11 -0
- package/dist/cjs/core/json-output.cjs +16 -0
- package/dist/cjs/core/json-output.cjs.map +1 -0
- package/dist/cjs/core/json-output.d.cts +4 -0
- package/dist/cjs/core/package-manager.cjs +64 -0
- package/dist/cjs/core/package-manager.cjs.map +1 -0
- package/dist/cjs/core/package-manager.d.cts +7 -0
- package/dist/cjs/core/parse-options.cjs +59 -0
- package/dist/cjs/core/parse-options.cjs.map +1 -0
- package/dist/cjs/core/parse-options.d.cts +18 -0
- package/dist/cjs/core/project-config.cjs +18 -0
- package/dist/cjs/core/project-config.cjs.map +1 -0
- package/dist/cjs/core/project-config.d.cts +2 -0
- package/dist/cjs/core/resolve-packages.cjs +52 -0
- package/dist/cjs/core/resolve-packages.cjs.map +1 -0
- package/dist/cjs/core/resolve-packages.d.cts +5 -0
- package/dist/cjs/core/scaffold-engine.cjs +73 -0
- package/dist/cjs/core/scaffold-engine.cjs.map +1 -0
- package/dist/cjs/core/scaffold-engine.d.cts +2 -0
- package/dist/cjs/core/types.cjs +27 -0
- package/dist/cjs/core/types.cjs.map +1 -0
- package/dist/cjs/core/types.d.cts +37 -0
- package/dist/cjs/core/validate-project-name.cjs +45 -0
- package/dist/cjs/core/validate-project-name.cjs.map +1 -0
- package/dist/cjs/core/validate-project-name.d.cts +1 -0
- package/dist/cjs/frameworks/index.cjs +106 -0
- package/dist/cjs/frameworks/index.cjs.map +1 -0
- package/dist/cjs/frameworks/index.d.cts +3 -0
- package/dist/cjs/scaffold.d.cts +3 -0
- package/dist/cjs/templates/base.cjs +186 -0
- package/dist/cjs/templates/base.cjs.map +1 -0
- package/dist/cjs/templates/base.d.cts +12 -0
- package/dist/cjs/types.d.cts +1 -0
- package/dist/esm/addons/drizzle/index.d.ts +2 -0
- package/dist/esm/addons/drizzle/index.js +124 -0
- package/dist/esm/addons/drizzle/index.js.map +1 -0
- package/dist/esm/addons/kysely/index.d.ts +2 -0
- package/dist/esm/addons/kysely/index.js +96 -0
- package/dist/esm/addons/kysely/index.js.map +1 -0
- package/dist/esm/addons/pino/index.d.ts +2 -0
- package/dist/esm/addons/pino/index.js +30 -0
- package/dist/esm/addons/pino/index.js.map +1 -0
- package/dist/esm/addons/prisma/index.d.ts +2 -0
- package/dist/esm/addons/prisma/index.js +66 -0
- package/dist/esm/addons/prisma/index.js.map +1 -0
- package/dist/esm/addons/registry.d.ts +5 -0
- package/dist/esm/addons/registry.js +50 -0
- package/dist/esm/addons/registry.js.map +1 -0
- package/dist/esm/addons/types.d.ts +16 -0
- package/dist/esm/addons/winston/index.d.ts +2 -0
- package/dist/esm/addons/winston/index.js +34 -0
- package/dist/esm/addons/winston/index.js.map +1 -0
- package/dist/esm/cli.d.ts +2 -0
- package/dist/esm/cli.js +53 -0
- package/dist/esm/cli.js.map +1 -0
- package/dist/esm/commands/create.d.ts +11 -0
- package/dist/esm/commands/create.js +238 -0
- package/dist/esm/commands/create.js.map +1 -0
- package/dist/esm/core/json-output.d.ts +4 -0
- package/dist/esm/core/json-output.js +14 -0
- package/dist/esm/core/json-output.js.map +1 -0
- package/dist/esm/core/package-manager.d.ts +7 -0
- package/dist/esm/core/package-manager.js +62 -0
- package/dist/esm/core/package-manager.js.map +1 -0
- package/dist/esm/core/parse-options.d.ts +18 -0
- package/dist/esm/core/parse-options.js +56 -0
- package/dist/esm/core/parse-options.js.map +1 -0
- package/dist/esm/core/project-config.d.ts +2 -0
- package/dist/esm/core/project-config.js +16 -0
- package/dist/esm/core/project-config.js.map +1 -0
- package/dist/esm/core/resolve-packages.d.ts +5 -0
- package/dist/esm/core/resolve-packages.js +52 -0
- package/dist/esm/core/resolve-packages.js.map +1 -0
- package/dist/esm/core/scaffold-engine.d.ts +2 -0
- package/dist/esm/core/scaffold-engine.js +71 -0
- package/dist/esm/core/scaffold-engine.js.map +1 -0
- package/dist/esm/core/types.d.ts +37 -0
- package/dist/esm/core/types.js +23 -0
- package/dist/esm/core/types.js.map +1 -0
- package/dist/esm/core/validate-project-name.d.ts +1 -0
- package/dist/esm/core/validate-project-name.js +43 -0
- package/dist/esm/core/validate-project-name.js.map +1 -0
- package/dist/esm/frameworks/index.d.ts +3 -0
- package/dist/esm/frameworks/index.js +105 -0
- package/dist/esm/frameworks/index.js.map +1 -0
- package/dist/esm/scaffold.d.ts +3 -0
- package/dist/esm/templates/base.d.ts +12 -0
- package/dist/esm/templates/base.js +178 -0
- package/dist/esm/templates/base.js.map +1 -0
- package/dist/esm/types.d.ts +1 -0
- package/package.json +45 -0
- package/src/addons/drizzle/index.ts +145 -0
- package/src/addons/kysely/index.ts +111 -0
- package/src/addons/pino/index.ts +30 -0
- package/src/addons/prisma/index.ts +81 -0
- package/src/addons/registry.ts +73 -0
- package/src/addons/types.ts +19 -0
- package/src/addons/winston/index.ts +34 -0
- package/src/cli.ts +57 -0
- package/src/commands/create.ts +253 -0
- package/src/core/json-output.ts +13 -0
- package/src/core/package-manager.ts +68 -0
- package/src/core/parse-options.ts +97 -0
- package/src/core/project-config.ts +27 -0
- package/src/core/resolve-packages.ts +62 -0
- package/src/core/scaffold-engine.ts +82 -0
- package/src/core/types.ts +51 -0
- package/src/core/validate-project-name.ts +59 -0
- package/src/frameworks/index.ts +111 -0
- package/src/scaffold.ts +3 -0
- package/src/templates/base.ts +209 -0
- package/src/types.ts +9 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold-engine.cjs","names":[],"sources":["../../../src/core/scaffold-engine.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\n\nimport { collectBootBindings, resolveAddons } from '../addons/registry.js'\nimport { indexTemplate, taserTsTemplate } from '../frameworks/index.js'\nimport { installPackages, resolveUserAgent } from './package-manager.js'\nimport { writeProjectConfig } from './project-config.js'\nimport { resolvePackages } from './resolve-packages.js'\nimport type { ScaffoldOptions, ScaffoldResult } from './types.js'\nimport {\n contextTemplate,\n gitignoreTemplate,\n healthRouteTemplate,\n indexRouteTemplate,\n packageJsonTemplate,\n rootLayoutTemplate,\n starterManifestTemplate,\n tsconfigTemplate,\n tsdownConfigTemplate,\n} from '../templates/base.js'\n\nasync function write(filePath: string, contents: string): Promise<void> {\n await mkdir(path.dirname(filePath), { recursive: true })\n await writeFile(filePath, contents, 'utf8')\n}\n\nexport async function scaffoldProject(options: ScaffoldOptions): Promise<ScaffoldResult> {\n const root = options.targetDir\n const ctx = {\n projectName: options.projectName,\n targetDir: root,\n framework: options.framework,\n ...(options.db ? { db: options.db, driver: options.driver } : {}),\n ...(options.logger ? { logger: options.logger } : {}),\n }\n\n const addons = resolveAddons(ctx)\n const packages = resolvePackages(ctx)\n const bootBindings = collectBootBindings(ctx)\n\n await write(path.join(root, 'package.json'), packageJsonTemplate(options.projectName, packages.scripts))\n await write(path.join(root, 'tsconfig.json'), tsconfigTemplate())\n await write(path.join(root, 'tsdown.config.ts'), tsdownConfigTemplate())\n await write(path.join(root, '.gitignore'), gitignoreTemplate())\n await write(path.join(root, 'src/context.ts'), contextTemplate(bootBindings))\n await write(path.join(root, 'src/taser.ts'), taserTsTemplate(options.framework))\n await write(path.join(root, 'src/index.ts'), indexTemplate(options.framework))\n await write(path.join(root, 'src/routes/$.ts'), rootLayoutTemplate())\n await write(path.join(root, 'src/routes/index.get.ts'), indexRouteTemplate())\n await write(path.join(root, 'src/routes/health.get.ts'), healthRouteTemplate(ctx))\n await write(path.join(root, 'src/routeManifest.gen.ts'), starterManifestTemplate())\n\n for (const addon of addons) {\n await addon.apply(ctx, (filePath, contents) => write(path.join(root, filePath), contents))\n }\n\n await writeProjectConfig(root, ctx)\n\n if (options.skipInstall) {\n return {\n projectName: ctx.projectName,\n targetDir: root,\n framework: ctx.framework,\n ...(ctx.db ? { db: ctx.db, driver: ctx.driver } : {}),\n ...(ctx.logger ? { logger: ctx.logger } : {}),\n }\n }\n\n const agent = options.agent ?? resolveUserAgent()\n await installPackages(agent, root, {\n dependencies: packages.dependencies,\n devDependencies: packages.devDependencies,\n })\n\n return {\n projectName: ctx.projectName,\n targetDir: root,\n framework: ctx.framework,\n ...(ctx.db ? { db: ctx.db, driver: ctx.driver } : {}),\n ...(ctx.logger ? { logger: ctx.logger } : {}),\n }\n}\n"],"mappings":";;;;;;;;;;;AAqBA,eAAe,MAAM,UAAkB,UAAiC;CACtE,OAAA,GAAM,iBAAA,MAAA,CAAM,UAAA,QAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;CACvD,OAAA,GAAM,iBAAA,UAAA,CAAU,UAAU,UAAU,MAAM;AAC5C;AAEA,eAAsB,gBAAgB,SAAmD;CACvF,MAAM,OAAO,QAAQ;CACrB,MAAM,MAAM;EACV,aAAa,QAAQ;EACrB,WAAW;EACX,WAAW,QAAQ;EACnB,GAAI,QAAQ,KAAK;GAAE,IAAI,QAAQ;GAAI,QAAQ,QAAQ;EAAO,IAAI,CAAC;EAC/D,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;CACrD;CAEA,MAAM,SAAS,iBAAA,cAAc,GAAG;CAChC,MAAM,WAAW,yBAAA,gBAAgB,GAAG;CACpC,MAAM,eAAe,iBAAA,oBAAoB,GAAG;CAE5C,MAAM,MAAM,UAAA,QAAK,KAAK,MAAM,cAAc,GAAG,aAAA,oBAAoB,QAAQ,aAAa,SAAS,OAAO,CAAC;CACvG,MAAM,MAAM,UAAA,QAAK,KAAK,MAAM,eAAe,GAAG,aAAA,iBAAiB,CAAC;CAChE,MAAM,MAAM,UAAA,QAAK,KAAK,MAAM,kBAAkB,GAAG,aAAA,qBAAqB,CAAC;CACvE,MAAM,MAAM,UAAA,QAAK,KAAK,MAAM,YAAY,GAAG,aAAA,kBAAkB,CAAC;CAC9D,MAAM,MAAM,UAAA,QAAK,KAAK,MAAM,gBAAgB,GAAG,aAAA,gBAAgB,YAAY,CAAC;CAC5E,MAAM,MAAM,UAAA,QAAK,KAAK,MAAM,cAAc,GAAG,cAAA,gBAAgB,QAAQ,SAAS,CAAC;CAC/E,MAAM,MAAM,UAAA,QAAK,KAAK,MAAM,cAAc,GAAG,cAAA,cAAc,QAAQ,SAAS,CAAC;CAC7E,MAAM,MAAM,UAAA,QAAK,KAAK,MAAM,iBAAiB,GAAG,aAAA,mBAAmB,CAAC;CACpE,MAAM,MAAM,UAAA,QAAK,KAAK,MAAM,yBAAyB,GAAG,aAAA,mBAAmB,CAAC;CAC5E,MAAM,MAAM,UAAA,QAAK,KAAK,MAAM,0BAA0B,GAAG,aAAA,oBAAoB,GAAG,CAAC;CACjF,MAAM,MAAM,UAAA,QAAK,KAAK,MAAM,0BAA0B,GAAG,aAAA,wBAAwB,CAAC;CAElF,KAAK,MAAM,SAAS,QAClB,MAAM,MAAM,MAAM,MAAM,UAAU,aAAa,MAAM,UAAA,QAAK,KAAK,MAAM,QAAQ,GAAG,QAAQ,CAAC;CAG3F,MAAM,uBAAA,mBAAmB,MAAM,GAAG;CAElC,IAAI,QAAQ,aACV,OAAO;EACL,aAAa,IAAI;EACjB,WAAW;EACX,WAAW,IAAI;EACf,GAAI,IAAI,KAAK;GAAE,IAAI,IAAI;GAAI,QAAQ,IAAI;EAAO,IAAI,CAAC;EACnD,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;CAC7C;CAGF,MAAM,QAAQ,QAAQ,SAAS,wBAAA,iBAAiB;CAChD,MAAM,wBAAA,gBAAgB,OAAO,MAAM;EACjC,cAAc,SAAS;EACvB,iBAAiB,SAAS;CAC5B,CAAC;CAED,OAAO;EACL,aAAa,IAAI;EACjB,WAAW;EACX,WAAW,IAAI;EACf,GAAI,IAAI,KAAK;GAAE,IAAI,IAAI;GAAI,QAAQ,IAAI;EAAO,IAAI,CAAC;EACnD,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;CAC7C;AACF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/core/types.ts
|
|
2
|
+
var FRAMEWORKS = [
|
|
3
|
+
"node",
|
|
4
|
+
"express",
|
|
5
|
+
"hono",
|
|
6
|
+
"fastify"
|
|
7
|
+
];
|
|
8
|
+
var DB_ODMS = [
|
|
9
|
+
"drizzle",
|
|
10
|
+
"prisma",
|
|
11
|
+
"kysely"
|
|
12
|
+
];
|
|
13
|
+
var DB_DRIVERS = [
|
|
14
|
+
"postgres",
|
|
15
|
+
"sqlite",
|
|
16
|
+
"mysql"
|
|
17
|
+
];
|
|
18
|
+
var DEFAULT_DB_DRIVER = "sqlite";
|
|
19
|
+
var LOGGERS = ["pino", "winston"];
|
|
20
|
+
//#endregion
|
|
21
|
+
exports.DB_DRIVERS = DB_DRIVERS;
|
|
22
|
+
exports.DB_ODMS = DB_ODMS;
|
|
23
|
+
exports.DEFAULT_DB_DRIVER = DEFAULT_DB_DRIVER;
|
|
24
|
+
exports.FRAMEWORKS = FRAMEWORKS;
|
|
25
|
+
exports.LOGGERS = LOGGERS;
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=types.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.cjs","names":[],"sources":["../../../src/core/types.ts"],"sourcesContent":["import type { Agent } from 'package-manager-detector'\n\nexport type Framework = 'node' | 'express' | 'hono' | 'fastify'\n\nexport const FRAMEWORKS: readonly Framework[] = ['node', 'express', 'hono', 'fastify']\n\nexport type DbOdm = 'drizzle' | 'prisma' | 'kysely'\n\nexport const DB_ODMS: readonly DbOdm[] = ['drizzle', 'prisma', 'kysely']\n\nexport type DbDriver = 'postgres' | 'sqlite' | 'mysql'\n\nexport const DB_DRIVERS: readonly DbDriver[] = ['postgres', 'sqlite', 'mysql']\n\nexport const DEFAULT_DB_DRIVER: DbDriver = 'sqlite'\n\nexport type LoggerId = 'pino' | 'winston'\n\nexport const LOGGERS: readonly LoggerId[] = ['pino', 'winston']\n\nexport type PackageGroups = {\n dependencies: string[]\n devDependencies: string[]\n scripts: Record<string, string>\n}\n\nexport type ScaffoldContext = {\n projectName: string\n targetDir: string\n framework: Framework\n db?: DbOdm\n driver?: DbDriver\n logger?: LoggerId\n}\n\nexport type ScaffoldOptions = ScaffoldContext & {\n skipInstall?: boolean\n agent?: Agent\n}\n\nexport type ScaffoldResult = ScaffoldContext\n\nexport type CapabilitiesCatalog = {\n frameworks: Framework[]\n db: {\n odms: DbOdm[]\n drivers: DbDriver[]\n defaultDriver: DbDriver\n }\n loggers: LoggerId[]\n}\n"],"mappings":";AAIA,IAAa,aAAmC;CAAC;CAAQ;CAAW;CAAQ;AAAS;AAIrF,IAAa,UAA4B;CAAC;CAAW;CAAU;AAAQ;AAIvE,IAAa,aAAkC;CAAC;CAAY;CAAU;AAAO;AAE7E,IAAa,oBAA8B;AAI3C,IAAa,UAA+B,CAAC,QAAQ,SAAS"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Agent } from 'package-manager-detector';
|
|
2
|
+
export type Framework = 'node' | 'express' | 'hono' | 'fastify';
|
|
3
|
+
export declare const FRAMEWORKS: readonly Framework[];
|
|
4
|
+
export type DbOdm = 'drizzle' | 'prisma' | 'kysely';
|
|
5
|
+
export declare const DB_ODMS: readonly DbOdm[];
|
|
6
|
+
export type DbDriver = 'postgres' | 'sqlite' | 'mysql';
|
|
7
|
+
export declare const DB_DRIVERS: readonly DbDriver[];
|
|
8
|
+
export declare const DEFAULT_DB_DRIVER: DbDriver;
|
|
9
|
+
export type LoggerId = 'pino' | 'winston';
|
|
10
|
+
export declare const LOGGERS: readonly LoggerId[];
|
|
11
|
+
export type PackageGroups = {
|
|
12
|
+
dependencies: string[];
|
|
13
|
+
devDependencies: string[];
|
|
14
|
+
scripts: Record<string, string>;
|
|
15
|
+
};
|
|
16
|
+
export type ScaffoldContext = {
|
|
17
|
+
projectName: string;
|
|
18
|
+
targetDir: string;
|
|
19
|
+
framework: Framework;
|
|
20
|
+
db?: DbOdm;
|
|
21
|
+
driver?: DbDriver;
|
|
22
|
+
logger?: LoggerId;
|
|
23
|
+
};
|
|
24
|
+
export type ScaffoldOptions = ScaffoldContext & {
|
|
25
|
+
skipInstall?: boolean;
|
|
26
|
+
agent?: Agent;
|
|
27
|
+
};
|
|
28
|
+
export type ScaffoldResult = ScaffoldContext;
|
|
29
|
+
export type CapabilitiesCatalog = {
|
|
30
|
+
frameworks: Framework[];
|
|
31
|
+
db: {
|
|
32
|
+
odms: DbOdm[];
|
|
33
|
+
drivers: DbDriver[];
|
|
34
|
+
defaultDriver: DbDriver;
|
|
35
|
+
};
|
|
36
|
+
loggers: LoggerId[];
|
|
37
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
let node_path = require("node:path");
|
|
3
|
+
node_path = require_runtime.__toESM(node_path, 1);
|
|
4
|
+
//#region src/core/validate-project-name.ts
|
|
5
|
+
var RESERVED_WINDOWS_NAMES = /* @__PURE__ */ new Set([
|
|
6
|
+
"CON",
|
|
7
|
+
"PRN",
|
|
8
|
+
"AUX",
|
|
9
|
+
"NVR",
|
|
10
|
+
"NULL",
|
|
11
|
+
"COM1",
|
|
12
|
+
"COM2",
|
|
13
|
+
"COM3",
|
|
14
|
+
"COM4",
|
|
15
|
+
"COM5",
|
|
16
|
+
"COM6",
|
|
17
|
+
"COM7",
|
|
18
|
+
"COM8",
|
|
19
|
+
"COM9",
|
|
20
|
+
"LPT1",
|
|
21
|
+
"LPT2",
|
|
22
|
+
"LPT3",
|
|
23
|
+
"LPT4",
|
|
24
|
+
"LPT5",
|
|
25
|
+
"LPT6",
|
|
26
|
+
"LPT7",
|
|
27
|
+
"LPT8",
|
|
28
|
+
"LPT9"
|
|
29
|
+
]);
|
|
30
|
+
function validateProjectName(name, cwd = process.cwd()) {
|
|
31
|
+
const trimmed = name.trim();
|
|
32
|
+
if (!trimmed) return "Project name is required";
|
|
33
|
+
if (trimmed.includes("..")) return "Project name cannot contain \"..\"";
|
|
34
|
+
if (trimmed.includes("/") || trimmed.includes("\\")) return "Project name cannot contain path separators";
|
|
35
|
+
if (trimmed.startsWith(".") || trimmed.endsWith(".")) return "Project name cannot start or end with a dot";
|
|
36
|
+
const baseName = trimmed.split(".")[0]?.toUpperCase();
|
|
37
|
+
if (baseName && RESERVED_WINDOWS_NAMES.has(baseName)) return `Project name "${trimmed}" is reserved on Windows`;
|
|
38
|
+
const targetDir = node_path.default.resolve(cwd, trimmed);
|
|
39
|
+
const relative = node_path.default.relative(cwd, targetDir);
|
|
40
|
+
if (relative.startsWith("..") || node_path.default.isAbsolute(relative)) return "Project name resolves outside the current directory";
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
exports.validateProjectName = validateProjectName;
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=validate-project-name.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-project-name.cjs","names":[],"sources":["../../../src/core/validate-project-name.ts"],"sourcesContent":["import path from 'node:path'\n\nconst RESERVED_WINDOWS_NAMES = new Set([\n 'CON',\n 'PRN',\n 'AUX',\n 'NVR',\n 'NULL',\n 'COM1',\n 'COM2',\n 'COM3',\n 'COM4',\n 'COM5',\n 'COM6',\n 'COM7',\n 'COM8',\n 'COM9',\n 'LPT1',\n 'LPT2',\n 'LPT3',\n 'LPT4',\n 'LPT5',\n 'LPT6',\n 'LPT7',\n 'LPT8',\n 'LPT9',\n])\n\nexport function validateProjectName(name: string, cwd = process.cwd()): string | undefined {\n const trimmed = name.trim()\n if (!trimmed) {\n return 'Project name is required'\n }\n\n if (trimmed.includes('..')) {\n return 'Project name cannot contain \"..\"'\n }\n\n if (trimmed.includes('/') || trimmed.includes('\\\\')) {\n return 'Project name cannot contain path separators'\n }\n\n if (trimmed.startsWith('.') || trimmed.endsWith('.')) {\n return 'Project name cannot start or end with a dot'\n }\n\n const baseName = trimmed.split('.')[0]?.toUpperCase()\n if (baseName && RESERVED_WINDOWS_NAMES.has(baseName)) {\n return `Project name \"${trimmed}\" is reserved on Windows`\n }\n\n const targetDir = path.resolve(cwd, trimmed)\n const relative = path.relative(cwd, targetDir)\n if (relative.startsWith('..') || path.isAbsolute(relative)) {\n return 'Project name resolves outside the current directory'\n }\n\n return undefined\n}\n"],"mappings":";;;;AAEA,IAAM,yCAAyB,IAAI,IAAI;CACrC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAgB,oBAAoB,MAAc,MAAM,QAAQ,IAAI,GAAuB;CACzF,MAAM,UAAU,KAAK,KAAK;CAC1B,IAAI,CAAC,SACH,OAAO;CAGT,IAAI,QAAQ,SAAS,IAAI,GACvB,OAAO;CAGT,IAAI,QAAQ,SAAS,GAAG,KAAK,QAAQ,SAAS,IAAI,GAChD,OAAO;CAGT,IAAI,QAAQ,WAAW,GAAG,KAAK,QAAQ,SAAS,GAAG,GACjD,OAAO;CAGT,MAAM,WAAW,QAAQ,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE,YAAY;CACpD,IAAI,YAAY,uBAAuB,IAAI,QAAQ,GACjD,OAAO,iBAAiB,QAAQ;CAGlC,MAAM,YAAY,UAAA,QAAK,QAAQ,KAAK,OAAO;CAC3C,MAAM,WAAW,UAAA,QAAK,SAAS,KAAK,SAAS;CAC7C,IAAI,SAAS,WAAW,IAAI,KAAK,UAAA,QAAK,WAAW,QAAQ,GACvD,OAAO;AAIX"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function validateProjectName(name: string, cwd?: string): string | undefined;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
//#region src/frameworks/index.ts
|
|
2
|
+
function indexTemplate(framework) {
|
|
3
|
+
switch (framework) {
|
|
4
|
+
case "express": return `import express from 'express'
|
|
5
|
+
import { createExpressHandler } from '@taserjs/adapter-express'
|
|
6
|
+
|
|
7
|
+
import { routeManifest } from '#src/routeManifest.gen.js'
|
|
8
|
+
import { t } from '#src/taser.js'
|
|
9
|
+
|
|
10
|
+
const router = t.create(routeManifest)
|
|
11
|
+
|
|
12
|
+
const taser = createExpressHandler(router)
|
|
13
|
+
const app = express()
|
|
14
|
+
taser.mount('/api{/*splat}', app)
|
|
15
|
+
|
|
16
|
+
const port = Number(process.env.PORT ?? 3000)
|
|
17
|
+
app.listen(port, () => {
|
|
18
|
+
console.log(\`Express listening on http://localhost:\${port}\`)
|
|
19
|
+
})
|
|
20
|
+
`;
|
|
21
|
+
case "hono": return `import { serve } from '@hono/node-server'
|
|
22
|
+
import { Hono } from 'hono'
|
|
23
|
+
|
|
24
|
+
import { routeManifest } from '#src/routeManifest.gen.js'
|
|
25
|
+
import { t } from '#src/taser.js'
|
|
26
|
+
|
|
27
|
+
const router = t.create(routeManifest)
|
|
28
|
+
|
|
29
|
+
const app = new Hono()
|
|
30
|
+
const api = router.base('/api')
|
|
31
|
+
app.all('/api/*', c => api.native(c).fetch(c.req.raw))
|
|
32
|
+
|
|
33
|
+
const port = Number(process.env.PORT ?? 3000)
|
|
34
|
+
serve({ fetch: app.fetch, port }, () => {
|
|
35
|
+
console.log(\`Hono listening on http://localhost:\${port}\`)
|
|
36
|
+
})
|
|
37
|
+
`;
|
|
38
|
+
case "fastify": return `import Fastify from 'fastify'
|
|
39
|
+
import { createFastifyHandler } from '@taserjs/adapter-fastify'
|
|
40
|
+
|
|
41
|
+
import { routeManifest } from '#src/routeManifest.gen.js'
|
|
42
|
+
import { t } from '#src/taser.js'
|
|
43
|
+
|
|
44
|
+
const router = t.create(routeManifest)
|
|
45
|
+
|
|
46
|
+
const taser = createFastifyHandler(router)
|
|
47
|
+
const app = Fastify()
|
|
48
|
+
taser.mount('/api/*', app)
|
|
49
|
+
|
|
50
|
+
const port = Number(process.env.PORT ?? 3000)
|
|
51
|
+
await app.listen({ port })
|
|
52
|
+
console.log(\`Fastify listening on http://localhost:\${port}\`)
|
|
53
|
+
`;
|
|
54
|
+
default: return `import { createServer } from 'node:http'
|
|
55
|
+
import { createNodeHandler } from '@taserjs/adapter-node'
|
|
56
|
+
|
|
57
|
+
import { routeManifest } from '#src/routeManifest.gen.js'
|
|
58
|
+
import { t } from '#src/taser.js'
|
|
59
|
+
|
|
60
|
+
const router = t.create(routeManifest)
|
|
61
|
+
|
|
62
|
+
const taser = createNodeHandler(router)
|
|
63
|
+
const app = createServer()
|
|
64
|
+
taser.mount('/api/*', app)
|
|
65
|
+
|
|
66
|
+
const port = Number(process.env.PORT ?? 3000)
|
|
67
|
+
app.listen(port, () => {
|
|
68
|
+
console.log(\`Node listening on http://localhost:\${port}\`)
|
|
69
|
+
})
|
|
70
|
+
`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function taserTsTemplate(framework = "node") {
|
|
74
|
+
if (framework === "hono") return `import type { Context } from 'hono'
|
|
75
|
+
import { createTaserApp, type InferAppContext } from '@taserjs/router'
|
|
76
|
+
|
|
77
|
+
import { context } from '#src/context.js'
|
|
78
|
+
|
|
79
|
+
declare module '@taserjs/router' {
|
|
80
|
+
interface RouterRegister {
|
|
81
|
+
NativeContext: Context
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export const t = createTaserApp({
|
|
86
|
+
response: { validate: true },
|
|
87
|
+
}).context(context)
|
|
88
|
+
|
|
89
|
+
export type AppContext = InferAppContext<typeof context>
|
|
90
|
+
`;
|
|
91
|
+
return `import { createTaserApp, type InferAppContext } from '@taserjs/router'
|
|
92
|
+
|
|
93
|
+
import { context } from '#src/context.js'
|
|
94
|
+
|
|
95
|
+
export const t = createTaserApp({
|
|
96
|
+
response: { validate: true },
|
|
97
|
+
}).context(context)
|
|
98
|
+
|
|
99
|
+
export type AppContext = InferAppContext<typeof context>
|
|
100
|
+
`;
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
exports.indexTemplate = indexTemplate;
|
|
104
|
+
exports.taserTsTemplate = taserTsTemplate;
|
|
105
|
+
|
|
106
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../../../src/frameworks/index.ts"],"sourcesContent":["import type { Framework } from '../core/types.js'\n\nexport function indexTemplate(framework: Framework): string {\n switch (framework) {\n case 'express':\n return `import express from 'express'\nimport { createExpressHandler } from '@taserjs/adapter-express'\n\nimport { routeManifest } from '#src/routeManifest.gen.js'\nimport { t } from '#src/taser.js'\n\nconst router = t.create(routeManifest)\n\nconst taser = createExpressHandler(router)\nconst app = express()\ntaser.mount('/api{/*splat}', app)\n\nconst port = Number(process.env.PORT ?? 3000)\napp.listen(port, () => {\n console.log(\\`Express listening on http://localhost:\\${port}\\`)\n})\n`\n case 'hono':\n return `import { serve } from '@hono/node-server'\nimport { Hono } from 'hono'\n\nimport { routeManifest } from '#src/routeManifest.gen.js'\nimport { t } from '#src/taser.js'\n\nconst router = t.create(routeManifest)\n\nconst app = new Hono()\nconst api = router.base('/api')\napp.all('/api/*', c => api.native(c).fetch(c.req.raw))\n\nconst port = Number(process.env.PORT ?? 3000)\nserve({ fetch: app.fetch, port }, () => {\n console.log(\\`Hono listening on http://localhost:\\${port}\\`)\n})\n`\n case 'fastify':\n return `import Fastify from 'fastify'\nimport { createFastifyHandler } from '@taserjs/adapter-fastify'\n\nimport { routeManifest } from '#src/routeManifest.gen.js'\nimport { t } from '#src/taser.js'\n\nconst router = t.create(routeManifest)\n\nconst taser = createFastifyHandler(router)\nconst app = Fastify()\ntaser.mount('/api/*', app)\n\nconst port = Number(process.env.PORT ?? 3000)\nawait app.listen({ port })\nconsole.log(\\`Fastify listening on http://localhost:\\${port}\\`)\n`\n case 'node':\n default:\n return `import { createServer } from 'node:http'\nimport { createNodeHandler } from '@taserjs/adapter-node'\n\nimport { routeManifest } from '#src/routeManifest.gen.js'\nimport { t } from '#src/taser.js'\n\nconst router = t.create(routeManifest)\n\nconst taser = createNodeHandler(router)\nconst app = createServer()\ntaser.mount('/api/*', app)\n\nconst port = Number(process.env.PORT ?? 3000)\napp.listen(port, () => {\n console.log(\\`Node listening on http://localhost:\\${port}\\`)\n})\n`\n }\n}\n\nexport function taserTsTemplate(framework: Framework = 'node'): string {\n if (framework === 'hono') {\n return `import type { Context } from 'hono'\nimport { createTaserApp, type InferAppContext } from '@taserjs/router'\n\nimport { context } from '#src/context.js'\n\ndeclare module '@taserjs/router' {\n interface RouterRegister {\n NativeContext: Context\n }\n}\n\nexport const t = createTaserApp({\n response: { validate: true },\n}).context(context)\n\nexport type AppContext = InferAppContext<typeof context>\n`\n }\n\n return `import { createTaserApp, type InferAppContext } from '@taserjs/router'\n\nimport { context } from '#src/context.js'\n\nexport const t = createTaserApp({\n response: { validate: true },\n}).context(context)\n\nexport type AppContext = InferAppContext<typeof context>\n`\n}\n"],"mappings":";AAEA,SAAgB,cAAc,WAA8B;CAC1D,QAAQ,WAAR;EACE,KAAK,WACH,OAAO;;;;;;;;;;;;;;;;;EAiBT,KAAK,QACH,OAAO;;;;;;;;;;;;;;;;;EAiBT,KAAK,WACH,OAAO;;;;;;;;;;;;;;;;EAiBT,SACE,OAAO;;;;;;;;;;;;;;;;;CAiBX;AACF;AAEA,SAAgB,gBAAgB,YAAuB,QAAgB;CACrE,IAAI,cAAc,QAChB,OAAO;;;;;;;;;;;;;;;;;CAmBT,OAAO;;;;;;;;;;AAUT"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
//#region src/templates/base.ts
|
|
2
|
+
function packageJsonTemplate(projectName, scripts = {}) {
|
|
3
|
+
const pkg = {
|
|
4
|
+
name: projectName,
|
|
5
|
+
version: "1.0.0",
|
|
6
|
+
private: true,
|
|
7
|
+
type: "module",
|
|
8
|
+
imports: { "#src/*": "./src/*" },
|
|
9
|
+
scripts: {
|
|
10
|
+
"dev": "run-p dev:server dev:taser",
|
|
11
|
+
"dev:server": "tsx watch src/index.ts",
|
|
12
|
+
"dev:taser": "taser watch",
|
|
13
|
+
"start": "tsx src/index.ts",
|
|
14
|
+
"generate": "taser generate",
|
|
15
|
+
"build": "taser generate && tsdown build",
|
|
16
|
+
"serve": "node dist/index.js",
|
|
17
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
18
|
+
...scripts
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
return `${JSON.stringify(pkg, null, 2)}\n`;
|
|
22
|
+
}
|
|
23
|
+
function tsdownConfigTemplate() {
|
|
24
|
+
return `import { defineConfig } from 'tsdown'
|
|
25
|
+
|
|
26
|
+
export default defineConfig({
|
|
27
|
+
entry: ['./src/index.ts'],
|
|
28
|
+
format: 'esm',
|
|
29
|
+
platform: 'node',
|
|
30
|
+
target: 'node20',
|
|
31
|
+
outDir: 'dist',
|
|
32
|
+
clean: true,
|
|
33
|
+
sourcemap: true,
|
|
34
|
+
})
|
|
35
|
+
`;
|
|
36
|
+
}
|
|
37
|
+
function tsconfigTemplate() {
|
|
38
|
+
return `${JSON.stringify({
|
|
39
|
+
compilerOptions: {
|
|
40
|
+
target: "ES2022",
|
|
41
|
+
lib: ["ES2022", "DOM"],
|
|
42
|
+
module: "ESNext",
|
|
43
|
+
moduleResolution: "bundler",
|
|
44
|
+
paths: { "#src/*": ["./src/*"] },
|
|
45
|
+
strict: true,
|
|
46
|
+
skipLibCheck: true,
|
|
47
|
+
verbatimModuleSyntax: true,
|
|
48
|
+
isolatedModules: true,
|
|
49
|
+
noEmit: true,
|
|
50
|
+
types: ["node"]
|
|
51
|
+
},
|
|
52
|
+
include: ["src"]
|
|
53
|
+
}, null, 2)}\n`;
|
|
54
|
+
}
|
|
55
|
+
function gitignoreTemplate() {
|
|
56
|
+
return `node_modules
|
|
57
|
+
dist
|
|
58
|
+
.DS_Store
|
|
59
|
+
*.log
|
|
60
|
+
.env
|
|
61
|
+
local.db
|
|
62
|
+
drizzle
|
|
63
|
+
`;
|
|
64
|
+
}
|
|
65
|
+
function contextTemplate(bindings) {
|
|
66
|
+
const imports = bindings.map((binding) => `import { ${binding.factoryName} } from '${binding.importPath}'`);
|
|
67
|
+
const bootBody = bindings.length > 0 ? bindings.map((binding) => ` ${binding.key}: ${binding.factoryName}(),`).join("\n") : "";
|
|
68
|
+
const bootBlock = bindings.length > 0 ? ` boot: () => ({\n${bootBody}\n }),` : "";
|
|
69
|
+
return `${imports.length > 0 ? `${imports.join("\n")}\n\n` : ""}import { createContext } from '@taserjs/router'
|
|
70
|
+
|
|
71
|
+
export const context = createContext({
|
|
72
|
+
${bootBlock}
|
|
73
|
+
request: () => ({
|
|
74
|
+
requestId: crypto.randomUUID(),
|
|
75
|
+
}),
|
|
76
|
+
})
|
|
77
|
+
`;
|
|
78
|
+
}
|
|
79
|
+
function rootLayoutTemplate() {
|
|
80
|
+
return `import { bodyLimit } from '@taserjs/router/body-limit'
|
|
81
|
+
import { secureHeaders } from '@taserjs/router/secure-headers'
|
|
82
|
+
|
|
83
|
+
import { t } from '#src/taser.js'
|
|
84
|
+
|
|
85
|
+
export const Middleware = t.middleware('/$')
|
|
86
|
+
.use(secureHeaders())
|
|
87
|
+
.use(bodyLimit({ maxSize: 1_000_000 }))
|
|
88
|
+
`;
|
|
89
|
+
}
|
|
90
|
+
function indexRouteTemplate() {
|
|
91
|
+
return `import { t } from '#src/taser.js'
|
|
92
|
+
|
|
93
|
+
export const Route = t.get('/').handler((ctx) => {
|
|
94
|
+
return ctx.reply.json({ message: 'Welcome to Taser' })
|
|
95
|
+
})
|
|
96
|
+
`;
|
|
97
|
+
}
|
|
98
|
+
function healthRouteTemplate(ctx) {
|
|
99
|
+
const lines = [];
|
|
100
|
+
if (ctx.logger) lines.push(" ctx.logger.info('health check')");
|
|
101
|
+
if (ctx.db) lines.push(" // ctx.db is available from context boot");
|
|
102
|
+
return `import { t } from '#src/taser.js'
|
|
103
|
+
|
|
104
|
+
export const Route = t.get('/health').handler((ctx) => {
|
|
105
|
+
${lines.length > 0 ? `${lines.join("\n")}\n` : ""} return ctx.reply.json({ ok: true })
|
|
106
|
+
})
|
|
107
|
+
`;
|
|
108
|
+
}
|
|
109
|
+
/** Minimal placeholder until `taser generate` runs. */
|
|
110
|
+
function starterManifestTemplate() {
|
|
111
|
+
return `/* eslint-disable */
|
|
112
|
+
// Run \`pnpm generate\` (taser generate) to replace this file.
|
|
113
|
+
import { Middleware as RootSplatLayoutImport } from './routes/$.js'
|
|
114
|
+
import { Route as RootIndexGetRouteImport } from './routes/index.get.js'
|
|
115
|
+
import { Route as HealthGetRouteImport } from './routes/health.get.js'
|
|
116
|
+
|
|
117
|
+
export const routeManifest = {
|
|
118
|
+
layouts: {
|
|
119
|
+
'/$': {
|
|
120
|
+
middlewares: RootSplatLayoutImport,
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
routes: {
|
|
124
|
+
'/': {
|
|
125
|
+
GET: {
|
|
126
|
+
layoutChain: ['/$'],
|
|
127
|
+
route: RootIndexGetRouteImport,
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
'/health': {
|
|
131
|
+
GET: {
|
|
132
|
+
layoutChain: ['/$'],
|
|
133
|
+
route: HealthGetRouteImport,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
} as const
|
|
138
|
+
|
|
139
|
+
export type RoutePathGen = '/' | '/health'
|
|
140
|
+
export type LayoutIdGen = '/$'
|
|
141
|
+
export type LayoutTreeGen = {
|
|
142
|
+
'/$': {
|
|
143
|
+
parent: null
|
|
144
|
+
middlewares: typeof RootSplatLayoutImport
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
export type RouteByPathMethodGen = {
|
|
148
|
+
'/': {
|
|
149
|
+
GET: {
|
|
150
|
+
parent: '/$'
|
|
151
|
+
layoutChain: ['/$']
|
|
152
|
+
route: typeof RootIndexGetRouteImport
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
'/health': {
|
|
156
|
+
GET: {
|
|
157
|
+
parent: '/$'
|
|
158
|
+
layoutChain: ['/$']
|
|
159
|
+
route: typeof HealthGetRouteImport
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
export type RouteManifest = typeof routeManifest
|
|
164
|
+
|
|
165
|
+
declare module '@taserjs/router' {
|
|
166
|
+
interface RouterRegister {
|
|
167
|
+
RoutePath: RoutePathGen
|
|
168
|
+
LayoutId: LayoutIdGen
|
|
169
|
+
LayoutTree: LayoutTreeGen
|
|
170
|
+
RouteByPathMethod: RouteByPathMethodGen
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
`;
|
|
174
|
+
}
|
|
175
|
+
//#endregion
|
|
176
|
+
exports.contextTemplate = contextTemplate;
|
|
177
|
+
exports.gitignoreTemplate = gitignoreTemplate;
|
|
178
|
+
exports.healthRouteTemplate = healthRouteTemplate;
|
|
179
|
+
exports.indexRouteTemplate = indexRouteTemplate;
|
|
180
|
+
exports.packageJsonTemplate = packageJsonTemplate;
|
|
181
|
+
exports.rootLayoutTemplate = rootLayoutTemplate;
|
|
182
|
+
exports.starterManifestTemplate = starterManifestTemplate;
|
|
183
|
+
exports.tsconfigTemplate = tsconfigTemplate;
|
|
184
|
+
exports.tsdownConfigTemplate = tsdownConfigTemplate;
|
|
185
|
+
|
|
186
|
+
//# sourceMappingURL=base.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.cjs","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 build',\n 'serve': 'node dist/index.js',\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 format: 'esm',\n platform: 'node',\n target: 'node20',\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 lib: ['ES2022', 'DOM'],\n module: 'ESNext',\n moduleResolution: 'bundler',\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((ctx) => {\n return ctx.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\n return `import { t } from '#src/taser.js'\n\nexport const Route = t.get('/health').handler((ctx) => {\n${body} return ctx.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;;;;;;;;;;;;AAYT;AAEA,SAAgB,mBAA2B;CACzC,OAAO,GAAG,KAAK,UAAU;EACvB,iBAAiB;GACf,QAAQ;GACR,KAAK,CAAC,UAAU,KAAK;GACrB,QAAQ;GACR,kBAAkB;GAClB,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;;;;;;AAMT;AAEA,SAAgB,oBAAoB,KAA8B;CAChE,MAAM,QAAkB,CAAC;CAEzB,IAAI,IAAI,QACN,MAAM,KAAK,mCAAqC;CAGlD,IAAI,IAAI,IACN,MAAM,KAAK,4CAA4C;CAKzD,OAAO;;;EAFM,MAAM,SAAS,IAAI,GAAG,MAAM,KAAK,IAAI,EAAE,MAAM,GAKrD;;;AAGP;;AAGA,SAAgB,0BAAkC;CAChD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+DT"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BootBinding } from '../addons/types.js';
|
|
2
|
+
import { ScaffoldContext } from '../core/types.js';
|
|
3
|
+
export declare function packageJsonTemplate(projectName: string, scripts?: Record<string, string>): string;
|
|
4
|
+
export declare function tsdownConfigTemplate(): string;
|
|
5
|
+
export declare function tsconfigTemplate(): string;
|
|
6
|
+
export declare function gitignoreTemplate(): string;
|
|
7
|
+
export declare function contextTemplate(bindings: BootBinding[]): string;
|
|
8
|
+
export declare function rootLayoutTemplate(): string;
|
|
9
|
+
export declare function indexRouteTemplate(): string;
|
|
10
|
+
export declare function healthRouteTemplate(ctx: ScaffoldContext): string;
|
|
11
|
+
/** Minimal placeholder until `taser generate` runs. */
|
|
12
|
+
export declare function starterManifestTemplate(): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { Framework, DbOdm, DbDriver, LoggerId, ScaffoldOptions, ScaffoldResult, PackageGroups, } from './core/types.js';
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
//#region src/addons/drizzle/index.ts
|
|
2
|
+
function schemaSource(driver) {
|
|
3
|
+
switch (driver) {
|
|
4
|
+
case "postgres": return `import { pgTable, serial, text } from 'drizzle-orm/pg-core'
|
|
5
|
+
|
|
6
|
+
export const users = pgTable('users', {
|
|
7
|
+
id: serial('id').primaryKey(),
|
|
8
|
+
email: text('email').notNull(),
|
|
9
|
+
})
|
|
10
|
+
`;
|
|
11
|
+
case "mysql": return `import { mysqlTable, serial, varchar } from 'drizzle-orm/mysql-core'
|
|
12
|
+
|
|
13
|
+
export const users = mysqlTable('users', {
|
|
14
|
+
id: serial('id').primaryKey(),
|
|
15
|
+
email: varchar('email', { length: 255 }).notNull(),
|
|
16
|
+
})
|
|
17
|
+
`;
|
|
18
|
+
default: return `import { sqliteTable, integer, text } from 'drizzle-orm/sqlite-core'
|
|
19
|
+
|
|
20
|
+
export const users = sqliteTable('users', {
|
|
21
|
+
id: integer('id').primaryKey({ autoIncrement: true }),
|
|
22
|
+
email: text('email').notNull(),
|
|
23
|
+
})
|
|
24
|
+
`;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function dbIndexSource(driver) {
|
|
28
|
+
switch (driver) {
|
|
29
|
+
case "postgres": return `import { drizzle } from 'drizzle-orm/node-postgres'
|
|
30
|
+
import pg from 'pg'
|
|
31
|
+
|
|
32
|
+
import * as schema from './schema.js'
|
|
33
|
+
|
|
34
|
+
export function createDb() {
|
|
35
|
+
const pool = new pg.Pool({
|
|
36
|
+
connectionString: process.env.DATABASE_URL,
|
|
37
|
+
})
|
|
38
|
+
return drizzle(pool, { schema })
|
|
39
|
+
}
|
|
40
|
+
`;
|
|
41
|
+
case "mysql": return `import { drizzle } from 'drizzle-orm/mysql2'
|
|
42
|
+
import mysql from 'mysql2/promise'
|
|
43
|
+
|
|
44
|
+
import * as schema from './schema.js'
|
|
45
|
+
|
|
46
|
+
export function createDb() {
|
|
47
|
+
const pool = mysql.createPool(process.env.DATABASE_URL ?? '')
|
|
48
|
+
return drizzle(pool, { schema, mode: 'default' })
|
|
49
|
+
}
|
|
50
|
+
`;
|
|
51
|
+
default: return `import Database from 'better-sqlite3'
|
|
52
|
+
import { drizzle } from 'drizzle-orm/better-sqlite3'
|
|
53
|
+
|
|
54
|
+
import * as schema from './schema.js'
|
|
55
|
+
|
|
56
|
+
export function createDb() {
|
|
57
|
+
const filePath = (process.env.DATABASE_URL ?? 'file:./local.db').replace(/^file:/, '')
|
|
58
|
+
const client = new Database(filePath)
|
|
59
|
+
return drizzle(client, { schema })
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function drizzleConfigSource(driver) {
|
|
65
|
+
return `import { defineConfig } from 'drizzle-kit'
|
|
66
|
+
|
|
67
|
+
export default defineConfig({
|
|
68
|
+
schema: './src/db/schema.ts',
|
|
69
|
+
out: './drizzle',
|
|
70
|
+
dialect: '${driver === "postgres" ? "postgresql" : driver === "mysql" ? "mysql" : "sqlite"}',
|
|
71
|
+
dbCredentials: {
|
|
72
|
+
url: process.env.DATABASE_URL ?? '',
|
|
73
|
+
},
|
|
74
|
+
})
|
|
75
|
+
`;
|
|
76
|
+
}
|
|
77
|
+
function envExample(driver) {
|
|
78
|
+
switch (driver) {
|
|
79
|
+
case "postgres": return "DATABASE_URL=postgresql://user:password@localhost:5432/mydb\n";
|
|
80
|
+
case "mysql": return "DATABASE_URL=mysql://user:password@localhost:3306/mydb\n";
|
|
81
|
+
default: return "DATABASE_URL=file:./local.db\n";
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function driverPackages(driver) {
|
|
85
|
+
switch (driver) {
|
|
86
|
+
case "postgres": return ["pg"];
|
|
87
|
+
case "mysql": return ["mysql2"];
|
|
88
|
+
default: return ["better-sqlite3"];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
var drizzleAddon = {
|
|
92
|
+
id: "drizzle",
|
|
93
|
+
category: "database",
|
|
94
|
+
dependencies(ctx) {
|
|
95
|
+
return ["drizzle-orm", ...driverPackages(ctx.driver ?? "sqlite")];
|
|
96
|
+
},
|
|
97
|
+
devDependencies() {
|
|
98
|
+
return ["drizzle-kit"];
|
|
99
|
+
},
|
|
100
|
+
scripts() {
|
|
101
|
+
return {
|
|
102
|
+
"db:generate": "drizzle-kit generate",
|
|
103
|
+
"db:push": "drizzle-kit push"
|
|
104
|
+
};
|
|
105
|
+
},
|
|
106
|
+
bootBinding() {
|
|
107
|
+
return {
|
|
108
|
+
key: "db",
|
|
109
|
+
importPath: "./db/index.js",
|
|
110
|
+
factoryName: "createDb"
|
|
111
|
+
};
|
|
112
|
+
},
|
|
113
|
+
async apply(ctx, write) {
|
|
114
|
+
const driver = ctx.driver ?? "sqlite";
|
|
115
|
+
await write("src/db/schema.ts", schemaSource(driver));
|
|
116
|
+
await write("src/db/index.ts", dbIndexSource(driver));
|
|
117
|
+
await write("drizzle.config.ts", drizzleConfigSource(driver));
|
|
118
|
+
await write(".env.example", envExample(driver));
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
//#endregion
|
|
122
|
+
export { drizzleAddon };
|
|
123
|
+
|
|
124
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/addons/drizzle/index.ts"],"sourcesContent":["import type { AddonDefinition } from '../types.js'\nimport type { DbDriver } from '../../core/types.js'\n\nfunction schemaSource(driver: DbDriver): string {\n switch (driver) {\n case 'postgres':\n return `import { pgTable, serial, text } from 'drizzle-orm/pg-core'\n\nexport const users = pgTable('users', {\n id: serial('id').primaryKey(),\n email: text('email').notNull(),\n})\n`\n case 'mysql':\n return `import { mysqlTable, serial, varchar } from 'drizzle-orm/mysql-core'\n\nexport const users = mysqlTable('users', {\n id: serial('id').primaryKey(),\n email: varchar('email', { length: 255 }).notNull(),\n})\n`\n case 'sqlite':\n default:\n return `import { sqliteTable, integer, text } from 'drizzle-orm/sqlite-core'\n\nexport const users = sqliteTable('users', {\n id: integer('id').primaryKey({ autoIncrement: true }),\n email: text('email').notNull(),\n})\n`\n }\n}\n\nfunction dbIndexSource(driver: DbDriver): string {\n switch (driver) {\n case 'postgres':\n return `import { drizzle } from 'drizzle-orm/node-postgres'\nimport pg from 'pg'\n\nimport * as schema from './schema.js'\n\nexport function createDb() {\n const pool = new pg.Pool({\n connectionString: process.env.DATABASE_URL,\n })\n return drizzle(pool, { schema })\n}\n`\n case 'mysql':\n return `import { drizzle } from 'drizzle-orm/mysql2'\nimport mysql from 'mysql2/promise'\n\nimport * as schema from './schema.js'\n\nexport function createDb() {\n const pool = mysql.createPool(process.env.DATABASE_URL ?? '')\n return drizzle(pool, { schema, mode: 'default' })\n}\n`\n case 'sqlite':\n default:\n return `import Database from 'better-sqlite3'\nimport { drizzle } from 'drizzle-orm/better-sqlite3'\n\nimport * as schema from './schema.js'\n\nexport function createDb() {\n const filePath = (process.env.DATABASE_URL ?? 'file:./local.db').replace(/^file:/, '')\n const client = new Database(filePath)\n return drizzle(client, { schema })\n}\n`\n }\n}\n\nfunction drizzleConfigSource(driver: DbDriver): string {\n const dialect = driver === 'postgres' ? 'postgresql' : driver === 'mysql' ? 'mysql' : 'sqlite'\n return `import { defineConfig } from 'drizzle-kit'\n\nexport default defineConfig({\n schema: './src/db/schema.ts',\n out: './drizzle',\n dialect: '${dialect}',\n dbCredentials: {\n url: process.env.DATABASE_URL ?? '',\n },\n})\n`\n}\n\nfunction envExample(driver: DbDriver): string {\n switch (driver) {\n case 'postgres':\n return 'DATABASE_URL=postgresql://user:password@localhost:5432/mydb\\n'\n case 'mysql':\n return 'DATABASE_URL=mysql://user:password@localhost:3306/mydb\\n'\n case 'sqlite':\n default:\n return 'DATABASE_URL=file:./local.db\\n'\n }\n}\n\nfunction driverPackages(driver: DbDriver): string[] {\n switch (driver) {\n case 'postgres':\n return ['pg']\n case 'mysql':\n return ['mysql2']\n case 'sqlite':\n default:\n return ['better-sqlite3']\n }\n}\n\nexport const drizzleAddon: AddonDefinition = {\n id: 'drizzle',\n category: 'database',\n dependencies(ctx) {\n const driver = ctx.driver ?? 'sqlite'\n return ['drizzle-orm', ...driverPackages(driver)]\n },\n devDependencies() {\n return ['drizzle-kit']\n },\n scripts() {\n return {\n 'db:generate': 'drizzle-kit generate',\n 'db:push': 'drizzle-kit push',\n }\n },\n bootBinding() {\n return {\n key: 'db',\n importPath: './db/index.js',\n factoryName: 'createDb',\n }\n },\n async apply(ctx, write) {\n const driver = ctx.driver ?? 'sqlite'\n await write('src/db/schema.ts', schemaSource(driver))\n await write('src/db/index.ts', dbIndexSource(driver))\n await write('drizzle.config.ts', drizzleConfigSource(driver))\n await write('.env.example', envExample(driver))\n },\n}\n"],"mappings":";AAGA,SAAS,aAAa,QAA0B;CAC9C,QAAQ,QAAR;EACE,KAAK,YACH,OAAO;;;;;;;EAOT,KAAK,SACH,OAAO;;;;;;;EAQT,SACE,OAAO;;;;;;;CAOX;AACF;AAEA,SAAS,cAAc,QAA0B;CAC/C,QAAQ,QAAR;EACE,KAAK,YACH,OAAO;;;;;;;;;;;;EAYT,KAAK,SACH,OAAO;;;;;;;;;;EAWT,SACE,OAAO;;;;;;;;;;;CAWX;AACF;AAEA,SAAS,oBAAoB,QAA0B;CAErD,OAAO;;;;;cADS,WAAW,aAAa,eAAe,WAAW,UAAU,UAAU,SAMlE;;;;;;AAMtB;AAEA,SAAS,WAAW,QAA0B;CAC5C,QAAQ,QAAR;EACE,KAAK,YACH,OAAO;EACT,KAAK,SACH,OAAO;EAET,SACE,OAAO;CACX;AACF;AAEA,SAAS,eAAe,QAA4B;CAClD,QAAQ,QAAR;EACE,KAAK,YACH,OAAO,CAAC,IAAI;EACd,KAAK,SACH,OAAO,CAAC,QAAQ;EAElB,SACE,OAAO,CAAC,gBAAgB;CAC5B;AACF;AAEA,IAAa,eAAgC;CAC3C,IAAI;CACJ,UAAU;CACV,aAAa,KAAK;EAEhB,OAAO,CAAC,eAAe,GAAG,eADX,IAAI,UAAU,QACkB,CAAC;CAClD;CACA,kBAAkB;EAChB,OAAO,CAAC,aAAa;CACvB;CACA,UAAU;EACR,OAAO;GACL,eAAe;GACf,WAAW;EACb;CACF;CACA,cAAc;EACZ,OAAO;GACL,KAAK;GACL,YAAY;GACZ,aAAa;EACf;CACF;CACA,MAAM,MAAM,KAAK,OAAO;EACtB,MAAM,SAAS,IAAI,UAAU;EAC7B,MAAM,MAAM,oBAAoB,aAAa,MAAM,CAAC;EACpD,MAAM,MAAM,mBAAmB,cAAc,MAAM,CAAC;EACpD,MAAM,MAAM,qBAAqB,oBAAoB,MAAM,CAAC;EAC5D,MAAM,MAAM,gBAAgB,WAAW,MAAM,CAAC;CAChD;AACF"}
|