@raiyyan/brisk 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/AGENTS.md +535 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1745 -2
  4. package/dist/bin/brisk.d.ts +3 -0
  5. package/dist/bin/brisk.d.ts.map +1 -0
  6. package/dist/bin/brisk.js +13 -0
  7. package/dist/bin/brisk.js.map +1 -0
  8. package/dist/src/cli/agents.d.ts +7 -0
  9. package/dist/src/cli/agents.d.ts.map +1 -0
  10. package/dist/src/cli/agents.js +55 -0
  11. package/dist/src/cli/agents.js.map +1 -0
  12. package/dist/src/cli/cli.d.ts +5 -0
  13. package/dist/src/cli/cli.d.ts.map +1 -0
  14. package/dist/src/cli/cli.js +113 -0
  15. package/dist/src/cli/cli.js.map +1 -0
  16. package/dist/src/cli/client.d.ts +12 -0
  17. package/dist/src/cli/client.d.ts.map +1 -0
  18. package/dist/src/cli/client.js +76 -0
  19. package/dist/src/cli/client.js.map +1 -0
  20. package/dist/src/cli/init.d.ts +16 -0
  21. package/dist/src/cli/init.d.ts.map +1 -0
  22. package/dist/src/cli/init.js +149 -0
  23. package/dist/src/cli/init.js.map +1 -0
  24. package/dist/src/cli/names.d.ts +14 -0
  25. package/dist/src/cli/names.d.ts.map +1 -0
  26. package/dist/src/cli/names.js +25 -0
  27. package/dist/src/cli/names.js.map +1 -0
  28. package/dist/src/cli/render.d.ts +30 -0
  29. package/dist/src/cli/render.d.ts.map +1 -0
  30. package/dist/src/cli/render.js +101 -0
  31. package/dist/src/cli/render.js.map +1 -0
  32. package/dist/src/cli/system.d.ts +35 -0
  33. package/dist/src/cli/system.d.ts.map +1 -0
  34. package/dist/src/cli/system.js +81 -0
  35. package/dist/src/cli/system.js.map +1 -0
  36. package/dist/src/client/client.d.ts +64 -0
  37. package/dist/src/client/client.d.ts.map +1 -0
  38. package/dist/src/client/client.js +170 -0
  39. package/dist/src/client/client.js.map +1 -0
  40. package/dist/src/client/index.d.ts +8 -0
  41. package/dist/src/client/index.d.ts.map +1 -0
  42. package/dist/src/client/index.js +7 -0
  43. package/dist/src/client/index.js.map +1 -0
  44. package/dist/src/config/env.d.ts +28 -0
  45. package/dist/src/config/env.d.ts.map +1 -0
  46. package/dist/src/config/env.js +35 -0
  47. package/dist/src/config/env.js.map +1 -0
  48. package/dist/src/config/logger.d.ts +32 -0
  49. package/dist/src/config/logger.d.ts.map +1 -0
  50. package/dist/src/config/logger.js +31 -0
  51. package/dist/src/config/logger.js.map +1 -0
  52. package/dist/src/di/container.d.ts +194 -0
  53. package/dist/src/di/container.d.ts.map +1 -0
  54. package/dist/src/di/container.js +225 -0
  55. package/dist/src/di/container.js.map +1 -0
  56. package/dist/src/di/index.d.ts +8 -0
  57. package/dist/src/di/index.d.ts.map +1 -0
  58. package/dist/src/di/index.js +8 -0
  59. package/dist/src/di/index.js.map +1 -0
  60. package/dist/src/errors/http-errors.d.ts +295 -0
  61. package/dist/src/errors/http-errors.d.ts.map +1 -0
  62. package/dist/src/errors/http-errors.js +311 -0
  63. package/dist/src/errors/http-errors.js.map +1 -0
  64. package/dist/src/errors/index.d.ts +8 -0
  65. package/dist/src/errors/index.d.ts.map +1 -0
  66. package/dist/src/errors/index.js +8 -0
  67. package/dist/src/errors/index.js.map +1 -0
  68. package/dist/src/http/app.d.ts +229 -0
  69. package/dist/src/http/app.d.ts.map +1 -0
  70. package/dist/src/http/app.js +45 -0
  71. package/dist/src/http/app.js.map +1 -0
  72. package/dist/src/http/context.d.ts +66 -0
  73. package/dist/src/http/context.d.ts.map +1 -0
  74. package/dist/src/http/context.js +96 -0
  75. package/dist/src/http/context.js.map +1 -0
  76. package/dist/src/http/controller.d.ts +195 -0
  77. package/dist/src/http/controller.d.ts.map +1 -0
  78. package/dist/src/http/controller.js +290 -0
  79. package/dist/src/http/controller.js.map +1 -0
  80. package/dist/src/http/error-handler.d.ts +86 -0
  81. package/dist/src/http/error-handler.d.ts.map +1 -0
  82. package/dist/src/http/error-handler.js +147 -0
  83. package/dist/src/http/error-handler.js.map +1 -0
  84. package/dist/src/http/instance.d.ts +14 -0
  85. package/dist/src/http/instance.d.ts.map +1 -0
  86. package/dist/src/http/instance.js +377 -0
  87. package/dist/src/http/instance.js.map +1 -0
  88. package/dist/src/http/middleware.d.ts +141 -0
  89. package/dist/src/http/middleware.d.ts.map +1 -0
  90. package/dist/src/http/middleware.js +160 -0
  91. package/dist/src/http/middleware.js.map +1 -0
  92. package/dist/src/http/openapi.d.ts +34 -0
  93. package/dist/src/http/openapi.d.ts.map +1 -0
  94. package/dist/src/http/openapi.js +151 -0
  95. package/dist/src/http/openapi.js.map +1 -0
  96. package/dist/src/http/path-params.d.ts +24 -0
  97. package/dist/src/http/path-params.d.ts.map +1 -0
  98. package/dist/src/http/path-params.js +2 -0
  99. package/dist/src/http/path-params.js.map +1 -0
  100. package/dist/src/http/routes.d.ts +141 -0
  101. package/dist/src/http/routes.d.ts.map +1 -0
  102. package/dist/src/http/routes.js +2 -0
  103. package/dist/src/http/routes.js.map +1 -0
  104. package/dist/src/http/server.d.ts +23 -0
  105. package/dist/src/http/server.d.ts.map +1 -0
  106. package/dist/src/http/server.js +22 -0
  107. package/dist/src/http/server.js.map +1 -0
  108. package/dist/src/http/validation.d.ts +16 -0
  109. package/dist/src/http/validation.d.ts.map +1 -0
  110. package/dist/src/http/validation.js +51 -0
  111. package/dist/src/http/validation.js.map +1 -0
  112. package/dist/src/index.d.ts +22 -0
  113. package/dist/src/index.d.ts.map +1 -0
  114. package/dist/src/index.js +19 -0
  115. package/dist/src/index.js.map +1 -0
  116. package/dist/src/testing/index.d.ts +7 -0
  117. package/dist/src/testing/index.d.ts.map +1 -0
  118. package/dist/src/testing/index.js +7 -0
  119. package/dist/src/testing/index.js.map +1 -0
  120. package/dist/src/testing/test-client.d.ts +67 -0
  121. package/dist/src/testing/test-client.d.ts.map +1 -0
  122. package/dist/src/testing/test-client.js +78 -0
  123. package/dist/src/testing/test-client.js.map +1 -0
  124. package/package.json +89 -3
  125. package/starters/minimal/.env.example +3 -0
  126. package/starters/minimal/.oxfmtrc.json +5 -0
  127. package/starters/minimal/.oxlintrc.json +14 -0
  128. package/starters/minimal/AGENTS.md +23 -0
  129. package/starters/minimal/CLAUDE.md +2 -0
  130. package/starters/minimal/README.md +53 -0
  131. package/starters/minimal/_gitignore +3 -0
  132. package/starters/minimal/package.json +29 -0
  133. package/starters/minimal/src/app.ts +14 -0
  134. package/starters/minimal/src/env.ts +7 -0
  135. package/starters/minimal/src/features/index.ts +8 -0
  136. package/starters/minimal/src/features/notes/notes.controller.ts +38 -0
  137. package/starters/minimal/src/features/notes/notes.repository.ts +36 -0
  138. package/starters/minimal/src/features/notes/notes.schema.ts +24 -0
  139. package/starters/minimal/src/features/notes/notes.service.ts +33 -0
  140. package/starters/minimal/src/main.ts +4 -0
  141. package/starters/minimal/src/schemas.ts +26 -0
  142. package/starters/minimal/templates/feature/src/features/index.ts.controllers.insert +1 -0
  143. package/starters/minimal/templates/feature/src/features/index.ts.imports.insert +1 -0
  144. package/starters/minimal/templates/feature/src/features/{{kebab}}/{{kebab}}.controller.ts +38 -0
  145. package/starters/minimal/templates/feature/src/features/{{kebab}}/{{kebab}}.repository.ts +36 -0
  146. package/starters/minimal/templates/feature/src/features/{{kebab}}/{{kebab}}.schema.ts +24 -0
  147. package/starters/minimal/templates/feature/src/features/{{kebab}}/{{kebab}}.service.ts +33 -0
  148. package/starters/minimal/templates/feature/test/{{kebab}}.service.test.ts +20 -0
  149. package/starters/minimal/templates/feature/test/{{kebab}}.test.ts +35 -0
  150. package/starters/minimal/templates/middleware/src/middlewares/{{kebab}}.ts +12 -0
  151. package/starters/minimal/test/notes.service.test.ts +20 -0
  152. package/starters/minimal/test/notes.test.ts +35 -0
  153. package/starters/minimal/tsconfig.json +17 -0
  154. package/starters/minimal/vitest.config.ts +9 -0
  155. package/starters/sqlite-auth/.dockerignore +8 -0
  156. package/starters/sqlite-auth/.env.example +9 -0
  157. package/starters/sqlite-auth/.oxfmtrc.json +5 -0
  158. package/starters/sqlite-auth/.oxlintrc.json +14 -0
  159. package/starters/sqlite-auth/AGENTS.md +23 -0
  160. package/starters/sqlite-auth/CLAUDE.md +2 -0
  161. package/starters/sqlite-auth/Dockerfile +23 -0
  162. package/starters/sqlite-auth/README.md +93 -0
  163. package/starters/sqlite-auth/_gitignore +5 -0
  164. package/starters/sqlite-auth/compose.yaml +14 -0
  165. package/starters/sqlite-auth/package.json +35 -0
  166. package/starters/sqlite-auth/public/.gitkeep +0 -0
  167. package/starters/sqlite-auth/src/app.ts +39 -0
  168. package/starters/sqlite-auth/src/auth/tokens.ts +41 -0
  169. package/starters/sqlite-auth/src/database/clock.ts +4 -0
  170. package/starters/sqlite-auth/src/database/database.ts +29 -0
  171. package/starters/sqlite-auth/src/database/errors.ts +11 -0
  172. package/starters/sqlite-auth/src/database/migrations.ts +29 -0
  173. package/starters/sqlite-auth/src/env.ts +17 -0
  174. package/starters/sqlite-auth/src/features/auth/auth.controller.ts +28 -0
  175. package/starters/sqlite-auth/src/features/index.ts +12 -0
  176. package/starters/sqlite-auth/src/features/notes/notes.controller.ts +39 -0
  177. package/starters/sqlite-auth/src/features/notes/notes.repository.ts +47 -0
  178. package/starters/sqlite-auth/src/features/notes/notes.schema.ts +24 -0
  179. package/starters/sqlite-auth/src/features/notes/notes.service.ts +33 -0
  180. package/starters/sqlite-auth/src/features/users/admin-seed.ts +21 -0
  181. package/starters/sqlite-auth/src/features/users/users.controller.ts +42 -0
  182. package/starters/sqlite-auth/src/features/users/users.errors.ts +13 -0
  183. package/starters/sqlite-auth/src/features/users/users.repository.ts +77 -0
  184. package/starters/sqlite-auth/src/features/users/users.schema.ts +35 -0
  185. package/starters/sqlite-auth/src/features/users/users.service.ts +80 -0
  186. package/starters/sqlite-auth/src/main.ts +4 -0
  187. package/starters/sqlite-auth/src/middlewares/authenticate.ts +29 -0
  188. package/starters/sqlite-auth/src/schemas.ts +26 -0
  189. package/starters/sqlite-auth/templates/feature/src/database/migrations.ts.migrations.insert +5 -0
  190. package/starters/sqlite-auth/templates/feature/src/features/index.ts.controllers.insert +1 -0
  191. package/starters/sqlite-auth/templates/feature/src/features/index.ts.imports.insert +1 -0
  192. package/starters/sqlite-auth/templates/feature/src/features/{{kebab}}/{{kebab}}.controller.ts +39 -0
  193. package/starters/sqlite-auth/templates/feature/src/features/{{kebab}}/{{kebab}}.repository.ts +47 -0
  194. package/starters/sqlite-auth/templates/feature/src/features/{{kebab}}/{{kebab}}.schema.ts +24 -0
  195. package/starters/sqlite-auth/templates/feature/src/features/{{kebab}}/{{kebab}}.service.ts +33 -0
  196. package/starters/sqlite-auth/templates/feature/test/{{kebab}}.service.test.ts +20 -0
  197. package/starters/sqlite-auth/templates/feature/test/{{kebab}}.test.ts +41 -0
  198. package/starters/sqlite-auth/templates/middleware/src/middlewares/{{kebab}}.ts +12 -0
  199. package/starters/sqlite-auth/test/auth.test.ts +18 -0
  200. package/starters/sqlite-auth/test/helpers.ts +13 -0
  201. package/starters/sqlite-auth/test/notes.service.test.ts +20 -0
  202. package/starters/sqlite-auth/test/notes.test.ts +41 -0
  203. package/starters/sqlite-auth/test/users.service.test.ts +25 -0
  204. package/starters/sqlite-auth/test/users.test.ts +164 -0
  205. package/starters/sqlite-auth/tsconfig.json +17 -0
  206. package/starters/sqlite-auth/vitest.config.ts +15 -0
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=brisk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brisk.d.ts","sourceRoot":"","sources":["../../bin/brisk.ts"],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import { createInterface } from "node:readline/promises";
3
+ import { runCli } from "../src/cli/cli.js";
4
+ const interactive = process.stdin.isTTY && process.stdout.isTTY;
5
+ const prompt = interactive ? createInterface({ input: process.stdin, output: process.stdout }) : undefined;
6
+ const code = await runCli(process.argv.slice(2), process.cwd(), {
7
+ log: console.log,
8
+ error: console.error,
9
+ ...(prompt ? { ask: (question) => prompt.question(question) } : {}),
10
+ });
11
+ prompt?.close();
12
+ process.exit(code);
13
+ //# sourceMappingURL=brisk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brisk.js","sourceRoot":"","sources":["../../bin/brisk.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;AAChE,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAE3G,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE;IAC9D,GAAG,EAAE,OAAO,CAAC,GAAG;IAChB,KAAK,EAAE,OAAO,CAAC,KAAK;IACpB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,QAAgB,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;CAC5E,CAAC,CAAC;AACH,MAAM,EAAE,KAAK,EAAE,CAAC;AAChB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Coding agents read the project's own `AGENTS.md` (Claude Code reads `CLAUDE.md`), not files in node_modules.
3
+ * Writes a brisk section between markers into `AGENTS.md`, refreshed in place on later runs without touching
4
+ * the rest of the file, and makes `CLAUDE.md` import both it and the full guide shipped in the package.
5
+ */
6
+ export declare function writeAgentGuides(root: string): string[];
7
+ //# sourceMappingURL=agents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../src/cli/agents.ts"],"names":[],"mappings":"AAQA;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA2BvD"}
@@ -0,0 +1,55 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { PACKAGE } from "./system.js";
4
+ const GUIDE = `node_modules/${PACKAGE}/AGENTS.md`;
5
+ const START = "<!-- brisk:start -->";
6
+ const END = "<!-- brisk:end -->";
7
+ /**
8
+ * Coding agents read the project's own `AGENTS.md` (Claude Code reads `CLAUDE.md`), not files in node_modules.
9
+ * Writes a brisk section between markers into `AGENTS.md`, refreshed in place on later runs without touching
10
+ * the rest of the file, and makes `CLAUDE.md` import both it and the full guide shipped in the package.
11
+ */
12
+ export function writeAgentGuides(root) {
13
+ const agentsPath = join(root, "AGENTS.md");
14
+ const block = `${START}\n${section}\n${END}`;
15
+ const existing = existsSync(agentsPath) ? readFileSync(agentsPath, "utf8") : "";
16
+ const start = existing.indexOf(START);
17
+ const end = existing.indexOf(END);
18
+ const agents = start !== -1 && end > start
19
+ ? existing.slice(0, start) + block + existing.slice(end + END.length)
20
+ : existing === ""
21
+ ? `# AGENTS.md\n\n${block}\n`
22
+ : `${existing.trimEnd()}\n\n${block}\n`;
23
+ writeFileSync(agentsPath, agents);
24
+ const claudePath = join(root, "CLAUDE.md");
25
+ const claude = existsSync(claudePath) ? readFileSync(claudePath, "utf8") : "";
26
+ const imports = ["@AGENTS.md", `@${GUIDE}`].filter((line) => !claude.split("\n").includes(line));
27
+ if (imports.length > 0) {
28
+ writeFileSync(claudePath, `${claude.trimEnd()}${claude === "" ? "" : "\n"}${imports.join("\n")}\n`);
29
+ }
30
+ return [
31
+ `${existing === "" ? "created" : "updated"} AGENTS.md`,
32
+ imports.length > 0
33
+ ? `${claude === "" ? "created" : "updated"} CLAUDE.md`
34
+ : "CLAUDE.md already imports the guide",
35
+ ];
36
+ }
37
+ const section = `## Building with brisk
38
+
39
+ This app uses [brisk](https://www.npmjs.com/package/${PACKAGE}), a typed layer over Express 5 and Zod.
40
+ Before writing or changing server code, read the full guide: \`${GUIDE}\`.
41
+
42
+ Essentials:
43
+
44
+ - The app is declared once in \`src/app.ts\` with \`defineApp\`; \`app.listen(port)\` runs it, \`createTestClient(app, { providers })\` tests it.
45
+ - Routes are named: a controller's setup returns \`{ list: route.get(...), create: route.post(...) }\`. The names form the typed client (\`api.users.create({ body })\`).
46
+ - Validate every input with a Zod schema on the route; set \`response\` to a DTO schema so internal fields never leak.
47
+ - New code follows this project's own templates: \`npx brisk g feature <name>\` renders \`templates/feature/\`. Edit the templates when the project's conventions change.
48
+ - Dependencies: \`readonly #repo = inject(Repository)\` in class fields. No decorators, no constructor wiring.
49
+ - Errors: \`throw new NotFoundError("…")\` (or another error class) anywhere. Never try/catch to build responses; never call \`next()\`.
50
+ - Shared request logic: \`defineMiddleware\` returning an object types \`ctx\`; declare \`params\` or \`query\` it reads to get them validated first. Express middleware such as multer goes in a route's \`use\` through \`fromExpress()\`.
51
+ - App-wide middleware goes in \`defineApp({ use })\` (\`fromExpress(cors())\` included); handlers that are not brisk routes (static files, GraphQL, webhooks) go in \`defineApp({ mount })\`. Express settings go in \`http.settings\`.
52
+ - Long-lived work (WebSockets, jobs, consumers, pools) is a provider class with \`onInit\`, \`onReady\`, \`onDrain\`, \`onShutdown\`; a feature lists its own in \`defineController({ providers })\`.
53
+ - Test with \`createTestClient\` from \`${PACKAGE}/testing\`: \`api.call.<controller>.<route>(input)\` is typed; \`api.post(path)\` checks raw HTTP.
54
+ `;
55
+ //# sourceMappingURL=agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents.js","sourceRoot":"","sources":["../../../src/cli/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtC,MAAM,KAAK,GAAG,gBAAgB,OAAO,YAAY,CAAC;AAClD,MAAM,KAAK,GAAG,sBAAsB,CAAC;AACrC,MAAM,GAAG,GAAG,oBAAoB,CAAC;AAEjC;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,GAAG,KAAK,KAAK,OAAO,KAAK,GAAG,EAAE,CAAC;IAC7C,MAAM,QAAQ,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAChF,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,MAAM,GACV,KAAK,KAAK,CAAC,CAAC,IAAI,GAAG,GAAG,KAAK;QACzB,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC;QACrE,CAAC,CAAC,QAAQ,KAAK,EAAE;YACf,CAAC,CAAC,kBAAkB,KAAK,IAAI;YAC7B,CAAC,CAAC,GAAG,QAAQ,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C,aAAa,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAElC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9E,MAAM,OAAO,GAAG,CAAC,YAAY,EAAE,IAAI,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IACjG,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,aAAa,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,OAAO,EAAE,GAAG,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtG,CAAC;IAED,OAAO;QACL,GAAG,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,YAAY;QACtD,OAAO,CAAC,MAAM,GAAG,CAAC;YAChB,CAAC,CAAC,GAAG,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,YAAY;YACtD,CAAC,CAAC,qCAAqC;KAC1C,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,GAAG;;sDAEsC,OAAO;iEACI,KAAK;;;;;;;;;;;;;0CAa5B,OAAO;CAChD,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { type CliIo } from "./system.ts";
2
+ export type { CliIo } from "./system.ts";
3
+ /** Entry point of the \`brisk\` binary; resolves with the exit code. */
4
+ export declare function runCli(argv: readonly string[], root: string, io?: CliIo): Promise<number>;
5
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../../src/cli/cli.ts"],"names":[],"mappings":"AAQA,OAAO,EAAoB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAE3D,YAAY,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAmBzC,wEAAwE;AACxE,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAE,KAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CA6DxG"}
@@ -0,0 +1,113 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { relative } from "node:path";
3
+ import { parseArgs } from "node:util";
4
+ import { writeAgentGuides } from "./agents.js";
5
+ import { generateClient, generateOpenApi } from "./client.js";
6
+ import { initProject, listStarters } from "./init.js";
7
+ import { toNames } from "./names.js";
8
+ import { renderTemplates } from "./render.js";
9
+ import { CliError, format } from "./system.js";
10
+ const USAGE = `Usage: brisk <command> [options]
11
+
12
+ Commands:
13
+ init Start a project here from a starter; never overwrites files
14
+ --starter <name> Which starter (default: minimal); \`brisk init --starter list\` shows them
15
+ --pm <pnpm|npm|yarn> Package manager (default: detected)
16
+ --no-install Print the install command instead of running it
17
+ g <kind> <name> Render the project's templates/<kind>/ for <name>, such as \`g feature notes\`
18
+ client --out <file> Write the route manifest for a frontend's typed client
19
+ openapi --out <file> Write the OpenAPI 3.1 document built from the routes' schemas
20
+ --app <file> Module exporting the app, for client and openapi (default src/app.ts)
21
+ agents Add or refresh the brisk guide for AI coding agents (AGENTS.md, CLAUDE.md)
22
+ help, --version
23
+
24
+ Run from the app's root. A starter brings its own choices (database, auth, tooling) and the templates that
25
+ \`brisk g\` renders; the templates are files in your project, yours to edit.`;
26
+ /** Entry point of the \`brisk\` binary; resolves with the exit code. */
27
+ export async function runCli(argv, root, io = console) {
28
+ try {
29
+ const { values, positionals } = parseArgs({
30
+ args: [...argv],
31
+ allowPositionals: true,
32
+ allowNegative: true,
33
+ options: {
34
+ starter: { type: "string", default: "minimal" },
35
+ pm: { type: "string" },
36
+ install: { type: "boolean", default: true },
37
+ out: { type: "string" },
38
+ app: { type: "string", default: "src/app.ts" },
39
+ help: { type: "boolean", short: "h", default: false },
40
+ version: { type: "boolean", default: false },
41
+ },
42
+ });
43
+ const [command, kind, name] = positionals;
44
+ if (values.version) {
45
+ io.log(version());
46
+ return 0;
47
+ }
48
+ if (values.help || command === "help" || command === undefined) {
49
+ io.log(USAGE);
50
+ return command === undefined && !values.help ? 1 : 0;
51
+ }
52
+ if (command === "init") {
53
+ if (values.starter === "list") {
54
+ io.log(`Starters: ${listStarters().join(", ")}`);
55
+ return 0;
56
+ }
57
+ for (const line of initProject(root, values, io))
58
+ io.log(line);
59
+ return 0;
60
+ }
61
+ if (command === "agents") {
62
+ for (const line of writeAgentGuides(root))
63
+ io.log(line);
64
+ return 0;
65
+ }
66
+ if (command === "client" || command === "openapi") {
67
+ if (!values.out)
68
+ throw new CliError(`brisk ${command} needs --out <file>`);
69
+ const generate = command === "client" ? generateClient : generateOpenApi;
70
+ for (const line of await generate(root, { app: values.app, out: values.out }))
71
+ io.log(line);
72
+ return 0;
73
+ }
74
+ if ((command !== "g" && command !== "generate") || !kind || !name)
75
+ throw new CliError(USAGE);
76
+ const rendered = renderTemplates(root, kind, toNames(name));
77
+ for (const file of rendered.created)
78
+ io.log(`created ${relative(root, file)}`);
79
+ for (const file of rendered.updated)
80
+ io.log(`updated ${relative(root, file)}`);
81
+ const formatted = format(root, [...rendered.created, ...rendered.updated]);
82
+ if (formatted)
83
+ io.log(formatted);
84
+ return 0;
85
+ }
86
+ catch (error) {
87
+ if (error instanceof CliError) {
88
+ io.error(error.message);
89
+ return 1;
90
+ }
91
+ if (error instanceof TypeError && "code" in error && String(error.code).startsWith("ERR_PARSE_ARGS")) {
92
+ io.error(`${error.message}\n\n${USAGE}`);
93
+ return 1;
94
+ }
95
+ throw error;
96
+ }
97
+ }
98
+ /** The installed brisk version: the nearest `package.json` above this file, in sources and in `dist` alike. */
99
+ function version() {
100
+ for (let dir = new URL(".", import.meta.url); dir.pathname !== "/"; dir = new URL("..", dir)) {
101
+ try {
102
+ const pkg = JSON.parse(readFileSync(new URL("package.json", dir), "utf8"));
103
+ const value = typeof pkg === "object" && pkg !== null ? Reflect.get(pkg, "version") : undefined;
104
+ if (typeof value === "string")
105
+ return value;
106
+ }
107
+ catch {
108
+ continue;
109
+ }
110
+ }
111
+ return "unknown";
112
+ }
113
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/cli/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ interface Target {
2
+ /** The module exporting `app` (made with `defineApp`), relative to the project root. */
3
+ app: string;
4
+ /** The file to write, relative to the project root. */
5
+ out: string;
6
+ }
7
+ /** Writes the app's route manifest as a TypeScript module, for a frontend's typed client. */
8
+ export declare function generateClient(root: string, { app, out }: Target): Promise<string[]>;
9
+ /** Writes the app's OpenAPI 3.1 document as JSON. */
10
+ export declare function generateOpenApi(root: string, { app, out }: Target): Promise<string[]>;
11
+ export {};
12
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/cli/client.ts"],"names":[],"mappings":"AAYA,UAAU,MAAM;IACd,wFAAwF;IACxF,GAAG,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,GAAG,EAAE,MAAM,CAAC;CACb;AAED,6FAA6F;AAC7F,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAW1F;AAED,qDAAqD;AACrD,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAI3F"}
@@ -0,0 +1,76 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import { existsSync } from "node:fs";
10
+ import { join, relative } from "node:path";
11
+ import { pathToFileURL } from "node:url";
12
+ import { CliError, write } from "./system.js";
13
+ /** Writes the app's route manifest as a TypeScript module, for a frontend's typed client. */
14
+ export async function generateClient(root, { app, out }) {
15
+ const { manifest } = await loadApp(root, app);
16
+ const target = write(join(root, out), `// Generated by \`brisk client\` from ${app}. Do not edit: run it again after changing routes.
17
+ import type { Manifest } from "@raiyyan/brisk/client";
18
+
19
+ export const manifest = ${serialize(manifest, "")} as const satisfies Manifest;
20
+ `);
21
+ return [`wrote ${relative(root, target)}`, "use it: createClient<Api>(manifest, { baseUrl })"];
22
+ }
23
+ /** Writes the app's OpenAPI 3.1 document as JSON. */
24
+ export async function generateOpenApi(root, { app, out }) {
25
+ const { openapi } = await loadApp(root, app);
26
+ const target = write(join(root, out), `${JSON.stringify(openapi(), null, 2)}\n`);
27
+ return [`wrote ${relative(root, target)}`];
28
+ }
29
+ /**
30
+ * Imports the app module and reads its `app` export. Nothing listens, but the module runs and the routes are
31
+ * built: the environment must be valid, as for starting the app.
32
+ */
33
+ async function loadApp(root, app) {
34
+ const source = join(root, app);
35
+ if (!existsSync(source)) {
36
+ throw new CliError(`${app} not found: pass --app <path to the module exporting app>`);
37
+ }
38
+ const module = await import(__rewriteRelativeImportExtension(pathToFileURL(source).href));
39
+ const loaded = findApp(module);
40
+ if (!loaded)
41
+ throw new CliError(`${app} must export app, made with defineApp()`);
42
+ return loaded;
43
+ }
44
+ function findApp(module) {
45
+ if (typeof module !== "object" || module === null)
46
+ return undefined;
47
+ const app = Reflect.get(module, "app");
48
+ if (typeof app !== "object" || app === null)
49
+ return undefined;
50
+ const manifest = Reflect.get(app, "manifest");
51
+ const openapi = Reflect.get(app, "openapi");
52
+ if (!isManifest(manifest))
53
+ return undefined;
54
+ return {
55
+ manifest,
56
+ openapi: () => (typeof openapi === "function" ? Reflect.apply(openapi, app, []) : {}),
57
+ };
58
+ }
59
+ /** The manifest as source, one route per line: `"get": ["GET", "/api/users/:id"],`. */
60
+ function serialize(manifest, indent) {
61
+ const inner = `${indent} `;
62
+ const lines = Object.entries(manifest).map(([name, entry]) => {
63
+ const value = isEndpoint(entry)
64
+ ? `[${entry.map((part) => JSON.stringify(part)).join(", ")}]`
65
+ : serialize(entry, inner);
66
+ return `${inner}${JSON.stringify(name)}: ${value},`;
67
+ });
68
+ return `{\n${lines.join("\n")}\n${indent}}`;
69
+ }
70
+ function isEndpoint(entry) {
71
+ return Array.isArray(entry);
72
+ }
73
+ function isManifest(value) {
74
+ return typeof value === "object" && value !== null && !Array.isArray(value);
75
+ }
76
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/cli/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { type CliIo } from "./system.ts";
2
+ /** `brisk init` flags. */
3
+ export interface InitFlags {
4
+ starter: string;
5
+ pm?: string | undefined;
6
+ install: boolean;
7
+ }
8
+ /**
9
+ * Starts a project from a starter: a complete, tested app that brings its own choices (database, auth,
10
+ * tooling) and the templates `brisk g` generates from. Files that already exist are kept; `package.json` gains
11
+ * what it lacks. Then the packages are installed and the agent guide is written.
12
+ */
13
+ export declare function initProject(root: string, flags: InitFlags, io: CliIo): string[];
14
+ /** The starters shipped with this version of brisk. */
15
+ export declare function listStarters(): string[];
16
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/init.ts"],"names":[],"mappings":"AAIA,OAAO,EAQL,KAAK,KAAK,EAEX,MAAM,aAAa,CAAC;AAErB,0BAA0B;AAC1B,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;CAClB;AAMD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,GAAG,MAAM,EAAE,CAgC/E;AAED,uDAAuD;AACvD,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAKvC"}
@@ -0,0 +1,149 @@
1
+ import { cpSync, existsSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
2
+ import { basename, dirname, join, relative } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { writeAgentGuides } from "./agents.js";
5
+ import { CliError, detectPackageManager, format, PACKAGE, PackageJson, readPackageJson, run, } from "./system.js";
6
+ /** Never copied out of a starter: installs, local data, secrets, and the guides `brisk agents` writes. */
7
+ const SKIPPED = new Set(["node_modules", "dist", "coverage", ".env", "AGENTS.md", "CLAUDE.md"]);
8
+ const SKIPPED_SUFFIXES = [".db", ".db-wal", ".db-shm", ".log"];
9
+ /**
10
+ * Starts a project from a starter: a complete, tested app that brings its own choices (database, auth,
11
+ * tooling) and the templates `brisk g` generates from. Files that already exist are kept; `package.json` gains
12
+ * what it lacks. Then the packages are installed and the agent guide is written.
13
+ */
14
+ export function initProject(root, flags, io) {
15
+ const starter = findStarter(flags.starter);
16
+ const pm = flags.pm ?? detectPackageManager(root);
17
+ if (!isPackageManager(pm))
18
+ throw new CliError(`Unknown package manager "${pm}": use pnpm, npm or yarn.`);
19
+ const lines = [];
20
+ for (const entry of readdirSync(starter)) {
21
+ if (!skipped(entry) && entry !== "package.json")
22
+ copy(join(starter, entry), join(root, published(entry)), root, lines);
23
+ }
24
+ lines.push(mergePackageJson(starter, root), ...writeAgentGuides(root));
25
+ for (const line of lines)
26
+ io.log(line);
27
+ const install = [pm, "install"];
28
+ if (!flags.install)
29
+ return [`install: ${install.join(" ")}`, "", ...nextSteps(pm)];
30
+ io.log(`$ ${install.join(" ")}`);
31
+ try {
32
+ run(install, root);
33
+ const formatted = format(root, ["package.json", "AGENTS.md", "CLAUDE.md"].map((file) => join(root, file)));
34
+ if (formatted)
35
+ io.log(formatted);
36
+ }
37
+ catch {
38
+ throw new CliError([
39
+ `The project files are in place, but \`${install.join(" ")}\` failed. Fix the cause above and run it again.`,
40
+ ...(pm === "pnpm" ? ["If pnpm blocked build scripts, review them with: pnpm approve-builds"] : []),
41
+ ].join("\n"));
42
+ }
43
+ return ["", ...nextSteps(pm)];
44
+ }
45
+ /** The starters shipped with this version of brisk. */
46
+ export function listStarters() {
47
+ const dir = startersDir();
48
+ return readdirSync(dir)
49
+ .filter((name) => statSync(join(dir, name)).isDirectory())
50
+ .toSorted();
51
+ }
52
+ /** Finds `starters/` above this file: the repository root in development, the package root once published. */
53
+ function startersDir() {
54
+ for (let dir = dirname(fileURLToPath(import.meta.url));; dir = dirname(dir)) {
55
+ if (existsSync(join(dir, "starters")))
56
+ return join(dir, "starters");
57
+ if (dirname(dir) === dir)
58
+ throw new CliError("No starters found next to this brisk installation.");
59
+ }
60
+ }
61
+ function findStarter(name) {
62
+ const path = join(startersDir(), name);
63
+ if (!/^[\w-]+$/.test(name) || !existsSync(path)) {
64
+ throw new CliError(`Unknown starter "${name}". Starters: ${listStarters().join(", ")}.`);
65
+ }
66
+ return path;
67
+ }
68
+ /**
69
+ * npm drops every `.gitignore` from a published package, so starters keep theirs as `_gitignore` and the
70
+ * project gets it back under its real name.
71
+ */
72
+ function published(name) {
73
+ return name === "_gitignore" ? ".gitignore" : name;
74
+ }
75
+ function skipped(name) {
76
+ return SKIPPED.has(name) || SKIPPED_SUFFIXES.some((suffix) => name.endsWith(suffix));
77
+ }
78
+ /** Copies a starter's file or folder into the project, keeping every file that is already there. */
79
+ function copy(source, target, root, lines) {
80
+ if (statSync(source).isDirectory()) {
81
+ for (const entry of readdirSync(source)) {
82
+ if (!skipped(entry))
83
+ copy(join(source, entry), join(target, entry), root, lines);
84
+ }
85
+ return;
86
+ }
87
+ const path = relative(root, target);
88
+ if (existsSync(target)) {
89
+ lines.push(`kept ${path}`);
90
+ return;
91
+ }
92
+ cpSync(source, target);
93
+ lines.push(`created ${path}`);
94
+ }
95
+ /**
96
+ * Gives the project's `package.json` what the starter's has and it lacks: `type`, `engines`, scripts and
97
+ * dependencies.
98
+ * The starter depends on brisk through the workspace; the project gets the version that is running.
99
+ */
100
+ function mergePackageJson(starter, root) {
101
+ const template = PackageJson.parse(JSON.parse(readFileSync(join(starter, "package.json"), "utf8")));
102
+ const project = readPackageJson(root);
103
+ const running = version();
104
+ const brisk = running === undefined ? "latest" : `^${running}`;
105
+ const pin = (deps) => Object.fromEntries(Object.entries(deps ?? {}).map(([name, range]) => [name, name === PACKAGE ? brisk : range]));
106
+ const merged = {
107
+ ...project,
108
+ name: typeof project["name"] === "string" ? project["name"] : basename(root),
109
+ type: "module",
110
+ engines: project["engines"] ?? template["engines"],
111
+ scripts: { ...template.scripts, ...withoutNpmStub(project.scripts) },
112
+ dependencies: { ...pin(template.dependencies), ...project.dependencies },
113
+ devDependencies: { ...pin(template.devDependencies), ...project.devDependencies },
114
+ };
115
+ writeFileSync(join(root, "package.json"), `${JSON.stringify(merged, null, 2)}\n`);
116
+ return project.type !== undefined && project.type !== "module"
117
+ ? `updated package.json ("type" is now "module": brisk apps are ES modules)`
118
+ : "updated package.json";
119
+ }
120
+ /** `npm init` writes a `test` script that only fails; the starter's replaces it. */
121
+ function withoutNpmStub(scripts) {
122
+ return Object.fromEntries(Object.entries(scripts ?? {}).filter(([, command]) => !command.includes("Error: no test specified")));
123
+ }
124
+ /** The running brisk's version: the nearest `package.json` named `@raiyyan/brisk` above this file. */
125
+ function version() {
126
+ for (let dir = dirname(fileURLToPath(import.meta.url));; dir = dirname(dir)) {
127
+ const path = join(dir, "package.json");
128
+ if (existsSync(path)) {
129
+ const pkg = PackageJson.parse(JSON.parse(readFileSync(path, "utf8")));
130
+ if (pkg["name"] === PACKAGE && typeof pkg["version"] === "string")
131
+ return pkg["version"];
132
+ }
133
+ if (dirname(dir) === dir)
134
+ return undefined;
135
+ }
136
+ }
137
+ function isPackageManager(value) {
138
+ return value === "pnpm" || value === "npm" || value === "yarn";
139
+ }
140
+ function nextSteps(pm) {
141
+ const exec = pm === "npm" ? "npx" : pm;
142
+ return [
143
+ "Next:",
144
+ " cp .env.example .env",
145
+ ` ${exec} brisk g feature tasks # renders templates/feature, which you own and can edit`,
146
+ ` ${pm} run dev`,
147
+ ];
148
+ }
149
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /** The spellings of a name a generator needs. */
2
+ export interface Names {
3
+ /** Folder, file and route name, as typed: `blog-posts`. */
4
+ kebab: string;
5
+ /** Controller and middleware variables, and the client's key: `blogPosts`. */
6
+ camel: string;
7
+ /** Service and repository classes: `BlogPosts`. */
8
+ pascal: string;
9
+ /** One record and its schemas: `BlogPost`, `CreateBlogPostBody`. */
10
+ entity: string;
11
+ }
12
+ /** `"BlogPosts"`, `"blog_posts"` and `"blog posts"` all give `blog-posts`, `blogPosts`, `BlogPosts`, `BlogPost`. */
13
+ export declare function toNames(raw: string): Names;
14
+ //# sourceMappingURL=names.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"names.d.ts","sourceRoot":"","sources":["../../../src/cli/names.ts"],"names":[],"mappings":"AAEA,iDAAiD;AACjD,MAAM,WAAW,KAAK;IACpB,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,oHAAoH;AACpH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAW1C"}
@@ -0,0 +1,25 @@
1
+ import { CliError } from "./system.js";
2
+ /** `"BlogPosts"`, `"blog_posts"` and `"blog posts"` all give `blog-posts`, `blogPosts`, `BlogPosts`, `BlogPost`. */
3
+ export function toNames(raw) {
4
+ const kebab = raw
5
+ .replace(/([a-z0-9])([A-Z])/g, "$1-$2")
6
+ .replace(/[\s_]+/g, "-")
7
+ .toLowerCase();
8
+ if (!/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(kebab)) {
9
+ throw new CliError(`Invalid name "${raw}": use letters, digits and dashes, starting with a letter.`);
10
+ }
11
+ const camel = kebab.replace(/-([a-z0-9])/g, (_match, char) => char.toUpperCase());
12
+ const pascal = camel.charAt(0).toUpperCase() + camel.slice(1);
13
+ return { kebab, camel, pascal, entity: singular(pascal) };
14
+ }
15
+ /** `Products` gives `Product`, `Categories` gives `Category`, `Addresses` gives `Address`; `Status` stays. */
16
+ function singular(word) {
17
+ if (/[^aeiou]ies$/.test(word))
18
+ return `${word.slice(0, -3)}y`;
19
+ if (/(ss|sh|ch|x|z|us)es$/.test(word))
20
+ return word.slice(0, -2);
21
+ if (/(ss|us|is)$/.test(word))
22
+ return word;
23
+ return word.endsWith("s") ? word.slice(0, -1) : word;
24
+ }
25
+ //# sourceMappingURL=names.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"names.js","sourceRoot":"","sources":["../../../src/cli/names.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAcvC,oHAAoH;AACpH,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,MAAM,KAAK,GAAG,GAAG;SACd,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;SACtC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,WAAW,EAAE,CAAC;IACjB,IAAI,CAAC,+BAA+B,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,QAAQ,CAAC,iBAAiB,GAAG,4DAA4D,CAAC,CAAC;IACvG,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IAC1F,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;AAC5D,CAAC;AAED,8GAA8G;AAC9G,SAAS,QAAQ,CAAC,IAAY;IAC5B,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;IAC9D,IAAI,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAChE,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACvD,CAAC"}
@@ -0,0 +1,30 @@
1
+ import type { Names } from "./names.ts";
2
+ /** What `brisk g` did: files it created, and existing files it added to. */
3
+ export interface Rendered {
4
+ created: string[];
5
+ updated: string[];
6
+ }
7
+ /** What rendering a template folder produces, before anything is written. */
8
+ export interface TemplatePlan {
9
+ /** New files, by path relative to the project root. */
10
+ files: Map<string, string>;
11
+ /** Text to add to existing files: target path relative to the root, the marker, and the text. */
12
+ inserts: {
13
+ target: string;
14
+ marker: string;
15
+ text: string;
16
+ }[];
17
+ }
18
+ /**
19
+ * Renders the project's own `templates/<kind>/` for `names`. Every file is copied with its path and contents
20
+ * rendered; `{{kebab}}`, `{{camel}}`, `{{pascal}}`, `{{snake}}`, `{{entity}}` and `{{entityCamel}}` are the
21
+ * tokens. A file named `<target>.<marker>.insert` is not copied: its text goes into the existing `<target>`,
22
+ * right before the line that holds `@brisk:<marker>`.
23
+ *
24
+ * Everything is checked before anything is written: an unknown token, a file that already exists, or a
25
+ * missing marker stops the run with nothing changed.
26
+ */
27
+ export declare function renderTemplates(root: string, kind: string, names: Names): Rendered;
28
+ /** Renders a template folder in memory: the files it creates and the text it adds, nothing written. */
29
+ export declare function planTemplates(dir: string, names: Names, root: string): TemplatePlan;
30
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/cli/render.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGxC,4EAA4E;AAC5E,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAKD,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,iGAAiG;IACjG,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC7D;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,QAAQ,CAoBlF;AAED,uGAAuG;AACvG,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,CAqBnF"}