create-template-project 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 +97 -0
- package/dist/cli.mjs +272 -0
- package/dist/config/dependencies.json +156 -0
- package/dist/generators/project.mjs +354 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.mjs +32 -0
- package/dist/templates/base/files/.github/workflows/node.js.yml +20 -0
- package/dist/templates/base/files/.prettierrc.json +6 -0
- package/dist/templates/base/files/AGENTS.md +5 -0
- package/dist/templates/base/files/CONTRIBUTING.md +31 -0
- package/dist/templates/base/files/README.md +23 -0
- package/dist/templates/base/files/_oxlint.config.ts +74 -0
- package/dist/templates/base/files/commitlint.config.js +1 -0
- package/dist/templates/base/files/package.json +32 -0
- package/dist/templates/base/files/tsconfig.json +42 -0
- package/dist/templates/base/files/vitest.config.ts +3 -0
- package/dist/templates/base/index.mjs +16 -0
- package/dist/templates/cli/files/package.json +14 -0
- package/dist/templates/cli/files/src/index.test.ts +5 -0
- package/dist/templates/cli/files/src/index.ts +13 -0
- package/dist/templates/cli/files/tsdown.config.ts +3 -0
- package/dist/templates/cli/index.mjs +16 -0
- package/dist/templates/fullstack/files/client/index.html +8 -0
- package/dist/templates/fullstack/files/client/package.json +10 -0
- package/dist/templates/fullstack/files/client/src/App.test.tsx +8 -0
- package/dist/templates/fullstack/files/client/src/App.tsx +50 -0
- package/dist/templates/fullstack/files/client/src/components/ProtectedRoute.tsx +21 -0
- package/dist/templates/fullstack/files/client/src/contexts/AuthContext.tsx +63 -0
- package/dist/templates/fullstack/files/client/src/main.tsx +9 -0
- package/dist/templates/fullstack/files/client/src/pages/Dashboard.tsx +39 -0
- package/dist/templates/fullstack/files/client/src/pages/Login.tsx +81 -0
- package/dist/templates/fullstack/files/client/src/trpc.ts +4 -0
- package/dist/templates/fullstack/files/client/tsdown.config.ts +3 -0
- package/dist/templates/fullstack/files/package.json +35 -0
- package/dist/templates/fullstack/files/server/package.json +10 -0
- package/dist/templates/fullstack/files/server/src/context.ts +24 -0
- package/dist/templates/fullstack/files/server/src/index.test.ts +7 -0
- package/dist/templates/fullstack/files/server/src/index.ts +32 -0
- package/dist/templates/fullstack/files/server/src/routers/_app.ts +8 -0
- package/dist/templates/fullstack/files/server/src/routers/auth.ts +29 -0
- package/dist/templates/fullstack/files/server/src/trpc.ts +18 -0
- package/dist/templates/fullstack/files/server/tsdown.config.ts +3 -0
- package/dist/templates/fullstack/index.mjs +42 -0
- package/dist/templates/webapp/files/backend/src/index.ts +17 -0
- package/dist/templates/webapp/files/frontend/index.html +9 -0
- package/dist/templates/webapp/files/frontend/src/index.ts +4 -0
- package/dist/templates/webapp/files/package.json +13 -0
- package/dist/templates/webapp/files/src/index.test.ts +5 -0
- package/dist/templates/webapp/files/tsdown.config.ts +10 -0
- package/dist/templates/webapp/index.mjs +16 -0
- package/dist/templates/webpage/files/index.html +8 -0
- package/dist/templates/webpage/files/package.json +8 -0
- package/dist/templates/webpage/files/src/index.test.ts +5 -0
- package/dist/templates/webpage/files/src/index.ts +1 -0
- package/dist/templates/webpage/index.mjs +16 -0
- package/dist/types.mjs +30 -0
- package/dist/utils/file.mjs +101 -0
- package/package.json +79 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
console.log('Hello from Browser Template!');
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
//#region src/templates/webpage/index.ts
|
|
4
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
5
|
+
const getWebpageTemplate = (_opts) => {
|
|
6
|
+
return {
|
|
7
|
+
name: "webpage",
|
|
8
|
+
dependencies: {},
|
|
9
|
+
devDependencies: {},
|
|
10
|
+
scripts: {},
|
|
11
|
+
files: [],
|
|
12
|
+
templateDir: path.resolve(__dirname, "files")
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
//#endregion
|
|
16
|
+
export { getWebpageTemplate };
|
package/dist/types.mjs
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region src/types.ts
|
|
3
|
+
const TemplateTypeSchema = z.enum([
|
|
4
|
+
"cli",
|
|
5
|
+
"webpage",
|
|
6
|
+
"webapp",
|
|
7
|
+
"fullstack"
|
|
8
|
+
]);
|
|
9
|
+
const PackageManagerSchema = z.enum([
|
|
10
|
+
"npm",
|
|
11
|
+
"pnpm",
|
|
12
|
+
"yarn"
|
|
13
|
+
]);
|
|
14
|
+
const ProjectOptionsSchema = z.object({
|
|
15
|
+
template: TemplateTypeSchema,
|
|
16
|
+
projectName: z.string().min(1, "Project name is required"),
|
|
17
|
+
packageManager: PackageManagerSchema.optional().default("npm"),
|
|
18
|
+
createGithubRepository: z.boolean().optional().default(false),
|
|
19
|
+
directory: z.string(),
|
|
20
|
+
overwrite: z.boolean().optional().default(false),
|
|
21
|
+
update: z.boolean().optional().default(false),
|
|
22
|
+
skipBuild: z.boolean().optional().default(false),
|
|
23
|
+
installDependencies: z.boolean().optional().default(false),
|
|
24
|
+
build: z.boolean().optional().default(false),
|
|
25
|
+
dev: z.boolean().optional().default(false),
|
|
26
|
+
open: z.boolean().optional().default(false),
|
|
27
|
+
silent: z.boolean().optional().default(false)
|
|
28
|
+
});
|
|
29
|
+
//#endregion
|
|
30
|
+
export { ProjectOptionsSchema };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import debugLib from "debug";
|
|
4
|
+
import { execa } from "execa";
|
|
5
|
+
//#region src/utils/file.ts
|
|
6
|
+
const debug = debugLib("create-template-project:utils:file");
|
|
7
|
+
async function getAllFiles(dirPath, arrayOfFiles = []) {
|
|
8
|
+
const files = await fs.readdir(dirPath);
|
|
9
|
+
for (const file of files) if ((await fs.stat(path.join(dirPath, file))).isDirectory()) arrayOfFiles = await getAllFiles(path.join(dirPath, file), arrayOfFiles);
|
|
10
|
+
else arrayOfFiles.push(path.join(dirPath, file));
|
|
11
|
+
return arrayOfFiles;
|
|
12
|
+
}
|
|
13
|
+
function processContent(filePath, content, opts, addedDeps) {
|
|
14
|
+
const { projectName, template } = opts;
|
|
15
|
+
let description = "";
|
|
16
|
+
switch (template) {
|
|
17
|
+
case "cli":
|
|
18
|
+
description = "A modern Node.js CLI application with TypeScript and automated tooling.";
|
|
19
|
+
break;
|
|
20
|
+
case "webpage":
|
|
21
|
+
description = "A standalone web page/application for modern browsers.";
|
|
22
|
+
break;
|
|
23
|
+
case "fullstack":
|
|
24
|
+
description = "A full-stack monorepo with an Express server and a React/MUI client.";
|
|
25
|
+
break;
|
|
26
|
+
case "webapp":
|
|
27
|
+
description = "A classic web application with an Express backend.";
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
let processed = content.replaceAll("{{projectName}}", projectName).replaceAll("{{description}}", description);
|
|
31
|
+
if (template === "webpage" && filePath === "index.html") processed = processed.replace("{{scriptSrc}}", opts.skipBuild ? "./src/index.js" : "./dist/index.js");
|
|
32
|
+
if (filePath === "CONTRIBUTING.md" && addedDeps.length > 0) {
|
|
33
|
+
processed += "\n## Dependencies\n\n";
|
|
34
|
+
const uniqueDeps = Array.from(new Set(addedDeps.map((d) => JSON.stringify(d)))).map((s) => JSON.parse(s));
|
|
35
|
+
for (const dep of uniqueDeps) processed += `- **${dep.name}**: ${dep.description}\n`;
|
|
36
|
+
}
|
|
37
|
+
if (template === "fullstack" && filePath === "tsconfig.json") {
|
|
38
|
+
processed = processed.replace(/"lib":\s*\["ESNext"\]/, "\"lib\": [\"ESNext\", \"DOM\"]");
|
|
39
|
+
processed = processed.replace(/"module":\s*"NodeNext"/, "\"module\": \"NodeNext\",\n \"jsx\": \"react-jsx\"");
|
|
40
|
+
processed = processed.replace(/"include":\s*\[\s*"src\/\*\*\/\*"\s*\]/, "\"include\": [\"client/src/**/*\", \"server/src/**/*\"]");
|
|
41
|
+
}
|
|
42
|
+
return processed;
|
|
43
|
+
}
|
|
44
|
+
function mergePackageJson(target, source) {
|
|
45
|
+
if (source.scripts) target.scripts = {
|
|
46
|
+
...target.scripts,
|
|
47
|
+
...source.scripts
|
|
48
|
+
};
|
|
49
|
+
if (source.dependencies) target.dependencies = {
|
|
50
|
+
...target.dependencies,
|
|
51
|
+
...source.dependencies
|
|
52
|
+
};
|
|
53
|
+
if (source.devDependencies) target.devDependencies = {
|
|
54
|
+
...target.devDependencies,
|
|
55
|
+
...source.devDependencies
|
|
56
|
+
};
|
|
57
|
+
if (source.workspaces) target.workspaces = source.workspaces;
|
|
58
|
+
}
|
|
59
|
+
function isSeedFile(filePath) {
|
|
60
|
+
return [
|
|
61
|
+
"src/",
|
|
62
|
+
"client/src/",
|
|
63
|
+
"server/src/",
|
|
64
|
+
"backend/src/",
|
|
65
|
+
"frontend/src/"
|
|
66
|
+
].some((dir) => filePath.startsWith(dir)) || [
|
|
67
|
+
"index.html",
|
|
68
|
+
"App.tsx",
|
|
69
|
+
"main.tsx"
|
|
70
|
+
].some((file) => filePath === file);
|
|
71
|
+
}
|
|
72
|
+
async function mergeFile(filePath, existing, template, log) {
|
|
73
|
+
debug("Merging file: %s", filePath);
|
|
74
|
+
const tempBase = filePath + ".base.tmp";
|
|
75
|
+
const tempNew = filePath + ".new.tmp";
|
|
76
|
+
try {
|
|
77
|
+
await fs.writeFile(tempNew, template);
|
|
78
|
+
await fs.writeFile(tempBase, "");
|
|
79
|
+
try {
|
|
80
|
+
await execa("git", [
|
|
81
|
+
"merge-file",
|
|
82
|
+
filePath,
|
|
83
|
+
tempBase,
|
|
84
|
+
tempNew
|
|
85
|
+
], { preferLocal: true });
|
|
86
|
+
return (await fs.readFile(filePath, "utf8")).trim() !== template.trim() ? "merged" : "updated";
|
|
87
|
+
} catch (e) {
|
|
88
|
+
if (e.exitCode === 1) return "conflict";
|
|
89
|
+
else {
|
|
90
|
+
debug("Git merge-file failed: %O", e);
|
|
91
|
+
log.error(`Failed to merge ${filePath}: ${e.message}`);
|
|
92
|
+
return "error";
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
} finally {
|
|
96
|
+
await fs.rm(tempBase, { force: true });
|
|
97
|
+
await fs.rm(tempNew, { force: true });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
101
|
+
export { getAllFiles, isSeedFile, mergeFile, mergePackageJson, processContent };
|
package/package.json
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-template-project",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Dieter Oberkofler",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"keywords": [
|
|
11
|
+
"scaffold",
|
|
12
|
+
"template",
|
|
13
|
+
"cli",
|
|
14
|
+
"typescript"
|
|
15
|
+
],
|
|
16
|
+
"bin": {
|
|
17
|
+
"create-template-project": "./dist/index.mjs"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"run-interactive": "node dist/index.mjs interactive",
|
|
21
|
+
"run-create-cli": "node dist/index.mjs create --name=my-cli --directory=./temp --template=cli --overwrite --package-manager=pnpm --build",
|
|
22
|
+
"run-create-webpage": "node dist/index.mjs create --name=my-webpage --directory=./temp --template=webpage --package-manager=pnpm --overwrite --build",
|
|
23
|
+
"run-create-webapp": "node dist/index.mjs create --name=my-webapp --directory=./temp --template=webapp --package-manager=pnpm --overwrite --build",
|
|
24
|
+
"run-create-fullstack": "node dist/index.mjs create --name=my-fullstack --directory=./temp --template=fullstack --package-manager=pnpm --overwrite --build",
|
|
25
|
+
"run-create-all": "npm run run-create-cli && npm run run-create-webpage && npm run run-create-webapp && npm run run-create-fullstack",
|
|
26
|
+
"build": "tsdown && node scripts/copy-templates.ts",
|
|
27
|
+
"dependencies-check": "node scripts/dependencies.ts",
|
|
28
|
+
"dependencies-update": "node scripts/dependencies.ts --update",
|
|
29
|
+
"lint": "tsc && oxlint --ignore-pattern \"src/templates/**/files\" && npm run prettier",
|
|
30
|
+
"prettier": "prettier --check .",
|
|
31
|
+
"prettier-write": "prettier --write .",
|
|
32
|
+
"test": "vitest run --coverage --exclude '**/*.integration.test.ts'",
|
|
33
|
+
"test:integration": "vitest run src/generators/project.integration.test.ts --fileParallelism=false --testTimeout=600000",
|
|
34
|
+
"ci": "npm run lint && npm run build && npm run test",
|
|
35
|
+
"create-changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
|
|
36
|
+
"prepare": "husky"
|
|
37
|
+
},
|
|
38
|
+
"main": "./dist/index.mjs",
|
|
39
|
+
"module": "./dist/index.mjs",
|
|
40
|
+
"types": "./dist/index.d.ts",
|
|
41
|
+
"exports": {
|
|
42
|
+
".": "./dist/index.mjs",
|
|
43
|
+
"./package.json": "./package.json"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=22"
|
|
47
|
+
},
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "git://github.com/doberkofler/create-template-project.git"
|
|
51
|
+
},
|
|
52
|
+
"homepage": "https://github.com/doberkofler/create-template-project#readme",
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@commitlint/cli": "20.4.4",
|
|
55
|
+
"@commitlint/config-conventional": "20.4.4",
|
|
56
|
+
"@types/cli-progress": "3.11.6",
|
|
57
|
+
"@types/debug": "4.1.12",
|
|
58
|
+
"@types/node": "25.5.0",
|
|
59
|
+
"@vitest/coverage-v8": "4.1.0",
|
|
60
|
+
"conventional-changelog": "^7.2.0",
|
|
61
|
+
"conventional-changelog-angular": "8.3.0",
|
|
62
|
+
"eslint-plugin-regexp": "3.1.0",
|
|
63
|
+
"husky": "9.1.7",
|
|
64
|
+
"oxlint": "1.55.0",
|
|
65
|
+
"oxlint-tsgolint": "0.16.0",
|
|
66
|
+
"pnpm": "^10.32.1",
|
|
67
|
+
"prettier": "3.8.1",
|
|
68
|
+
"tsdown": "0.21.2",
|
|
69
|
+
"typescript": "5.9.3",
|
|
70
|
+
"vitest": "4.1.0"
|
|
71
|
+
},
|
|
72
|
+
"dependencies": {
|
|
73
|
+
"@clack/prompts": "^1.1.0",
|
|
74
|
+
"commander": "14.0.3",
|
|
75
|
+
"debug": "4.4.3",
|
|
76
|
+
"execa": "^9.6.1",
|
|
77
|
+
"zod": "4.3.6"
|
|
78
|
+
}
|
|
79
|
+
}
|