@jxsuite/create 0.19.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/generate.js +139 -0
- package/index.js +50 -0
- package/package.json +24 -0
- package/template/gitignore +3 -0
- package/template/layouts/base.json +65 -0
- package/template/pages/index.md +7 -0
package/generate.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared project generation logic. Used by both the CLI scaffolder and the Studio server endpoint.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { mkdir, writeFile, cp } from "node:fs/promises";
|
|
6
|
+
import { join, dirname } from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { existsSync } from "node:fs";
|
|
9
|
+
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const TEMPLATE_DIR = join(__dirname, "template");
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {{
|
|
15
|
+
* name: string;
|
|
16
|
+
* description?: string;
|
|
17
|
+
* url?: string;
|
|
18
|
+
* adapter?: "static" | "cloudflare-pages" | "node" | "bun";
|
|
19
|
+
* }} ProjectOptions
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Generate a new Jx project at the given path.
|
|
24
|
+
*
|
|
25
|
+
* @param {string} destPath — absolute path to the project directory
|
|
26
|
+
* @param {ProjectOptions} opts
|
|
27
|
+
*/
|
|
28
|
+
export async function generateProject(destPath, opts) {
|
|
29
|
+
const { name, description = "", url = "", adapter = "static" } = opts;
|
|
30
|
+
|
|
31
|
+
if (existsSync(destPath)) {
|
|
32
|
+
const { readdirSync } = await import("node:fs");
|
|
33
|
+
if (readdirSync(destPath).length > 0) {
|
|
34
|
+
throw new Error(`Directory "${destPath}" is not empty`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
await mkdir(destPath, { recursive: true });
|
|
39
|
+
await mkdir(join(destPath, "components"), { recursive: true });
|
|
40
|
+
await mkdir(join(destPath, "public"), { recursive: true });
|
|
41
|
+
await mkdir(join(destPath, "content"), { recursive: true });
|
|
42
|
+
|
|
43
|
+
const projectJson = buildProjectJson({ name, description, url, adapter });
|
|
44
|
+
const packageJson = buildPackageJson({ name, description, adapter });
|
|
45
|
+
|
|
46
|
+
await Promise.all([
|
|
47
|
+
writeFile(join(destPath, "project.json"), JSON.stringify(projectJson, null, "\t") + "\n"),
|
|
48
|
+
writeFile(join(destPath, "package.json"), JSON.stringify(packageJson, null, " ") + "\n"),
|
|
49
|
+
cp(join(TEMPLATE_DIR, "gitignore"), join(destPath, ".gitignore")),
|
|
50
|
+
cp(join(TEMPLATE_DIR, "layouts"), join(destPath, "layouts"), { recursive: true }),
|
|
51
|
+
cp(join(TEMPLATE_DIR, "pages"), join(destPath, "pages"), { recursive: true }),
|
|
52
|
+
]);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @param {ProjectOptions} opts
|
|
57
|
+
*/
|
|
58
|
+
function buildProjectJson({ name, description, url, adapter }) {
|
|
59
|
+
const $head = [
|
|
60
|
+
{
|
|
61
|
+
tagName: "meta",
|
|
62
|
+
attributes: { name: "viewport", content: "width=device-width, initial-scale=1" },
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
if (description) {
|
|
67
|
+
$head.push({
|
|
68
|
+
tagName: "meta",
|
|
69
|
+
attributes: { name: "description", content: description },
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** @type {{ outDir: string; format: string; trailingSlash: string; adapter?: string }} */
|
|
74
|
+
const build = {
|
|
75
|
+
outDir: "./dist",
|
|
76
|
+
format: "directory",
|
|
77
|
+
trailingSlash: "always",
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
if (adapter && adapter !== "static") {
|
|
81
|
+
build.adapter = adapter;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
name,
|
|
86
|
+
url: url || "https://example.com",
|
|
87
|
+
defaults: {
|
|
88
|
+
layout: "./layouts/base.json",
|
|
89
|
+
lang: "en",
|
|
90
|
+
},
|
|
91
|
+
$head,
|
|
92
|
+
$media: {
|
|
93
|
+
"--": "1280px",
|
|
94
|
+
"--lg": "(max-width: 1024px)",
|
|
95
|
+
"--md": "(max-width: 768px)",
|
|
96
|
+
"--sm": "(max-width: 640px)",
|
|
97
|
+
},
|
|
98
|
+
style: {
|
|
99
|
+
margin: "0",
|
|
100
|
+
padding: "0",
|
|
101
|
+
fontFamily: "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif",
|
|
102
|
+
lineHeight: "1.6",
|
|
103
|
+
color: "#1a1a1a",
|
|
104
|
+
},
|
|
105
|
+
build,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @param {{ name: string; description?: string; adapter?: string }} opts
|
|
111
|
+
*/
|
|
112
|
+
function buildPackageJson({ name, description, adapter }) {
|
|
113
|
+
const slug = name
|
|
114
|
+
.toLowerCase()
|
|
115
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
116
|
+
.replace(/^-|-$/g, "");
|
|
117
|
+
|
|
118
|
+
/** @type {Record<string, string>} */
|
|
119
|
+
const devDependencies = {
|
|
120
|
+
"@jxsuite/compiler": "^0.19.0",
|
|
121
|
+
"@jxsuite/runtime": "^0.19.0",
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
if (adapter === "cloudflare-pages") {
|
|
125
|
+
devDependencies["wrangler"] = "^4";
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
name: slug,
|
|
130
|
+
private: true,
|
|
131
|
+
description: description || "",
|
|
132
|
+
license: "MIT",
|
|
133
|
+
scripts: {
|
|
134
|
+
build: "jx build",
|
|
135
|
+
dev: "jx dev",
|
|
136
|
+
},
|
|
137
|
+
devDependencies,
|
|
138
|
+
};
|
|
139
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Scaffold a new Jx project.
|
|
4
|
+
*
|
|
5
|
+
* Usage: bun create @jxsuite my-site
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { createInterface } from "node:readline/promises";
|
|
9
|
+
import { stdin, stdout } from "node:process";
|
|
10
|
+
import { resolve, basename } from "node:path";
|
|
11
|
+
import { generateProject } from "./generate.js";
|
|
12
|
+
|
|
13
|
+
const dest = process.argv[2];
|
|
14
|
+
if (!dest) {
|
|
15
|
+
console.error("Usage: bun create @jxsuite <directory>");
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const destPath = resolve(dest);
|
|
20
|
+
const dirName = basename(destPath);
|
|
21
|
+
|
|
22
|
+
const rl = createInterface({ input: stdin, output: stdout });
|
|
23
|
+
|
|
24
|
+
const name = (await rl.question(`Project name (${dirName}): `)) || dirName;
|
|
25
|
+
const description = await rl.question("Description: ");
|
|
26
|
+
const url = await rl.question("Production URL (https://example.com): ");
|
|
27
|
+
|
|
28
|
+
console.log(`
|
|
29
|
+
Deployment adapter:
|
|
30
|
+
1) static (default)
|
|
31
|
+
2) cloudflare-pages
|
|
32
|
+
3) node
|
|
33
|
+
4) bun
|
|
34
|
+
`);
|
|
35
|
+
const adapterChoice = await rl.question("Adapter [1]: ");
|
|
36
|
+
rl.close();
|
|
37
|
+
|
|
38
|
+
const adapterMap = { "1": "static", "2": "cloudflare-pages", "3": "node", "4": "bun" };
|
|
39
|
+
const adapter = adapterMap[adapterChoice] || "static";
|
|
40
|
+
|
|
41
|
+
await generateProject(destPath, { name, description, url, adapter });
|
|
42
|
+
|
|
43
|
+
console.log(`
|
|
44
|
+
Project created at ${destPath}
|
|
45
|
+
|
|
46
|
+
Next steps:
|
|
47
|
+
cd ${dest}
|
|
48
|
+
bun install
|
|
49
|
+
bun run dev
|
|
50
|
+
`);
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bin": {
|
|
3
|
+
"create-jxsuite": "./index.js"
|
|
4
|
+
},
|
|
5
|
+
"description": "Scaffold a new Jx project",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./index.js",
|
|
8
|
+
"./generate": "./generate.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"index.js",
|
|
12
|
+
"generate.js",
|
|
13
|
+
"template/"
|
|
14
|
+
],
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"name": "@jxsuite/create",
|
|
17
|
+
"repository": {
|
|
18
|
+
"directory": "packages/create",
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/jxsuite/jx.git"
|
|
21
|
+
},
|
|
22
|
+
"type": "module",
|
|
23
|
+
"version": "0.19.0"
|
|
24
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tagName": "div",
|
|
3
|
+
"style": {
|
|
4
|
+
"margin": "0",
|
|
5
|
+
"padding": "0",
|
|
6
|
+
"minHeight": "100vh",
|
|
7
|
+
"display": "flex",
|
|
8
|
+
"flexDirection": "column",
|
|
9
|
+
"fontFamily": "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif",
|
|
10
|
+
"lineHeight": "1.6",
|
|
11
|
+
"color": "#1a1a1a"
|
|
12
|
+
},
|
|
13
|
+
"children": [
|
|
14
|
+
{
|
|
15
|
+
"tagName": "header",
|
|
16
|
+
"style": {
|
|
17
|
+
"padding": "1rem 2rem",
|
|
18
|
+
"borderBottom": "1px solid #e5e5e5"
|
|
19
|
+
},
|
|
20
|
+
"children": [
|
|
21
|
+
{
|
|
22
|
+
"tagName": "a",
|
|
23
|
+
"attributes": { "href": "/" },
|
|
24
|
+
"style": {
|
|
25
|
+
"textDecoration": "none",
|
|
26
|
+
"fontSize": "1.25rem",
|
|
27
|
+
"fontWeight": "700",
|
|
28
|
+
"color": "#1a1a1a"
|
|
29
|
+
},
|
|
30
|
+
"children": ["My Site"]
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"tagName": "main",
|
|
36
|
+
"style": {
|
|
37
|
+
"flex": "1",
|
|
38
|
+
"maxWidth": "800px",
|
|
39
|
+
"margin": "0 auto",
|
|
40
|
+
"padding": "2rem",
|
|
41
|
+
"width": "100%"
|
|
42
|
+
},
|
|
43
|
+
"children": [
|
|
44
|
+
{ "tagName": "slot" }
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"tagName": "footer",
|
|
49
|
+
"style": {
|
|
50
|
+
"padding": "1.5rem 2rem",
|
|
51
|
+
"borderTop": "1px solid #e5e5e5",
|
|
52
|
+
"textAlign": "center",
|
|
53
|
+
"fontSize": "0.875rem",
|
|
54
|
+
"color": "#666"
|
|
55
|
+
},
|
|
56
|
+
"children": [
|
|
57
|
+
{
|
|
58
|
+
"tagName": "p",
|
|
59
|
+
"style": { "margin": "0" },
|
|
60
|
+
"children": ["Built with Jx"]
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
}
|