@mastrojs/create-mastro 0.0.9 → 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/index.js +186 -30
- package/package.json +2 -5
package/index.js
CHANGED
|
@@ -14,11 +14,15 @@ import { createWriteStream } from "node:fs";
|
|
|
14
14
|
import fs from "node:fs/promises";
|
|
15
15
|
import { join } from "node:path";
|
|
16
16
|
import { stdin, stdout } from "node:process";
|
|
17
|
+
import readline from "node:readline";
|
|
17
18
|
import { createInterface } from "node:readline/promises";
|
|
18
19
|
import { Readable } from "node:stream";
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Constants
|
|
23
|
+
*/
|
|
21
24
|
|
|
25
|
+
const userAgent = process.env.npm_config_user_agent;
|
|
22
26
|
const runtime = (() => {
|
|
23
27
|
if (typeof Deno === "object") {
|
|
24
28
|
return "deno"
|
|
@@ -31,6 +35,65 @@ const runtime = (() => {
|
|
|
31
35
|
return "node";
|
|
32
36
|
}
|
|
33
37
|
})();
|
|
38
|
+
const packageManager = (() => {
|
|
39
|
+
if (runtime === "deno") return "deno";
|
|
40
|
+
switch (userAgent?.split("/")[0]) {
|
|
41
|
+
case "pnpm": return "pnpm";
|
|
42
|
+
case "yarn": return "yarn";
|
|
43
|
+
case "bun": return "bun";
|
|
44
|
+
default: return "npm";
|
|
45
|
+
}
|
|
46
|
+
})();
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Helper Functions
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @template {string} T
|
|
55
|
+
* @param {string} question
|
|
56
|
+
* @param {T[]} options
|
|
57
|
+
* @returns {Promise<T>}
|
|
58
|
+
*/
|
|
59
|
+
const select = async (question, options) =>
|
|
60
|
+
new Promise(resolve => {
|
|
61
|
+
let index = 0;
|
|
62
|
+
|
|
63
|
+
const render = () => {
|
|
64
|
+
console.clear();
|
|
65
|
+
console.log(question);
|
|
66
|
+
options.forEach((opt, i) => {
|
|
67
|
+
console.log(i === index ? `● ${opt}` : `\x1b[2m○ ${opt}\x1b[0m`);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
render();
|
|
71
|
+
|
|
72
|
+
process.stdin.on("keypress", (_, key) => {
|
|
73
|
+
switch (key.name) {
|
|
74
|
+
case "c": {
|
|
75
|
+
if (key.ctrl) {
|
|
76
|
+
console.clear();
|
|
77
|
+
process.exit();
|
|
78
|
+
}
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
case "up": {
|
|
82
|
+
index = (index - 1 + options.length) % options.length;
|
|
83
|
+
return render();
|
|
84
|
+
}
|
|
85
|
+
case "down": {
|
|
86
|
+
index = (index + 1) % options.length;
|
|
87
|
+
return render();
|
|
88
|
+
}
|
|
89
|
+
case "return": {
|
|
90
|
+
console.clear();
|
|
91
|
+
process.stdin.removeAllListeners("keypress");
|
|
92
|
+
return resolve(options[index]);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
34
97
|
|
|
35
98
|
|
|
36
99
|
/**
|
|
@@ -66,19 +129,12 @@ const execCmd = (cmd) =>
|
|
|
66
129
|
}))
|
|
67
130
|
);
|
|
68
131
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
rl.close();
|
|
76
|
-
stdin.destroy();
|
|
77
|
-
|
|
78
|
-
if (dir) {
|
|
79
|
-
const outDir = repoName + "-main"; // this cannot be changed and is determined by the zip file
|
|
80
|
-
const zipFileName = outDir + ".zip";
|
|
81
|
-
const res = await zipFilePromise;
|
|
132
|
+
/**
|
|
133
|
+
* @param { {fetchZipPromise: Promise<Response>; zipFileName: string } } opts
|
|
134
|
+
*/
|
|
135
|
+
const unzip = async (opts) => {
|
|
136
|
+
const { fetchZipPromise, zipFileName } = opts;
|
|
137
|
+
const res = await fetchZipPromise;
|
|
82
138
|
if (res.ok && res.body) {
|
|
83
139
|
await writeFile(zipFileName, res.body);
|
|
84
140
|
}
|
|
@@ -92,30 +148,127 @@ if (dir) {
|
|
|
92
148
|
}
|
|
93
149
|
await fs.rm(zipFileName, { force: true, recursive: true });
|
|
94
150
|
|
|
95
|
-
if (unzipSuccess) {
|
|
96
|
-
|
|
151
|
+
if (!unzipSuccess) {
|
|
152
|
+
process.exit(-1);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
97
155
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
156
|
+
/**
|
|
157
|
+
* @param { string } dir
|
|
158
|
+
* @param { (dependencies: Record<string, string>) => void } cb
|
|
159
|
+
*/
|
|
160
|
+
const updateDeps = async (dir, cb) => {
|
|
161
|
+
const path = join(dir, runtime === "deno" ? "deno.json" : "package.json");
|
|
162
|
+
const json = JSON.parse(await fs.readFile(path, { encoding: "utf8" }));
|
|
163
|
+
cb(json[runtime === "deno" ? "imports" : "dependencies"]);
|
|
164
|
+
await fs.writeFile(path, JSON.stringify(json, null, 2));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* @param { string } dir
|
|
169
|
+
*/
|
|
170
|
+
const addSveltiaFiles = async (dir) => {
|
|
171
|
+
const sveltiaConfig = `# yaml-language-server: $schema=https://unpkg.com/@sveltia/cms/schema/sveltia-cms.json
|
|
172
|
+
|
|
173
|
+
backend:
|
|
174
|
+
name: github
|
|
175
|
+
repo: user/repo
|
|
176
|
+
|
|
177
|
+
media_folder: /routes/media
|
|
178
|
+
public_folder: /media
|
|
179
|
+
|
|
180
|
+
collections:
|
|
181
|
+
- name: posts
|
|
182
|
+
label: Posts
|
|
183
|
+
folder: /data/posts
|
|
184
|
+
fields:
|
|
185
|
+
- { label: Title, name: title, widget: string }
|
|
186
|
+
- { label: Body, name: body, widget: markdown }
|
|
187
|
+
`;
|
|
188
|
+
|
|
189
|
+
const sveltiaIndexHtml = `<!DOCTYPE html>
|
|
190
|
+
<html>
|
|
191
|
+
<head>
|
|
192
|
+
<meta charset="utf-8" />
|
|
193
|
+
<meta name="robots" content="noindex" />
|
|
194
|
+
<title>Sveltia CMS</title>
|
|
195
|
+
</head>
|
|
196
|
+
<body>
|
|
197
|
+
<!--
|
|
198
|
+
You can also pin a version like https://unpkg.com/@sveltia/cms@0.129.2/dist/sveltia-cms.js
|
|
199
|
+
or innstead of loading from unpkg.com, download the file into your routes folder.
|
|
200
|
+
-->
|
|
201
|
+
<script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js"></script>
|
|
202
|
+
</body>
|
|
203
|
+
</html>
|
|
204
|
+
`;
|
|
205
|
+
await fs.mkdir(join(dir, "routes", "admin"));
|
|
206
|
+
await fs.writeFile(join(dir, "routes", "admin", "config.yml"), sveltiaConfig);
|
|
207
|
+
await fs.writeFile(join(dir, "routes", "admin", "index.html"), sveltiaIndexHtml);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Main function
|
|
212
|
+
*/
|
|
213
|
+
const main = async () => {
|
|
214
|
+
const repoName = `template-basic-${runtime}`;
|
|
215
|
+
const fetchZipPromise = fetch(`https://github.com/mastrojs/${repoName}/archive/refs/heads/main.zip`);
|
|
216
|
+
|
|
217
|
+
const rl = createInterface({ input: stdin, output: stdout, crlfDelay: Infinity });
|
|
218
|
+
const dir = await rl.question("What name should we use for your new project folder?\n");
|
|
219
|
+
if (dir) {
|
|
220
|
+
readline.emitKeypressEvents(process.stdin);
|
|
221
|
+
process.stdin.setRawMode(true);
|
|
222
|
+
|
|
223
|
+
const template = await select("Which template do you want to start with?", ["basic", "blog"]);
|
|
224
|
+
const templateFetchZipPromise = template === "basic"
|
|
225
|
+
? undefined
|
|
226
|
+
: fetch(`https://github.com/mastrojs/mastro/archive/refs/heads/main.zip`);
|
|
227
|
+
|
|
228
|
+
const addSveltia = template === "blog"
|
|
229
|
+
? await select(
|
|
230
|
+
"Do you want to add a git-based CMS? This adds a routes/admin/ folder.",
|
|
231
|
+
["No", "Add Sveltia CMS"],
|
|
232
|
+
) === "Add Sveltia CMS"
|
|
233
|
+
: false;
|
|
234
|
+
|
|
235
|
+
const zipOutDir = repoName + "-main"; // cannot be changed and is determined by the zip file
|
|
236
|
+
await unzip({ fetchZipPromise, zipFileName: zipOutDir + ".zip" });
|
|
237
|
+
await fs.rename(zipOutDir, dir);
|
|
106
238
|
|
|
107
239
|
if (packageManager === "npm") {
|
|
108
240
|
try {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
await fs.writeFile(path, JSON.stringify(packageJson, null, 2));
|
|
241
|
+
await updateDeps(dir, dependencies => {
|
|
242
|
+
dependencies["@mastrojs/mastro"] = "npm:@jsr/mastrojs__mastro@^0";
|
|
243
|
+
});
|
|
113
244
|
await fs.writeFile(join(dir, ".npmrc"), "@jsr:registry=https://npm.jsr.io");
|
|
114
245
|
} catch (e) {
|
|
115
246
|
console.error(`Created folder ${dir} but failed to patch it for npm. Please use pnpm instead.`);
|
|
116
247
|
}
|
|
117
248
|
}
|
|
118
249
|
|
|
250
|
+
if (templateFetchZipPromise) {
|
|
251
|
+
// Update dir with things from @mastrojs/mastro's `examples/blog/` folder.
|
|
252
|
+
const templateOutDir = "mastro-main"; // determined by zip file
|
|
253
|
+
await unzip({ fetchZipPromise: templateFetchZipPromise, zipFileName: templateOutDir + ".zip" });
|
|
254
|
+
|
|
255
|
+
await Promise.all(["components", "data", "routes"].map(async folder => {
|
|
256
|
+
await fs.rm(join(dir, folder), { recursive: true, force: true });
|
|
257
|
+
return fs.rename(join(templateOutDir, "examples", "blog", folder), join(dir, folder));
|
|
258
|
+
}));
|
|
259
|
+
await updateDeps(dir, deps => {
|
|
260
|
+
deps["@mastrojs/markdown"] = packageManager === "npm"
|
|
261
|
+
? "npm:@jsr/mastrojs__markdown@^0"
|
|
262
|
+
: "jsr:@mastrojs/markdown@^0";
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
await fs.rm(templateOutDir, { recursive: true });
|
|
266
|
+
|
|
267
|
+
if (addSveltia) {
|
|
268
|
+
await addSveltiaFiles(dir);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
119
272
|
const installInstr = runtime === "deno"
|
|
120
273
|
? ""
|
|
121
274
|
: `\n\nThen install dependencies with: ${packageManager} install\n`;
|
|
@@ -124,8 +277,7 @@ if (dir) {
|
|
|
124
277
|
: `${packageManager} run start`;
|
|
125
278
|
|
|
126
279
|
const codeStyle = "color: blue";
|
|
127
|
-
console.log(
|
|
128
|
-
`
|
|
280
|
+
console.log(`
|
|
129
281
|
Success!
|
|
130
282
|
|
|
131
283
|
Enter the newly created folder with: %ccd ${dir}${installInstr}
|
|
@@ -134,5 +286,9 @@ Enter the newly created folder with: %ccd ${dir}${installInstr}
|
|
|
134
286
|
"",
|
|
135
287
|
codeStyle,
|
|
136
288
|
);
|
|
289
|
+
|
|
290
|
+
rl.close();
|
|
291
|
+
stdin.destroy();
|
|
137
292
|
}
|
|
138
293
|
}
|
|
294
|
+
await main();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastrojs/create-mastro",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"npm-publish": "deno check && npm publish --access public"
|
|
@@ -17,8 +17,5 @@
|
|
|
17
17
|
"bugs": {
|
|
18
18
|
"url": "https://github.com/mastrojs/mastro/issues"
|
|
19
19
|
},
|
|
20
|
-
"homepage": "https://mastrojs.github.io/"
|
|
21
|
-
"volta": {
|
|
22
|
-
"node": "24.9.0"
|
|
23
|
-
}
|
|
20
|
+
"homepage": "https://mastrojs.github.io/"
|
|
24
21
|
}
|