@abcnews/aunty 17.0.0-next.4 → 17.0.0-next.6
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/CONTRIBUTING.md +19 -22
- package/README.md +37 -0
- package/TEMPLATES.md +112 -0
- package/dist/bin/aunty.js +1782 -0
- package/dist/bin/commander.js +1638 -0
- package/dist/lib/vite.js +133 -0
- package/dist/scripts/postinstall.d.ts +6 -0
- package/dist/src/bin/aunty.d.ts +9 -0
- package/dist/src/bin/commander.d.ts +5 -0
- package/dist/src/commands/build/index.d.ts +4 -0
- package/dist/src/commands/create/index.d.ts +4 -0
- package/dist/src/commands/create/types.d.ts +7 -0
- package/dist/src/commands/deploy/fs.d.ts +11 -0
- package/dist/src/commands/deploy/index.d.ts +12 -0
- package/dist/src/commands/migrate/index.d.ts +14 -0
- package/dist/src/commands/release/index.d.ts +8 -0
- package/dist/src/commands/release-check/git.d.ts +25 -0
- package/dist/src/commands/release-check/index.d.ts +9 -0
- package/dist/src/commands/serve/index.d.ts +4 -0
- package/dist/src/lib/constants.d.ts +3 -0
- package/dist/src/lib/ftp.d.ts +45 -0
- package/dist/src/lib/git.d.ts +29 -0
- package/dist/src/lib/initHelpers.d.ts +78 -0
- package/dist/src/lib/semver.d.ts +12 -0
- package/dist/src/lib/terminal.d.ts +14 -0
- package/dist/src/lib/util.d.ts +31 -0
- package/dist/src/lib/vite.d.ts +26 -0
- package/dist/src/types.d.ts +14 -0
- package/dist/templates/index.d.ts +8 -0
- package/dist/templates/svelte/base/init.d.ts +2 -0
- package/dist/templates/svelte/index.d.ts +2 -0
- package/dist/templates/svelte/patch-builder/init.d.ts +5 -0
- package/dist/templates/svelte/patch-js/init.d.ts +5 -0
- package/dist/templates/svelte/patch-odyssey/init.d.ts +2 -0
- package/dist/templates/svelte/patch-scrollyteller/init.d.ts +2 -0
- package/dist/templates/vanilla/base/init.d.ts +2 -0
- package/dist/templates/vanilla/index.d.ts +2 -0
- package/dist/templates/vanilla/patch-js/init.d.ts +5 -0
- package/eslint.config.mjs +6 -1
- package/package.json +27 -11
- package/src/bin/aunty.js +72 -0
- package/src/bin/aunty.ts +39 -52
- package/src/bin/commander.ts +174 -0
- package/src/commands/build/index.ts +23 -0
- package/src/commands/create/index.ts +148 -0
- package/src/commands/create/types.ts +7 -0
- package/src/commands/deploy/index.ts +40 -32
- package/src/commands/migrate/index.ts +320 -0
- package/src/commands/release/index.ts +127 -0
- package/src/commands/release-check/git.ts +14 -2
- package/src/commands/release-check/index.ts +139 -35
- package/src/commands/serve/index.ts +44 -0
- package/src/lib/colours.json +12 -0
- package/src/lib/constants.ts +3 -0
- package/src/{commands/deploy → lib}/ftp.ts +52 -23
- package/src/lib/git.ts +93 -0
- package/src/lib/initHelpers.ts +208 -0
- package/src/lib/semver.ts +50 -0
- package/src/lib/terminal.ts +85 -9
- package/src/lib/util.ts +66 -3
- package/src/lib/vite.ts +179 -0
- package/src/types.ts +16 -0
- package/templates/index.ts +11 -0
- package/templates/svelte/base/README.md +26 -0
- package/templates/svelte/base/contents/.editorconfig +12 -0
- package/templates/svelte/base/contents/.prettierrc +7 -0
- package/templates/svelte/base/contents/.vscode/extensions.json +3 -0
- package/templates/svelte/base/contents/LICENSE +21 -0
- package/templates/svelte/base/contents/README.md +16 -0
- package/templates/svelte/base/contents/_gitignore +24 -0
- package/templates/svelte/base/contents/index.html +22 -0
- package/templates/svelte/base/contents/package-lock.json +1373 -0
- package/templates/svelte/base/contents/package.json +29 -0
- package/templates/svelte/base/contents/src/App.svelte +21 -0
- package/templates/svelte/base/contents/src/assets/favicon.svg +4 -0
- package/templates/svelte/base/contents/src/components/Worm/Worm.svelte +59 -0
- package/templates/svelte/base/contents/src/components/Worm/worm.svg +4 -0
- package/templates/svelte/base/contents/src/iframe.ts +15 -0
- package/templates/svelte/base/contents/src/index.ts +26 -0
- package/templates/svelte/base/contents/svelte.config.js +2 -0
- package/templates/svelte/base/contents/tsconfig.app.json +22 -0
- package/templates/svelte/base/contents/tsconfig.json +7 -0
- package/templates/svelte/base/contents/tsconfig.node.json +28 -0
- package/templates/svelte/base/contents/vite-env.d.ts +7 -0
- package/templates/svelte/base/contents/vite.config.ts +40 -0
- package/templates/svelte/base/init.ts +39 -0
- package/templates/svelte/index.ts +52 -0
- package/templates/svelte/patch-builder/contents/builder/index.html +39 -0
- package/templates/svelte/patch-builder/contents/src/components/Builder/Builder.svelte +15 -0
- package/templates/svelte/patch-builder/init.ts +43 -0
- package/templates/svelte/patch-js/README.md +16 -0
- package/templates/svelte/patch-js/init.ts +61 -0
- package/templates/svelte/patch-odyssey/init.ts +10 -0
- package/templates/svelte/patch-scrollyteller/README.md +6 -0
- package/templates/svelte/patch-scrollyteller/contents/index.html +35 -0
- package/templates/svelte/patch-scrollyteller/contents/src/App.svelte +37 -0
- package/templates/svelte/patch-scrollyteller/contents/src/index.ts +36 -0
- package/templates/svelte/patch-scrollyteller/contents/src/types.ts +2 -0
- package/templates/svelte/patch-scrollyteller/init.ts +20 -0
- package/templates/vanilla/base/contents/LICENSE +21 -0
- package/templates/vanilla/base/contents/_gitignore +24 -0
- package/templates/vanilla/base/contents/index.html +22 -0
- package/templates/vanilla/base/contents/package-lock.json +999 -0
- package/templates/vanilla/base/contents/package.json +25 -0
- package/templates/vanilla/base/contents/public/favicon.svg +1 -0
- package/templates/vanilla/base/contents/public/icons.svg +24 -0
- package/templates/vanilla/base/contents/src/assets/hero.png +0 -0
- package/templates/vanilla/base/contents/src/assets/javascript.svg +1 -0
- package/templates/vanilla/base/contents/src/assets/vite.svg +1 -0
- package/templates/vanilla/base/contents/src/iframe.ts +17 -0
- package/templates/vanilla/base/contents/src/index.ts +17 -0
- package/templates/vanilla/base/contents/src/style.css +8 -0
- package/templates/vanilla/base/contents/tsconfig.app.json +23 -0
- package/templates/vanilla/base/contents/tsconfig.json +7 -0
- package/templates/vanilla/base/contents/tsconfig.node.json +28 -0
- package/templates/vanilla/base/contents/vite-env.d.ts +7 -0
- package/templates/vanilla/base/contents/vite.config.js +38 -0
- package/templates/vanilla/base/init.ts +33 -0
- package/templates/vanilla/index.ts +34 -0
- package/templates/vanilla/patch-js/README.md +0 -0
- package/templates/vanilla/patch-js/init.ts +27 -0
- package/test/helpers.ts +198 -0
- package/test/semver.test.ts +45 -0
- package/test/templates-e2e.test.ts +268 -0
- package/tsconfig.json +3 -1
|
@@ -0,0 +1,1782 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res, err) => function __init() {
|
|
5
|
+
if (err) throw err[0];
|
|
6
|
+
try {
|
|
7
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
8
|
+
} catch (e) {
|
|
9
|
+
throw err = [e], e;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// src/lib/util.ts
|
|
18
|
+
import { realpathSync } from "node:fs";
|
|
19
|
+
import { readFile } from "node:fs/promises";
|
|
20
|
+
import path from "node:path";
|
|
21
|
+
import pc from "picocolors";
|
|
22
|
+
function isLocalDevelopment() {
|
|
23
|
+
try {
|
|
24
|
+
const realDir = realpathSync(import.meta.dirname);
|
|
25
|
+
return !realDir.includes("node_modules");
|
|
26
|
+
} catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function loadJson(filePath) {
|
|
31
|
+
try {
|
|
32
|
+
const content = await readFile(filePath, "utf8");
|
|
33
|
+
return JSON.parse(content);
|
|
34
|
+
} catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function formatSize(bytes) {
|
|
39
|
+
const units = ["B", "KB", "MB", "GB"];
|
|
40
|
+
let unitIndex = 0;
|
|
41
|
+
let size = bytes;
|
|
42
|
+
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
43
|
+
size /= 1024;
|
|
44
|
+
unitIndex++;
|
|
45
|
+
}
|
|
46
|
+
const formatted = `${size.toFixed(1)}${units[unitIndex]}`;
|
|
47
|
+
if (bytes >= 1024 * 1024) {
|
|
48
|
+
return pc.yellow(formatted);
|
|
49
|
+
}
|
|
50
|
+
return pc.green(formatted);
|
|
51
|
+
}
|
|
52
|
+
async function findProjectDetails(currentDir) {
|
|
53
|
+
if (currentDir === path.parse(currentDir).root) {
|
|
54
|
+
const { log: log8 } = await import("@clack/prompts");
|
|
55
|
+
log8.error(
|
|
56
|
+
`Could not find ${pc.cyan("package.json")} in this or any parent directory.`
|
|
57
|
+
);
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
const pkgPath2 = path.join(currentDir, "package.json");
|
|
61
|
+
const pkg2 = await loadJson(pkgPath2);
|
|
62
|
+
if (pkg2) {
|
|
63
|
+
return { root: currentDir, pkg: pkg2 };
|
|
64
|
+
}
|
|
65
|
+
return findProjectDetails(path.dirname(currentDir));
|
|
66
|
+
}
|
|
67
|
+
async function runBuild(options = {}) {
|
|
68
|
+
const { stdio = "inherit" } = options;
|
|
69
|
+
const details = await findProjectDetails(process.cwd());
|
|
70
|
+
if (!details) {
|
|
71
|
+
throw new Error("Could not find project details.");
|
|
72
|
+
}
|
|
73
|
+
const { pkg: pkg2 } = details;
|
|
74
|
+
if (!pkg2.scripts?.build) {
|
|
75
|
+
throw new Error("Could not find a build script in package.json.");
|
|
76
|
+
}
|
|
77
|
+
const { $: $10 } = await import("zx");
|
|
78
|
+
await $10({ stdio })`npm run build`;
|
|
79
|
+
}
|
|
80
|
+
var init_util = __esm({
|
|
81
|
+
"src/lib/util.ts"() {
|
|
82
|
+
"use strict";
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// src/lib/constants.ts
|
|
87
|
+
var BUILD_DIRECTORY_NAME, FTP_PROJECTS_PATH, PUBLIC_PROJECTS_URL;
|
|
88
|
+
var init_constants = __esm({
|
|
89
|
+
"src/lib/constants.ts"() {
|
|
90
|
+
"use strict";
|
|
91
|
+
BUILD_DIRECTORY_NAME = "dist";
|
|
92
|
+
FTP_PROJECTS_PATH = "/www/res/sites/news-projects/";
|
|
93
|
+
PUBLIC_PROJECTS_URL = "https://www.abc.net.au/res/sites/news-projects/";
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// src/lib/ftp.ts
|
|
98
|
+
import ftp from "basic-ftp";
|
|
99
|
+
import os from "node:os";
|
|
100
|
+
import path2 from "node:path";
|
|
101
|
+
import slugify from "slugify";
|
|
102
|
+
async function getCredentials() {
|
|
103
|
+
const credentials = await loadJson(CREDENTIALS_PATH);
|
|
104
|
+
const contentftp = credentials?.contentftp;
|
|
105
|
+
if (!contentftp) {
|
|
106
|
+
throw new Error(
|
|
107
|
+
`Credentials file not found or missing 'contentftp' at ${CREDENTIALS_PATH}`
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
return contentftp;
|
|
111
|
+
}
|
|
112
|
+
async function isProjectNameAndVersionAvailable(projectName, version2, ftpClient) {
|
|
113
|
+
const client = ftpClient || new FtpClient();
|
|
114
|
+
try {
|
|
115
|
+
if (!ftpClient) {
|
|
116
|
+
await client.connect(5e3);
|
|
117
|
+
}
|
|
118
|
+
const nameSlug = slugify(
|
|
119
|
+
projectName,
|
|
120
|
+
{ strict: true }
|
|
121
|
+
);
|
|
122
|
+
const remoteDir = version2 ? path2.join(FTP_PROJECTS_PATH, nameSlug, version2, "/") : path2.join(FTP_PROJECTS_PATH, nameSlug, "/");
|
|
123
|
+
const exists = await client.exists(remoteDir);
|
|
124
|
+
return exists ? "exists" : "available";
|
|
125
|
+
} catch {
|
|
126
|
+
return "available";
|
|
127
|
+
} finally {
|
|
128
|
+
if (!ftpClient) {
|
|
129
|
+
client.close();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async function testFtpConnection(timeout = 5e3) {
|
|
134
|
+
const ftpClient = new FtpClient();
|
|
135
|
+
try {
|
|
136
|
+
await ftpClient.connect(timeout);
|
|
137
|
+
return { success: true, ftpClient };
|
|
138
|
+
} catch (err) {
|
|
139
|
+
ftpClient.close();
|
|
140
|
+
return {
|
|
141
|
+
success: false,
|
|
142
|
+
error: err instanceof Error ? err.message : String(err)
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
var CREDENTIALS_PATH, FtpClient;
|
|
147
|
+
var init_ftp = __esm({
|
|
148
|
+
"src/lib/ftp.ts"() {
|
|
149
|
+
"use strict";
|
|
150
|
+
init_util();
|
|
151
|
+
init_constants();
|
|
152
|
+
CREDENTIALS_PATH = path2.resolve(os.homedir(), ".abc-credentials");
|
|
153
|
+
FtpClient = class {
|
|
154
|
+
ftpClient;
|
|
155
|
+
ensuredDirs;
|
|
156
|
+
credentialsPromise;
|
|
157
|
+
constructor(verbose = false) {
|
|
158
|
+
this.ftpClient = new ftp.Client();
|
|
159
|
+
this.ensuredDirs = /* @__PURE__ */ new Set();
|
|
160
|
+
this.credentialsPromise = getCredentials();
|
|
161
|
+
if (verbose) {
|
|
162
|
+
this.ftpClient.ftp.verbose = true;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Connect to the FTP server
|
|
167
|
+
*/
|
|
168
|
+
async connect(timeout = 5e3) {
|
|
169
|
+
this.ftpClient.ftp.timeout = timeout;
|
|
170
|
+
const credentials = await this.credentialsPromise;
|
|
171
|
+
await this.ftpClient.access({
|
|
172
|
+
host: credentials.host,
|
|
173
|
+
user: credentials.username,
|
|
174
|
+
password: credentials.password,
|
|
175
|
+
port: Number(credentials.port) || 21,
|
|
176
|
+
secure: false
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Check if a directory exists on the remote
|
|
181
|
+
*/
|
|
182
|
+
async exists(remotePath) {
|
|
183
|
+
try {
|
|
184
|
+
const parent = path2.dirname(remotePath);
|
|
185
|
+
const name = path2.basename(remotePath);
|
|
186
|
+
const list = await this.ftpClient.list(parent);
|
|
187
|
+
return list.some((item) => item.name === name);
|
|
188
|
+
} catch {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Upload a directory to a remote path
|
|
194
|
+
*/
|
|
195
|
+
async uploadDir(localDir, remoteDir, onProgress) {
|
|
196
|
+
if (onProgress) {
|
|
197
|
+
this.ftpClient.trackProgress(onProgress);
|
|
198
|
+
}
|
|
199
|
+
await this.ftpClient.ensureDir(remoteDir);
|
|
200
|
+
await this.ftpClient.uploadFromDir(localDir);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Ensure a remote directory exists (with local caching)
|
|
204
|
+
*/
|
|
205
|
+
async ensureDir(remoteDir) {
|
|
206
|
+
if (this.ensuredDirs.has(remoteDir)) return;
|
|
207
|
+
await this.ftpClient.ensureDir(remoteDir);
|
|
208
|
+
this.ensuredDirs.add(remoteDir);
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Close the connection
|
|
212
|
+
*/
|
|
213
|
+
close() {
|
|
214
|
+
this.ftpClient.close();
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// src/lib/terminal.ts
|
|
221
|
+
import { spinner } from "@clack/prompts";
|
|
222
|
+
import pc2 from "picocolors";
|
|
223
|
+
var getColorFn, styleLogoLine, getGradientLogo, getHeader, spin, printDevColours;
|
|
224
|
+
var init_terminal = __esm({
|
|
225
|
+
"src/lib/terminal.ts"() {
|
|
226
|
+
"use strict";
|
|
227
|
+
getColorFn = (colourName) => {
|
|
228
|
+
switch (colourName) {
|
|
229
|
+
case "blue":
|
|
230
|
+
return pc2.blue;
|
|
231
|
+
case "green":
|
|
232
|
+
return pc2.green;
|
|
233
|
+
case "magenta":
|
|
234
|
+
return pc2.magenta;
|
|
235
|
+
case "yellow":
|
|
236
|
+
return pc2.yellow;
|
|
237
|
+
case "cyan":
|
|
238
|
+
return pc2.cyan;
|
|
239
|
+
case "red":
|
|
240
|
+
return pc2.red;
|
|
241
|
+
default:
|
|
242
|
+
return pc2.dim;
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
styleLogoLine = (text2, colourName, dimmedIndices) => {
|
|
246
|
+
const rainbowColors = [pc2.red, pc2.yellow, pc2.green, pc2.cyan, pc2.blue, pc2.magenta];
|
|
247
|
+
const isRainbow = colourName === "rainbow";
|
|
248
|
+
const singleColorFn = isRainbow ? null : getColorFn(colourName);
|
|
249
|
+
let rainbowIndex = 0;
|
|
250
|
+
return [...text2].map((char, index2) => {
|
|
251
|
+
if (char === " ") return char;
|
|
252
|
+
const colorFn = isRainbow ? rainbowColors[rainbowIndex++ % rainbowColors.length] : singleColorFn;
|
|
253
|
+
const colored = colorFn(char);
|
|
254
|
+
return dimmedIndices.includes(index2) ? pc2.dim(colored) : colored;
|
|
255
|
+
}).join("");
|
|
256
|
+
};
|
|
257
|
+
getGradientLogo = (colour = "rainbow") => {
|
|
258
|
+
return {
|
|
259
|
+
line1: styleLogoLine(" \u28FE\u28B7\u287E\u28B7\u287E\u28F7 ", colour, [2, 5]),
|
|
260
|
+
line2: styleLogoLine(" \u28BF\u287E\u28B7\u287E\u28B7\u287F ", colour, [3, 4])
|
|
261
|
+
};
|
|
262
|
+
};
|
|
263
|
+
getHeader = (line1 = "", line2 = "", options = {}) => {
|
|
264
|
+
const prepend = typeof options === "string" ? options : options.prepend ?? `${pc2.gray("\u2502")}`;
|
|
265
|
+
const colour = typeof options === "string" ? "rainbow" : options.colour ?? "rainbow";
|
|
266
|
+
const { line1: logoLine1, line2: logoLine2 } = getGradientLogo(colour);
|
|
267
|
+
return [
|
|
268
|
+
"",
|
|
269
|
+
`${prepend}${logoLine1} ${line1}`,
|
|
270
|
+
`${prepend}${logoLine2} ${pc2.bold(line2)}`
|
|
271
|
+
].join("\n");
|
|
272
|
+
};
|
|
273
|
+
spin = (text2 = "", frames = [
|
|
274
|
+
"\u28CF\u2800\u2800",
|
|
275
|
+
"\u285F\u2800\u2800",
|
|
276
|
+
"\u281F\u2804\u2800",
|
|
277
|
+
"\u281B\u2844\u2800",
|
|
278
|
+
"\u2819\u28C4\u2800",
|
|
279
|
+
"\u2818\u28E4\u2800",
|
|
280
|
+
"\u2810\u28E4\u2802",
|
|
281
|
+
"\u2800\u28E4\u2803",
|
|
282
|
+
"\u2800\u28E0\u280B",
|
|
283
|
+
"\u2800\u28A0\u281B",
|
|
284
|
+
"\u2800\u2820\u283B",
|
|
285
|
+
"\u2800\u2800\u28BB",
|
|
286
|
+
"\u2800\u2800\u28F9",
|
|
287
|
+
"\u2800\u2800\u28FC",
|
|
288
|
+
"\u2800\u2810\u28F4",
|
|
289
|
+
"\u2800\u2818\u28E4",
|
|
290
|
+
"\u2800\u2819\u28C4",
|
|
291
|
+
"\u2800\u281B\u2844",
|
|
292
|
+
"\u2820\u281B\u2804",
|
|
293
|
+
"\u28A0\u281B\u2800",
|
|
294
|
+
"\u28E0\u280B\u2800",
|
|
295
|
+
"\u28E4\u2803\u2800",
|
|
296
|
+
"\u28E6\u2802\u2800",
|
|
297
|
+
"\u28E7\u2800\u2800"
|
|
298
|
+
]) => {
|
|
299
|
+
const s = spinner({ frames });
|
|
300
|
+
s.start(text2);
|
|
301
|
+
return s;
|
|
302
|
+
};
|
|
303
|
+
printDevColours = () => {
|
|
304
|
+
const testColours = [
|
|
305
|
+
"rainbow",
|
|
306
|
+
"blue",
|
|
307
|
+
"green",
|
|
308
|
+
"cyan",
|
|
309
|
+
"yellow",
|
|
310
|
+
"magenta",
|
|
311
|
+
"red"
|
|
312
|
+
];
|
|
313
|
+
testColours.forEach((colour) => {
|
|
314
|
+
console.log(`
|
|
315
|
+
--- ${colour.toUpperCase()} ---`);
|
|
316
|
+
console.log(
|
|
317
|
+
getHeader("aunty", `dev-mode (${colour})`, {
|
|
318
|
+
colour
|
|
319
|
+
})
|
|
320
|
+
);
|
|
321
|
+
});
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
// src/commands/deploy/fs.ts
|
|
327
|
+
import fs from "node:fs/promises";
|
|
328
|
+
import path3 from "node:path";
|
|
329
|
+
async function getFileInventory(dirPath, baseDir = dirPath) {
|
|
330
|
+
const inventory = [];
|
|
331
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
332
|
+
for (const entry of entries) {
|
|
333
|
+
const fullPath = path3.join(dirPath, entry.name);
|
|
334
|
+
if (entry.isDirectory()) {
|
|
335
|
+
inventory.push(...await getFileInventory(fullPath, baseDir));
|
|
336
|
+
} else if (entry.isFile()) {
|
|
337
|
+
const stats = await fs.stat(fullPath);
|
|
338
|
+
inventory.push({
|
|
339
|
+
path: fullPath,
|
|
340
|
+
relPath: path3.relative(baseDir, fullPath),
|
|
341
|
+
size: stats.size
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return inventory;
|
|
346
|
+
}
|
|
347
|
+
var init_fs = __esm({
|
|
348
|
+
"src/commands/deploy/fs.ts"() {
|
|
349
|
+
"use strict";
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
// src/commands/deploy/index.ts
|
|
354
|
+
import { intro, outro, confirm, log, cancel, isCancel } from "@clack/prompts";
|
|
355
|
+
import path4 from "node:path";
|
|
356
|
+
import pc3 from "picocolors";
|
|
357
|
+
import slugify2 from "slugify";
|
|
358
|
+
async function run(options = {}) {
|
|
359
|
+
if (!options.skipHeader) {
|
|
360
|
+
intro(
|
|
361
|
+
getHeader(
|
|
362
|
+
pc3.dim("aunty"),
|
|
363
|
+
`deploy${options.dryRun ? ` ${pc3.cyan("[dry]")}` : ""}`,
|
|
364
|
+
{ colour: "red" }
|
|
365
|
+
)
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
const details = await findProjectDetails(process.cwd());
|
|
369
|
+
if (!details) return 1;
|
|
370
|
+
const { root: projectRoot, pkg: config } = details;
|
|
371
|
+
const { name, version: version2 } = config;
|
|
372
|
+
if (!name || !version2) {
|
|
373
|
+
cancel("Missing name or version in package.json");
|
|
374
|
+
return 1;
|
|
375
|
+
}
|
|
376
|
+
const localDir = path4.resolve(
|
|
377
|
+
projectRoot,
|
|
378
|
+
options.buildDir || BUILD_DIRECTORY_NAME
|
|
379
|
+
);
|
|
380
|
+
const nameSlug = slugify2(
|
|
381
|
+
name,
|
|
382
|
+
{ strict: true }
|
|
383
|
+
);
|
|
384
|
+
const targetFolder = options.destDir || version2;
|
|
385
|
+
const remoteDir = path4.join(FTP_PROJECTS_PATH, nameSlug, targetFolder, "/");
|
|
386
|
+
const publicUrl = `${PUBLIC_PROJECTS_URL}${nameSlug}/${targetFolder}/`;
|
|
387
|
+
let inventory;
|
|
388
|
+
try {
|
|
389
|
+
inventory = await getFileInventory(localDir);
|
|
390
|
+
} catch {
|
|
391
|
+
cancel(
|
|
392
|
+
`Build directory not found at ${pc3.cyan(localDir)}. Have you run the build command?`
|
|
393
|
+
);
|
|
394
|
+
return 1;
|
|
395
|
+
}
|
|
396
|
+
if (inventory.length === 0) {
|
|
397
|
+
cancel(`Build directory is empty! Nothing to deploy.`);
|
|
398
|
+
return 1;
|
|
399
|
+
}
|
|
400
|
+
const list = inventory.map(
|
|
401
|
+
(f) => ` ${pc3.dim(f.relPath)} (${formatSize(f.size)})`
|
|
402
|
+
).join("\n");
|
|
403
|
+
log.step(`Found ${pc3.bold(inventory.length)} files to deploy:
|
|
404
|
+
${list}`);
|
|
405
|
+
if (options.dryRun) {
|
|
406
|
+
outro(pc3.green("Dry run complete. No files were uploaded."));
|
|
407
|
+
return 0;
|
|
408
|
+
}
|
|
409
|
+
const ftpClient = new FtpClient();
|
|
410
|
+
try {
|
|
411
|
+
await ftpClient.connect();
|
|
412
|
+
} catch (err) {
|
|
413
|
+
log.error(
|
|
414
|
+
`FTP connection failed: ${err instanceof Error ? err.message : String(err)}`
|
|
415
|
+
);
|
|
416
|
+
return 1;
|
|
417
|
+
}
|
|
418
|
+
const exists = await ftpClient.exists(remoteDir);
|
|
419
|
+
if (exists && !options.force) {
|
|
420
|
+
ftpClient.close();
|
|
421
|
+
const shouldOverwrite = await confirm({
|
|
422
|
+
message: `${pc3.red(`Directory ${pc3.bold(remoteDir)} already exists.`)} Overwrite?`,
|
|
423
|
+
initialValue: false
|
|
424
|
+
});
|
|
425
|
+
if (!shouldOverwrite || isCancel(shouldOverwrite)) {
|
|
426
|
+
cancel("Deploy cancelled.");
|
|
427
|
+
return 0;
|
|
428
|
+
}
|
|
429
|
+
await ftpClient.connect();
|
|
430
|
+
} else if (!exists) {
|
|
431
|
+
await ftpClient.ensureDir(remoteDir);
|
|
432
|
+
} else if (options.force) {
|
|
433
|
+
log.info(pc3.yellow("Force flag used. Overwriting remote directory."));
|
|
434
|
+
}
|
|
435
|
+
const uploadSpinner = spin("Uploading files...");
|
|
436
|
+
let uploadedCount = 0;
|
|
437
|
+
let currentFile = "";
|
|
438
|
+
const totalFilesStr = inventory.length.toString();
|
|
439
|
+
try {
|
|
440
|
+
await ftpClient.uploadDir(localDir, remoteDir, (info) => {
|
|
441
|
+
if (info.name !== currentFile) {
|
|
442
|
+
uploadedCount++;
|
|
443
|
+
currentFile = info.name;
|
|
444
|
+
const countStr = uploadedCount.toString().padStart(totalFilesStr.length, " ");
|
|
445
|
+
uploadSpinner.message(`${countStr}/${totalFilesStr} ${info.name}`);
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
uploadSpinner.stop(`Upload finished`);
|
|
449
|
+
} catch (err) {
|
|
450
|
+
uploadSpinner.cancel("Upload failed");
|
|
451
|
+
ftpClient.close();
|
|
452
|
+
throw err;
|
|
453
|
+
}
|
|
454
|
+
ftpClient.close();
|
|
455
|
+
outro(`${pc3.bold("Released to:")} ${pc3.cyan(publicUrl)}`);
|
|
456
|
+
return 0;
|
|
457
|
+
}
|
|
458
|
+
var init_deploy = __esm({
|
|
459
|
+
"src/commands/deploy/index.ts"() {
|
|
460
|
+
"use strict";
|
|
461
|
+
init_ftp();
|
|
462
|
+
init_util();
|
|
463
|
+
init_terminal();
|
|
464
|
+
init_constants();
|
|
465
|
+
init_fs();
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
// src/lib/git.ts
|
|
470
|
+
import { $ } from "zx";
|
|
471
|
+
import { log as log2 } from "@clack/prompts";
|
|
472
|
+
async function isAccessible() {
|
|
473
|
+
try {
|
|
474
|
+
await $`git --version`.quiet();
|
|
475
|
+
return true;
|
|
476
|
+
} catch {
|
|
477
|
+
return false;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
async function isInsideRepo() {
|
|
481
|
+
try {
|
|
482
|
+
await $`git rev-parse --is-inside-work-tree`.quiet();
|
|
483
|
+
return true;
|
|
484
|
+
} catch {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
async function isClean() {
|
|
489
|
+
const result = await $`git status --porcelain`.quiet();
|
|
490
|
+
return result.stdout.trim() === "";
|
|
491
|
+
}
|
|
492
|
+
async function getBranch() {
|
|
493
|
+
const result = await $`git branch --show-current`.quiet();
|
|
494
|
+
return result.stdout.trim();
|
|
495
|
+
}
|
|
496
|
+
async function isBehindRemote() {
|
|
497
|
+
await $`git fetch`.quiet();
|
|
498
|
+
const result = await $`git rev-list --count HEAD..@{u}`.quiet();
|
|
499
|
+
return Number(result.stdout.trim()) > 0;
|
|
500
|
+
}
|
|
501
|
+
async function hasRemote() {
|
|
502
|
+
try {
|
|
503
|
+
await $`git rev-parse --abbrev-ref @{u}`.quiet();
|
|
504
|
+
return true;
|
|
505
|
+
} catch {
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
async function rollback(version2) {
|
|
510
|
+
try {
|
|
511
|
+
const lastCommitMsg = (await $`git log -1 --pretty=%B`.quiet()).stdout.trim();
|
|
512
|
+
if (lastCommitMsg !== `v${version2}` && lastCommitMsg !== version2) {
|
|
513
|
+
log2.warn(
|
|
514
|
+
`Abort rollback: Last commit message "${lastCommitMsg}" does not match version v${version2}.`
|
|
515
|
+
);
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
log2.info("Rolling back local version bump commit and tag...");
|
|
519
|
+
await $`git tag -d v${version2}`;
|
|
520
|
+
await $`git reset --hard HEAD~1`;
|
|
521
|
+
log2.info(
|
|
522
|
+
"This release has been rolled back, your workspace is clean to try again."
|
|
523
|
+
);
|
|
524
|
+
} catch (err) {
|
|
525
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
526
|
+
log2.error(`Failed to completely roll back: ${errorMessage}`);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
var init_git = __esm({
|
|
530
|
+
"src/lib/git.ts"() {
|
|
531
|
+
"use strict";
|
|
532
|
+
}
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
// src/commands/release-check/index.ts
|
|
536
|
+
import { intro as intro2 } from "@clack/prompts";
|
|
537
|
+
import pc4 from "picocolors";
|
|
538
|
+
async function run2(options = {}) {
|
|
539
|
+
if (!options.skipHeader) {
|
|
540
|
+
intro2(getHeader(pc4.dim("aunty"), "release-check", { colour: "magenta" }));
|
|
541
|
+
}
|
|
542
|
+
const s = spin("Performing pre-release checks...");
|
|
543
|
+
const checks = [];
|
|
544
|
+
const gitAccessible = await isAccessible();
|
|
545
|
+
const insideRepo = gitAccessible ? await isInsideRepo() : false;
|
|
546
|
+
if (!gitAccessible) {
|
|
547
|
+
checks.push(
|
|
548
|
+
renderError(
|
|
549
|
+
"Git is not accessible (please ensure git is installed and Xcode/licenses are accepted)"
|
|
550
|
+
)
|
|
551
|
+
);
|
|
552
|
+
} else if (!insideRepo) {
|
|
553
|
+
checks.push(renderError("The current directory is not a git repository"));
|
|
554
|
+
} else {
|
|
555
|
+
checks.push(
|
|
556
|
+
await isClean() ? renderSuccess("Changes are all committed") : renderError("You have uncommitted changes")
|
|
557
|
+
);
|
|
558
|
+
const branch = await getBranch();
|
|
559
|
+
const isMain = branch === "main";
|
|
560
|
+
checks.push(
|
|
561
|
+
isMain ? renderSuccess("On the release branch (main)") : renderError(
|
|
562
|
+
`You are on the ${pc4.bold(branch)} branch (releases must be from ${pc4.bold("main")})`
|
|
563
|
+
)
|
|
564
|
+
);
|
|
565
|
+
if (await hasRemote()) {
|
|
566
|
+
checks.push(
|
|
567
|
+
!await isBehindRemote() ? renderSuccess("Synchronised with remote branch") : renderError("Your local branch is behind the remote")
|
|
568
|
+
);
|
|
569
|
+
} else {
|
|
570
|
+
checks.push(
|
|
571
|
+
renderError(
|
|
572
|
+
"Your local branch has no remote tracking branch. Try running git push."
|
|
573
|
+
)
|
|
574
|
+
);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
s.message("Testing FTP connection...");
|
|
578
|
+
const {
|
|
579
|
+
success: ftpSuccess,
|
|
580
|
+
error: ftpError,
|
|
581
|
+
ftpClient
|
|
582
|
+
} = await testFtpConnection(5e3);
|
|
583
|
+
checks.push(
|
|
584
|
+
ftpSuccess ? renderSuccess("FTP is reachable") : renderError(`FTP connection failed: ${ftpError}`)
|
|
585
|
+
);
|
|
586
|
+
if (ftpSuccess) {
|
|
587
|
+
if (options.projectName && options.version) {
|
|
588
|
+
s.message("Checking project version availability...");
|
|
589
|
+
const availability = await isProjectNameAndVersionAvailable(
|
|
590
|
+
options.projectName,
|
|
591
|
+
options.version,
|
|
592
|
+
ftpClient
|
|
593
|
+
);
|
|
594
|
+
if (availability === "exists") {
|
|
595
|
+
checks.push(
|
|
596
|
+
renderError(
|
|
597
|
+
`Project version ${pc4.bold(options.version)} already exists on the FTP server`
|
|
598
|
+
)
|
|
599
|
+
);
|
|
600
|
+
} else if (availability === "error") {
|
|
601
|
+
checks.push(
|
|
602
|
+
renderError(
|
|
603
|
+
"Failed to check project version availability on the FTP server"
|
|
604
|
+
)
|
|
605
|
+
);
|
|
606
|
+
} else {
|
|
607
|
+
checks.push(renderSuccess("Project version is available"));
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
ftpClient?.close();
|
|
611
|
+
}
|
|
612
|
+
s.message("Running npm run build check...");
|
|
613
|
+
try {
|
|
614
|
+
await runBuild({ stdio: "pipe" });
|
|
615
|
+
checks.push(renderSuccess("Project built successfully"));
|
|
616
|
+
} catch (err) {
|
|
617
|
+
if (err.stdout) {
|
|
618
|
+
process.stdout.write(err.stdout);
|
|
619
|
+
}
|
|
620
|
+
if (err.stderr) {
|
|
621
|
+
process.stderr.write(err.stderr);
|
|
622
|
+
}
|
|
623
|
+
checks.push(
|
|
624
|
+
renderError(
|
|
625
|
+
`Project build failed: ${err instanceof Error ? err.message : String(err)}`
|
|
626
|
+
)
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
const haveChecksFailed = checks.some((c) => c.includes("\u2718"));
|
|
630
|
+
if (haveChecksFailed) {
|
|
631
|
+
s.cancel("Release checks failed");
|
|
632
|
+
} else {
|
|
633
|
+
s.stop("Release checks passed");
|
|
634
|
+
}
|
|
635
|
+
if (haveChecksFailed || !options.quiet) {
|
|
636
|
+
if (checks.length > 0) {
|
|
637
|
+
console.log(`${pc4.gray("\u2502")}`);
|
|
638
|
+
checks.forEach((check) => console.log(check));
|
|
639
|
+
console.log(`${pc4.gray("\u2502")}`);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
if (haveChecksFailed) {
|
|
643
|
+
return 1;
|
|
644
|
+
}
|
|
645
|
+
return 0;
|
|
646
|
+
}
|
|
647
|
+
var renderSuccess, renderError;
|
|
648
|
+
var init_release_check = __esm({
|
|
649
|
+
"src/commands/release-check/index.ts"() {
|
|
650
|
+
"use strict";
|
|
651
|
+
init_terminal();
|
|
652
|
+
init_ftp();
|
|
653
|
+
init_util();
|
|
654
|
+
init_git();
|
|
655
|
+
renderSuccess = (message) => `${pc4.gray("\u2502")} ${pc4.green("\u2714")} ${pc4.bold(message)}`;
|
|
656
|
+
renderError = (message) => `${pc4.gray("\u2502")} ${pc4.red("\u2718")} ${pc4.bold(message)}`;
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
// src/lib/semver.ts
|
|
661
|
+
import semver from "semver";
|
|
662
|
+
function getVersionOptions(currentVersion) {
|
|
663
|
+
const prereleaseParts = semver.prerelease(currentVersion);
|
|
664
|
+
const isPrerelease = !!prereleaseParts;
|
|
665
|
+
const preid = prereleaseParts && typeof prereleaseParts[0] === "string" ? prereleaseParts[0] : PRERELEASE_LABEL;
|
|
666
|
+
if (isPrerelease) {
|
|
667
|
+
const releaseVersion = semver.inc(currentVersion, "patch");
|
|
668
|
+
const nextPrerelease = semver.inc(currentVersion, "prerelease", preid);
|
|
669
|
+
return [
|
|
670
|
+
{ value: releaseVersion, label: `Release (${releaseVersion})` },
|
|
671
|
+
{ value: nextPrerelease, label: `Prerelease (${nextPrerelease})` }
|
|
672
|
+
];
|
|
673
|
+
}
|
|
674
|
+
const patch = semver.inc(currentVersion, "patch");
|
|
675
|
+
const minor = semver.inc(currentVersion, "minor");
|
|
676
|
+
const major = semver.inc(currentVersion, "major");
|
|
677
|
+
const prepatch = semver.inc(currentVersion, "prepatch", PRERELEASE_LABEL);
|
|
678
|
+
const preminor = semver.inc(currentVersion, "preminor", PRERELEASE_LABEL);
|
|
679
|
+
const premajor = semver.inc(currentVersion, "premajor", PRERELEASE_LABEL);
|
|
680
|
+
return [
|
|
681
|
+
{ value: patch, label: `Patch (${patch})` },
|
|
682
|
+
{ value: minor, label: `Minor (${minor})` },
|
|
683
|
+
{ value: major, label: `Major (${major})` },
|
|
684
|
+
{ value: prepatch, label: `Prerelease Patch (${prepatch})` },
|
|
685
|
+
{ value: preminor, label: `Prerelease Minor (${preminor})` },
|
|
686
|
+
{ value: premajor, label: `Prerelease Major (${premajor})` }
|
|
687
|
+
];
|
|
688
|
+
}
|
|
689
|
+
var PRERELEASE_LABEL;
|
|
690
|
+
var init_semver = __esm({
|
|
691
|
+
"src/lib/semver.ts"() {
|
|
692
|
+
"use strict";
|
|
693
|
+
PRERELEASE_LABEL = "prerelease";
|
|
694
|
+
}
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
// src/commands/release/index.ts
|
|
698
|
+
import { intro as intro3, outro as outro2, select, cancel as cancel2, isCancel as isCancel2, log as log3 } from "@clack/prompts";
|
|
699
|
+
import pc5 from "picocolors";
|
|
700
|
+
import semver2 from "semver";
|
|
701
|
+
import { $ as $2 } from "zx";
|
|
702
|
+
async function run3(options = {}) {
|
|
703
|
+
intro3(getHeader(pc5.dim("aunty"), "release", { colour: "yellow" }));
|
|
704
|
+
const details = await findProjectDetails(process.cwd());
|
|
705
|
+
if (!details) {
|
|
706
|
+
return 1;
|
|
707
|
+
}
|
|
708
|
+
const { pkg: pkg2 } = details;
|
|
709
|
+
const currentVersion = pkg2.version;
|
|
710
|
+
if (!currentVersion) {
|
|
711
|
+
cancel2("No version found in package.json, please set up your project.");
|
|
712
|
+
return 1;
|
|
713
|
+
}
|
|
714
|
+
if (!semver2.valid(currentVersion)) {
|
|
715
|
+
cancel2(
|
|
716
|
+
`Current version ${pc5.bold(currentVersion)} is not a valid semver version`
|
|
717
|
+
);
|
|
718
|
+
return 1;
|
|
719
|
+
}
|
|
720
|
+
let nextVersion = void 0;
|
|
721
|
+
if (options.version) {
|
|
722
|
+
if (!semver2.valid(options.version)) {
|
|
723
|
+
cancel2(
|
|
724
|
+
`The version specified (${pc5.bold(options.version)}) is not a valid semver version`
|
|
725
|
+
);
|
|
726
|
+
return 1;
|
|
727
|
+
}
|
|
728
|
+
nextVersion = options.version;
|
|
729
|
+
log3.info(`Using specified version: ${pc5.green(nextVersion)}`);
|
|
730
|
+
}
|
|
731
|
+
if (!nextVersion) {
|
|
732
|
+
const selectOptions = getVersionOptions(currentVersion);
|
|
733
|
+
const bumpSelection = await select({
|
|
734
|
+
message: "What package version bump is this release?",
|
|
735
|
+
options: selectOptions
|
|
736
|
+
});
|
|
737
|
+
if (isCancel2(bumpSelection)) {
|
|
738
|
+
cancel2("Release cancelled");
|
|
739
|
+
return 1;
|
|
740
|
+
}
|
|
741
|
+
nextVersion = bumpSelection;
|
|
742
|
+
}
|
|
743
|
+
const checkResult = await run2({
|
|
744
|
+
skipHeader: true,
|
|
745
|
+
quiet: true,
|
|
746
|
+
projectName: details.pkg.name,
|
|
747
|
+
version: nextVersion
|
|
748
|
+
});
|
|
749
|
+
if (checkResult !== 0) {
|
|
750
|
+
outro2(pc5.red("Release checks failed."));
|
|
751
|
+
return checkResult;
|
|
752
|
+
}
|
|
753
|
+
try {
|
|
754
|
+
await $2`npm version ${nextVersion}`;
|
|
755
|
+
} catch (err) {
|
|
756
|
+
outro2(
|
|
757
|
+
pc5.red(
|
|
758
|
+
`Failed to set version: ${err instanceof Error ? err.message : String(err)}`
|
|
759
|
+
)
|
|
760
|
+
);
|
|
761
|
+
return 1;
|
|
762
|
+
}
|
|
763
|
+
const pushSpinner = spin("Pushing release & tag to remote...");
|
|
764
|
+
try {
|
|
765
|
+
await $2`git push origin HEAD --follow-tags`.quiet();
|
|
766
|
+
pushSpinner.stop("Pushed to remote");
|
|
767
|
+
} catch (err) {
|
|
768
|
+
pushSpinner.cancel("Push failed");
|
|
769
|
+
outro2(
|
|
770
|
+
pc5.red(
|
|
771
|
+
`Failed to push to remote: ${err instanceof Error ? err.message : String(err)}`
|
|
772
|
+
)
|
|
773
|
+
);
|
|
774
|
+
await rollback(nextVersion);
|
|
775
|
+
return 1;
|
|
776
|
+
}
|
|
777
|
+
const deployResult = await run({ skipHeader: true });
|
|
778
|
+
if (deployResult !== 0) {
|
|
779
|
+
outro2(
|
|
780
|
+
pc5.red(
|
|
781
|
+
"Deployment failed. You can retry manually with `npm run deploy`."
|
|
782
|
+
)
|
|
783
|
+
);
|
|
784
|
+
return deployResult;
|
|
785
|
+
}
|
|
786
|
+
return 0;
|
|
787
|
+
}
|
|
788
|
+
var init_release = __esm({
|
|
789
|
+
"src/commands/release/index.ts"() {
|
|
790
|
+
"use strict";
|
|
791
|
+
init_terminal();
|
|
792
|
+
init_util();
|
|
793
|
+
init_semver();
|
|
794
|
+
init_release_check();
|
|
795
|
+
init_deploy();
|
|
796
|
+
init_git();
|
|
797
|
+
}
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
// src/lib/initHelpers.ts
|
|
801
|
+
import fs2 from "node:fs/promises";
|
|
802
|
+
import path5 from "node:path";
|
|
803
|
+
import { stripTypeScriptTypes } from "node:module";
|
|
804
|
+
import { $ as $3 } from "zx";
|
|
805
|
+
async function copyContents(src, dest) {
|
|
806
|
+
await fs2.mkdir(dest, { recursive: true });
|
|
807
|
+
const entries = await fs2.readdir(src, { withFileTypes: true });
|
|
808
|
+
await Promise.all(
|
|
809
|
+
entries.map(async (entry) => {
|
|
810
|
+
const srcPath = path5.join(src, entry.name);
|
|
811
|
+
const destPath = path5.join(dest, entry.name);
|
|
812
|
+
if (entry.isDirectory()) {
|
|
813
|
+
await copyContents(srcPath, destPath);
|
|
814
|
+
} else {
|
|
815
|
+
await fs2.copyFile(srcPath, destPath);
|
|
816
|
+
}
|
|
817
|
+
})
|
|
818
|
+
);
|
|
819
|
+
}
|
|
820
|
+
async function editPackageJson(dir, callback) {
|
|
821
|
+
const pkgPath2 = path5.join(dir, "package.json");
|
|
822
|
+
const pkg2 = await loadJson(pkgPath2) || {};
|
|
823
|
+
const result = await callback(pkg2);
|
|
824
|
+
const finalPkg = result || pkg2;
|
|
825
|
+
await fs2.writeFile(pkgPath2, JSON.stringify(finalPkg, null, 2) + "\n");
|
|
826
|
+
}
|
|
827
|
+
async function findFiles(dir, pattern) {
|
|
828
|
+
const { glob: glob2 } = await import("zx");
|
|
829
|
+
return await glob2(pattern, { cwd: dir, absolute: true });
|
|
830
|
+
}
|
|
831
|
+
async function replaceInFile(baseDir, relPath, replacements) {
|
|
832
|
+
const filePath = path5.join(baseDir, relPath);
|
|
833
|
+
let content = await fs2.readFile(filePath, "utf-8");
|
|
834
|
+
Object.entries(replacements).forEach(([search, replace]) => {
|
|
835
|
+
content = content.replaceAll(search, replace);
|
|
836
|
+
});
|
|
837
|
+
await fs2.writeFile(filePath, content);
|
|
838
|
+
}
|
|
839
|
+
async function replaceInFiles(baseDir, relPaths, replacements) {
|
|
840
|
+
await Promise.all(
|
|
841
|
+
relPaths.map((relPath) => replaceInFile(baseDir, relPath, replacements))
|
|
842
|
+
);
|
|
843
|
+
}
|
|
844
|
+
async function getGitUser() {
|
|
845
|
+
try {
|
|
846
|
+
const name = (await $3`git config user.name`.quiet()).stdout.trim();
|
|
847
|
+
const email = (await $3`git config user.email`.quiet()).stdout.trim();
|
|
848
|
+
if (!name || !email) return null;
|
|
849
|
+
return { name, email };
|
|
850
|
+
} catch {
|
|
851
|
+
return null;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
async function installAunty(baseDir) {
|
|
855
|
+
const localDev = isLocalDevelopment();
|
|
856
|
+
let auntyDepValue = "";
|
|
857
|
+
const auntyRoot = path5.resolve(import.meta.dirname, "../../");
|
|
858
|
+
if (localDev) {
|
|
859
|
+
auntyDepValue = `file:${auntyRoot}`;
|
|
860
|
+
} else {
|
|
861
|
+
const pkg2 = await loadJson(
|
|
862
|
+
path5.join(auntyRoot, "package.json")
|
|
863
|
+
);
|
|
864
|
+
auntyDepValue = pkg2 ? `^${pkg2.version}` : "latest";
|
|
865
|
+
}
|
|
866
|
+
await editPackageJson(baseDir, (pkg2) => {
|
|
867
|
+
if (!pkg2.devDependencies) {
|
|
868
|
+
pkg2.devDependencies = {};
|
|
869
|
+
}
|
|
870
|
+
pkg2.devDependencies["@abcnews/aunty"] = auntyDepValue;
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
async function renameGitignore(baseDir) {
|
|
874
|
+
const { log: log8 } = await import("@clack/prompts");
|
|
875
|
+
const gitignoreFromPath = path5.resolve(baseDir, "_gitignore");
|
|
876
|
+
const gitignoreToPath = path5.resolve(baseDir, ".gitignore");
|
|
877
|
+
try {
|
|
878
|
+
await fs2.access(gitignoreFromPath);
|
|
879
|
+
} catch {
|
|
880
|
+
log8.error(
|
|
881
|
+
"Base template must include a _gitignore file (npm strips .gitignore)"
|
|
882
|
+
);
|
|
883
|
+
throw new Error("Missing _gitignore file");
|
|
884
|
+
}
|
|
885
|
+
await fs2.rename(gitignoreFromPath, gitignoreToPath);
|
|
886
|
+
}
|
|
887
|
+
function rewriteImports(content) {
|
|
888
|
+
return content.replace(/(from\s+['"])(.*?)\.ts(['"])/g, "$1$2.js$3").replace(/(import\s+['"])(.*?)\.ts(['"])/g, "$1$2.js$3");
|
|
889
|
+
}
|
|
890
|
+
async function stripTypesFromFile(tsFile) {
|
|
891
|
+
const jsFile = tsFile.replace(/\.ts$/, ".js");
|
|
892
|
+
const content = await fs2.readFile(tsFile, "utf-8");
|
|
893
|
+
const stripped = stripTypeScriptTypes(content);
|
|
894
|
+
const rewritten = rewriteImports(stripped);
|
|
895
|
+
await fs2.writeFile(jsFile, rewritten);
|
|
896
|
+
await fs2.unlink(tsFile);
|
|
897
|
+
}
|
|
898
|
+
var init_initHelpers = __esm({
|
|
899
|
+
"src/lib/initHelpers.ts"() {
|
|
900
|
+
"use strict";
|
|
901
|
+
init_util();
|
|
902
|
+
}
|
|
903
|
+
});
|
|
904
|
+
|
|
905
|
+
// templates/svelte/base/init.ts
|
|
906
|
+
import path6 from "node:path";
|
|
907
|
+
async function init({ projectName, baseDir }) {
|
|
908
|
+
const contentsDir = path6.resolve(import.meta.dirname, "contents");
|
|
909
|
+
await copyContents(contentsDir, baseDir);
|
|
910
|
+
await replaceInFiles(
|
|
911
|
+
baseDir,
|
|
912
|
+
["index.html", "src/index.ts", "README.md"],
|
|
913
|
+
{
|
|
914
|
+
__PROJECT_NAME__: projectName,
|
|
915
|
+
__PROJECT_NAME_ACTO__: projectName.replace(/-/g, ""),
|
|
916
|
+
__PROJECT_TYPE__: "Svelte"
|
|
917
|
+
}
|
|
918
|
+
);
|
|
919
|
+
await renameGitignore(baseDir);
|
|
920
|
+
const gitUser = await getGitUser();
|
|
921
|
+
await editPackageJson(baseDir, (pkg2) => {
|
|
922
|
+
Object.assign(pkg2, {
|
|
923
|
+
name: projectName,
|
|
924
|
+
license: "MIT",
|
|
925
|
+
contributors: gitUser ? [gitUser] : [],
|
|
926
|
+
aunty: { type: "svelte" }
|
|
927
|
+
});
|
|
928
|
+
});
|
|
929
|
+
await installAunty(baseDir);
|
|
930
|
+
}
|
|
931
|
+
var init_init = __esm({
|
|
932
|
+
"templates/svelte/base/init.ts"() {
|
|
933
|
+
"use strict";
|
|
934
|
+
init_initHelpers();
|
|
935
|
+
}
|
|
936
|
+
});
|
|
937
|
+
|
|
938
|
+
// templates/svelte/patch-odyssey/init.ts
|
|
939
|
+
async function init2({ baseDir }) {
|
|
940
|
+
await replaceInFile(baseDir, "src/index.ts", {
|
|
941
|
+
whenDOMReady: "whenOdysseyLoaded"
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
var init_init2 = __esm({
|
|
945
|
+
"templates/svelte/patch-odyssey/init.ts"() {
|
|
946
|
+
"use strict";
|
|
947
|
+
init_initHelpers();
|
|
948
|
+
}
|
|
949
|
+
});
|
|
950
|
+
|
|
951
|
+
// templates/svelte/patch-scrollyteller/init.ts
|
|
952
|
+
import path7 from "node:path";
|
|
953
|
+
async function init3({ projectName, baseDir }) {
|
|
954
|
+
const contentsDir = path7.resolve(import.meta.dirname, "contents");
|
|
955
|
+
await copyContents(contentsDir, baseDir);
|
|
956
|
+
await editPackageJson(baseDir, (pkg2) => {
|
|
957
|
+
pkg2.dependencies = pkg2.dependencies || {};
|
|
958
|
+
pkg2.dependencies["@abcnews/svelte-scrollyteller"] = "^3.0.0";
|
|
959
|
+
});
|
|
960
|
+
await replaceInFiles(baseDir, ["index.html", "src/index.ts"], {
|
|
961
|
+
__PROJECT_NAME__: projectName,
|
|
962
|
+
__PROJECT_NAME_ACTO__: projectName.replace(/-/g, "")
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
var init_init3 = __esm({
|
|
966
|
+
"templates/svelte/patch-scrollyteller/init.ts"() {
|
|
967
|
+
"use strict";
|
|
968
|
+
init_initHelpers();
|
|
969
|
+
}
|
|
970
|
+
});
|
|
971
|
+
|
|
972
|
+
// templates/svelte/patch-builder/init.ts
|
|
973
|
+
var init_exports = {};
|
|
974
|
+
__export(init_exports, {
|
|
975
|
+
init: () => init4
|
|
976
|
+
});
|
|
977
|
+
import path8 from "node:path";
|
|
978
|
+
import fs3 from "node:fs/promises";
|
|
979
|
+
async function init4({ projectName, baseDir }) {
|
|
980
|
+
const contentsDir = path8.resolve(import.meta.dirname, "contents");
|
|
981
|
+
await copyContents(contentsDir, baseDir);
|
|
982
|
+
await replaceInFile(baseDir, "builder/index.html", {
|
|
983
|
+
__PROJECT_NAME__: projectName
|
|
984
|
+
});
|
|
985
|
+
const entryFile = "src/index.ts";
|
|
986
|
+
const entryPath = path8.join(baseDir, entryFile);
|
|
987
|
+
const entryContent = await fs3.readFile(entryPath, "utf-8");
|
|
988
|
+
const searchPattern = `// __ADDITIONAL_MOUNTS__`;
|
|
989
|
+
const builderMountCode = `const [builderMountEl] = selectMounts('builder');
|
|
990
|
+
|
|
991
|
+
if (builderMountEl) {
|
|
992
|
+
const appProps = getMountValue(builderMountEl);
|
|
993
|
+
const builderModule = await import('./components/Builder/Builder.svelte');
|
|
994
|
+
mount(builderModule.default, {
|
|
995
|
+
target: builderMountEl
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
// __ADDITIONAL_MOUNTS__`;
|
|
1000
|
+
if (entryContent.includes(searchPattern)) {
|
|
1001
|
+
await replaceInFile(baseDir, entryFile, {
|
|
1002
|
+
[searchPattern]: builderMountCode
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
var init_init4 = __esm({
|
|
1007
|
+
"templates/svelte/patch-builder/init.ts"() {
|
|
1008
|
+
"use strict";
|
|
1009
|
+
init_initHelpers();
|
|
1010
|
+
}
|
|
1011
|
+
});
|
|
1012
|
+
|
|
1013
|
+
// templates/svelte/patch-js/init.ts
|
|
1014
|
+
var init_exports2 = {};
|
|
1015
|
+
__export(init_exports2, {
|
|
1016
|
+
init: () => init5
|
|
1017
|
+
});
|
|
1018
|
+
import fs4 from "node:fs/promises";
|
|
1019
|
+
import { $ as $4 } from "zx";
|
|
1020
|
+
import { stripTypeScriptTypes as stripTypeScriptTypes2 } from "node:module";
|
|
1021
|
+
async function processSvelteFile(file) {
|
|
1022
|
+
let content = await fs4.readFile(file, "utf-8");
|
|
1023
|
+
const scriptRegex = /<script lang="ts">([\s\S]*?)<\/script>/g;
|
|
1024
|
+
const matches = Array.from(content.matchAll(scriptRegex));
|
|
1025
|
+
if (matches.length === 0) return;
|
|
1026
|
+
for (const match of matches) {
|
|
1027
|
+
const stripped = stripTypeScriptTypes2(match[1]);
|
|
1028
|
+
const rewritten = rewriteImports(stripped);
|
|
1029
|
+
content = content.replace(
|
|
1030
|
+
match[0],
|
|
1031
|
+
`<script>
|
|
1032
|
+
${rewritten.trim()}
|
|
1033
|
+
</script>`
|
|
1034
|
+
);
|
|
1035
|
+
}
|
|
1036
|
+
await fs4.writeFile(file, content);
|
|
1037
|
+
}
|
|
1038
|
+
async function init5({ baseDir }, hasBuilder) {
|
|
1039
|
+
const s = spin("Converting project to JavaScript");
|
|
1040
|
+
s.message("Converting .ts to .js");
|
|
1041
|
+
const tsFiles = await findFiles(baseDir, "**/*.ts");
|
|
1042
|
+
await Promise.all(tsFiles.map(stripTypesFromFile));
|
|
1043
|
+
const svelteFiles = await findFiles(baseDir, "**/*.svelte");
|
|
1044
|
+
await Promise.all(svelteFiles.map(processSvelteFile));
|
|
1045
|
+
const htmlFiles = ["index.html"];
|
|
1046
|
+
if (hasBuilder) {
|
|
1047
|
+
htmlFiles.push("builder/index.html");
|
|
1048
|
+
}
|
|
1049
|
+
await replaceInFiles(baseDir, htmlFiles, { ".ts": ".js" });
|
|
1050
|
+
s.message("Updating config");
|
|
1051
|
+
s.message("Installing dependencies");
|
|
1052
|
+
await $4({ cwd: baseDir })`npm install`.quiet();
|
|
1053
|
+
s.message("Formatting project");
|
|
1054
|
+
await $4({ cwd: baseDir })`npm run format`.quiet();
|
|
1055
|
+
s.stop("Project converted to JavaScript");
|
|
1056
|
+
}
|
|
1057
|
+
var init_init5 = __esm({
|
|
1058
|
+
"templates/svelte/patch-js/init.ts"() {
|
|
1059
|
+
"use strict";
|
|
1060
|
+
init_initHelpers();
|
|
1061
|
+
init_terminal();
|
|
1062
|
+
}
|
|
1063
|
+
});
|
|
1064
|
+
|
|
1065
|
+
// templates/svelte/index.ts
|
|
1066
|
+
import { multiselect, cancel as cancel3, isCancel as isCancel3 } from "@clack/prompts";
|
|
1067
|
+
async function run4(options) {
|
|
1068
|
+
const features = await multiselect({
|
|
1069
|
+
message: "Select features to enable:",
|
|
1070
|
+
options: [
|
|
1071
|
+
{ value: "odyssey", label: "Odyssey" },
|
|
1072
|
+
{ value: "scrollyteller", label: "Scrollyteller" },
|
|
1073
|
+
{ value: "builder", label: "Builder" },
|
|
1074
|
+
{ value: "typescript", label: "TypeScript" }
|
|
1075
|
+
],
|
|
1076
|
+
initialValues: ["typescript"],
|
|
1077
|
+
required: false
|
|
1078
|
+
});
|
|
1079
|
+
if (isCancel3(features)) {
|
|
1080
|
+
cancel3("Operation cancelled.");
|
|
1081
|
+
return 1;
|
|
1082
|
+
}
|
|
1083
|
+
const useTypescript = features.includes("typescript");
|
|
1084
|
+
const useBuilder = features.includes("builder");
|
|
1085
|
+
const useScrollyteller = features.includes("scrollyteller");
|
|
1086
|
+
const useOdyssey = features.includes("odyssey");
|
|
1087
|
+
await init(options);
|
|
1088
|
+
if (useScrollyteller) {
|
|
1089
|
+
await init3(options);
|
|
1090
|
+
} else if (useOdyssey) {
|
|
1091
|
+
await init2(options);
|
|
1092
|
+
}
|
|
1093
|
+
if (useBuilder) {
|
|
1094
|
+
const { init: builderInit } = await Promise.resolve().then(() => (init_init4(), init_exports));
|
|
1095
|
+
await builderInit(options);
|
|
1096
|
+
}
|
|
1097
|
+
if (!useTypescript) {
|
|
1098
|
+
const { init: jsInit } = await Promise.resolve().then(() => (init_init5(), init_exports2));
|
|
1099
|
+
await jsInit(options, useBuilder);
|
|
1100
|
+
}
|
|
1101
|
+
return 0;
|
|
1102
|
+
}
|
|
1103
|
+
var init_svelte = __esm({
|
|
1104
|
+
"templates/svelte/index.ts"() {
|
|
1105
|
+
"use strict";
|
|
1106
|
+
init_init();
|
|
1107
|
+
init_init2();
|
|
1108
|
+
init_init3();
|
|
1109
|
+
}
|
|
1110
|
+
});
|
|
1111
|
+
|
|
1112
|
+
// templates/vanilla/base/init.ts
|
|
1113
|
+
import path9 from "node:path";
|
|
1114
|
+
async function init6({ projectName, baseDir }) {
|
|
1115
|
+
const contentsDir = path9.resolve(import.meta.dirname, "contents");
|
|
1116
|
+
await copyContents(contentsDir, baseDir);
|
|
1117
|
+
await replaceInFiles(baseDir, ["index.html", "src/index.ts"], {
|
|
1118
|
+
__PROJECT_NAME__: projectName,
|
|
1119
|
+
__PROJECT_NAME_ACTO__: projectName.replace(/-/g, ""),
|
|
1120
|
+
__PROJECT_TYPE__: "Svelte"
|
|
1121
|
+
});
|
|
1122
|
+
await renameGitignore(baseDir);
|
|
1123
|
+
const gitUser = await getGitUser();
|
|
1124
|
+
await editPackageJson(baseDir, (pkg2) => {
|
|
1125
|
+
Object.assign(pkg2, {
|
|
1126
|
+
name: projectName,
|
|
1127
|
+
license: "MIT",
|
|
1128
|
+
contributors: gitUser ? [gitUser] : [],
|
|
1129
|
+
aunty: { type: "svelte" }
|
|
1130
|
+
});
|
|
1131
|
+
});
|
|
1132
|
+
await installAunty(baseDir);
|
|
1133
|
+
}
|
|
1134
|
+
var init_init6 = __esm({
|
|
1135
|
+
"templates/vanilla/base/init.ts"() {
|
|
1136
|
+
"use strict";
|
|
1137
|
+
init_initHelpers();
|
|
1138
|
+
}
|
|
1139
|
+
});
|
|
1140
|
+
|
|
1141
|
+
// templates/vanilla/patch-js/init.ts
|
|
1142
|
+
var init_exports3 = {};
|
|
1143
|
+
__export(init_exports3, {
|
|
1144
|
+
init: () => init7
|
|
1145
|
+
});
|
|
1146
|
+
import { $ as $5 } from "zx";
|
|
1147
|
+
async function init7({ baseDir }) {
|
|
1148
|
+
const s = spin("Converting project to JavaScript");
|
|
1149
|
+
s.message("Converting .ts to .js");
|
|
1150
|
+
const tsFiles = await findFiles(baseDir, "**/*.ts");
|
|
1151
|
+
await Promise.all(tsFiles.map(stripTypesFromFile));
|
|
1152
|
+
await replaceInFiles(baseDir, ["index.html"], { ".ts": ".js" });
|
|
1153
|
+
s.message("Installing dependencies");
|
|
1154
|
+
await $5({ cwd: baseDir })`npm install`.quiet();
|
|
1155
|
+
s.message("Formatting project");
|
|
1156
|
+
await $5({ cwd: baseDir })`npm run format`.quiet();
|
|
1157
|
+
s.stop("Project converted to JavaScript");
|
|
1158
|
+
}
|
|
1159
|
+
var init_init7 = __esm({
|
|
1160
|
+
"templates/vanilla/patch-js/init.ts"() {
|
|
1161
|
+
"use strict";
|
|
1162
|
+
init_initHelpers();
|
|
1163
|
+
init_terminal();
|
|
1164
|
+
}
|
|
1165
|
+
});
|
|
1166
|
+
|
|
1167
|
+
// templates/vanilla/index.ts
|
|
1168
|
+
import { select as select2, confirm as confirm2, cancel as cancel4, isCancel as isCancel4 } from "@clack/prompts";
|
|
1169
|
+
async function run5(options) {
|
|
1170
|
+
const projectType = await select2({
|
|
1171
|
+
message: "What kind of project do you want?",
|
|
1172
|
+
options: [{ value: "base", label: "Basic iframe/CoreMedia" }]
|
|
1173
|
+
});
|
|
1174
|
+
if (isCancel4(projectType)) {
|
|
1175
|
+
cancel4("Operation cancelled.");
|
|
1176
|
+
return 1;
|
|
1177
|
+
}
|
|
1178
|
+
const useTypescript = await confirm2({
|
|
1179
|
+
message: "Do you want to use TypeScript?",
|
|
1180
|
+
initialValue: true
|
|
1181
|
+
});
|
|
1182
|
+
if (isCancel4(useTypescript)) {
|
|
1183
|
+
cancel4("Operation cancelled.");
|
|
1184
|
+
return 1;
|
|
1185
|
+
}
|
|
1186
|
+
await init6(options);
|
|
1187
|
+
if (!useTypescript) {
|
|
1188
|
+
const { init: jsInit } = await Promise.resolve().then(() => (init_init7(), init_exports3));
|
|
1189
|
+
await jsInit(options);
|
|
1190
|
+
}
|
|
1191
|
+
return 0;
|
|
1192
|
+
}
|
|
1193
|
+
var init_vanilla = __esm({
|
|
1194
|
+
"templates/vanilla/index.ts"() {
|
|
1195
|
+
"use strict";
|
|
1196
|
+
init_init6();
|
|
1197
|
+
}
|
|
1198
|
+
});
|
|
1199
|
+
|
|
1200
|
+
// templates/index.ts
|
|
1201
|
+
var index, templates_default;
|
|
1202
|
+
var init_templates = __esm({
|
|
1203
|
+
"templates/index.ts"() {
|
|
1204
|
+
"use strict";
|
|
1205
|
+
init_svelte();
|
|
1206
|
+
init_vanilla();
|
|
1207
|
+
index = {
|
|
1208
|
+
projects: [
|
|
1209
|
+
{ name: "Svelte", run: run4 },
|
|
1210
|
+
{ name: "Plain JS", run: run5 }
|
|
1211
|
+
]
|
|
1212
|
+
};
|
|
1213
|
+
templates_default = index;
|
|
1214
|
+
}
|
|
1215
|
+
});
|
|
1216
|
+
|
|
1217
|
+
// src/commands/create/index.ts
|
|
1218
|
+
import {
|
|
1219
|
+
intro as intro4,
|
|
1220
|
+
outro as outro3,
|
|
1221
|
+
text,
|
|
1222
|
+
select as select3,
|
|
1223
|
+
confirm as confirm3,
|
|
1224
|
+
log as log4,
|
|
1225
|
+
cancel as cancel5,
|
|
1226
|
+
isCancel as isCancel5
|
|
1227
|
+
} from "@clack/prompts";
|
|
1228
|
+
import path10 from "node:path";
|
|
1229
|
+
import fs5 from "node:fs/promises";
|
|
1230
|
+
import pc6 from "picocolors";
|
|
1231
|
+
import { $ as $6 } from "zx";
|
|
1232
|
+
async function run6(destDirArg) {
|
|
1233
|
+
intro4(getHeader(pc6.dim("aunty"), "create", { colour: "green" }));
|
|
1234
|
+
const projectName = destDirArg || await text({
|
|
1235
|
+
message: "What is your project named?",
|
|
1236
|
+
placeholder: destDirArg || "my-new-project",
|
|
1237
|
+
validate: (value) => {
|
|
1238
|
+
if (!value || value.length === 0) {
|
|
1239
|
+
return "Project name is required";
|
|
1240
|
+
}
|
|
1241
|
+
if (!value.match(/^[a-z0-9-]+$/)) {
|
|
1242
|
+
return "Project name should be lowercase-alphanumeric-with-hypens";
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
});
|
|
1246
|
+
if (isCancel5(projectName)) {
|
|
1247
|
+
cancel5("Operation cancelled.");
|
|
1248
|
+
return 0;
|
|
1249
|
+
}
|
|
1250
|
+
const finalProjectName = projectName || destDirArg || "my-new-project";
|
|
1251
|
+
const projectDest = path10.resolve(process.cwd(), finalProjectName);
|
|
1252
|
+
const ftpSpinner = spin("Checking project name availability...");
|
|
1253
|
+
const isAvailable = await isProjectNameAndVersionAvailable(finalProjectName);
|
|
1254
|
+
ftpSpinner.stop("Project name checked");
|
|
1255
|
+
if (isAvailable === "error") {
|
|
1256
|
+
const shouldContinue = await confirm3({
|
|
1257
|
+
message: pc6.red(
|
|
1258
|
+
"Could not connect to FTP to check name availability. Continue anyway?"
|
|
1259
|
+
),
|
|
1260
|
+
initialValue: true
|
|
1261
|
+
});
|
|
1262
|
+
if (!shouldContinue || isCancel5(shouldContinue)) {
|
|
1263
|
+
cancel5("Create cancelled.");
|
|
1264
|
+
return 0;
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
if (isAvailable === "exists") {
|
|
1268
|
+
const shouldContinue = await confirm3({
|
|
1269
|
+
message: pc6.yellow(
|
|
1270
|
+
`Project name "${finalProjectName}" already exists on FTP. Continue?`
|
|
1271
|
+
),
|
|
1272
|
+
initialValue: false
|
|
1273
|
+
});
|
|
1274
|
+
if (!shouldContinue || isCancel5(shouldContinue)) {
|
|
1275
|
+
cancel5("Create cancelled.");
|
|
1276
|
+
return 0;
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
const projectType = await select3({
|
|
1280
|
+
message: "Select a project type:",
|
|
1281
|
+
options: templates_default.projects.map((p) => ({ value: p, label: p.name }))
|
|
1282
|
+
});
|
|
1283
|
+
if (isCancel5(projectType)) {
|
|
1284
|
+
cancel5("Operation cancelled.");
|
|
1285
|
+
return 0;
|
|
1286
|
+
}
|
|
1287
|
+
const selectedProject = projectType;
|
|
1288
|
+
if (await fs5.access(projectDest).then(() => true).catch(() => false)) {
|
|
1289
|
+
cancel5(`Directory ${pc6.cyan(projectDest)} already exists.`);
|
|
1290
|
+
return 1;
|
|
1291
|
+
}
|
|
1292
|
+
try {
|
|
1293
|
+
const exitCode = await selectedProject.run({
|
|
1294
|
+
projectName: finalProjectName,
|
|
1295
|
+
baseDir: projectDest
|
|
1296
|
+
});
|
|
1297
|
+
if (exitCode !== 0) {
|
|
1298
|
+
return 0;
|
|
1299
|
+
}
|
|
1300
|
+
} catch (err) {
|
|
1301
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1302
|
+
cancel5(`Failed to create project: ${message}`);
|
|
1303
|
+
if (err instanceof Error && err.stack) {
|
|
1304
|
+
console.error(err.stack);
|
|
1305
|
+
}
|
|
1306
|
+
return 1;
|
|
1307
|
+
}
|
|
1308
|
+
const installSpinner = spin("Installing dependencies...");
|
|
1309
|
+
try {
|
|
1310
|
+
await $6({ cwd: projectDest })`npm install`.quiet();
|
|
1311
|
+
installSpinner.stop("Dependencies installed");
|
|
1312
|
+
} catch {
|
|
1313
|
+
installSpinner.cancel(
|
|
1314
|
+
"Failed to install dependencies. You may need to run 'npm install' manually."
|
|
1315
|
+
);
|
|
1316
|
+
}
|
|
1317
|
+
try {
|
|
1318
|
+
await $6({ cwd: projectDest })`git init`.quiet();
|
|
1319
|
+
} catch {
|
|
1320
|
+
}
|
|
1321
|
+
log4.step("Next steps:");
|
|
1322
|
+
log4.message(
|
|
1323
|
+
`
|
|
1324
|
+
${pc6.bold(1)}. cd ${finalProjectName}
|
|
1325
|
+
${pc6.bold(2)}. npm run dev
|
|
1326
|
+
`.trim()
|
|
1327
|
+
);
|
|
1328
|
+
outro3("Happy coding.");
|
|
1329
|
+
return 0;
|
|
1330
|
+
}
|
|
1331
|
+
var init_create = __esm({
|
|
1332
|
+
"src/commands/create/index.ts"() {
|
|
1333
|
+
"use strict";
|
|
1334
|
+
init_terminal();
|
|
1335
|
+
init_ftp();
|
|
1336
|
+
init_templates();
|
|
1337
|
+
}
|
|
1338
|
+
});
|
|
1339
|
+
|
|
1340
|
+
// src/commands/build/index.ts
|
|
1341
|
+
import { intro as intro5, outro as outro4, log as log5 } from "@clack/prompts";
|
|
1342
|
+
import pc7 from "picocolors";
|
|
1343
|
+
async function run7() {
|
|
1344
|
+
intro5(getHeader(pc7.dim("aunty"), "build", { colour: "blue" }));
|
|
1345
|
+
outro4("Building project for production...");
|
|
1346
|
+
try {
|
|
1347
|
+
await runBuild({ stdio: "inherit" });
|
|
1348
|
+
return 0;
|
|
1349
|
+
} catch (err) {
|
|
1350
|
+
if (err.exitCode !== void 0) {
|
|
1351
|
+
return err.exitCode;
|
|
1352
|
+
}
|
|
1353
|
+
log5.error(err.message || `Failed to start npm command: ${err.message}`);
|
|
1354
|
+
return 1;
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
var init_build = __esm({
|
|
1358
|
+
"src/commands/build/index.ts"() {
|
|
1359
|
+
"use strict";
|
|
1360
|
+
init_terminal();
|
|
1361
|
+
init_util();
|
|
1362
|
+
}
|
|
1363
|
+
});
|
|
1364
|
+
|
|
1365
|
+
// src/commands/serve/index.ts
|
|
1366
|
+
import { intro as intro6, outro as outro5, log as log6 } from "@clack/prompts";
|
|
1367
|
+
import pc8 from "picocolors";
|
|
1368
|
+
import { $ as $7 } from "zx";
|
|
1369
|
+
async function run8() {
|
|
1370
|
+
intro6(getHeader(pc8.dim("aunty"), "serve", { colour: "cyan" }));
|
|
1371
|
+
outro5("Starting development server...");
|
|
1372
|
+
const details = await findProjectDetails(process.cwd());
|
|
1373
|
+
if (!details) return 1;
|
|
1374
|
+
const { pkg: pkg2 } = details;
|
|
1375
|
+
const hasDevScript = !!pkg2.scripts?.dev;
|
|
1376
|
+
if (!hasDevScript) {
|
|
1377
|
+
log6.error(
|
|
1378
|
+
`Could not find a ${pc8.cyan("dev")} script in package.json.`
|
|
1379
|
+
);
|
|
1380
|
+
return 1;
|
|
1381
|
+
}
|
|
1382
|
+
try {
|
|
1383
|
+
const isVite = pkg2.scripts?.dev?.includes("vite");
|
|
1384
|
+
if (isVite) {
|
|
1385
|
+
await $7({ stdio: "inherit" })`npm run dev -- --clearScreen false`;
|
|
1386
|
+
} else {
|
|
1387
|
+
await $7({ stdio: "inherit" })`npm run dev`;
|
|
1388
|
+
}
|
|
1389
|
+
return 0;
|
|
1390
|
+
} catch (err) {
|
|
1391
|
+
if (err.exitCode !== void 0) {
|
|
1392
|
+
return err.exitCode;
|
|
1393
|
+
}
|
|
1394
|
+
log6.error(`Failed to start npm command: ${err.message}`);
|
|
1395
|
+
return 1;
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
var init_serve = __esm({
|
|
1399
|
+
"src/commands/serve/index.ts"() {
|
|
1400
|
+
"use strict";
|
|
1401
|
+
init_terminal();
|
|
1402
|
+
init_util();
|
|
1403
|
+
}
|
|
1404
|
+
});
|
|
1405
|
+
|
|
1406
|
+
// src/commands/migrate/index.ts
|
|
1407
|
+
import { intro as intro7, outro as outro6, confirm as confirm4, log as log7, cancel as cancel6, isCancel as isCancel6 } from "@clack/prompts";
|
|
1408
|
+
import path11 from "node:path";
|
|
1409
|
+
import fs6 from "node:fs/promises";
|
|
1410
|
+
import pc9 from "picocolors";
|
|
1411
|
+
import { $ as $8, glob } from "zx";
|
|
1412
|
+
async function migrateHtmlFile(srcPath, destPath, entryFile) {
|
|
1413
|
+
let content = await fs6.readFile(srcPath, "utf-8");
|
|
1414
|
+
content = content.replace(
|
|
1415
|
+
/<script\s+src=["'](?:index\.js|index_modern\.js)["']\s*><\/script>/gi,
|
|
1416
|
+
""
|
|
1417
|
+
);
|
|
1418
|
+
content = content.replace(/<!--[\s\S]*?-->/g, "");
|
|
1419
|
+
content = content.replace(/<script([\s\S]*?)>([\s\S]*?)<\/script>/gi, (match, attributes, innerContent) => {
|
|
1420
|
+
const hasOdysseyApi = innerContent.includes("odyssey:api");
|
|
1421
|
+
const isClassicScript = !attributes.trim() || attributes.includes('type="text/javascript"') || attributes.includes("type='text/javascript'");
|
|
1422
|
+
if (hasOdysseyApi && isClassicScript) {
|
|
1423
|
+
return `<script type="module">${innerContent}</script>`;
|
|
1424
|
+
}
|
|
1425
|
+
return match;
|
|
1426
|
+
});
|
|
1427
|
+
const scriptTag = `<script type="module" src="/${entryFile}"></script>`;
|
|
1428
|
+
if (content.includes("</head>")) {
|
|
1429
|
+
content = content.replace("</head>", ` ${scriptTag}
|
|
1430
|
+
</head>`);
|
|
1431
|
+
} else {
|
|
1432
|
+
content = scriptTag + "\n" + content;
|
|
1433
|
+
}
|
|
1434
|
+
await fs6.mkdir(path11.dirname(destPath), { recursive: true });
|
|
1435
|
+
await fs6.writeFile(destPath, content);
|
|
1436
|
+
await fs6.unlink(srcPath);
|
|
1437
|
+
}
|
|
1438
|
+
async function run9(options = {}) {
|
|
1439
|
+
intro7(getHeader(pc9.dim("aunty"), "migrate", { colour: "rainbow" }));
|
|
1440
|
+
const details = await findProjectDetails(process.cwd());
|
|
1441
|
+
if (!details) {
|
|
1442
|
+
cancel6(
|
|
1443
|
+
"Could not find package.json. Please run this command inside an aunty project."
|
|
1444
|
+
);
|
|
1445
|
+
return 1;
|
|
1446
|
+
}
|
|
1447
|
+
const baseDir = details.root;
|
|
1448
|
+
const configPath = path11.join(baseDir, "aunty.config.js");
|
|
1449
|
+
const hasConfig = await fs6.access(configPath).then(() => true).catch(() => false);
|
|
1450
|
+
if (hasConfig) {
|
|
1451
|
+
log7.error(
|
|
1452
|
+
`Found legacy ${pc9.cyan("aunty.config.js")} at the root of the project. We cannot migrate this project automatically. Please delete or rename the file before continuing, and configure Vite manually after migration.`
|
|
1453
|
+
);
|
|
1454
|
+
return 1;
|
|
1455
|
+
}
|
|
1456
|
+
if (!options.skipGit) {
|
|
1457
|
+
const gitAccessible = await isAccessible();
|
|
1458
|
+
const insideRepo = gitAccessible ? await isInsideRepo() : false;
|
|
1459
|
+
if (!gitAccessible) {
|
|
1460
|
+
log7.error(
|
|
1461
|
+
"Git is not accessible (please ensure git is installed and Xcode/licenses are accepted)."
|
|
1462
|
+
);
|
|
1463
|
+
return 1;
|
|
1464
|
+
}
|
|
1465
|
+
if (!insideRepo) {
|
|
1466
|
+
log7.error("The current directory is not a git repository.");
|
|
1467
|
+
return 1;
|
|
1468
|
+
}
|
|
1469
|
+
if (!await isClean()) {
|
|
1470
|
+
log7.error(
|
|
1471
|
+
"You have uncommitted changes. Please commit or stash them before migrating."
|
|
1472
|
+
);
|
|
1473
|
+
return 1;
|
|
1474
|
+
}
|
|
1475
|
+
if (await hasRemote()) {
|
|
1476
|
+
if (await isBehindRemote()) {
|
|
1477
|
+
log7.error(
|
|
1478
|
+
"Your local branch is behind the remote. Please pull the latest changes before migrating."
|
|
1479
|
+
);
|
|
1480
|
+
return 1;
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
const publicHtmlPath = path11.join(baseDir, "public/index.html");
|
|
1485
|
+
try {
|
|
1486
|
+
await fs6.access(publicHtmlPath);
|
|
1487
|
+
} catch {
|
|
1488
|
+
log7.error(
|
|
1489
|
+
`Could not find public/index.html. This project does not seem to match the expected legacy structure.`
|
|
1490
|
+
);
|
|
1491
|
+
return 1;
|
|
1492
|
+
}
|
|
1493
|
+
const hasTS = await fs6.access(path11.join(baseDir, "src/index.ts")).then(() => true).catch(() => false);
|
|
1494
|
+
const hasJS = await fs6.access(path11.join(baseDir, "src/index.js")).then(() => true).catch(() => false);
|
|
1495
|
+
if (!hasTS && !hasJS) {
|
|
1496
|
+
log7.error("Could not find src/index.ts or src/index.js entry point.");
|
|
1497
|
+
return 1;
|
|
1498
|
+
}
|
|
1499
|
+
const entryFile = hasTS ? "src/index.ts" : "src/index.js";
|
|
1500
|
+
log7.message("Attempt to migrate an Aunty Webpack project to Aunty Vite.");
|
|
1501
|
+
log7.message(
|
|
1502
|
+
"This is a fairly naive and destructive process, and may not work for your specific configuration."
|
|
1503
|
+
);
|
|
1504
|
+
log7.message(
|
|
1505
|
+
"Please make take a backup or ensure Git is pushed before proceeding."
|
|
1506
|
+
);
|
|
1507
|
+
if (!options.yes) {
|
|
1508
|
+
const shouldContinue = await confirm4({
|
|
1509
|
+
message: "Are you sure you want to migrate this project to Vite?",
|
|
1510
|
+
initialValue: true
|
|
1511
|
+
});
|
|
1512
|
+
if (!shouldContinue || isCancel6(shouldContinue)) {
|
|
1513
|
+
cancel6("Migration cancelled.");
|
|
1514
|
+
return 0;
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
const migrationSpinner = spin("Migrating configuration files...");
|
|
1518
|
+
try {
|
|
1519
|
+
const templateDir = path11.resolve(
|
|
1520
|
+
import.meta.dirname,
|
|
1521
|
+
"../../../templates/svelte/base/contents"
|
|
1522
|
+
);
|
|
1523
|
+
const filesToCopy = [
|
|
1524
|
+
"vite.config.ts",
|
|
1525
|
+
"svelte.config.js",
|
|
1526
|
+
"tsconfig.json",
|
|
1527
|
+
"tsconfig.app.json",
|
|
1528
|
+
"tsconfig.node.json"
|
|
1529
|
+
];
|
|
1530
|
+
for (const file of filesToCopy) {
|
|
1531
|
+
const srcPath = path11.join(templateDir, file);
|
|
1532
|
+
const destPath = path11.join(baseDir, file);
|
|
1533
|
+
await fs6.copyFile(srcPath, destPath);
|
|
1534
|
+
}
|
|
1535
|
+
const templateGitignorePath = path11.join(templateDir, "_gitignore");
|
|
1536
|
+
const targetGitignorePath = path11.join(baseDir, ".gitignore");
|
|
1537
|
+
let existingGitignore = "";
|
|
1538
|
+
try {
|
|
1539
|
+
existingGitignore = await fs6.readFile(targetGitignorePath, "utf-8");
|
|
1540
|
+
} catch {
|
|
1541
|
+
}
|
|
1542
|
+
const templateGitignore = await fs6.readFile(templateGitignorePath, "utf-8");
|
|
1543
|
+
const uniqueRules = Array.from(
|
|
1544
|
+
new Set(
|
|
1545
|
+
[
|
|
1546
|
+
...existingGitignore.split(/\r?\n/),
|
|
1547
|
+
...templateGitignore.split(/\r?\n/)
|
|
1548
|
+
].map((line) => line.trim()).filter((line) => line && !line.startsWith("#"))
|
|
1549
|
+
)
|
|
1550
|
+
);
|
|
1551
|
+
await fs6.writeFile(targetGitignorePath, uniqueRules.join("\n") + "\n");
|
|
1552
|
+
const destHtmlPath = path11.join(baseDir, "index.html");
|
|
1553
|
+
await migrateHtmlFile(publicHtmlPath, destHtmlPath, entryFile);
|
|
1554
|
+
const publicBuilderHtmlPath = path11.join(baseDir, "public/builder/index.html");
|
|
1555
|
+
const hasLegacyBuilder = await fs6.access(publicBuilderHtmlPath).then(() => true).catch(() => false);
|
|
1556
|
+
if (hasLegacyBuilder) {
|
|
1557
|
+
const destBuilderHtmlPath = path11.join(baseDir, "builder/index.html");
|
|
1558
|
+
await migrateHtmlFile(publicBuilderHtmlPath, destBuilderHtmlPath, entryFile);
|
|
1559
|
+
try {
|
|
1560
|
+
await fs6.rmdir(path11.join(baseDir, "public/builder"));
|
|
1561
|
+
} catch {
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
migrationSpinner.stop(
|
|
1565
|
+
"Configuration files updated and index.html migrated successfully" + (hasLegacyBuilder ? " (including builder)" : "")
|
|
1566
|
+
);
|
|
1567
|
+
} catch (err) {
|
|
1568
|
+
migrationSpinner.cancel("Failed during file migration step");
|
|
1569
|
+
log7.error(err.message || String(err));
|
|
1570
|
+
return 1;
|
|
1571
|
+
}
|
|
1572
|
+
const pkgSpinner = spin("Updating package.json dependencies and scripts...");
|
|
1573
|
+
try {
|
|
1574
|
+
const templateDir = path11.resolve(
|
|
1575
|
+
import.meta.dirname,
|
|
1576
|
+
"../../../templates/svelte/base/contents"
|
|
1577
|
+
);
|
|
1578
|
+
const pkgPath2 = path11.join(baseDir, "package.json");
|
|
1579
|
+
const pkg2 = await loadJson(pkgPath2);
|
|
1580
|
+
const templatePkg = await loadJson(
|
|
1581
|
+
path11.join(templateDir, "package.json")
|
|
1582
|
+
);
|
|
1583
|
+
pkg2.type = "module";
|
|
1584
|
+
if (!pkg2.scripts) pkg2.scripts = {};
|
|
1585
|
+
pkg2.scripts.dev = "vite serve";
|
|
1586
|
+
pkg2.scripts.build = "vite build";
|
|
1587
|
+
pkg2.scripts.check = "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json";
|
|
1588
|
+
pkg2.scripts.format = "prettier --write .";
|
|
1589
|
+
if (pkg2.scripts.start === "aunty serve") {
|
|
1590
|
+
delete pkg2.scripts.start;
|
|
1591
|
+
}
|
|
1592
|
+
if (!pkg2.dependencies) pkg2.dependencies = {};
|
|
1593
|
+
if (!pkg2.devDependencies) pkg2.devDependencies = {};
|
|
1594
|
+
const oldDeps = { ...pkg2.dependencies || {}, ...pkg2.devDependencies || {} };
|
|
1595
|
+
const hasSassDep = "sass" in oldDeps || "node-sass" in oldDeps;
|
|
1596
|
+
const scssFiles = await glob("src/**/*.s[ac]ss", { cwd: baseDir });
|
|
1597
|
+
const hasSass = hasSassDep || scssFiles.length > 0;
|
|
1598
|
+
Object.assign(pkg2.dependencies, templatePkg.dependencies || {});
|
|
1599
|
+
Object.assign(pkg2.devDependencies, templatePkg.devDependencies || {});
|
|
1600
|
+
if (hasSass) {
|
|
1601
|
+
pkg2.devDependencies["sass-embedded"] = "^1.83.0";
|
|
1602
|
+
}
|
|
1603
|
+
await fs6.writeFile(pkgPath2, JSON.stringify(pkg2, null, 2) + "\n");
|
|
1604
|
+
await installAunty(baseDir);
|
|
1605
|
+
pkgSpinner.stop("package.json updated");
|
|
1606
|
+
} catch (err) {
|
|
1607
|
+
pkgSpinner.cancel("Failed to update package.json");
|
|
1608
|
+
log7.error(err.message || String(err));
|
|
1609
|
+
return 1;
|
|
1610
|
+
}
|
|
1611
|
+
const installSpinner = spin("Installing dependencies via npm...");
|
|
1612
|
+
try {
|
|
1613
|
+
await $8({ cwd: baseDir })`npm install`.quiet();
|
|
1614
|
+
installSpinner.stop("Dependencies installed");
|
|
1615
|
+
} catch (err) {
|
|
1616
|
+
installSpinner.cancel("Failed to install dependencies.");
|
|
1617
|
+
log7.error(`npm install failed: ${err.message || String(err)}`);
|
|
1618
|
+
return 1;
|
|
1619
|
+
}
|
|
1620
|
+
outro6(
|
|
1621
|
+
"Migration completed successfully! You can now run 'npm run dev' to start development."
|
|
1622
|
+
);
|
|
1623
|
+
return 0;
|
|
1624
|
+
}
|
|
1625
|
+
var init_migrate = __esm({
|
|
1626
|
+
"src/commands/migrate/index.ts"() {
|
|
1627
|
+
"use strict";
|
|
1628
|
+
init_terminal();
|
|
1629
|
+
init_util();
|
|
1630
|
+
init_git();
|
|
1631
|
+
init_initHelpers();
|
|
1632
|
+
}
|
|
1633
|
+
});
|
|
1634
|
+
|
|
1635
|
+
// src/lib/colours.json
|
|
1636
|
+
var colours_default;
|
|
1637
|
+
var init_colours = __esm({
|
|
1638
|
+
"src/lib/colours.json"() {
|
|
1639
|
+
colours_default = {
|
|
1640
|
+
commands: {
|
|
1641
|
+
deploy: "red",
|
|
1642
|
+
create: "green",
|
|
1643
|
+
new: "green",
|
|
1644
|
+
"release-check": "magenta",
|
|
1645
|
+
release: "yellow",
|
|
1646
|
+
serve: "cyan",
|
|
1647
|
+
build: "blue",
|
|
1648
|
+
migrate: "rainbow"
|
|
1649
|
+
}
|
|
1650
|
+
};
|
|
1651
|
+
}
|
|
1652
|
+
});
|
|
1653
|
+
|
|
1654
|
+
// src/bin/commander.ts
|
|
1655
|
+
var commander_exports = {};
|
|
1656
|
+
import path12 from "node:path";
|
|
1657
|
+
import { Command, Help } from "commander";
|
|
1658
|
+
import pc10 from "picocolors";
|
|
1659
|
+
var colours, pcColors, pkgPath, pkg, version, program;
|
|
1660
|
+
var init_commander = __esm({
|
|
1661
|
+
async "src/bin/commander.ts"() {
|
|
1662
|
+
"use strict";
|
|
1663
|
+
init_deploy();
|
|
1664
|
+
init_release_check();
|
|
1665
|
+
init_release();
|
|
1666
|
+
init_create();
|
|
1667
|
+
init_build();
|
|
1668
|
+
init_serve();
|
|
1669
|
+
init_migrate();
|
|
1670
|
+
init_terminal();
|
|
1671
|
+
init_util();
|
|
1672
|
+
init_colours();
|
|
1673
|
+
colours = colours_default;
|
|
1674
|
+
pcColors = pc10;
|
|
1675
|
+
pkgPath = path12.join(import.meta.dirname, "../../package.json");
|
|
1676
|
+
pkg = await loadJson(pkgPath);
|
|
1677
|
+
version = pkg?.version || "0.0.0";
|
|
1678
|
+
program = new Command();
|
|
1679
|
+
program.name("aunty").description(
|
|
1680
|
+
getHeader(
|
|
1681
|
+
`${pkg.name}${pc10.dim("@" + pkg.version)}`,
|
|
1682
|
+
`${pc10.dim(pkg.description.slice(0, 73))}`,
|
|
1683
|
+
{ prepend: "" }
|
|
1684
|
+
) + "\n" + pc10.dim("\u2500".repeat(80))
|
|
1685
|
+
).version(version);
|
|
1686
|
+
program.configureHelp({
|
|
1687
|
+
subcommandTerm: (cmd) => {
|
|
1688
|
+
const name = cmd.name();
|
|
1689
|
+
const colourName = colours.commands[name];
|
|
1690
|
+
const colourFn = colourName && typeof pcColors[colourName] === "function" ? pcColors[colourName] : (str) => str;
|
|
1691
|
+
const term = new Help().subcommandTerm(cmd);
|
|
1692
|
+
return term.replace(name, colourFn(name));
|
|
1693
|
+
},
|
|
1694
|
+
formatHelp: (cmd, helper) => {
|
|
1695
|
+
const baseHelp = new Help().formatHelp(cmd, helper);
|
|
1696
|
+
if (cmd.parent) {
|
|
1697
|
+
const name = cmd.name();
|
|
1698
|
+
const colourName = colours.commands[name] || "rainbow";
|
|
1699
|
+
const logoHeader = getHeader("aunty", name, {
|
|
1700
|
+
prepend: "",
|
|
1701
|
+
colour: colourName
|
|
1702
|
+
});
|
|
1703
|
+
return `${logoHeader}
|
|
1704
|
+
|
|
1705
|
+
${baseHelp}`;
|
|
1706
|
+
}
|
|
1707
|
+
return baseHelp;
|
|
1708
|
+
}
|
|
1709
|
+
});
|
|
1710
|
+
program.command("deploy").description(
|
|
1711
|
+
"Deploy the project to FTP. This deploys the current dist/ folder to the specified remote folder, falling back to the current version number. Use this to retry a failed release."
|
|
1712
|
+
).argument(
|
|
1713
|
+
"[destDir]",
|
|
1714
|
+
"Override the target folder name (defaults to package.json version)"
|
|
1715
|
+
).option("-d, --dry-run", "Show what would happen without uploading", false).option("-f, --force", "Overwrite the remote directory if it exists", false).action(async (destDir, options) => {
|
|
1716
|
+
process.exit(await run({ destDir, ...options }));
|
|
1717
|
+
});
|
|
1718
|
+
program.command("create").description("Create a new project from a template").argument("[destDir]", "Directory to create the project in").action(async (destDir) => {
|
|
1719
|
+
process.exit(await run6(destDir));
|
|
1720
|
+
});
|
|
1721
|
+
program.command("new", { hidden: true }).description("Alias for create").argument("[destDir]", "Directory to create the project in").action(async (destDir) => {
|
|
1722
|
+
process.exit(await run6(destDir));
|
|
1723
|
+
});
|
|
1724
|
+
program.command("release-check").description("Perform pre-release checks").action(async () => {
|
|
1725
|
+
process.exit(await run2());
|
|
1726
|
+
});
|
|
1727
|
+
program.command("release").description("Version and release your project to FTP").option("--version <version>", "Override the release version directly").action(async (options) => {
|
|
1728
|
+
process.exit(await run3(options));
|
|
1729
|
+
});
|
|
1730
|
+
program.command("serve").description("Start a local development server").action(async () => {
|
|
1731
|
+
await run8();
|
|
1732
|
+
});
|
|
1733
|
+
program.command("build").description("Build the project for production").action(async () => {
|
|
1734
|
+
process.exit(await run7());
|
|
1735
|
+
});
|
|
1736
|
+
program.command("migrate").description("Migrate a legacy project to use Vite and the latest version of aunty").option("-y, --yes", "Skip confirmation prompt", false).option("--skip-git", "Skip Git safety checks", false).action(async (options) => {
|
|
1737
|
+
process.exit(await run9(options));
|
|
1738
|
+
});
|
|
1739
|
+
program.command("dev-colours", { hidden: true }).description("Test all available gradient colours").action(() => {
|
|
1740
|
+
printDevColours();
|
|
1741
|
+
process.exit(0);
|
|
1742
|
+
});
|
|
1743
|
+
try {
|
|
1744
|
+
await program.parseAsync(process.argv);
|
|
1745
|
+
} catch (err) {
|
|
1746
|
+
if (err instanceof Error) {
|
|
1747
|
+
console.error(`${pc10.dim(err.stack)}`);
|
|
1748
|
+
} else {
|
|
1749
|
+
console.error(`${pc10.red(pc10.bold("Error:"))} ${pc10.red(`\u2018${String(err)}\u2019`)}`);
|
|
1750
|
+
}
|
|
1751
|
+
console.error(
|
|
1752
|
+
`${pc10.red(pc10.bold("\u25A0 Aunty has encountered an unhandled error."))}
|
|
1753
|
+
\u2514 This is likely a bug. Please report it at: ${pc10.cyan("https://github.com/abcnews/aunty/issues/new")}`
|
|
1754
|
+
);
|
|
1755
|
+
process.exit(1);
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
});
|
|
1759
|
+
|
|
1760
|
+
// src/bin/aunty.ts
|
|
1761
|
+
import { existsSync } from "node:fs";
|
|
1762
|
+
import { realpath } from "node:fs/promises";
|
|
1763
|
+
import path13 from "node:path";
|
|
1764
|
+
import { fileURLToPath } from "node:url";
|
|
1765
|
+
import { $ as $9 } from "zx";
|
|
1766
|
+
var filename = fileURLToPath(import.meta.url);
|
|
1767
|
+
async function run10() {
|
|
1768
|
+
const localAuntyPath = path13.join(
|
|
1769
|
+
process.cwd(),
|
|
1770
|
+
"node_modules/@abcnews/aunty/dist/bin/aunty.js"
|
|
1771
|
+
);
|
|
1772
|
+
const isMigrate = process.argv.includes("migrate");
|
|
1773
|
+
if (!isMigrate && existsSync(localAuntyPath) && await realpath(localAuntyPath) !== await realpath(filename)) {
|
|
1774
|
+
const result = await $9({ stdio: "inherit", nothrow: true })`${process.execPath} ${localAuntyPath} ${process.argv.slice(2)}`;
|
|
1775
|
+
process.exit(result.exitCode);
|
|
1776
|
+
}
|
|
1777
|
+
await init_commander().then(() => commander_exports);
|
|
1778
|
+
}
|
|
1779
|
+
run10().catch((err) => {
|
|
1780
|
+
console.error(err);
|
|
1781
|
+
process.exit(1);
|
|
1782
|
+
});
|