create-jen-app 0.1.0 → 0.1.1
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/dist/colors.js +92 -0
- package/dist/create.js +167 -0
- package/dist/generator.js +149 -0
- package/dist/index.js +5 -71
- package/package.json +2 -2
- package/templates/static/package.json +5 -1
package/dist/colors.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of Jen.js.
|
|
3
|
+
* Copyright (C) 2026 oopsio
|
|
4
|
+
*
|
|
5
|
+
* This program is free software: you can redistribute it and/or modify
|
|
6
|
+
* it under the terms of the GNU General Public License as published by
|
|
7
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
* (at your option) any later version.
|
|
9
|
+
*
|
|
10
|
+
* This program is distributed in the hope that it will be useful,
|
|
11
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
* GNU General Public License for more details.
|
|
14
|
+
*
|
|
15
|
+
* You should have received a copy of the GNU General Public License
|
|
16
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
// ANSI color codes for beautiful terminal output
|
|
19
|
+
export const colors = {
|
|
20
|
+
// Main colors
|
|
21
|
+
primary: (str) => `\x1b[38;2;99;102;241m${str}\x1b[0m`, // Indigo
|
|
22
|
+
accent: (str) => `\x1b[38;2;139;92;246m${str}\x1b[0m`, // Violet
|
|
23
|
+
success: (str) => `\x1b[38;2;34;197;94m${str}\x1b[0m`, // Green
|
|
24
|
+
warning: (str) => `\x1b[38;2;251;146;60m${str}\x1b[0m`, // Orange
|
|
25
|
+
error: (str) => `\x1b[38;2;239;68;68m${str}\x1b[0m`, // Red
|
|
26
|
+
// Utility colors
|
|
27
|
+
cyan: (str) => `\x1b[38;2;34;211;238m${str}\x1b[0m`,
|
|
28
|
+
magenta: (str) => `\x1b[38;2;219;39;119m${str}\x1b[0m`,
|
|
29
|
+
yellow: (str) => `\x1b[38;2;250;204;21m${str}\x1b[0m`,
|
|
30
|
+
// Text styles
|
|
31
|
+
bold: (str) => `\x1b[1m${str}\x1b[0m`,
|
|
32
|
+
dim: (str) => `\x1b[2m${str}\x1b[0m`,
|
|
33
|
+
italic: (str) => `\x1b[3m${str}\x1b[0m`,
|
|
34
|
+
underline: (str) => `\x1b[4m${str}\x1b[0m`,
|
|
35
|
+
// Background colors (dark theme)
|
|
36
|
+
bgDark: (str) => `\x1b[48;2;23;23;23m${str}\x1b[0m`,
|
|
37
|
+
bgPrimary: (str) => `\x1b[48;2;99;102;241m${str}\x1b[0m`,
|
|
38
|
+
// Reset
|
|
39
|
+
reset: "\x1b[0m",
|
|
40
|
+
};
|
|
41
|
+
export const symbols = {
|
|
42
|
+
arrow: "→",
|
|
43
|
+
check: "✓",
|
|
44
|
+
cross: "✕",
|
|
45
|
+
dot: "•",
|
|
46
|
+
star: "★",
|
|
47
|
+
sparkles: "✨",
|
|
48
|
+
rocket: "🚀",
|
|
49
|
+
folder: "📁",
|
|
50
|
+
package: "📦",
|
|
51
|
+
code: "💻",
|
|
52
|
+
};
|
|
53
|
+
export function printBanner() {
|
|
54
|
+
const banner = `
|
|
55
|
+
${colors.accent(colors.bold(`
|
|
56
|
+
██╗███████╗███╗ ██╗ █████╗ ██████╗ ██████╗
|
|
57
|
+
██║██╔════╝████╗ ██║ ██╔══██╗██╔══██╗██╔══██╗
|
|
58
|
+
██║█████╗ ██╔██╗ ██║ ███████║██████╔╝██████╔╝
|
|
59
|
+
██║██╔══╝ ██║╚██╗██║ ██╔══██║██╔═══╝ ██╔═══╝
|
|
60
|
+
██║███████╗██║ ╚████║ ██║ ██║██║ ██║
|
|
61
|
+
╚═╝╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝
|
|
62
|
+
`))}
|
|
63
|
+
|
|
64
|
+
${colors.primary(colors.bold("Create a beautiful Jen.js application"))}
|
|
65
|
+
${colors.dim("v1.0.0")}
|
|
66
|
+
`;
|
|
67
|
+
console.log(banner);
|
|
68
|
+
}
|
|
69
|
+
export function printSection(title) {
|
|
70
|
+
console.log(`\n${colors.primary(colors.bold(title))}`);
|
|
71
|
+
}
|
|
72
|
+
export function printSubsection(title) {
|
|
73
|
+
console.log(`${colors.accent(" " + title)}`);
|
|
74
|
+
}
|
|
75
|
+
export function printSuccess(message) {
|
|
76
|
+
console.log(`${colors.success(symbols.check)} ${message}`);
|
|
77
|
+
}
|
|
78
|
+
export function printInfo(message) {
|
|
79
|
+
console.log(`${colors.cyan("ℹ")} ${message}`);
|
|
80
|
+
}
|
|
81
|
+
export function printStep(step, total, message) {
|
|
82
|
+
console.log(`${colors.primary(`[${step}/${total}]`)} ${colors.bold(message)}`);
|
|
83
|
+
}
|
|
84
|
+
export function printCode(code) {
|
|
85
|
+
console.log(`\n${colors.dim(" " + code)}\n`);
|
|
86
|
+
}
|
|
87
|
+
export function printNext(steps) {
|
|
88
|
+
console.log(`\n${colors.accent(colors.bold("Next steps:"))}`);
|
|
89
|
+
steps.forEach((step, i) => {
|
|
90
|
+
console.log(` ${colors.primary(i + 1 + ".")} ${step}`);
|
|
91
|
+
});
|
|
92
|
+
}
|
package/dist/create.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of Jen.js.
|
|
3
|
+
* Copyright (C) 2026 oopsio
|
|
4
|
+
*
|
|
5
|
+
* This program is free software: you can redistribute it and/or modify
|
|
6
|
+
* it under the terms of the GNU General Public License as published by
|
|
7
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
* (at your option) any later version.
|
|
9
|
+
*
|
|
10
|
+
* This program is distributed in the hope that it will be useful,
|
|
11
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
* GNU General Public License for more details.
|
|
14
|
+
*
|
|
15
|
+
* You should have received a copy of the GNU General Public License
|
|
16
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
import fs from "fs";
|
|
19
|
+
import path from "path";
|
|
20
|
+
import { fileURLToPath } from "url";
|
|
21
|
+
import pc from "picocolors";
|
|
22
|
+
import { intro, outro, text, confirm, select, cancel, isCancel, note, spinner, } from "@clack/prompts";
|
|
23
|
+
import { copyTemplateFiles, createProjectFiles } from "./generator.js";
|
|
24
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
function validateProjectName(val) {
|
|
26
|
+
if (!val)
|
|
27
|
+
return "Project name is required";
|
|
28
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(val)) {
|
|
29
|
+
return "Project name can only contain alphanumeric characters, dots, dashes and underscores";
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
export async function createJenApp() {
|
|
34
|
+
intro(pc.cyan(pc.bold("Jen.js")) + pc.dim(" - create app"));
|
|
35
|
+
// Get project name from CLI args or prompt
|
|
36
|
+
let projectName = process.argv[2];
|
|
37
|
+
// @ts-nocheck
|
|
38
|
+
if (!projectName) {
|
|
39
|
+
const res = await text({
|
|
40
|
+
message: "Project name",
|
|
41
|
+
placeholder: "my-jen-app",
|
|
42
|
+
defaultValue: "my-jen-app",
|
|
43
|
+
validate: validateProjectName,
|
|
44
|
+
});
|
|
45
|
+
if (isCancel(res)) {
|
|
46
|
+
cancel(pc.dim("Cancelled"));
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
projectName = res;
|
|
50
|
+
}
|
|
51
|
+
const projectDir = path.resolve(process.cwd(), projectName);
|
|
52
|
+
// Check if directory exists
|
|
53
|
+
if (fs.existsSync(projectDir)) {
|
|
54
|
+
const overwrite = await confirm({
|
|
55
|
+
message: `${pc.yellow(projectName)} already exists. Overwrite?`,
|
|
56
|
+
initialValue: false,
|
|
57
|
+
});
|
|
58
|
+
if (isCancel(overwrite)) {
|
|
59
|
+
cancel(pc.dim("Cancelled"));
|
|
60
|
+
process.exit(0);
|
|
61
|
+
}
|
|
62
|
+
if (!overwrite) {
|
|
63
|
+
cancel(pc.dim("Cancelled"));
|
|
64
|
+
process.exit(0);
|
|
65
|
+
}
|
|
66
|
+
fs.rmSync(projectDir, { recursive: true, force: true });
|
|
67
|
+
}
|
|
68
|
+
note("Configuring your project", pc.magenta("Setup"));
|
|
69
|
+
// Template selection
|
|
70
|
+
const template = await select({
|
|
71
|
+
message: "Select a template",
|
|
72
|
+
options: [
|
|
73
|
+
{
|
|
74
|
+
label: `${pc.cyan("Static")} - Pure SSG with components`,
|
|
75
|
+
value: "static",
|
|
76
|
+
hint: "Fast, lightweight static sites",
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
});
|
|
80
|
+
if (isCancel(template)) {
|
|
81
|
+
cancel(pc.dim("Cancelled"));
|
|
82
|
+
process.exit(0);
|
|
83
|
+
}
|
|
84
|
+
// TypeScript
|
|
85
|
+
const typescript = await confirm({
|
|
86
|
+
message: "Use TypeScript?",
|
|
87
|
+
initialValue: true,
|
|
88
|
+
});
|
|
89
|
+
if (isCancel(typescript)) {
|
|
90
|
+
cancel(pc.dim("Cancelled"));
|
|
91
|
+
process.exit(0);
|
|
92
|
+
}
|
|
93
|
+
// Deps installation
|
|
94
|
+
const installDeps = await confirm({
|
|
95
|
+
message: "Install dependencies?",
|
|
96
|
+
initialValue: true,
|
|
97
|
+
});
|
|
98
|
+
if (isCancel(installDeps)) {
|
|
99
|
+
cancel(pc.dim("Cancelled"));
|
|
100
|
+
process.exit(0);
|
|
101
|
+
}
|
|
102
|
+
// Git initialization
|
|
103
|
+
const gitInit = await confirm({
|
|
104
|
+
message: "Initialize git repository?",
|
|
105
|
+
initialValue: true,
|
|
106
|
+
});
|
|
107
|
+
if (isCancel(gitInit)) {
|
|
108
|
+
cancel(pc.dim("Cancelled"));
|
|
109
|
+
process.exit(0);
|
|
110
|
+
}
|
|
111
|
+
const options = {
|
|
112
|
+
projectName,
|
|
113
|
+
template,
|
|
114
|
+
typescript,
|
|
115
|
+
installDeps,
|
|
116
|
+
gitInit,
|
|
117
|
+
};
|
|
118
|
+
note("Creating project files", pc.green("Generator"));
|
|
119
|
+
// Spinner for progress
|
|
120
|
+
const s = spinner();
|
|
121
|
+
// Create project structure
|
|
122
|
+
s.start("Setting up directories");
|
|
123
|
+
fs.mkdirSync(projectDir, { recursive: true });
|
|
124
|
+
s.stop(pc.green("Directories created"));
|
|
125
|
+
// Copy template files
|
|
126
|
+
s.start("Copying template files");
|
|
127
|
+
const templateDir = path.join(__dirname, "..", "templates", options.template);
|
|
128
|
+
if (fs.existsSync(templateDir)) {
|
|
129
|
+
copyTemplateFiles(templateDir, projectDir);
|
|
130
|
+
}
|
|
131
|
+
s.stop(pc.green("Template files copied"));
|
|
132
|
+
// Create project files
|
|
133
|
+
s.start("Generating configuration files");
|
|
134
|
+
createProjectFiles(projectDir, options);
|
|
135
|
+
s.stop(pc.green("Configuration files generated"));
|
|
136
|
+
// Git init
|
|
137
|
+
if (options.gitInit) {
|
|
138
|
+
s.start("Initializing git repository");
|
|
139
|
+
try {
|
|
140
|
+
const { execSync } = await import("child_process");
|
|
141
|
+
execSync("git init", { cwd: projectDir, stdio: "pipe" });
|
|
142
|
+
fs.writeFileSync(path.join(projectDir, ".gitignore"), `node_modules/
|
|
143
|
+
dist/
|
|
144
|
+
.jen/
|
|
145
|
+
.env
|
|
146
|
+
.env.local
|
|
147
|
+
.DS_Store
|
|
148
|
+
*.log
|
|
149
|
+
`);
|
|
150
|
+
s.stop(pc.green("Git repository initialized"));
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
s.stop(pc.yellow("Git initialization skipped"));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
outro(pc.green(pc.bold("✨ Your Jen.js app is ready!")));
|
|
157
|
+
const nextSteps = [
|
|
158
|
+
pc.cyan(`cd ${projectName}`),
|
|
159
|
+
installDeps
|
|
160
|
+
? pc.cyan("npm run dev") + pc.dim(" # start dev server")
|
|
161
|
+
: pc.cyan("npm install") + pc.dim(" # then npm run dev"),
|
|
162
|
+
];
|
|
163
|
+
console.log("\n" + pc.bold("Next steps:"));
|
|
164
|
+
for (const step of nextSteps)
|
|
165
|
+
console.log(" " + pc.dim("• ") + step);
|
|
166
|
+
console.log("\n" + pc.dim("Happy coding! 🎉") + "\n");
|
|
167
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of Jen.js.
|
|
3
|
+
* Copyright (C) 2026 oopsio
|
|
4
|
+
*
|
|
5
|
+
* This program is free software: you can redistribute it and/or modify
|
|
6
|
+
* it under the terms of the GNU General Public License as published by
|
|
7
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
* (at your option) any later version.
|
|
9
|
+
*
|
|
10
|
+
* This program is distributed in the hope that it will be useful,
|
|
11
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
* GNU General Public License for more details.
|
|
14
|
+
*
|
|
15
|
+
* You should have received a copy of the GNU General Public License
|
|
16
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
import fs from "fs";
|
|
19
|
+
import path from "path";
|
|
20
|
+
export function copyTemplateFiles(src, dest) {
|
|
21
|
+
if (!fs.existsSync(src)) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const files = fs.readdirSync(src);
|
|
25
|
+
for (const file of files) {
|
|
26
|
+
const srcPath = path.join(src, file);
|
|
27
|
+
const destPath = path.join(dest, file);
|
|
28
|
+
const stat = fs.statSync(srcPath);
|
|
29
|
+
if (stat.isDirectory()) {
|
|
30
|
+
fs.mkdirSync(destPath, { recursive: true });
|
|
31
|
+
copyTemplateFiles(srcPath, destPath);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
fs.copyFileSync(srcPath, destPath);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export function createProjectFiles(dir, options) {
|
|
39
|
+
// Read template's package.json if it exists
|
|
40
|
+
let templatePackageJson = {};
|
|
41
|
+
const templatePackagePath = path.join(dir, "package.json");
|
|
42
|
+
if (fs.existsSync(templatePackagePath)) {
|
|
43
|
+
const content = fs.readFileSync(templatePackagePath, "utf-8");
|
|
44
|
+
templatePackageJson = JSON.parse(content);
|
|
45
|
+
}
|
|
46
|
+
// Merge with user project name
|
|
47
|
+
const packageJson = {
|
|
48
|
+
...templatePackageJson,
|
|
49
|
+
name: options.projectName.toLowerCase().replace(/\s+/g, "-"),
|
|
50
|
+
version: "0.1.0",
|
|
51
|
+
type: "module",
|
|
52
|
+
scripts: {
|
|
53
|
+
...templatePackageJson.scripts,
|
|
54
|
+
dev: "jen dev",
|
|
55
|
+
build: "jen build",
|
|
56
|
+
start: "jen start",
|
|
57
|
+
...(options.typescript && { typecheck: "tsc --noEmit" }),
|
|
58
|
+
},
|
|
59
|
+
dependencies: {
|
|
60
|
+
...templatePackageJson.dependencies,
|
|
61
|
+
"@jenjs/master": "^1.2.5",
|
|
62
|
+
},
|
|
63
|
+
devDependencies: {
|
|
64
|
+
...templatePackageJson.devDependencies,
|
|
65
|
+
...(options.typescript && {
|
|
66
|
+
"@types/node": "^22.10.0",
|
|
67
|
+
typescript: "^5.7.2",
|
|
68
|
+
}),
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
fs.writeFileSync(path.join(dir, "package.json"), JSON.stringify(packageJson, null, 2));
|
|
72
|
+
// Create tsconfig.json if TypeScript
|
|
73
|
+
if (options.typescript) {
|
|
74
|
+
const tsconfig = {
|
|
75
|
+
compilerOptions: {
|
|
76
|
+
target: "ES2022",
|
|
77
|
+
module: "ESNext",
|
|
78
|
+
moduleResolution: "node",
|
|
79
|
+
strict: true,
|
|
80
|
+
jsx: "react-jsx",
|
|
81
|
+
jsxImportSource: "preact",
|
|
82
|
+
lib: ["ES2022", "DOM", "DOM.Iterable"],
|
|
83
|
+
skipLibCheck: true,
|
|
84
|
+
forceConsistentCasingInFileNames: true,
|
|
85
|
+
resolveJsonModule: true,
|
|
86
|
+
allowImportingTsExtensions: true,
|
|
87
|
+
},
|
|
88
|
+
include: ["site/**/*"],
|
|
89
|
+
exclude: ["node_modules", "dist"],
|
|
90
|
+
};
|
|
91
|
+
fs.writeFileSync(path.join(dir, "tsconfig.json"), JSON.stringify(tsconfig, null, 2));
|
|
92
|
+
}
|
|
93
|
+
// Create README
|
|
94
|
+
const readme = `# ${options.projectName}
|
|
95
|
+
|
|
96
|
+
A beautiful Jen.js application.
|
|
97
|
+
|
|
98
|
+
## Getting Started
|
|
99
|
+
|
|
100
|
+
\`\`\`bash
|
|
101
|
+
npm install
|
|
102
|
+
npm run dev
|
|
103
|
+
\`\`\`
|
|
104
|
+
|
|
105
|
+
## Available Commands
|
|
106
|
+
|
|
107
|
+
- \`npm run dev\` - Start development server (http://localhost:3000)
|
|
108
|
+
- \`npm run build\` - Build for production
|
|
109
|
+
- \`npm run start\` - Start production server
|
|
110
|
+
${options.typescript ? "- \`npm run typecheck\` - Check TypeScript types\n" : ""}
|
|
111
|
+
|
|
112
|
+
## Project Structure
|
|
113
|
+
|
|
114
|
+
\`\`\`
|
|
115
|
+
src/
|
|
116
|
+
├── styles/ # Global styles
|
|
117
|
+
├── components/ # Preact components
|
|
118
|
+
└── routes/ # Page routes
|
|
119
|
+
dist/ # Build output
|
|
120
|
+
jen.config.ts # Jen.js configuration
|
|
121
|
+
\`\`\`
|
|
122
|
+
|
|
123
|
+
## Learn More
|
|
124
|
+
|
|
125
|
+
- [Jen.js Documentation](https://github.com/kessud2021/Jen.js)
|
|
126
|
+
- [Preact Documentation](https://preactjs.com)
|
|
127
|
+
|
|
128
|
+
## License
|
|
129
|
+
|
|
130
|
+
MIT
|
|
131
|
+
`;
|
|
132
|
+
fs.writeFileSync(path.join(dir, "README.md"), readme);
|
|
133
|
+
// Create .env.example
|
|
134
|
+
const envExample = `# Database
|
|
135
|
+
DATABASE_URL=
|
|
136
|
+
|
|
137
|
+
# API
|
|
138
|
+
API_SECRET=
|
|
139
|
+
|
|
140
|
+
# Environment
|
|
141
|
+
NODE_ENV=development
|
|
142
|
+
`;
|
|
143
|
+
fs.writeFileSync(path.join(dir, ".env.example"), envExample);
|
|
144
|
+
// Create directory structure
|
|
145
|
+
const dirs = ["site/styles", "site/components", "site/routes", "site/assets"];
|
|
146
|
+
for (const dir_path of dirs) {
|
|
147
|
+
fs.mkdirSync(path.join(dir, dir_path), { recursive: true });
|
|
148
|
+
}
|
|
149
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,72 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u255D
|
|
8
|
-
\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551
|
|
9
|
-
\u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D
|
|
10
|
-
`))}
|
|
11
|
-
|
|
12
|
-
${t.primary(t.bold("Create a beautiful Jen.js application"))}
|
|
13
|
-
${t.dim("v1.0.0")}
|
|
14
|
-
`;console.log(e)}function j(e){console.log(`
|
|
15
|
-
${t.primary(t.bold(e))}`)}function g(e){console.log(`${t.success(f.check)} ${e}`)}function h(e){console.log(`${t.cyan("\u2139")} ${e}`)}function u(e,n,i){console.log(`${t.primary(`[${e}/${n}]`)} ${t.bold(i)}`)}function w(e){console.log(`
|
|
16
|
-
${t.accent(t.bold("Next steps:"))}`),e.forEach((n,i)=>{console.log(` ${t.primary(i+1+".")} ${n}`)})}import r from"fs";import s from"path";function S(e,n){if(!r.existsSync(e))return;let i=r.readdirSync(e);for(let o of i){let c=s.join(e,o),a=s.join(n,o);r.statSync(c).isDirectory()?(r.mkdirSync(a,{recursive:!0}),S(c,a)):r.copyFileSync(c,a)}}function k(e,n){let i={},o=s.join(e,"package.json");if(r.existsSync(o)){let p=r.readFileSync(o,"utf-8");i=JSON.parse(p)}let c={...i,name:n.projectName.toLowerCase().replace(/\s+/g,"-"),version:"0.1.0",type:"module",scripts:{...i.scripts,dev:"jen dev",build:"jen build",start:"jen start",...n.typescript&&{typecheck:"tsc --noEmit"}},dependencies:{...i.dependencies,"@jenjs/master":"^1.2.5"},devDependencies:{...i.devDependencies,...n.typescript&&{"@types/node":"^22.10.0",typescript:"^5.7.2"}}};if(r.writeFileSync(s.join(e,"package.json"),JSON.stringify(c,null,2)),n.typescript){let p={compilerOptions:{target:"ES2022",module:"ESNext",moduleResolution:"node",strict:!0,jsx:"react-jsx",jsxImportSource:"preact",lib:["ES2022","DOM","DOM.Iterable"],skipLibCheck:!0,forceConsistentCasingInFileNames:!0,resolveJsonModule:!0,allowImportingTsExtensions:!0},include:["site/**/*"],exclude:["node_modules","dist"]};r.writeFileSync(s.join(e,"tsconfig.json"),JSON.stringify(p,null,2))}let a=`# ${n.projectName}
|
|
17
|
-
|
|
18
|
-
A beautiful Jen.js application.
|
|
19
|
-
|
|
20
|
-
## Getting Started
|
|
21
|
-
|
|
22
|
-
\`\`\`bash
|
|
23
|
-
npm install
|
|
24
|
-
npm run dev
|
|
25
|
-
\`\`\`
|
|
26
|
-
|
|
27
|
-
## Available Commands
|
|
28
|
-
|
|
29
|
-
- \`npm run dev\` - Start development server (http://localhost:3000)
|
|
30
|
-
- \`npm run build\` - Build for production
|
|
31
|
-
- \`npm run start\` - Start production server
|
|
32
|
-
${n.typescript?"- `npm run typecheck` - Check TypeScript types\n":""}
|
|
33
|
-
|
|
34
|
-
## Project Structure
|
|
35
|
-
|
|
36
|
-
\`\`\`
|
|
37
|
-
src/
|
|
38
|
-
\u251C\u2500\u2500 styles/ # Global styles
|
|
39
|
-
\u251C\u2500\u2500 components/ # Preact components
|
|
40
|
-
\u2514\u2500\u2500 routes/ # Page routes
|
|
41
|
-
dist/ # Build output
|
|
42
|
-
jen.config.ts # Jen.js configuration
|
|
43
|
-
\`\`\`
|
|
44
|
-
|
|
45
|
-
## Learn More
|
|
46
|
-
|
|
47
|
-
- [Jen.js Documentation](https://github.com/kessud2021/Jen.js)
|
|
48
|
-
- [Preact Documentation](https://preactjs.com)
|
|
49
|
-
|
|
50
|
-
## License
|
|
51
|
-
|
|
52
|
-
MIT
|
|
53
|
-
`;r.writeFileSync(s.join(e,"README.md"),a),r.writeFileSync(s.join(e,".env.example"),`# Database
|
|
54
|
-
DATABASE_URL=
|
|
55
|
-
|
|
56
|
-
# API
|
|
57
|
-
API_SECRET=
|
|
58
|
-
|
|
59
|
-
# Environment
|
|
60
|
-
NODE_ENV=development
|
|
61
|
-
`);let y=["site/styles","site/components","site/routes","site/assets"];for(let p of y)r.mkdirSync(s.join(e,p),{recursive:!0})}var I=b.dirname(D(import.meta.url));async function P(){v();let e=process.argv[2];e||(e=(await m({type:"text",name:"projectName",message:"Project name",initial:"my-jen-app",validate:$=>$?/^[a-zA-Z0-9._-]+$/.test($)?!0:"Project name can only contain alphanumeric characters, dots, dashes and underscores":"Project name is required"})).projectName);let n=b.resolve(process.cwd(),e);d.existsSync(n)&&((await m({type:"confirm",name:"overwrite",message:`${t.warning(e)} already exists. Overwrite?`,initial:!1})).overwrite||(console.log(`${t.dim("Cancelled")}`),process.exit(0)),d.rmSync(n,{recursive:!0})),j(`${f.sparkles} Configuring your project`);let i=await m({type:"select",name:"template",message:"Select a template",choices:[{title:`${t.accent("Static")} - Pure SSG with components`,value:"static",description:"Fast, lightweight static sites"}]}),o=await m({type:"confirm",name:"typescript",message:"Use TypeScript?",initial:!0}),c=await m({type:"confirm",name:"installDeps",message:"Install dependencies?",initial:!0}),a=await m({type:"confirm",name:"gitInit",message:"Initialize git repository?",initial:!0}),l={projectName:e,template:i.template,typescript:o.typescript,installDeps:c.installDeps,gitInit:a.gitInit};j(`${f.rocket} Creating project`),u(1,4,"Setting up directories"),d.mkdirSync(n,{recursive:!0}),g("Directories created"),u(2,4,"Copying template files");let y=b.join(I,"..","templates",l.template);if(d.existsSync(y)&&S(y,n),g("Template files copied"),u(3,4,"Generating configuration files"),k(n,l),g("Configuration files generated"),l.gitInit){u(4,4,"Initializing git repository");try{let{execSync:x}=await import("child_process");x("git init",{cwd:n,stdio:"pipe"}),d.writeFileSync(b.join(n,".gitignore"),`node_modules/
|
|
62
|
-
dist/
|
|
63
|
-
.jen/
|
|
64
|
-
.env
|
|
65
|
-
.env.local
|
|
66
|
-
.DS_Store
|
|
67
|
-
*.log
|
|
68
|
-
`),g("Git repository initialized")}catch{h("Git initialization skipped")}}console.log(`
|
|
69
|
-
${t.accent(t.bold("\u2728 Your Jen.js app is ready!"))}`);let p=[`${t.cyan(`cd ${e}`)}`,l.installDeps?`${t.cyan("npm run dev")} ${t.dim("to start development server")}`:`${t.cyan("npm install")} then ${t.cyan("npm run dev")}`];w(p),console.log(`
|
|
70
|
-
${t.dim("Happy coding! \u{1F389}")}
|
|
71
|
-
`)}P().catch(e=>{console.error(`
|
|
72
|
-
\u274C Error:`,e.message),process.exit(1)});
|
|
2
|
+
import { createJenApp } from "./create.js";
|
|
3
|
+
createJenApp().catch((error) => {
|
|
4
|
+
console.error("\n❌ Error:", error.message);
|
|
5
|
+
process.exit(1);
|
|
6
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-jen-app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Create a beautiful Jen.js application with a single command",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"tsx": "^4.7.0",
|
|
47
47
|
"typescript": "^5.7.2"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "fb883341104d6b3fc197930af24182ceccccbdef"
|
|
50
50
|
}
|
|
@@ -8,10 +8,14 @@
|
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@jenjs/master": "^1.2.5",
|
|
11
|
+
"@vue/compiler-sfc": "^3.5.28",
|
|
11
12
|
"esbuild": "^0.25.0",
|
|
13
|
+
"glob": "^13.0.5",
|
|
12
14
|
"preact": "^10.25.4",
|
|
13
15
|
"preact-render-to-string": "^6.5.13",
|
|
14
|
-
"
|
|
16
|
+
"sass": "^1.97.3",
|
|
17
|
+
"sirv": "^3.0.1",
|
|
18
|
+
"svelte": "^5.51.3"
|
|
15
19
|
},
|
|
16
20
|
"devDependencies": {
|
|
17
21
|
"@types/node": "^22.10.0",
|