create-astro 1.0.2 → 1.2.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/dist/index.js CHANGED
@@ -1,24 +1,27 @@
1
+ import { color, generateProjectName, label, say } from "@astrojs/cli-kit";
2
+ import { random } from "@astrojs/cli-kit/utils";
1
3
  import { assign, parse, stringify } from "comment-json";
2
- import degit from "degit";
3
4
  import { execa, execaCommand } from "execa";
4
5
  import fs from "fs";
5
- import { bgCyan, black, bold, cyan, dim, gray, green, red, reset, yellow } from "kleur/colors";
6
+ import { downloadTemplate } from "giget";
7
+ import { bold, dim, green, reset, yellow } from "kleur/colors";
6
8
  import ora from "ora";
7
- import os from "os";
8
9
  import path from "path";
9
10
  import prompts from "prompts";
10
11
  import detectPackageManager from "which-pm-runs";
11
12
  import yargs from "yargs-parser";
12
13
  import { loadWithRocketGradient, rocketAscii } from "./gradient.js";
13
- import { defaultLogLevel, logger } from "./logger.js";
14
+ import { logger } from "./logger.js";
15
+ import {
16
+ banner,
17
+ getName,
18
+ getVersion,
19
+ info,
20
+ nextSteps,
21
+ typescriptByDefault,
22
+ welcome
23
+ } from "./messages.js";
14
24
  import { TEMPLATES } from "./templates.js";
15
- function wait(ms) {
16
- return new Promise((resolve) => setTimeout(resolve, ms));
17
- }
18
- function logAndWait(message, ms = 100) {
19
- console.log(message);
20
- return wait(ms);
21
- }
22
25
  const cleanArgv = process.argv.filter((arg) => arg !== "--");
23
26
  const args = yargs(cleanArgv);
24
27
  prompts.override(args);
@@ -31,9 +34,6 @@ function mkdirp(dir) {
31
34
  throw e;
32
35
  }
33
36
  }
34
- function isEmpty(dirPath) {
35
- return !fs.existsSync(dirPath) || fs.readdirSync(dirPath).length === 0;
36
- }
37
37
  const VALID_PROJECT_DIRECTORY_SAFE_LIST = [
38
38
  ".DS_Store",
39
39
  ".git",
@@ -68,18 +68,25 @@ function isValidProjectDirectory(dirPath) {
68
68
  });
69
69
  return conflicts.length === 0;
70
70
  }
71
- const { version } = JSON.parse(
72
- fs.readFileSync(new URL("../package.json", import.meta.url), "utf-8")
73
- );
74
71
  const FILES_TO_REMOVE = [".stackblitzrc", "sandbox.config.json", "CHANGELOG.md"];
75
72
  async function main() {
76
73
  var _a;
77
74
  const pkgManager = ((_a = detectPackageManager()) == null ? void 0 : _a.name) || "npm";
75
+ const [username, version] = await Promise.all([getName(), getVersion()]);
78
76
  logger.debug("Verbose logging turned on");
79
- console.log(`
80
- ${bold("Welcome to Astro!")} ${gray(`(create-astro v${version})`)}`);
81
- console.log(`Lets walk through setting up your new Astro project.
82
- `);
77
+ if (!args.skipHouston) {
78
+ await say([
79
+ [
80
+ "Welcome",
81
+ "to",
82
+ label("astro", color.bgGreen, color.black),
83
+ color.green(`v${version}`) + ",",
84
+ `${username}!`
85
+ ],
86
+ random(welcome)
87
+ ]);
88
+ await banner(version);
89
+ }
83
90
  let cwd = args["_"][2];
84
91
  if (cwd && isValidProjectDirectory(cwd)) {
85
92
  let acknowledgeProjectDir = ora({
@@ -99,7 +106,7 @@ ${bold("Welcome to Astro!")} ${gray(`(create-astro v${version})`)}`);
99
106
  type: "text",
100
107
  name: "directory",
101
108
  message: "Where would you like to create your new project?",
102
- initial: "./my-astro-site",
109
+ initial: `./${generateProjectName()}`,
103
110
  validate(value) {
104
111
  if (!isValidProjectDirectory(value)) {
105
112
  return notEmptyMsg(value);
@@ -119,7 +126,7 @@ ${bold("Welcome to Astro!")} ${gray(`(create-astro v${version})`)}`);
119
126
  {
120
127
  type: "select",
121
128
  name: "template",
122
- message: "Which template would you like to use?",
129
+ message: "How would you like to setup your new project?",
123
130
  choices: TEMPLATES
124
131
  }
125
132
  ],
@@ -132,72 +139,20 @@ ${bold("Welcome to Astro!")} ${gray(`(create-astro v${version})`)}`);
132
139
  const hash = args.commit ? `#${args.commit}` : "";
133
140
  const isThirdParty = options.template.includes("/");
134
141
  const templateTarget = isThirdParty ? options.template : `withastro/astro/examples/${options.template}#latest`;
135
- const emitter = degit(`${templateTarget}${hash}`, {
136
- cache: false,
137
- force: true,
138
- verbose: defaultLogLevel === "debug" ? true : false
139
- });
140
- logger.debug("Initialized degit with following config:", `${templateTarget}${hash}`, {
141
- cache: false,
142
- force: true,
143
- verbose: defaultLogLevel === "debug" ? true : false
144
- });
145
142
  if (!args.dryRun) {
146
143
  try {
147
- emitter.on("info", (info) => {
148
- logger.debug(info.message);
144
+ await downloadTemplate(`${templateTarget}${hash}`, {
145
+ force: true,
146
+ provider: "github",
147
+ cwd,
148
+ dir: "."
149
149
  });
150
- await emitter.clone(cwd);
151
- if (isValidProjectDirectory(cwd)) {
152
- if (isEmpty(cwd)) {
153
- fs.rmdirSync(cwd);
154
- }
155
- throw new Error(`Error: The provided template (${cyan(options.template)}) does not exist`);
156
- }
157
150
  } catch (err) {
158
- templateSpinner.fail();
159
- logger.debug(err);
160
- console.error(red(err.message));
161
- if (err.message === "zlib: unexpected end of file" || err.message === "TAR_BAD_ARCHIVE: Unrecognized archive format") {
162
- console.log(
163
- yellow(
164
- "Local degit cache seems to be corrupted. For more information check out this issue: https://github.com/withastro/astro/issues/655. "
165
- )
166
- );
167
- const cacheIssueResponse = await prompts({
168
- type: "confirm",
169
- name: "cache",
170
- message: "Would you like us to clear the cache and try again?",
171
- initial: true
172
- });
173
- if (cacheIssueResponse.cache) {
174
- const homeDirectory = os.homedir();
175
- const cacheDir = path.join(homeDirectory, ".degit", "github", "withastro");
176
- fs.rmSync(cacheDir, { recursive: true, force: true, maxRetries: 3 });
177
- templateSpinner = await loadWithRocketGradient("Copying project files...");
178
- try {
179
- await emitter.clone(cwd);
180
- } catch (e) {
181
- logger.debug(e);
182
- console.error(red(e.message));
183
- }
184
- } else {
185
- console.log(
186
- "Okay, no worries! To fix this manually, remove the folder '~/.degit/github/withastro' and rerun the command."
187
- );
188
- }
189
- }
190
- if (err.code === "MISSING_REF") {
191
- console.log(
192
- yellow(
193
- "This seems to be an issue with degit. Please check if you have 'git' installed on your system, and install it if you don't have (https://git-scm.com)."
194
- )
195
- );
196
- console.log(
197
- yellow(
198
- "If you do have 'git' installed, please run this command with the --verbose flag and file a new issue with the command output here: https://github.com/withastro/astro/issues"
199
- )
200
- );
151
+ fs.rmdirSync(cwd);
152
+ if (err.message.includes("404")) {
153
+ console.error(`Template ${color.underline(options.template)} does not exist!`);
154
+ } else {
155
+ console.error(err.message);
201
156
  }
202
157
  process.exit(1);
203
158
  }
@@ -252,7 +207,7 @@ ${bold(
252
207
  installSpinner.text = green("Packages installed!");
253
208
  installSpinner.succeed();
254
209
  } else {
255
- ora().info(dim(`No problem! Remember to install dependencies after setup.`));
210
+ await info("No problem!", "Remember to install dependencies after setup.");
256
211
  }
257
212
  const gitResponse = await prompts(
258
213
  {
@@ -276,7 +231,10 @@ ${bold(
276
231
  await execaCommand("git init", { cwd });
277
232
  ora().succeed("Git repository created!");
278
233
  } else {
279
- ora().info(dim(`Sounds good! You can come back and run ${cyan(`git init`)} later.`));
234
+ await info(
235
+ "Sounds good!",
236
+ `You can come back and run ${color.reset(`git init`)}${color.dim(" later.")}`
237
+ );
280
238
  }
281
239
  const tsResponse = await prompts(
282
240
  {
@@ -284,25 +242,10 @@ ${bold(
284
242
  name: "typescript",
285
243
  message: "How would you like to setup TypeScript?",
286
244
  choices: [
287
- {
288
- title: "Relaxed",
289
- value: "default"
290
- },
291
- {
292
- title: "Strict (recommended)",
293
- description: "Enable `strict` typechecking rules",
294
- value: "strict"
295
- },
296
- {
297
- title: "Strictest",
298
- description: "Enable all typechecking rules",
299
- value: "strictest"
300
- },
301
- {
302
- title: "I prefer not to use TypeScript",
303
- description: `That's cool too!`,
304
- value: "optout"
305
- }
245
+ { value: "strict", title: "Strict", description: "(recommended)" },
246
+ { value: "strictest", title: "Strictest" },
247
+ { value: "base", title: "Relaxed" },
248
+ { value: "unsure", title: "Help me choose" }
306
249
  ]
307
250
  },
308
251
  {
@@ -316,72 +259,42 @@ ${bold(
316
259
  }
317
260
  }
318
261
  );
319
- if (tsResponse.typescript === "optout") {
320
- console.log(``);
321
- ora().warn(yellow(bold(`Astro \u2764\uFE0F TypeScript!`)));
322
- console.log(` Astro supports TypeScript inside of ".astro" component scripts, so`);
323
- console.log(` we still need to create some TypeScript-related files in your project.`);
324
- console.log(` You can safely ignore these files, but don't delete them!`);
325
- console.log(dim(" (ex: tsconfig.json, src/env.d.ts)"));
326
- console.log(``);
327
- tsResponse.typescript = "default";
328
- await wait(300);
262
+ if (tsResponse.typescript === "unsure") {
263
+ await typescriptByDefault();
264
+ tsResponse.typescript = "base";
329
265
  }
330
266
  if (args.dryRun) {
331
267
  ora().info(dim(`--dry-run enabled, skipping.`));
332
268
  } else if (tsResponse.typescript) {
333
- if (tsResponse.typescript !== "default") {
334
- const templateTSConfigPath = path.join(cwd, "tsconfig.json");
335
- fs.readFile(templateTSConfigPath, (err, data) => {
336
- if (err && err.code === "ENOENT") {
337
- fs.writeFileSync(
338
- templateTSConfigPath,
339
- stringify({ extends: `astro/tsconfigs/${tsResponse.typescript}` }, null, 2)
340
- );
341
- return;
342
- }
343
- const templateTSConfig = parse(data.toString());
344
- if (templateTSConfig && typeof templateTSConfig === "object") {
345
- const result = assign(templateTSConfig, {
346
- extends: `astro/tsconfigs/${tsResponse.typescript}`
347
- });
348
- fs.writeFileSync(templateTSConfigPath, stringify(result, null, 2));
349
- } else {
350
- console.log(
351
- yellow(
352
- "There was an error applying the requested TypeScript settings. This could be because the template's tsconfig.json is malformed"
353
- )
354
- );
355
- }
356
- });
357
- }
269
+ const templateTSConfigPath = path.join(cwd, "tsconfig.json");
270
+ fs.readFile(templateTSConfigPath, (err, data) => {
271
+ if (err && err.code === "ENOENT") {
272
+ fs.writeFileSync(
273
+ templateTSConfigPath,
274
+ stringify({ extends: `astro/tsconfigs/${tsResponse.typescript}` }, null, 2)
275
+ );
276
+ return;
277
+ }
278
+ const templateTSConfig = parse(data.toString());
279
+ if (templateTSConfig && typeof templateTSConfig === "object") {
280
+ const result = assign(templateTSConfig, {
281
+ extends: `astro/tsconfigs/${tsResponse.typescript}`
282
+ });
283
+ fs.writeFileSync(templateTSConfigPath, stringify(result, null, 2));
284
+ } else {
285
+ console.log(
286
+ yellow(
287
+ "There was an error applying the requested TypeScript settings. This could be because the template's tsconfig.json is malformed"
288
+ )
289
+ );
290
+ }
291
+ });
358
292
  ora().succeed("TypeScript settings applied!");
359
293
  }
360
- ora().succeed("Setup complete.");
361
- ora({ text: green("Ready for liftoff!") }).succeed();
362
- await wait(300);
363
- console.log(`
364
- ${bgCyan(black(" Next steps "))}
365
- `);
366
294
  let projectDir = path.relative(process.cwd(), cwd);
367
295
  const devCmd = pkgManager === "npm" ? "npm run dev" : `${pkgManager} dev`;
368
- if (projectDir !== "/") {
369
- await logAndWait(
370
- `You can now ${bold(cyan("cd"))} into the ${bold(cyan(projectDir))} project directory.`
371
- );
372
- }
373
- await logAndWait(
374
- `Run ${bold(cyan(devCmd))} to start the Astro dev server. ${bold(cyan("CTRL-C"))} to close.`
375
- );
376
- await logAndWait(
377
- `Add frameworks like ${bold(cyan("react"))} and ${bold(
378
- cyan("tailwind")
379
- )} to your project using ${bold(cyan("astro add"))}`
380
- );
381
- await logAndWait("");
382
- await logAndWait(`Stuck? Come join us at ${bold(cyan("https://astro.build/chat"))}`, 750);
383
- await logAndWait(dim("Good luck out there, astronaut."));
384
- await logAndWait("", 300);
296
+ await nextSteps({ projectDir, devCmd });
297
+ await say(["Good luck out there, astronaut!"]);
385
298
  }
386
299
  function emojiWithFallback(char, fallback) {
387
300
  return process.platform !== "win32" ? char : fallback;
@@ -0,0 +1,134 @@
1
+ import { color, label } from "@astrojs/cli-kit";
2
+ import { sleep } from "@astrojs/cli-kit/utils";
3
+ import { exec } from "node:child_process";
4
+ import { get } from "node:https";
5
+ import stripAnsi from "strip-ansi";
6
+ const welcome = [
7
+ `Let's claim your corner of the internet.`,
8
+ `I'll be your assistant today.`,
9
+ `Let's build something awesome!`,
10
+ `Let's build something great!`,
11
+ `Let's build something fast!`,
12
+ `Let's make the web weird!`,
13
+ `Let's make the web a better place!`,
14
+ `Let's create a new project!`,
15
+ `Let's create something unqiue!`,
16
+ `Time to build a new website.`,
17
+ `Time to build a faster website.`,
18
+ `Time to build a sweet new website.`,
19
+ `We're glad to have you on board.`,
20
+ `Keeping the internet weird since 2021.`,
21
+ `Initiating launch sequence...`,
22
+ `Initiating launch sequence... right... now!`,
23
+ `Awaiting further instructions.`
24
+ ];
25
+ function getName() {
26
+ return new Promise((resolve) => {
27
+ exec("git config user.name", { encoding: "utf-8" }, (_1, gitName, _2) => {
28
+ if (gitName.trim()) {
29
+ return resolve(gitName.split(" ")[0].trim());
30
+ }
31
+ exec("whoami", { encoding: "utf-8" }, (_3, whoami, _4) => {
32
+ if (whoami.trim()) {
33
+ return resolve(whoami.split(" ")[0].trim());
34
+ }
35
+ return resolve("astronaut");
36
+ });
37
+ });
38
+ });
39
+ }
40
+ let v;
41
+ function getVersion() {
42
+ return new Promise((resolve) => {
43
+ if (v)
44
+ return resolve(v);
45
+ get("https://registry.npmjs.org/astro/latest", (res) => {
46
+ let body = "";
47
+ res.on("data", (chunk) => body += chunk);
48
+ res.on("end", () => {
49
+ const { version } = JSON.parse(body);
50
+ v = version;
51
+ resolve(version);
52
+ });
53
+ });
54
+ });
55
+ }
56
+ async function banner(version) {
57
+ return console.log(
58
+ `
59
+ ${label("astro", color.bgGreen, color.black)} ${color.green(
60
+ color.bold(`v${version}`)
61
+ )} ${color.bold("Launch sequence initiated.")}
62
+ `
63
+ );
64
+ }
65
+ async function info(prefix, text) {
66
+ await sleep(100);
67
+ if (process.stdout.columns < 80) {
68
+ console.log(`${color.cyan("\u25FC")} ${color.cyan(prefix)}`);
69
+ console.log(`${" ".repeat(3)}${color.dim(text)}
70
+ `);
71
+ } else {
72
+ console.log(`${color.cyan("\u25FC")} ${color.cyan(prefix)} ${color.dim(text)}
73
+ `);
74
+ }
75
+ }
76
+ async function error(prefix, text) {
77
+ if (process.stdout.columns < 80) {
78
+ console.log(`${" ".repeat(5)} ${color.red("\u25B2")} ${color.red(prefix)}`);
79
+ console.log(`${" ".repeat(9)}${color.dim(text)}`);
80
+ } else {
81
+ console.log(`${" ".repeat(5)} ${color.red("\u25B2")} ${color.red(prefix)} ${color.dim(text)}`);
82
+ }
83
+ }
84
+ async function typescriptByDefault() {
85
+ await info(`Cool!`, "Astro comes with TypeScript support enabled by default.");
86
+ console.log(
87
+ `${" ".repeat(3)}${color.dim(`We'll default to the most relaxed settings for you.`)}`
88
+ );
89
+ await sleep(300);
90
+ }
91
+ async function nextSteps({ projectDir, devCmd }) {
92
+ const max = process.stdout.columns;
93
+ const prefix = max < 80 ? " " : " ".repeat(9);
94
+ await sleep(200);
95
+ console.log(
96
+ `
97
+ ${color.bgCyan(` ${color.black("next")} `)} ${color.bold(
98
+ "Liftoff confirmed. Explore your project!"
99
+ )}`
100
+ );
101
+ await sleep(100);
102
+ if (projectDir !== "") {
103
+ const enter = [
104
+ `
105
+ ${prefix}Enter your project directory using`,
106
+ color.cyan(`cd ./${projectDir}`, "")
107
+ ];
108
+ const len = enter[0].length + stripAnsi(enter[1]).length;
109
+ console.log(enter.join(len > max ? "\n" + prefix : " "));
110
+ }
111
+ console.log(
112
+ `${prefix}Run ${color.cyan(devCmd)} to start the dev server. ${color.cyan("CTRL+C")} to stop.`
113
+ );
114
+ await sleep(100);
115
+ console.log(
116
+ `${prefix}Add frameworks like ${color.cyan(`react`)} or ${color.cyan(
117
+ "tailwind"
118
+ )} using ${color.cyan("astro add")}.`
119
+ );
120
+ await sleep(100);
121
+ console.log(`
122
+ ${prefix}Stuck? Join us at ${color.cyan(`https://astro.build/chat`)}`);
123
+ await sleep(200);
124
+ }
125
+ export {
126
+ banner,
127
+ error,
128
+ getName,
129
+ getVersion,
130
+ info,
131
+ nextSteps,
132
+ typescriptByDefault,
133
+ welcome
134
+ };
package/dist/templates.js CHANGED
@@ -1,24 +1,7 @@
1
1
  const TEMPLATES = [
2
- {
3
- title: "Just the basics (recommended)",
4
- value: "basics"
5
- },
6
- {
7
- title: "Blog",
8
- value: "blog"
9
- },
10
- {
11
- title: "Portfolio",
12
- value: "portfolio"
13
- },
14
- {
15
- title: "Documentation Site",
16
- value: "docs"
17
- },
18
- {
19
- title: "Empty project",
20
- value: "minimal"
21
- }
2
+ { value: "basics", title: "a few best practices (recommended)" },
3
+ { value: "blog", title: "a personal website starter kit" },
4
+ { value: "minimal", title: "an empty project" }
22
5
  ];
23
6
  export {
24
7
  TEMPLATES
@@ -0,0 +1,11 @@
1
+ export declare const welcome: string[];
2
+ export declare function getName(): Promise<unknown>;
3
+ export declare function getVersion(): Promise<string>;
4
+ export declare function banner(version: string): Promise<void>;
5
+ export declare function info(prefix: string, text: string): Promise<void>;
6
+ export declare function error(prefix: string, text: string): Promise<void>;
7
+ export declare function typescriptByDefault(): Promise<void>;
8
+ export declare function nextSteps({ projectDir, devCmd }: {
9
+ projectDir: string;
10
+ devCmd: string;
11
+ }): Promise<void>;
@@ -1,4 +1,4 @@
1
1
  export declare const TEMPLATES: {
2
- title: string;
3
2
  value: string;
3
+ title: string;
4
4
  }[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-astro",
3
- "version": "1.0.2",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "author": "withastro",
6
6
  "license": "MIT",
@@ -23,13 +23,15 @@
23
23
  "tsconfigs"
24
24
  ],
25
25
  "dependencies": {
26
+ "@astrojs/cli-kit": "^0.1.0",
26
27
  "chalk": "^5.0.1",
27
28
  "comment-json": "^4.2.3",
28
- "degit": "^2.8.4",
29
29
  "execa": "^6.1.0",
30
+ "giget": "^0.1.7",
30
31
  "kleur": "^4.1.4",
31
32
  "ora": "^6.1.0",
32
33
  "prompts": "^2.4.2",
34
+ "strip-ansi": "^7.0.1",
33
35
  "which-pm-runs": "^1.1.0",
34
36
  "yargs-parser": "^21.0.1"
35
37
  },
@@ -40,7 +42,7 @@
40
42
  "@types/prompts": "^2.0.14",
41
43
  "@types/which-pm-runs": "^1.0.0",
42
44
  "@types/yargs-parser": "^21.0.0",
43
- "astro-scripts": "0.0.7",
45
+ "astro-scripts": "0.0.8",
44
46
  "chai": "^4.3.6",
45
47
  "mocha": "^9.2.2",
46
48
  "uvu": "^0.5.3"