summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/create-astro/src/actions/context.ts54
-rw-r--r--packages/create-astro/src/actions/dependencies.ts21
-rw-r--r--packages/create-astro/src/actions/git.ts19
-rw-r--r--packages/create-astro/src/actions/intro.ts6
-rw-r--r--packages/create-astro/src/actions/next-steps.ts4
-rw-r--r--packages/create-astro/src/actions/project-name.ts6
-rw-r--r--packages/create-astro/src/actions/shared.ts18
-rw-r--r--packages/create-astro/src/actions/template.ts42
-rw-r--r--packages/create-astro/src/actions/typescript.ts20
-rw-r--r--packages/create-astro/src/index.ts34
-rw-r--r--packages/create-astro/src/messages.ts211
-rw-r--r--packages/create-astro/test/context.test.js28
-rw-r--r--packages/create-astro/test/dependencies.test.js52
-rw-r--r--packages/create-astro/test/git.test.js23
-rw-r--r--packages/create-astro/test/intro.test.js6
-rw-r--r--packages/create-astro/test/next.test.js6
-rw-r--r--packages/create-astro/test/project-name.test.js46
-rw-r--r--packages/create-astro/test/template.test.js18
-rw-r--r--packages/create-astro/test/typescript.test.js75
-rw-r--r--packages/create-astro/test/utils.js24
20 files changed, 412 insertions, 301 deletions
diff --git a/packages/create-astro/src/actions/context.ts b/packages/create-astro/src/actions/context.ts
index a73a42e13..35e2e4688 100644
--- a/packages/create-astro/src/actions/context.ts
+++ b/packages/create-astro/src/actions/context.ts
@@ -1,7 +1,7 @@
-import os from 'node:os';
+import { prompt } from '@astrojs/cli-kit';
import arg from 'arg';
+import os from 'node:os';
import detectPackageManager from 'which-pm-runs';
-import { prompt } from '@astrojs/cli-kit';
import { getName, getVersion } from '../messages.js';
@@ -26,27 +26,29 @@ export interface Context {
exit(code: number): never;
}
-
export async function getContext(argv: string[]): Promise<Context> {
- const flags = arg({
- '--template': String,
- '--ref': String,
- '--yes': Boolean,
- '--no': Boolean,
- '--install': Boolean,
- '--no-install': Boolean,
- '--git': Boolean,
- '--no-git': Boolean,
- '--typescript': String,
- '--skip-houston': Boolean,
- '--dry-run': Boolean,
- '--help': Boolean,
- '--fancy': Boolean,
+ const flags = arg(
+ {
+ '--template': String,
+ '--ref': String,
+ '--yes': Boolean,
+ '--no': Boolean,
+ '--install': Boolean,
+ '--no-install': Boolean,
+ '--git': Boolean,
+ '--no-git': Boolean,
+ '--typescript': String,
+ '--skip-houston': Boolean,
+ '--dry-run': Boolean,
+ '--help': Boolean,
+ '--fancy': Boolean,
- '-y': '--yes',
- '-n': '--no',
- '-h': '--help',
- }, { argv, permissive: true });
+ '-y': '--yes',
+ '-n': '--no',
+ '-h': '--help',
+ },
+ { argv, permissive: true }
+ );
const pkgManager = detectPackageManager()?.name ?? 'npm';
const [username, version] = await Promise.all([getName(), getVersion()]);
@@ -75,8 +77,10 @@ export async function getContext(argv: string[]): Promise<Context> {
if (typescript == undefined) typescript = 'strict';
}
- skipHouston = ((os.platform() === 'win32' && !fancy) || skipHouston) ?? [yes, no, install, git, typescript].some((v) => v !== undefined);
-
+ skipHouston =
+ ((os.platform() === 'win32' && !fancy) || skipHouston) ??
+ [yes, no, install, git, typescript].some((v) => v !== undefined);
+
const context: Context = {
help,
prompt,
@@ -95,7 +99,7 @@ export async function getContext(argv: string[]): Promise<Context> {
cwd,
exit(code) {
process.exit(code);
- }
- }
+ },
+ };
return context;
}
diff --git a/packages/create-astro/src/actions/dependencies.ts b/packages/create-astro/src/actions/dependencies.ts
index fb935c208..5991e958f 100644
--- a/packages/create-astro/src/actions/dependencies.ts
+++ b/packages/create-astro/src/actions/dependencies.ts
@@ -1,9 +1,11 @@
-import type { Context } from "./context";
+import type { Context } from './context';
-import { title, info, spinner } from '../messages.js';
import { execa } from 'execa';
+import { info, spinner, title } from '../messages.js';
-export async function dependencies(ctx: Pick<Context, 'install'|'yes'|'prompt'|'pkgManager'|'cwd'|'dryRun'>) {
+export async function dependencies(
+ ctx: Pick<Context, 'install' | 'yes' | 'prompt' | 'pkgManager' | 'cwd' | 'dryRun'>
+) {
let deps = ctx.install ?? ctx.yes;
if (deps === undefined) {
({ deps } = await ctx.prompt({
@@ -33,11 +35,10 @@ export async function dependencies(ctx: Pick<Context, 'install'|'yes'|'prompt'|'
}
}
-async function install({ pkgManager, cwd }: { pkgManager: string, cwd: string }) {
- const installExec = execa(pkgManager, ['install'], { cwd });
- return new Promise<void>((resolve, reject) => {
- installExec.on('error', (error) => reject(error));
- installExec.on('close', () => resolve());
- });
+async function install({ pkgManager, cwd }: { pkgManager: string; cwd: string }) {
+ const installExec = execa(pkgManager, ['install'], { cwd });
+ return new Promise<void>((resolve, reject) => {
+ installExec.on('error', (error) => reject(error));
+ installExec.on('close', () => resolve());
+ });
}
-
diff --git a/packages/create-astro/src/actions/git.ts b/packages/create-astro/src/actions/git.ts
index 6510a0f24..51a7e09c8 100644
--- a/packages/create-astro/src/actions/git.ts
+++ b/packages/create-astro/src/actions/git.ts
@@ -1,15 +1,15 @@
-import type { Context } from "./context";
import fs from 'node:fs';
import path from 'node:path';
+import type { Context } from './context';
import { color } from '@astrojs/cli-kit';
-import { title, info, spinner } from '../messages.js';
import { execa } from 'execa';
+import { info, spinner, title } from '../messages.js';
-export async function git(ctx: Pick<Context, 'cwd'|'git'|'yes'|'prompt'|'dryRun'>) {
+export async function git(ctx: Pick<Context, 'cwd' | 'git' | 'yes' | 'prompt' | 'dryRun'>) {
if (fs.existsSync(path.join(ctx.cwd, '.git'))) {
await info('Nice!', `Git has already been initialized`);
- return
+ return;
}
let _git = ctx.git ?? ctx.yes;
if (_git === undefined) {
@@ -43,6 +43,15 @@ async function init({ cwd }: { cwd: string }) {
try {
await execa('git', ['init'], { cwd, stdio: 'ignore' });
await execa('git', ['add', '-A'], { cwd, stdio: 'ignore' });
- await execa('git', ['commit', '-m', 'Initial commit from Astro', '--author="houston[bot] <astrobot-houston@users.noreply.github.com>"'], { cwd, stdio: 'ignore' });
+ await execa(
+ 'git',
+ [
+ 'commit',
+ '-m',
+ 'Initial commit from Astro',
+ '--author="houston[bot] <astrobot-houston@users.noreply.github.com>"',
+ ],
+ { cwd, stdio: 'ignore' }
+ );
} catch (e) {}
}
diff --git a/packages/create-astro/src/actions/intro.ts b/packages/create-astro/src/actions/intro.ts
index b3ab88122..ec0c2248b 100644
--- a/packages/create-astro/src/actions/intro.ts
+++ b/packages/create-astro/src/actions/intro.ts
@@ -1,10 +1,10 @@
import { type Context } from './context';
-import { banner, welcome, say } from '../messages.js';
-import { label, color } from '@astrojs/cli-kit';
+import { color, label } from '@astrojs/cli-kit';
import { random } from '@astrojs/cli-kit/utils';
+import { banner, say, welcome } from '../messages.js';
-export async function intro(ctx: Pick<Context, 'skipHouston'|'version'|'username'>) {
+export async function intro(ctx: Pick<Context, 'skipHouston' | 'version' | 'username'>) {
if (!ctx.skipHouston) {
await say([
[
diff --git a/packages/create-astro/src/actions/next-steps.ts b/packages/create-astro/src/actions/next-steps.ts
index 94b0ba71b..db7387ad1 100644
--- a/packages/create-astro/src/actions/next-steps.ts
+++ b/packages/create-astro/src/actions/next-steps.ts
@@ -1,9 +1,9 @@
-import { Context } from "./context";
import path from 'node:path';
+import { Context } from './context';
import { nextSteps, say } from '../messages.js';
-export async function next(ctx: Pick<Context, 'cwd'|'pkgManager'|'skipHouston'>) {
+export async function next(ctx: Pick<Context, 'cwd' | 'pkgManager' | 'skipHouston'>) {
let projectDir = path.relative(process.cwd(), ctx.cwd);
const devCmd = ctx.pkgManager === 'npm' ? 'npm run dev' : `${ctx.pkgManager} dev`;
await nextSteps({ projectDir, devCmd });
diff --git a/packages/create-astro/src/actions/project-name.ts b/packages/create-astro/src/actions/project-name.ts
index c849a9060..e293c86a2 100644
--- a/packages/create-astro/src/actions/project-name.ts
+++ b/packages/create-astro/src/actions/project-name.ts
@@ -1,12 +1,12 @@
-import type { Context } from "./context";
+import type { Context } from './context';
import { color, generateProjectName } from '@astrojs/cli-kit';
-import { title, info, log } from '../messages.js';
import path from 'node:path';
+import { info, log, title } from '../messages.js';
import { isEmpty, toValidName } from './shared.js';
-export async function projectName(ctx: Pick<Context, 'cwd'|'prompt'|'projectName'|'exit'>) {
+export async function projectName(ctx: Pick<Context, 'cwd' | 'prompt' | 'projectName' | 'exit'>) {
await checkCwd(ctx.cwd);
if (!ctx.cwd || !isEmpty(ctx.cwd)) {
diff --git a/packages/create-astro/src/actions/shared.ts b/packages/create-astro/src/actions/shared.ts
index 838ee5e23..4bd852529 100644
--- a/packages/create-astro/src/actions/shared.ts
+++ b/packages/create-astro/src/actions/shared.ts
@@ -42,20 +42,18 @@ export function isEmpty(dirPath: string) {
}
export function isValidName(projectName: string) {
- return /^(?:@[a-z\d\-*~][a-z\d\-*._~]*\/)?[a-z\d\-~][a-z\d\-._~]*$/.test(
- projectName,
- )
+ return /^(?:@[a-z\d\-*~][a-z\d\-*._~]*\/)?[a-z\d\-~][a-z\d\-._~]*$/.test(projectName);
}
export function toValidName(projectName: string) {
if (isValidName(projectName)) return projectName;
- return projectName
- .trim()
- .toLowerCase()
- .replace(/\s+/g, '-')
- .replace(/^[._]/, '')
- .replace(/[^a-z\d\-~]+/g, '-')
+ return projectName
+ .trim()
+ .toLowerCase()
+ .replace(/\s+/g, '-')
+ .replace(/^[._]/, '')
+ .replace(/[^a-z\d\-~]+/g, '-')
.replace(/^-+/, '')
- .replace(/-+$/, '')
+ .replace(/-+$/, '');
}
diff --git a/packages/create-astro/src/actions/template.ts b/packages/create-astro/src/actions/template.ts
index 805e9ddca..e809005a2 100644
--- a/packages/create-astro/src/actions/template.ts
+++ b/packages/create-astro/src/actions/template.ts
@@ -1,14 +1,15 @@
/* eslint no-console: 'off' */
-import type { Context } from "./context";
+import type { Context } from './context';
+import { color } from '@astrojs/cli-kit';
+import { downloadTemplate } from 'giget';
import fs from 'node:fs';
import path from 'node:path';
-import { downloadTemplate } from 'giget';
-import { error } from '../messages.js';
-import { color } from '@astrojs/cli-kit';
-import { title, info, spinner } from '../messages.js';
+import { error, info, spinner, title } from '../messages.js';
-export async function template(ctx: Pick<Context, 'template'|'prompt'|'dryRun'|'exit'|'exit'>) {
+export async function template(
+ ctx: Pick<Context, 'template' | 'prompt' | 'dryRun' | 'exit' | 'exit'>
+) {
if (!ctx.template) {
const { template: tmpl } = await ctx.prompt({
name: 'template',
@@ -43,18 +44,27 @@ export async function template(ctx: Pick<Context, 'template'|'prompt'|'dryRun'|'
// some files are only needed for online editors when using astro.new. Remove for create-astro installs.
const FILES_TO_REMOVE = ['sandbox.config.json', 'CHANGELOG.md'];
const FILES_TO_UPDATE = {
- 'package.json': (file: string, overrides: { name: string }) => fs.promises.readFile(file, 'utf-8').then(value => (
- fs.promises.writeFile(file, JSON.stringify(Object.assign(JSON.parse(value), Object.assign(overrides, { private: undefined })), null, '\t'), 'utf-8')
- ))
-}
+ 'package.json': (file: string, overrides: { name: string }) =>
+ fs.promises
+ .readFile(file, 'utf-8')
+ .then((value) =>
+ fs.promises.writeFile(
+ file,
+ JSON.stringify(
+ Object.assign(JSON.parse(value), Object.assign(overrides, { private: undefined })),
+ null,
+ '\t'
+ ),
+ 'utf-8'
+ )
+ ),
+};
export default async function copyTemplate(tmpl: string, ctx: Context) {
const ref = ctx.ref || 'latest';
const isThirdParty = tmpl.includes('/');
- const templateTarget = isThirdParty
- ? tmpl
- : `github:withastro/astro/examples/${tmpl}#${ref}`;
+ const templateTarget = isThirdParty ? tmpl : `github:withastro/astro/examples/${tmpl}#${ref}`;
// Copy
if (!ctx.dryRun) {
@@ -64,7 +74,7 @@ export default async function copyTemplate(tmpl: string, ctx: Context) {
provider: 'github',
cwd: ctx.cwd,
dir: '.',
- })
+ });
} catch (err: any) {
fs.rmdirSync(ctx.cwd);
if (err.message.includes('404')) {
@@ -85,9 +95,9 @@ export default async function copyTemplate(tmpl: string, ctx: Context) {
const updateFiles = Object.entries(FILES_TO_UPDATE).map(async ([file, update]) => {
const fileLoc = path.resolve(path.join(ctx.cwd, file));
if (fs.existsSync(fileLoc)) {
- return update(fileLoc, { name: ctx.projectName! })
+ return update(fileLoc, { name: ctx.projectName! });
}
- })
+ });
await Promise.all([...removeFiles, ...updateFiles]);
}
diff --git a/packages/create-astro/src/actions/typescript.ts b/packages/create-astro/src/actions/typescript.ts
index 0c624f889..24e9e8362 100644
--- a/packages/create-astro/src/actions/typescript.ts
+++ b/packages/create-astro/src/actions/typescript.ts
@@ -1,13 +1,15 @@
-import type { Context } from "./context";
+import type { Context } from './context';
-import fs from 'node:fs'
-import { readFile } from 'node:fs/promises'
+import { color } from '@astrojs/cli-kit';
+import fs from 'node:fs';
+import { readFile } from 'node:fs/promises';
import path from 'node:path';
import stripJsonComments from 'strip-json-comments';
-import { color } from '@astrojs/cli-kit';
-import { title, info, error, typescriptByDefault, spinner } from '../messages.js';
+import { error, info, spinner, title, typescriptByDefault } from '../messages.js';
-export async function typescript(ctx: Pick<Context, 'typescript'|'yes'|'prompt'|'dryRun'|'cwd'|'exit'>) {
+export async function typescript(
+ ctx: Pick<Context, 'typescript' | 'yes' | 'prompt' | 'dryRun' | 'cwd' | 'exit'>
+) {
let ts = ctx.typescript ?? (typeof ctx.yes !== 'undefined' ? 'strict' : undefined);
if (ts === undefined) {
const { useTs } = await ctx.prompt({
@@ -68,7 +70,7 @@ export async function typescript(ctx: Pick<Context, 'typescript'|'yes'|'prompt'|
export async function setupTypeScript(value: string, { cwd }: { cwd: string }) {
const templateTSConfigPath = path.join(cwd, 'tsconfig.json');
try {
- const data = await readFile(templateTSConfigPath, { encoding: 'utf-8' })
+ const data = await readFile(templateTSConfigPath, { encoding: 'utf-8' });
const templateTSConfig = JSON.parse(stripJsonComments(data));
if (templateTSConfig && typeof templateTSConfig === 'object') {
const result = Object.assign(templateTSConfig, {
@@ -77,7 +79,9 @@ export async function setupTypeScript(value: string, { cwd }: { cwd: string }) {
fs.writeFileSync(templateTSConfigPath, JSON.stringify(result, null, 2));
} else {
- throw new Error("There was an error applying the requested TypeScript settings. This could be because the template's tsconfig.json is malformed")
+ throw new Error(
+ "There was an error applying the requested TypeScript settings. This could be because the template's tsconfig.json is malformed"
+ );
}
} catch (err) {
if (err && (err as any).code === 'ENOENT') {
diff --git a/packages/create-astro/src/index.ts b/packages/create-astro/src/index.ts
index 5ba94d53f..5090a6c1c 100644
--- a/packages/create-astro/src/index.ts
+++ b/packages/create-astro/src/index.ts
@@ -1,18 +1,18 @@
import { getContext } from './actions/context.js';
-import { setStdout } from './messages.js';
-import { help } from './actions/help.js';
-import { intro } from './actions/intro.js';
-import { projectName } from './actions/project-name.js';
-import { template } from './actions/template.js'
import { dependencies } from './actions/dependencies.js';
import { git } from './actions/git.js';
-import { typescript, setupTypeScript } from './actions/typescript.js';
+import { help } from './actions/help.js';
+import { intro } from './actions/intro.js';
import { next } from './actions/next-steps.js';
+import { projectName } from './actions/project-name.js';
+import { template } from './actions/template.js';
+import { setupTypeScript, typescript } from './actions/typescript.js';
+import { setStdout } from './messages.js';
-const exit = () => process.exit(0)
-process.on('SIGINT', exit)
-process.on('SIGTERM', exit)
+const exit = () => process.exit(0);
+process.on('SIGINT', exit);
+process.on('SIGTERM', exit);
// Please also update the installation instructions in the docs at
// https://github.com/withastro/docs/blob/main/src/pages/en/install/auto.md
@@ -29,18 +29,10 @@ export async function main() {
return;
}
- const steps = [
- intro,
- projectName,
- template,
- dependencies,
- git,
- typescript,
- next
- ]
+ const steps = [intro, projectName, template, dependencies, git, typescript, next];
for (const step of steps) {
- await step(ctx)
+ await step(ctx);
}
process.exit(0);
}
@@ -55,5 +47,5 @@ export {
git,
typescript,
setupTypeScript,
- next
-}
+ next,
+};
diff --git a/packages/create-astro/src/messages.ts b/packages/create-astro/src/messages.ts
index c70857ada..c0adbaa4a 100644
--- a/packages/create-astro/src/messages.ts
+++ b/packages/create-astro/src/messages.ts
@@ -1,8 +1,8 @@
/* eslint no-console: 'off' */
+import { color, label, say as houston, spinner as load } from '@astrojs/cli-kit';
+import { align, sleep } from '@astrojs/cli-kit/utils';
import { exec } from 'node:child_process';
import { get } from 'node:https';
-import { color, label, spinner as load, say as houston } from '@astrojs/cli-kit';
-import { sleep, align } from '@astrojs/cli-kit/utils';
import stripAnsi from 'strip-ansi';
let stdout = process.stdout;
@@ -11,113 +11,136 @@ export function setStdout(writable: typeof process.stdout) {
stdout = writable;
}
-export async function say(messages: string|string[], { clear = false, hat = '' } = {}) {
+export async function say(messages: string | string[], { clear = false, hat = '' } = {}) {
return houston(messages, { clear, hat, stdout });
}
-export async function spinner(args: { start: string; end: string; while: (...args: any) => Promise<any>; }) {
+export async function spinner(args: {
+ start: string;
+ end: string;
+ while: (...args: any) => Promise<any>;
+}) {
await load(args, { stdout });
}
export const title = (text: string) => align(label(text), 'end', 7) + ' ';
export const welcome = [
- `Let's claim your corner of the internet.`,
- `I'll be your assistant today.`,
- `Let's build something awesome!`,
- `Let's build something great!`,
- `Let's build something fast!`,
- `Let's build the web we want.`,
- `Let's make the web weird!`,
- `Let's make the web a better place!`,
- `Let's create a new project!`,
- `Let's create something unique!`,
- `Time to build a new website.`,
- `Time to build a faster website.`,
- `Time to build a sweet new website.`,
- `We're glad to have you on board.`,
- `Keeping the internet weird since 2021.`,
- `Initiating launch sequence...`,
- `Initiating launch sequence... right... now!`,
- `Awaiting further instructions.`,
-]
-
-export const getName = () => new Promise<string>((resolve) => {
- exec('git config user.name', { encoding: 'utf-8' }, (_1, gitName, _2) => {
- if (gitName.trim()) {
- return resolve(gitName.split(' ')[0].trim());
- }
- exec('whoami', { encoding: 'utf-8' }, (_3, whoami, _4) => {
- if (whoami.trim()) {
- return resolve(whoami.split(' ')[0].trim());
- }
- return resolve('astronaut');
- });
- });
-});
+ `Let's claim your corner of the internet.`,
+ `I'll be your assistant today.`,
+ `Let's build something awesome!`,
+ `Let's build something great!`,
+ `Let's build something fast!`,
+ `Let's build the web we want.`,
+ `Let's make the web weird!`,
+ `Let's make the web a better place!`,
+ `Let's create a new project!`,
+ `Let's create something unique!`,
+ `Time to build a new website.`,
+ `Time to build a faster website.`,
+ `Time to build a sweet new website.`,
+ `We're glad to have you on board.`,
+ `Keeping the internet weird since 2021.`,
+ `Initiating launch sequence...`,
+ `Initiating launch sequence... right... now!`,
+ `Awaiting further instructions.`,
+];
+
+export const getName = () =>
+ new Promise<string>((resolve) => {
+ exec('git config user.name', { encoding: 'utf-8' }, (_1, gitName, _2) => {
+ if (gitName.trim()) {
+ return resolve(gitName.split(' ')[0].trim());
+ }
+ exec('whoami', { encoding: 'utf-8' }, (_3, whoami, _4) => {
+ if (whoami.trim()) {
+ return resolve(whoami.split(' ')[0].trim());
+ }
+ return resolve('astronaut');
+ });
+ });
+ });
let v: string;
-export const getVersion = () => new Promise<string>((resolve) => {
- if (v) return resolve(v);
- get('https://registry.npmjs.org/astro/latest', (res) => {
- let body = '';
- res.on('data', chunk => body += chunk)
- res.on('end', () => {
- const { version } = JSON.parse(body);
- v = version;
- resolve(version);
- })
- })
-})
-
-export const log = (message: string) => stdout.write(message + "\n");
-export const banner = async (version: string) => log(`\n${label('astro', color.bgGreen, color.black)} ${color.green(color.bold(`v${version}`))} ${color.bold('Launch sequence initiated.')}`);
+export const getVersion = () =>
+ new Promise<string>((resolve) => {
+ if (v) return resolve(v);
+ get('https://registry.npmjs.org/astro/latest', (res) => {
+ let body = '';
+ res.on('data', (chunk) => (body += chunk));
+ res.on('end', () => {
+ const { version } = JSON.parse(body);
+ v = version;
+ resolve(version);
+ });
+ });
+ });
+
+export const log = (message: string) => stdout.write(message + '\n');
+export const banner = async (version: string) =>
+ log(
+ `\n${label('astro', color.bgGreen, color.black)} ${color.green(
+ color.bold(`v${version}`)
+ )} ${color.bold('Launch sequence initiated.')}`
+ );
export const info = async (prefix: string, text: string) => {
- await sleep(100)
- if (stdout.columns < 80) {
- log(`${' '.repeat(5)} ${color.cyan('◼')} ${color.cyan(prefix)}`);
- log(`${' '.repeat(9)}${color.dim(text)}`);
- } else {
- log(`${' '.repeat(5)} ${color.cyan('◼')} ${color.cyan(prefix)} ${color.dim(text)}`);
- }
-}
+ await sleep(100);
+ if (stdout.columns < 80) {
+ log(`${' '.repeat(5)} ${color.cyan('◼')} ${color.cyan(prefix)}`);
+ log(`${' '.repeat(9)}${color.dim(text)}`);
+ } else {
+ log(`${' '.repeat(5)} ${color.cyan('◼')} ${color.cyan(prefix)} ${color.dim(text)}`);
+ }
+};
export const error = async (prefix: string, text: string) => {
- if (stdout.columns < 80) {
- log(`${' '.repeat(5)} ${color.red('▲')} ${color.red(prefix)}`);
- log(`${' '.repeat(9)}${color.dim(text)}`);
- } else {
- log(`${' '.repeat(5)} ${color.red('▲')} ${color.red(prefix)} ${color.dim(text)}`);
- }
-}
+ if (stdout.columns < 80) {
+ log(`${' '.repeat(5)} ${color.red('▲')} ${color.red(prefix)}`);
+ log(`${' '.repeat(9)}${color.dim(text)}`);
+ } else {
+ log(`${' '.repeat(5)} ${color.red('▲')} ${color.red(prefix)} ${color.dim(text)}`);
+ }
+};
export const typescriptByDefault = async () => {
- await info(`No worries!`, 'TypeScript is supported in Astro by default,');
- log(`${' '.repeat(9)}${color.dim('but you are free to continue writing JavaScript instead.')}`);
- await sleep(1000);
-}
-
-export const nextSteps = async ({ projectDir, devCmd }: { projectDir: string, devCmd: string }) => {
- const max = stdout.columns;
- const prefix = max < 80 ? ' ' : ' '.repeat(9);
- await sleep(200);
- log(`\n ${color.bgCyan(` ${color.black('next')} `)} ${color.bold('Liftoff confirmed. Explore your project!')}`)
-
- await sleep(100);
- if (projectDir !== '') {
- const enter = [`\n${prefix}Enter your project directory using`, color.cyan(`cd ./${projectDir}`, '')];
- const len = enter[0].length + stripAnsi(enter[1]).length;
- log(enter.join((len > max) ? '\n' + prefix : ' '));
- }
- log(`${prefix}Run ${color.cyan(devCmd)} to start the dev server. ${color.cyan('CTRL+C')} to stop.`)
- await sleep(100);
- log(`${prefix}Add frameworks like ${color.cyan(`react`)} or ${color.cyan('tailwind')} using ${color.cyan('astro add')}.`)
- await sleep(100);
- log(`\n${prefix}Stuck? Join us at ${color.cyan(`https://astro.build/chat`)}`)
- await sleep(200);
-}
-
+ await info(`No worries!`, 'TypeScript is supported in Astro by default,');
+ log(`${' '.repeat(9)}${color.dim('but you are free to continue writing JavaScript instead.')}`);
+ await sleep(1000);
+};
+
+export const nextSteps = async ({ projectDir, devCmd }: { projectDir: string; devCmd: string }) => {
+ const max = stdout.columns;
+ const prefix = max < 80 ? ' ' : ' '.repeat(9);
+ await sleep(200);
+ log(
+ `\n ${color.bgCyan(` ${color.black('next')} `)} ${color.bold(
+ 'Liftoff confirmed. Explore your project!'
+ )}`
+ );
+
+ await sleep(100);
+ if (projectDir !== '') {
+ const enter = [
+ `\n${prefix}Enter your project directory using`,
+ color.cyan(`cd ./${projectDir}`, ''),
+ ];
+ const len = enter[0].length + stripAnsi(enter[1]).length;
+ log(enter.join(len > max ? '\n' + prefix : ' '));
+ }
+ log(
+ `${prefix}Run ${color.cyan(devCmd)} to start the dev server. ${color.cyan('CTRL+C')} to stop.`
+ );
+ await sleep(100);
+ log(
+ `${prefix}Add frameworks like ${color.cyan(`react`)} or ${color.cyan(
+ 'tailwind'
+ )} using ${color.cyan('astro add')}.`
+ );
+ await sleep(100);
+ log(`\n${prefix}Stuck? Join us at ${color.cyan(`https://astro.build/chat`)}`);
+ await sleep(200);
+};
export function printHelp({
commandName,
@@ -154,9 +177,7 @@ export function printHelp({
if (headline) {
message.push(
linebreak(),
- `${title(commandName)} ${color.green(
- `v${process.env.PACKAGE_VERSION ?? ''}`
- )} ${headline}`
+ `${title(commandName)} ${color.green(`v${process.env.PACKAGE_VERSION ?? ''}`)} ${headline}`
);
}
diff --git a/packages/create-astro/test/context.test.js b/packages/create-astro/test/context.test.js
index d6cb1c70f..113417417 100644
--- a/packages/create-astro/test/context.test.js
+++ b/packages/create-astro/test/context.test.js
@@ -10,53 +10,53 @@ describe('context', () => {
expect(ctx.template).to.be.undefined;
expect(ctx.skipHouston).to.eq(os.platform() === 'win32');
expect(ctx.dryRun).to.be.undefined;
- })
+ });
it('project name', async () => {
const ctx = await getContext(['foobar']);
expect(ctx.projectName).to.eq('foobar');
- })
+ });
it('template', async () => {
const ctx = await getContext(['--template', 'minimal']);
expect(ctx.template).to.eq('minimal');
- })
+ });
it('skip houston (explicit)', async () => {
const ctx = await getContext(['--skip-houston']);
expect(ctx.skipHouston).to.eq(true);
- })
+ });
it('skip houston (yes)', async () => {
const ctx = await getContext(['-y']);
expect(ctx.skipHouston).to.eq(true);
- })
+ });
it('skip houston (no)', async () => {
const ctx = await getContext(['-n']);
expect(ctx.skipHouston).to.eq(true);
- })
+ });
it('skip houston (install)', async () => {
const ctx = await getContext(['--install']);
expect(ctx.skipHouston).to.eq(true);
- })
+ });
it('dry run', async () => {
const ctx = await getContext(['--dry-run']);
expect(ctx.dryRun).to.eq(true);
- })
+ });
it('install', async () => {
const ctx = await getContext(['--install']);
expect(ctx.install).to.eq(true);
- })
+ });
it('no install', async () => {
const ctx = await getContext(['--no-install']);
expect(ctx.install).to.eq(false);
- })
+ });
it('git', async () => {
const ctx = await getContext(['--git']);
expect(ctx.git).to.eq(true);
- })
+ });
it('no git', async () => {
const ctx = await getContext(['--no-git']);
expect(ctx.git).to.eq(false);
- })
+ });
it('typescript', async () => {
const ctx = await getContext(['--typescript', 'strict']);
expect(ctx.typescript).to.eq('strict');
- })
-})
+ });
+});
diff --git a/packages/create-astro/test/dependencies.test.js b/packages/create-astro/test/dependencies.test.js
index 515c42294..88e43597b 100644
--- a/packages/create-astro/test/dependencies.test.js
+++ b/packages/create-astro/test/dependencies.test.js
@@ -7,36 +7,66 @@ describe('dependencies', () => {
const fixture = setup();
it('--yes', async () => {
- const context = { cwd: '', yes: true, pkgManager: 'npm', dryRun: true, prompt: (() => ({ deps: true }))};
+ const context = {
+ cwd: '',
+ yes: true,
+ pkgManager: 'npm',
+ dryRun: true,
+ prompt: () => ({ deps: true }),
+ };
await dependencies(context);
expect(fixture.hasMessage('Skipping dependency installation')).to.be.true;
- })
+ });
it('prompt yes', async () => {
- const context = { cwd: '', pkgManager: 'npm', dryRun: true, prompt: (() => ({ deps: true })), install: undefined };
+ const context = {
+ cwd: '',
+ pkgManager: 'npm',
+ dryRun: true,
+ prompt: () => ({ deps: true }),
+ install: undefined,
+ };
await dependencies(context);
expect(fixture.hasMessage('Skipping dependency installation')).to.be.true;
expect(context.install).to.eq(true);
- })
+ });
it('prompt no', async () => {
- const context = { cwd: '', pkgManager: 'npm', dryRun: true, prompt: (() => ({ deps: false })), install: undefined };
+ const context = {
+ cwd: '',
+ pkgManager: 'npm',
+ dryRun: true,
+ prompt: () => ({ deps: false }),
+ install: undefined,
+ };
await dependencies(context);
expect(fixture.hasMessage('Skipping dependency installation')).to.be.true;
expect(context.install).to.eq(false);
- })
+ });
it('--install', async () => {
- const context = { cwd: '', install: true, pkgManager: 'npm', dryRun: true, prompt: (() => ({ deps: false })) };
+ const context = {
+ cwd: '',
+ install: true,
+ pkgManager: 'npm',
+ dryRun: true,
+ prompt: () => ({ deps: false }),
+ };
await dependencies(context);
expect(fixture.hasMessage('Skipping dependency installation')).to.be.true;
expect(context.install).to.eq(true);
- })
+ });
it('--no-install', async () => {
- const context = { cwd: '', install: false, pkgManager: 'npm', dryRun: true, prompt: (() => ({ deps: false })) };
+ const context = {
+ cwd: '',
+ install: false,
+ pkgManager: 'npm',
+ dryRun: true,
+ prompt: () => ({ deps: false }),
+ };
await dependencies(context);
expect(fixture.hasMessage('Skipping dependency installation')).to.be.true;
expect(context.install).to.eq(false);
- })
-})
+ });
+});
diff --git a/packages/create-astro/test/git.test.js b/packages/create-astro/test/git.test.js
index 4b048156a..6111b1398 100644
--- a/packages/create-astro/test/git.test.js
+++ b/packages/create-astro/test/git.test.js
@@ -10,14 +10,19 @@ describe('git', () => {
const fixture = setup();
it('none', async () => {
- const context = { cwd: '', dryRun: true, prompt: (() => ({ git: false }))};
+ const context = { cwd: '', dryRun: true, prompt: () => ({ git: false }) };
await git(context);
expect(fixture.hasMessage('Skipping Git initialization')).to.be.true;
- })
+ });
it('already initialized', async () => {
- const context = { git: true, cwd: './test/fixtures/not-empty', dryRun: true, prompt: (() => ({ git: false }))};
+ const context = {
+ git: true,
+ cwd: './test/fixtures/not-empty',
+ dryRun: true,
+ prompt: () => ({ git: false }),
+ };
await execa('git', ['init'], { cwd: './test/fixtures/not-empty' });
await git(context);
@@ -25,19 +30,19 @@ describe('git', () => {
// Cleanup
fs.rmSync('./test/fixtures/not-empty/.git', { recursive: true, force: true });
- })
+ });
it('yes (--dry-run)', async () => {
- const context = { cwd: '', dryRun: true, prompt: (() => ({ git: true }))};
+ const context = { cwd: '', dryRun: true, prompt: () => ({ git: true }) };
await git(context);
expect(fixture.hasMessage('Skipping Git initialization')).to.be.true;
- })
+ });
it('no (--dry-run)', async () => {
- const context = { cwd: '', dryRun: true, prompt: (() => ({ git: false }))};
+ const context = { cwd: '', dryRun: true, prompt: () => ({ git: false }) };
await git(context);
expect(fixture.hasMessage('Skipping Git initialization')).to.be.true;
- })
-})
+ });
+});
diff --git a/packages/create-astro/test/intro.test.js b/packages/create-astro/test/intro.test.js
index af13954d1..9014da457 100644
--- a/packages/create-astro/test/intro.test.js
+++ b/packages/create-astro/test/intro.test.js
@@ -10,11 +10,11 @@ describe('intro', () => {
await intro({ skipHouston: false, version: '0.0.0', username: 'user' });
expect(fixture.hasMessage('Houston:')).to.be.true;
expect(fixture.hasMessage('Welcome to astro v0.0.0')).to.be.true;
- })
+ });
it('--skip-houston', async () => {
await intro({ skipHouston: true, version: '0.0.0', username: 'user' });
expect(fixture.length()).to.eq(1);
expect(fixture.hasMessage('Houston:')).to.be.false;
expect(fixture.hasMessage('Launch sequence initiated')).to.be.true;
- })
-})
+ });
+});
diff --git a/packages/create-astro/test/next.test.js b/packages/create-astro/test/next.test.js
index 46efdf67f..efc0e6728 100644
--- a/packages/create-astro/test/next.test.js
+++ b/packages/create-astro/test/next.test.js
@@ -11,10 +11,10 @@ describe('next steps', () => {
expect(fixture.hasMessage('Liftoff confirmed.')).to.be.true;
expect(fixture.hasMessage('npm run dev')).to.be.true;
expect(fixture.hasMessage('Good luck out there, astronaut!')).to.be.true;
- })
+ });
it('--skip-houston', async () => {
await next({ skipHouston: true, cwd: './it/fixtures/not-empty', pkgManager: 'npm' });
expect(fixture.hasMessage('Good luck out there, astronaut!')).to.be.false;
- })
-})
+ });
+});
diff --git a/packages/create-astro/test/project-name.test.js b/packages/create-astro/test/project-name.test.js
index 38f1359b6..f297da076 100644
--- a/packages/create-astro/test/project-name.test.js
+++ b/packages/create-astro/test/project-name.test.js
@@ -7,73 +7,81 @@ describe('project name', () => {
const fixture = setup();
it('pass in name', async () => {
- const context = { projectName: '', cwd: './foo/bar/baz', prompt: (() => {})};
+ const context = { projectName: '', cwd: './foo/bar/baz', prompt: () => {} };
await projectName(context);
expect(context.cwd).to.eq('./foo/bar/baz');
expect(context.projectName).to.eq('baz');
- })
+ });
it('dot', async () => {
- const context = { projectName: '', cwd: '.', prompt: (() => ({ name: 'foobar' }))};
+ const context = { projectName: '', cwd: '.', prompt: () => ({ name: 'foobar' }) };
await projectName(context);
expect(fixture.hasMessage('"." is not empty!')).to.be.true;
expect(context.projectName).to.eq('foobar');
- })
+ });
it('dot slash', async () => {
- const context = { projectName: '', cwd: './', prompt: (() => ({ name: 'foobar' }))};
+ const context = { projectName: '', cwd: './', prompt: () => ({ name: 'foobar' }) };
await projectName(context);
expect(fixture.hasMessage('"./" is not empty!')).to.be.true;
expect(context.projectName).to.eq('foobar');
- })
+ });
it('empty', async () => {
- const context = { projectName: '', cwd: './test/fixtures/empty', prompt: (() => ({ name: 'foobar' }))};
+ const context = {
+ projectName: '',
+ cwd: './test/fixtures/empty',
+ prompt: () => ({ name: 'foobar' }),
+ };
await projectName(context);
expect(fixture.hasMessage('"./test/fixtures/empty" is not empty!')).to.be.false;
expect(context.projectName).to.eq('empty');
- })
+ });
it('not empty', async () => {
- const context = { projectName: '', cwd: './test/fixtures/not-empty', prompt: (() => ({ name: 'foobar' }))};
+ const context = {
+ projectName: '',
+ cwd: './test/fixtures/not-empty',
+ prompt: () => ({ name: 'foobar' }),
+ };
await projectName(context);
expect(fixture.hasMessage('"./test/fixtures/not-empty" is not empty!')).to.be.true;
expect(context.projectName).to.eq('foobar');
- })
+ });
it('basic', async () => {
- const context = { projectName: '', cwd: '', prompt: (() => ({ name: 'foobar' }))};
+ const context = { projectName: '', cwd: '', prompt: () => ({ name: 'foobar' }) };
await projectName(context);
expect(context.cwd).to.eq('foobar');
expect(context.projectName).to.eq('foobar');
- })
+ });
it('normalize', async () => {
- const context = { projectName: '', cwd: '', prompt: (() => ({ name: 'Invalid Name' }))};
+ const context = { projectName: '', cwd: '', prompt: () => ({ name: 'Invalid Name' }) };
await projectName(context);
expect(context.cwd).to.eq('Invalid Name');
expect(context.projectName).to.eq('invalid-name');
- })
+ });
it('remove leading/trailing dashes', async () => {
- const context = { projectName: '', cwd: '', prompt: (() => ({ name: '(invalid)' }))};
+ const context = { projectName: '', cwd: '', prompt: () => ({ name: '(invalid)' }) };
await projectName(context);
expect(context.projectName).to.eq('invalid');
- })
+ });
it('handles scoped packages', async () => {
- const context = { projectName: '', cwd: '', prompt: (() => ({ name: '@astro/site' }))};
+ const context = { projectName: '', cwd: '', prompt: () => ({ name: '@astro/site' }) };
await projectName(context);
expect(context.cwd).to.eq('@astro/site');
expect(context.projectName).to.eq('@astro/site');
- })
-})
+ });
+});
diff --git a/packages/create-astro/test/template.test.js b/packages/create-astro/test/template.test.js
index 53b9777ff..66c7f5446 100644
--- a/packages/create-astro/test/template.test.js
+++ b/packages/create-astro/test/template.test.js
@@ -7,30 +7,30 @@ describe('template', () => {
const fixture = setup();
it('none', async () => {
- const context = { template: '', cwd: '', dryRun: true, prompt: (() => ({ template: 'blog' })) };
+ const context = { template: '', cwd: '', dryRun: true, prompt: () => ({ template: 'blog' }) };
await template(context);
expect(fixture.hasMessage('Skipping template copying')).to.be.true;
expect(context.template).to.eq('blog');
- })
+ });
it('minimal (--dry-run)', async () => {
- const context = { template: 'minimal', cwd: '', dryRun: true, prompt: (() => {})};
+ const context = { template: 'minimal', cwd: '', dryRun: true, prompt: () => {} };
await template(context);
expect(fixture.hasMessage('Using minimal as project template')).to.be.true;
- })
+ });
it('basics (--dry-run)', async () => {
- const context = { template: 'basics', cwd: '', dryRun: true, prompt: (() => {})};
+ const context = { template: 'basics', cwd: '', dryRun: true, prompt: () => {} };
await template(context);
expect(fixture.hasMessage('Using basics as project template')).to.be.true;
- })
+ });
it('blog (--dry-run)', async () => {
- const context = { template: 'blog', cwd: '', dryRun: true, prompt: (() => {})};
+ const context = { template: 'blog', cwd: '', dryRun: true, prompt: () => {} };
await template(context);
expect(fixture.hasMessage('Using blog as project template')).to.be.true;
- })
-})
+ });
+});
diff --git a/packages/create-astro/test/typescript.test.js b/packages/create-astro/test/typescript.test.js
index 599214dff..be89a499d 100644
--- a/packages/create-astro/test/typescript.test.js
+++ b/packages/create-astro/test/typescript.test.js
@@ -1,7 +1,7 @@
import { expect } from 'chai';
-import fs from 'node:fs'
-import { fileURLToPath } from 'node:url'
+import fs from 'node:fs';
+import { fileURLToPath } from 'node:url';
import { typescript, setupTypeScript } from '../dist/index.js';
import { setup } from './utils.js';
@@ -10,70 +10,97 @@ describe('typescript', () => {
const fixture = setup();
it('none', async () => {
- const context = { cwd: '', dryRun: true, prompt: (() => ({ ts: 'strict', useTs: true }))};
+ const context = { cwd: '', dryRun: true, prompt: () => ({ ts: 'strict', useTs: true }) };
await typescript(context);
-
+
expect(fixture.hasMessage('Skipping TypeScript setup')).to.be.true;
- })
+ });
it('use false', async () => {
- const context = { cwd: '', dryRun: true, prompt: (() => ({ ts: 'strict', useTs: false }))};
+ const context = { cwd: '', dryRun: true, prompt: () => ({ ts: 'strict', useTs: false }) };
await typescript(context);
expect(fixture.hasMessage('No worries')).to.be.true;
- })
+ });
it('strict', async () => {
- const context = { typescript: 'strict', cwd: '', dryRun: true, prompt: (() => ({ ts: 'strict' }))};
+ const context = {
+ typescript: 'strict',
+ cwd: '',
+ dryRun: true,
+ prompt: () => ({ ts: 'strict' }),
+ };
await typescript(context);
expect(fixture.hasMessage('Using strict TypeScript configuration')).to.be.true;
expect(fixture.hasMessage('Skipping TypeScript setup')).to.be.true;
- })
+ });
it('default', async () => {
- const context = { typescript: 'default', cwd: '', dryRun: true, prompt: (() => ({ ts: 'strict' }))};
+ const context = {
+ typescript: 'default',
+ cwd: '',
+ dryRun: true,
+ prompt: () => ({ ts: 'strict' }),
+ };
await typescript(context);
expect(fixture.hasMessage('Using default TypeScript configuration')).to.be.true;
expect(fixture.hasMessage('Skipping TypeScript setup')).to.be.true;
- })
+ });
it('relaxed', async () => {
- const context = { typescript: 'relaxed', cwd: '', dryRun: true, prompt: (() => ({ ts: 'strict' }))};
+ const context = {
+ typescript: 'relaxed',
+ cwd: '',
+ dryRun: true,
+ prompt: () => ({ ts: 'strict' }),
+ };
await typescript(context);
expect(fixture.hasMessage('Using relaxed TypeScript configuration')).to.be.true;
expect(fixture.hasMessage('Skipping TypeScript setup')).to.be.true;
- })
+ });
it('other', async () => {
- const context = { typescript: 'other', cwd: '', dryRun: true, prompt: (() => ({ ts: 'strict' })), exit(code) { throw code }};
+ const context = {
+ typescript: 'other',
+ cwd: '',
+ dryRun: true,
+ prompt: () => ({ ts: 'strict' }),
+ exit(code) {
+ throw code;
+ },
+ };
let err = null;
try {
await typescript(context);
} catch (e) {
err = e;
}
- expect(err).to.eq(1)
- })
-})
+ expect(err).to.eq(1);
+ });
+});
describe('typescript: setup', () => {
it('none', async () => {
const root = new URL('./fixtures/empty/', import.meta.url);
const tsconfig = new URL('./tsconfig.json', root);
- await setupTypeScript('strict', { cwd: fileURLToPath(root) })
- expect(JSON.parse(fs.readFileSync(tsconfig, { encoding: 'utf-8' }))).to.deep.eq({ "extends": "astro/tsconfigs/strict" });
+ await setupTypeScript('strict', { cwd: fileURLToPath(root) });
+ expect(JSON.parse(fs.readFileSync(tsconfig, { encoding: 'utf-8' }))).to.deep.eq({
+ extends: 'astro/tsconfigs/strict',
+ });
fs.rmSync(tsconfig);
- })
+ });
it('exists', async () => {
const root = new URL('./fixtures/not-empty/', import.meta.url);
const tsconfig = new URL('./tsconfig.json', root);
- await setupTypeScript('strict', { cwd: fileURLToPath(root) })
- expect(JSON.parse(fs.readFileSync(tsconfig, { encoding: 'utf-8' }))).to.deep.eq({ "extends": "astro/tsconfigs/strict" });
+ await setupTypeScript('strict', { cwd: fileURLToPath(root) });
+ expect(JSON.parse(fs.readFileSync(tsconfig, { encoding: 'utf-8' }))).to.deep.eq({
+ extends: 'astro/tsconfigs/strict',
+ });
fs.writeFileSync(tsconfig, `{}`);
- })
-})
+ });
+});
diff --git a/packages/create-astro/test/utils.js b/packages/create-astro/test/utils.js
index c2cbb7245..ff5d5dd83 100644
--- a/packages/create-astro/test/utils.js
+++ b/packages/create-astro/test/utils.js
@@ -4,26 +4,28 @@ import stripAnsi from 'strip-ansi';
export function setup() {
const ctx = { messages: [] };
before(() => {
- setStdout(Object.assign({}, process.stdout, {
- write(buf) {
- ctx.messages.push(stripAnsi(String(buf)).trim())
- return true;
- }
- }))
+ setStdout(
+ Object.assign({}, process.stdout, {
+ write(buf) {
+ ctx.messages.push(stripAnsi(String(buf)).trim());
+ return true;
+ },
+ })
+ );
});
beforeEach(() => {
ctx.messages = [];
- })
+ });
return {
messages() {
- return ctx.messages
+ return ctx.messages;
},
length() {
- return ctx.messages.length
+ return ctx.messages.length;
},
hasMessage(content) {
- return !!ctx.messages.find(msg => msg.includes(content))
- }
+ return !!ctx.messages.find((msg) => msg.includes(content));
+ },
};
}