diff --git a/.changeset/ninety-planets-work.md b/.changeset/ninety-planets-work.md new file mode 100644 index 000000000000..42116375af6c --- /dev/null +++ b/.changeset/ninety-planets-work.md @@ -0,0 +1,5 @@ +--- +'create-astro': minor +--- + +Add a step to configure how strict TypeScript should be diff --git a/packages/create-astro/package.json b/packages/create-astro/package.json index 476d9b5caef2..e4bd4d1f4df4 100644 --- a/packages/create-astro/package.json +++ b/packages/create-astro/package.json @@ -25,7 +25,8 @@ }, "files": [ "dist", - "create-astro.js" + "create-astro.js", + "tsconfigs" ], "dependencies": { "chalk": "^5.0.1", diff --git a/packages/create-astro/src/index.ts b/packages/create-astro/src/index.ts index 5ee160e386f1..4f026e99767f 100644 --- a/packages/create-astro/src/index.ts +++ b/packages/create-astro/src/index.ts @@ -7,6 +7,7 @@ import ora from 'ora'; import os from 'os'; import path from 'path'; import prompts from 'prompts'; +import url from 'url'; import detectPackageManager from 'which-pm-runs'; import yargs from 'yargs-parser'; import { loadWithRocketGradient, rocketAscii } from './gradient.js'; @@ -284,10 +285,75 @@ export async function main() { ora().info(dim(`--dry-run enabled, skipping.`)); } else if (gitResponse.git) { await execaCommand('git init', { cwd }); + ora().succeed('Git repository created!'); } else { ora().info(dim(`Sounds good! You can come back and run ${cyan(`git init`)} later.`)); } + const tsResponse = await prompts( + { + type: 'select', + name: 'typescript', + message: 'How would you like to setup TypeScript?', + choices: [ + { + title: 'Relaxed', + value: 'default', + }, + { + title: 'Strict (recommended)', + description: 'Enable `strict` typechecking rules', + value: 'strict', + }, + { + title: 'Strictest', + description: 'Enable all typechecking rules', + value: 'stricter', + }, + { + title: 'I prefer not to use TypeScript', + description: `That's cool too!`, + value: 'optout', + }, + ], + }, + { + onCancel: () => { + ora().info( + dim( + 'Operation cancelled. Your project folder has been created but no TypeScript configuration file was created.' + ) + ); + process.exit(1); + }, + } + ); + + if (tsResponse.typescript === 'optout') { + console.log(``); + ora().warn(yellow(bold(`Astro ❤️ TypeScript!`))); + console.log(` Astro supports TypeScript inside of ".astro" component scripts, so`); + console.log(` we still need to create some TypeScript-related files in your project.`); + console.log(` You can safely ignore these files, but don't delete them!`); + console.log(dim(' (ex: tsconfig.json, src/types.d.ts)')); + console.log(``); + tsResponse.typescript = 'default'; + await wait(300); + } + if (args.dryRun) { + ora().info(dim(`--dry-run enabled, skipping.`)); + } else if (tsResponse.typescript) { + fs.copyFileSync( + path.join( + url.fileURLToPath(new URL('..', import.meta.url)), + 'tsconfigs', + `tsconfig.${tsResponse.typescript}.json` + ), + path.join(cwd, 'tsconfig.json') + ); + ora().succeed('TypeScript settings applied!'); + } + ora().succeed('Setup complete.'); ora({ text: green('Ready for liftoff!') }).succeed(); await wait(300); diff --git a/packages/create-astro/tsconfigs/tsconfig.strict.json b/packages/create-astro/tsconfigs/tsconfig.strict.json new file mode 100644 index 000000000000..a2ebcb5c4414 --- /dev/null +++ b/packages/create-astro/tsconfigs/tsconfig.strict.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + // Enable top-level await, and other modern ESM features. + "target": "ESNext", + "module": "ESNext", + // Enable node-style module resolution, for things like npm package imports. + "moduleResolution": "node", + // Enable JSON imports. + "resolveJsonModule": true, + // Enable stricter transpilation for better output. + "isolatedModules": true, + // Astro will directly run your TypeScript code, no transpilation needed. + "noEmit": true, + // Enable strict type checking. + "strict": true, + // Error when a value import is only used as a type. + "importsNotUsedAsValues": "error" + } +} diff --git a/packages/create-astro/tsconfigs/tsconfig.stricter.json b/packages/create-astro/tsconfigs/tsconfig.stricter.json new file mode 100644 index 000000000000..662098fac415 --- /dev/null +++ b/packages/create-astro/tsconfigs/tsconfig.stricter.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + // Enable top-level await, and other modern ESM features. + "target": "ESNext", + "module": "ESNext", + // Enable node-style module resolution, for things like npm package imports. + "moduleResolution": "node", + // Enable JSON imports. + "resolveJsonModule": true, + // Enable stricter transpilation for better output. + "isolatedModules": true, + // Astro will directly run your TypeScript code, no transpilation needed. + "noEmit": true, + // Enable strict type checking. + "strict": true, + // Error when a value import is only used as a type. + "importsNotUsedAsValues": "error", + // Report errors for fallthrough cases in switch statements + "noFallthroughCasesInSwitch": true, + // Force functions designed to override their parent class to be specified as `override`. + "noImplicitOverride": true, + // Force functions to specify that they can return `undefined` if a possibe code path does not return a value. + "noImplicitReturns": true, + // Report an error when a variable is declared but never used. + "noUnusedLocals": true, + // Report an error when a parameter is declared but never used. + "noUnusedParameters": true, + // Force the usage of the indexed syntax to access fields declared using an index signature. + "noUncheckedIndexedAccess": true, + // Report an error when the value `undefined` is given to an optional property that doesn't specify `undefined` as a valid value. + "exactOptionalPropertyTypes": true + } +}