@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.
- package/LICENSE +21 -0
- package/README.md +67 -0
- package/dist/chunk-2A65KFCS.js +76 -0
- package/dist/chunk-2A65KFCS.js.map +1 -0
- package/dist/file-5IKT7CEX.js +24 -0
- package/dist/file-5IKT7CEX.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +833 -0
- package/dist/index.js.map +1 -0
- package/package.json +70 -0
- package/src/templates/angular/base/angular.json.hbs +35 -0
- package/src/templates/angular/base/package.json.hbs +36 -0
- package/src/templates/angular/base/src/app/app.component.ts.hbs +19 -0
- package/src/templates/angular/base/src/app/app.config.ts.hbs +5 -0
- package/src/templates/angular/base/src/main.ts.hbs +7 -0
- package/src/templates/angular/base/tsconfig.json.hbs +26 -0
- package/src/templates/express/base/package.json.hbs +32 -0
- package/src/templates/express/base/src/index.ts.hbs +20 -0
- package/src/templates/express/base/src/middleware/errorHandler.ts.hbs +15 -0
- package/src/templates/express/base/src/routes/index.ts.hbs +11 -0
- package/src/templates/express/base/tsconfig.json.hbs +18 -0
- package/src/templates/express/with-prisma/prisma/schema.prisma.hbs +16 -0
- package/src/templates/express/with-prisma/prisma/seed.ts.hbs +27 -0
- package/src/templates/express/with-prisma/src/lib/db.ts.hbs +11 -0
- package/src/templates/fastapi/base/app/main.py.hbs +13 -0
- package/src/templates/fastapi/base/app/models/__init__.py.hbs +1 -0
- package/src/templates/fastapi/base/app/routes/__init__.py.hbs +1 -0
- package/src/templates/fastapi/base/pyproject.toml.hbs +8 -0
- package/src/templates/fastapi/base/requirements.txt.hbs +7 -0
- package/src/templates/nextjs/base/next.config.ts.hbs +5 -0
- package/src/templates/nextjs/base/package.json.hbs +33 -0
- package/src/templates/nextjs/base/src/app/globals.css.hbs +22 -0
- package/src/templates/nextjs/base/src/app/layout.tsx.hbs +19 -0
- package/src/templates/nextjs/base/src/app/page.tsx.hbs +8 -0
- package/src/templates/nextjs/base/tsconfig.json.hbs +25 -0
- package/src/templates/nextjs/with-auth/src/app/api/auth/[...nextauth]/route.ts.hbs +6 -0
- package/src/templates/nextjs/with-auth/src/lib/auth.ts.hbs +14 -0
- package/src/templates/nextjs/with-prisma/prisma/schema.prisma.hbs +16 -0
- package/src/templates/nextjs/with-prisma/prisma/seed.ts.hbs +27 -0
- package/src/templates/nextjs/with-prisma/src/lib/db.ts.hbs +11 -0
- package/src/templates/react/base/index.html.hbs +12 -0
- package/src/templates/react/base/package.json.hbs +36 -0
- package/src/templates/react/base/src/App.tsx.hbs +10 -0
- package/src/templates/react/base/src/index.css.hbs +17 -0
- package/src/templates/react/base/src/main.tsx.hbs +10 -0
- package/src/templates/react/base/tests/App.test.tsx.hbs +10 -0
- package/src/templates/react/base/tsconfig.json.hbs +16 -0
- package/src/templates/react/base/vite.config.ts.hbs +13 -0
- package/src/templates/react/with-shadcn/components.json.hbs +16 -0
- package/src/templates/react/with-shadcn/src/lib/utils.ts.hbs +6 -0
- package/src/templates/react/with-tailwind/postcss.config.js.hbs +6 -0
- package/src/templates/react/with-tailwind/src/index.css.hbs +3 -0
- package/src/templates/react/with-tailwind/tailwind.config.ts.hbs +9 -0
- package/src/templates/shared/docker/Dockerfile.hbs +42 -0
- package/src/templates/shared/docker/docker-compose.yml.hbs +30 -0
- package/src/templates/shared/eslint.config.js.hbs +17 -0
- package/src/templates/shared/github-ci.yml.hbs +58 -0
- package/src/templates/shared/gitignore.hbs +36 -0
- package/src/templates/shared/license.hbs +21 -0
- package/src/templates/shared/prettier.config.js.hbs +7 -0
- package/src/templates/shared/readme.md.hbs +43 -0
- 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
|
+
[](https://github.com/CodeCanvasCollective/scaffold/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@codecanvascollective/scaffold)
|
|
5
|
+
[](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":[]}
|
package/dist/index.d.ts
ADDED