@codecanvascollective/scaffold 0.1.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 (62) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -0
  3. package/dist/chunk-2A65KFCS.js +76 -0
  4. package/dist/chunk-2A65KFCS.js.map +1 -0
  5. package/dist/file-5IKT7CEX.js +24 -0
  6. package/dist/file-5IKT7CEX.js.map +1 -0
  7. package/dist/index.d.ts +2 -0
  8. package/dist/index.js +833 -0
  9. package/dist/index.js.map +1 -0
  10. package/package.json +70 -0
  11. package/src/templates/angular/base/angular.json.hbs +35 -0
  12. package/src/templates/angular/base/package.json.hbs +36 -0
  13. package/src/templates/angular/base/src/app/app.component.ts.hbs +19 -0
  14. package/src/templates/angular/base/src/app/app.config.ts.hbs +5 -0
  15. package/src/templates/angular/base/src/main.ts.hbs +7 -0
  16. package/src/templates/angular/base/tsconfig.json.hbs +26 -0
  17. package/src/templates/express/base/package.json.hbs +32 -0
  18. package/src/templates/express/base/src/index.ts.hbs +20 -0
  19. package/src/templates/express/base/src/middleware/errorHandler.ts.hbs +15 -0
  20. package/src/templates/express/base/src/routes/index.ts.hbs +11 -0
  21. package/src/templates/express/base/tsconfig.json.hbs +18 -0
  22. package/src/templates/express/with-prisma/prisma/schema.prisma.hbs +16 -0
  23. package/src/templates/express/with-prisma/prisma/seed.ts.hbs +27 -0
  24. package/src/templates/express/with-prisma/src/lib/db.ts.hbs +11 -0
  25. package/src/templates/fastapi/base/app/main.py.hbs +13 -0
  26. package/src/templates/fastapi/base/app/models/__init__.py.hbs +1 -0
  27. package/src/templates/fastapi/base/app/routes/__init__.py.hbs +1 -0
  28. package/src/templates/fastapi/base/pyproject.toml.hbs +8 -0
  29. package/src/templates/fastapi/base/requirements.txt.hbs +7 -0
  30. package/src/templates/nextjs/base/next.config.ts.hbs +5 -0
  31. package/src/templates/nextjs/base/package.json.hbs +33 -0
  32. package/src/templates/nextjs/base/src/app/globals.css.hbs +22 -0
  33. package/src/templates/nextjs/base/src/app/layout.tsx.hbs +19 -0
  34. package/src/templates/nextjs/base/src/app/page.tsx.hbs +8 -0
  35. package/src/templates/nextjs/base/tsconfig.json.hbs +25 -0
  36. package/src/templates/nextjs/with-auth/src/app/api/auth/[...nextauth]/route.ts.hbs +6 -0
  37. package/src/templates/nextjs/with-auth/src/lib/auth.ts.hbs +14 -0
  38. package/src/templates/nextjs/with-prisma/prisma/schema.prisma.hbs +16 -0
  39. package/src/templates/nextjs/with-prisma/prisma/seed.ts.hbs +27 -0
  40. package/src/templates/nextjs/with-prisma/src/lib/db.ts.hbs +11 -0
  41. package/src/templates/react/base/index.html.hbs +12 -0
  42. package/src/templates/react/base/package.json.hbs +36 -0
  43. package/src/templates/react/base/src/App.tsx.hbs +10 -0
  44. package/src/templates/react/base/src/index.css.hbs +17 -0
  45. package/src/templates/react/base/src/main.tsx.hbs +10 -0
  46. package/src/templates/react/base/tests/App.test.tsx.hbs +10 -0
  47. package/src/templates/react/base/tsconfig.json.hbs +16 -0
  48. package/src/templates/react/base/vite.config.ts.hbs +13 -0
  49. package/src/templates/react/with-shadcn/components.json.hbs +16 -0
  50. package/src/templates/react/with-shadcn/src/lib/utils.ts.hbs +6 -0
  51. package/src/templates/react/with-tailwind/postcss.config.js.hbs +6 -0
  52. package/src/templates/react/with-tailwind/src/index.css.hbs +3 -0
  53. package/src/templates/react/with-tailwind/tailwind.config.ts.hbs +9 -0
  54. package/src/templates/shared/docker/Dockerfile.hbs +42 -0
  55. package/src/templates/shared/docker/docker-compose.yml.hbs +30 -0
  56. package/src/templates/shared/eslint.config.js.hbs +17 -0
  57. package/src/templates/shared/github-ci.yml.hbs +58 -0
  58. package/src/templates/shared/gitignore.hbs +36 -0
  59. package/src/templates/shared/license.hbs +21 -0
  60. package/src/templates/shared/prettier.config.js.hbs +7 -0
  61. package/src/templates/shared/readme.md.hbs +43 -0
  62. package/src/templates/shared/tsconfig.base.json.hbs +14 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CodeCanvas Collective
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # scaffold
2
+
3
+ [![CI](https://github.com/CodeCanvasCollective/scaffold/actions/workflows/ci.yml/badge.svg)](https://github.com/CodeCanvasCollective/scaffold/actions/workflows/ci.yml)
4
+ [![npm version](https://img.shields.io/npm/v/@codecanvascollective/scaffold)](https://www.npmjs.com/package/@codecanvascollective/scaffold)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ > Interactive CLI tool for scaffolding modern full-stack projects.
8
+
9
+ Generate production-ready project structures for React, Next.js, Angular, Express, and FastAPI — with TypeScript, ESLint, Prettier, testing, and CI/CD pre-configured.
10
+
11
+ ## Quick Start
12
+
13
+ ```bash
14
+ npx @codecanvascollective/scaffold create my-app
15
+ ```
16
+
17
+ Or use quick mode to skip prompts:
18
+
19
+ ```bash
20
+ npx @codecanvascollective/scaffold create my-app --react
21
+ npx @codecanvascollective/scaffold create my-app --nextjs
22
+ npx @codecanvascollective/scaffold create my-app --express
23
+ ```
24
+
25
+ ## Supported Frameworks
26
+
27
+ | Framework | Type | Variants |
28
+ |-----------|------|----------|
29
+ | React + Vite | Frontend | Base, Tailwind, shadcn/ui |
30
+ | Next.js (App Router) | Frontend | Base, NextAuth, Prisma |
31
+ | Angular 18 | Frontend | Base |
32
+ | Express.js | Backend | Base, Prisma |
33
+ | FastAPI | Backend | Base |
34
+
35
+ ## Features
36
+
37
+ - **Interactive prompts** — guided project setup with framework, features, and config selection
38
+ - **Quick mode** — skip prompts with `--react`, `--nextjs`, `--express` flags
39
+ - **Template variants** — choose between base setup and pre-configured add-ons
40
+ - **Feature selection** — ESLint, Prettier, Tailwind, testing, Docker, GitHub Actions, and more
41
+ - **Plugin system** — extend with custom templates and hooks
42
+ - **Multiple package managers** — npm, yarn, or pnpm
43
+
44
+ ## Commands
45
+
46
+ ```bash
47
+ scaffold create <name> # Interactive project creation
48
+ scaffold create <name> --react # Quick mode (skip prompts)
49
+ scaffold create <name> -y # Use all defaults
50
+ scaffold create <name> --from config.json # From config file
51
+ scaffold list # List available templates
52
+ scaffold doctor # Check system dependencies
53
+ scaffold --version # Show version
54
+ scaffold --help # Show help
55
+ ```
56
+
57
+ ## Contributing
58
+
59
+ See [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for development setup and contribution guidelines.
60
+
61
+ ## Plugin System
62
+
63
+ Extend scaffold with custom plugins. See [docs/PLUGIN_GUIDE.md](docs/PLUGIN_GUIDE.md).
64
+
65
+ ## License
66
+
67
+ MIT — [CodeCanvas Collective](https://codecanvascollective.com)
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/utils/file.ts
4
+ import path from "path";
5
+ import fs from "fs-extra";
6
+ import Handlebars from "handlebars";
7
+ import { fileURLToPath } from "url";
8
+ var __filename = fileURLToPath(import.meta.url);
9
+ var __dirname = path.dirname(__filename);
10
+ Handlebars.registerHelper("eq", (a, b) => a === b);
11
+ Handlebars.registerHelper("neq", (a, b) => a !== b);
12
+ Handlebars.registerHelper("or", (a, b) => a || b);
13
+ Handlebars.registerHelper("and", (a, b) => a && b);
14
+ Handlebars.registerHelper("lowercase", (str) => str?.toLowerCase());
15
+ Handlebars.registerHelper("year", () => (/* @__PURE__ */ new Date()).getFullYear());
16
+ Handlebars.registerHelper(
17
+ "join",
18
+ (arr, sep) => Array.isArray(arr) ? arr.join(typeof sep === "string" ? sep : ", ") : ""
19
+ );
20
+ function getTemplatesDir() {
21
+ const isBundled = __dirname.replace(/\\/g, "/").endsWith("/dist") || __dirname.replace(/\\/g, "/").includes("/dist/");
22
+ const projectRoot = isBundled ? path.resolve(__dirname, "..") : path.resolve(__dirname, "..", "..");
23
+ return path.resolve(projectRoot, "src", "templates");
24
+ }
25
+ async function createDir(dirPath) {
26
+ await fs.ensureDir(dirPath);
27
+ }
28
+ async function writeFile(filePath, content) {
29
+ await fs.ensureDir(path.dirname(filePath));
30
+ await fs.writeFile(filePath, content, "utf-8");
31
+ }
32
+ async function copyFile(src, dest) {
33
+ await fs.ensureDir(path.dirname(dest));
34
+ await fs.copy(src, dest);
35
+ }
36
+ async function renderTemplate(templatePath, data) {
37
+ const templateContent = await fs.readFile(templatePath, "utf-8");
38
+ const template = Handlebars.compile(templateContent, { noEscape: true });
39
+ return template(data);
40
+ }
41
+ async function renderAndWrite(templatePath, outputPath, data) {
42
+ const content = await renderTemplate(templatePath, data);
43
+ await writeFile(outputPath, content);
44
+ }
45
+ async function directoryExists(dirPath) {
46
+ try {
47
+ const stat = await fs.stat(dirPath);
48
+ return stat.isDirectory();
49
+ } catch {
50
+ return false;
51
+ }
52
+ }
53
+ async function fileExists(filePath) {
54
+ try {
55
+ const stat = await fs.stat(filePath);
56
+ return stat.isFile();
57
+ } catch {
58
+ return false;
59
+ }
60
+ }
61
+ function getOutputFileName(templateName) {
62
+ return templateName.replace(/\.hbs$/, "");
63
+ }
64
+
65
+ export {
66
+ getTemplatesDir,
67
+ createDir,
68
+ writeFile,
69
+ copyFile,
70
+ renderTemplate,
71
+ renderAndWrite,
72
+ directoryExists,
73
+ fileExists,
74
+ getOutputFileName
75
+ };
76
+ //# sourceMappingURL=chunk-2A65KFCS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/file.ts"],"sourcesContent":["import path from 'node:path';\nimport fs from 'fs-extra';\nimport Handlebars from 'handlebars';\nimport { fileURLToPath } from 'node:url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n// Register custom Handlebars helpers\nHandlebars.registerHelper('eq', (a: unknown, b: unknown) => a === b);\nHandlebars.registerHelper('neq', (a: unknown, b: unknown) => a !== b);\nHandlebars.registerHelper('or', (a: unknown, b: unknown) => a || b);\nHandlebars.registerHelper('and', (a: unknown, b: unknown) => a && b);\nHandlebars.registerHelper('lowercase', (str: string) => str?.toLowerCase());\nHandlebars.registerHelper('year', () => new Date().getFullYear());\nHandlebars.registerHelper('join', (arr: string[], sep: string) =>\n Array.isArray(arr) ? arr.join(typeof sep === 'string' ? sep : ', ') : '',\n);\n\nexport function getTemplatesDir(): string {\n // When bundled with tsup, __dirname is dist/ → go up 1 level to project root\n // When running unbundled (vitest), __dirname is src/utils/ → go up 2 levels to project root\n // In both cases, templates live at <projectRoot>/src/templates\n const isBundled = __dirname.replace(/\\\\/g, '/').endsWith('/dist') ||\n __dirname.replace(/\\\\/g, '/').includes('/dist/');\n const projectRoot = isBundled\n ? path.resolve(__dirname, '..')\n : path.resolve(__dirname, '..', '..');\n return path.resolve(projectRoot, 'src', 'templates');\n}\n\nexport async function createDir(dirPath: string): Promise<void> {\n await fs.ensureDir(dirPath);\n}\n\nexport async function writeFile(filePath: string, content: string): Promise<void> {\n await fs.ensureDir(path.dirname(filePath));\n await fs.writeFile(filePath, content, 'utf-8');\n}\n\nexport async function copyFile(src: string, dest: string): Promise<void> {\n await fs.ensureDir(path.dirname(dest));\n await fs.copy(src, dest);\n}\n\nexport async function renderTemplate(templatePath: string, data: object): Promise<string> {\n const templateContent = await fs.readFile(templatePath, 'utf-8');\n const template = Handlebars.compile(templateContent, { noEscape: true });\n return template(data);\n}\n\nexport async function renderAndWrite(\n templatePath: string,\n outputPath: string,\n data: object,\n): Promise<void> {\n const content = await renderTemplate(templatePath, data);\n await writeFile(outputPath, content);\n}\n\nexport async function directoryExists(dirPath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(dirPath);\n return stat.isDirectory();\n } catch {\n return false;\n }\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(filePath);\n return stat.isFile();\n } catch {\n return false;\n }\n}\n\nexport function getOutputFileName(templateName: string): string {\n return templateName.replace(/\\.hbs$/, '');\n}\n"],"mappings":";;;AAAA,OAAO,UAAU;AACjB,OAAO,QAAQ;AACf,OAAO,gBAAgB;AACvB,SAAS,qBAAqB;AAE9B,IAAM,aAAa,cAAc,YAAY,GAAG;AAChD,IAAM,YAAY,KAAK,QAAQ,UAAU;AAGzC,WAAW,eAAe,MAAM,CAAC,GAAY,MAAe,MAAM,CAAC;AACnE,WAAW,eAAe,OAAO,CAAC,GAAY,MAAe,MAAM,CAAC;AACpE,WAAW,eAAe,MAAM,CAAC,GAAY,MAAe,KAAK,CAAC;AAClE,WAAW,eAAe,OAAO,CAAC,GAAY,MAAe,KAAK,CAAC;AACnE,WAAW,eAAe,aAAa,CAAC,QAAgB,KAAK,YAAY,CAAC;AAC1E,WAAW,eAAe,QAAQ,OAAM,oBAAI,KAAK,GAAE,YAAY,CAAC;AAChE,WAAW;AAAA,EAAe;AAAA,EAAQ,CAAC,KAAe,QAChD,MAAM,QAAQ,GAAG,IAAI,IAAI,KAAK,OAAO,QAAQ,WAAW,MAAM,IAAI,IAAI;AACxE;AAEO,SAAS,kBAA0B;AAIxC,QAAM,YAAY,UAAU,QAAQ,OAAO,GAAG,EAAE,SAAS,OAAO,KAC9D,UAAU,QAAQ,OAAO,GAAG,EAAE,SAAS,QAAQ;AACjD,QAAM,cAAc,YAChB,KAAK,QAAQ,WAAW,IAAI,IAC5B,KAAK,QAAQ,WAAW,MAAM,IAAI;AACtC,SAAO,KAAK,QAAQ,aAAa,OAAO,WAAW;AACrD;AAEA,eAAsB,UAAU,SAAgC;AAC9D,QAAM,GAAG,UAAU,OAAO;AAC5B;AAEA,eAAsB,UAAU,UAAkB,SAAgC;AAChF,QAAM,GAAG,UAAU,KAAK,QAAQ,QAAQ,CAAC;AACzC,QAAM,GAAG,UAAU,UAAU,SAAS,OAAO;AAC/C;AAEA,eAAsB,SAAS,KAAa,MAA6B;AACvE,QAAM,GAAG,UAAU,KAAK,QAAQ,IAAI,CAAC;AACrC,QAAM,GAAG,KAAK,KAAK,IAAI;AACzB;AAEA,eAAsB,eAAe,cAAsB,MAA+B;AACxF,QAAM,kBAAkB,MAAM,GAAG,SAAS,cAAc,OAAO;AAC/D,QAAM,WAAW,WAAW,QAAQ,iBAAiB,EAAE,UAAU,KAAK,CAAC;AACvE,SAAO,SAAS,IAAI;AACtB;AAEA,eAAsB,eACpB,cACA,YACA,MACe;AACf,QAAM,UAAU,MAAM,eAAe,cAAc,IAAI;AACvD,QAAM,UAAU,YAAY,OAAO;AACrC;AAEA,eAAsB,gBAAgB,SAAmC;AACvE,MAAI;AACF,UAAM,OAAO,MAAM,GAAG,KAAK,OAAO;AAClC,WAAO,KAAK,YAAY;AAAA,EAC1B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,WAAW,UAAoC;AACnE,MAAI;AACF,UAAM,OAAO,MAAM,GAAG,KAAK,QAAQ;AACnC,WAAO,KAAK,OAAO;AAAA,EACrB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,kBAAkB,cAA8B;AAC9D,SAAO,aAAa,QAAQ,UAAU,EAAE;AAC1C;","names":[]}
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ copyFile,
4
+ createDir,
5
+ directoryExists,
6
+ fileExists,
7
+ getOutputFileName,
8
+ getTemplatesDir,
9
+ renderAndWrite,
10
+ renderTemplate,
11
+ writeFile
12
+ } from "./chunk-2A65KFCS.js";
13
+ export {
14
+ copyFile,
15
+ createDir,
16
+ directoryExists,
17
+ fileExists,
18
+ getOutputFileName,
19
+ getTemplatesDir,
20
+ renderAndWrite,
21
+ renderTemplate,
22
+ writeFile
23
+ };
24
+ //# sourceMappingURL=file-5IKT7CEX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,2 @@
1
+
2
+ export { }