diff --git a/docs/FAQs.md b/docs/FAQs.md index 1ce013c52..ab65b4be9 100644 --- a/docs/FAQs.md +++ b/docs/FAQs.md @@ -164,10 +164,10 @@ Using `eslint-config-prettier` would be redundant. The four bases correspond to what have seemed to be the most common user needs of template consumers: -1. **Minimum**: Developers who just want the barest of starting templates. +1. **Minimal**: Developers who just want the barest of starting templates. - They may be very new to TypeScript tooling, or they may have made an informed decision that the additional tooling isn't worth the complexity and/or time investment. - Tooling in this base is only what would be essential for a small TypeScript package that can be built, formatted, linted, and released. -2. **Common**: The common case of users who want the minimum tooling along with common repository management. +2. **Common**: The common case of users who want the minimal tooling along with common repository management. - Tooling added in this base should be essential for a TypeScript repository that additionally automates useful GitHub tasks: contributor recognition, release management, and testing. 3. **Everything**: Power users (including this repository) who want as much of the latest and greatest safety checks and standardization as possible. diff --git a/docs/Options.md b/docs/Options.md index d622decb7..bedb99cda 100644 --- a/docs/Options.md +++ b/docs/Options.md @@ -13,8 +13,8 @@ The following required options will be prompted for interactively if not provide These required options determine how the creation script will set up and scaffold the repository: - `--base`: Whether to scaffold the repository with: - - `minimum`: Just the bare starter tooling most repositories should ideally include - - `common`: Important additions to the minimum starters such as releases and tests + - `minimal`: Just the bare starter tooling most repositories should ideally include + - `common`: Important additions to the minimal starters such as releases and tests - `everything`: The most thorough tooling imaginable: sorting, spellchecking, and more! - `prompt`: Fine-grained control over which tooling pieces to use - `--mode`: Whether to: @@ -84,6 +84,7 @@ The setup scripts normally will prompt you to select how much of the tooling you Alternately, you can bypass that prompt by providing any number of the following CLI flags: - `--exclude-all-contributors`: Don't add all-contributors to track contributions and display them in a README.md table. +- `--exclude-build`: Don't add a build task to generate built `.js`, `.d.ts`, and related output. - `--exclude-compliance`: Don't add a GitHub Actions workflow to verify that PRs match an expected format. - `--exclude-lint-json`: Don't apply linting and sorting to `*.json` and `*.jsonc` files. - `--exclude-lint-knip`: Don't add Knip to detect unused files, dependencies, and code exports. diff --git a/docs/Tooling.md b/docs/Tooling.md index bb8cb7fd2..ab9d9524f 100644 --- a/docs/Tooling.md +++ b/docs/Tooling.md @@ -8,8 +8,8 @@ Those template levels provide common presets of which tooling pieces to enable. ```plaintext ◆ How much tooling would you like the template to set up for you? -│ ○ minimum Just the bare starter tooling most repositories should ideally include. -│ ○ common Important additions to the minimum starters such as releases and tests. +│ ○ minimal Just the bare starter tooling most repositories should ideally include. +│ ○ common Important additions to the minimal starters such as releases and tests. │ ○ everything The most thorough tooling imaginable: sorting, spellchecking, and more! │ ○ prompt (allow me to customize) └ @@ -17,7 +17,7 @@ Those template levels provide common presets of which tooling pieces to enable. This table summarizes each tooling piece and which base levels they're included in: -| Tooling Piece | Exclusion Flag | Minimum | Common | Everything | +| Tooling Piece | Exclusion Flag | Minimal | Common | Everything | | --------------------------------------------- | ------------------------------ | ------- | ------ | ---------- | | [Building](#building) | | ✔️ | ✅ | 💯 | | [Compliance](#compliance) | `--exclude-compliance` | | | 💯 | @@ -46,12 +46,12 @@ This table summarizes each tooling piece and which base levels they're included See also [Options](./Options.md) for how to customize the way template is run. -## "Minimum" Base Level +## "Minimal" Base Level These tooling pieces are the ones that most repositories should generally always have enabled. Other pieces of tooling are likely to not work as well (or at all) if these are removed. -The _"minimum"_ base is best suited for projects that are very small and not likely to change very frequently. +The _"minimal"_ base is best suited for projects that are very small and not likely to change very frequently. However, they'll be missing out on many of the great tooling pieces enabled in more comprehensive bases. We strongly recommend using at least the [_"common"_ base level](#common-base-level) instead for most repositories. diff --git a/src/bin/help.test.ts b/src/bin/help.test.ts index 851a6b162..c253a8295 100644 --- a/src/bin/help.test.ts +++ b/src/bin/help.test.ts @@ -62,7 +62,8 @@ describe("logHelpText", () => { " --base (string): Whether to scaffold the repository with: • everything: that comes with the template (recommended) - • minimum: amounts of tooling, essentially opting out of everything + • common: additions to the minimal starters such as releases and tests + • minimal: amounts of tooling, essentially opting out of everything • prompt: for which portions to exclude", ], [ diff --git a/src/create/createRerunSuggestion.test.ts b/src/create/createRerunSuggestion.test.ts index b31b0204c..7dfbe203c 100644 --- a/src/create/createRerunSuggestion.test.ts +++ b/src/create/createRerunSuggestion.test.ts @@ -133,15 +133,15 @@ describe("createRerunSuggestion", () => { ); }); - it("does not list all excludes when using minimum base", () => { - const minimum = createRerunSuggestion({ - base: "minimum", - ...getExclusions(options, "minimum"), + it("does not list all excludes when using minimal base", () => { + const minimal = createRerunSuggestion({ + base: "minimal", + ...getExclusions(options, "minimal"), excludeLintKnip: undefined, }); - expect(minimum).toMatchInlineSnapshot( - `"npx create-typescript-app --base minimum"`, + expect(minimal).toMatchInlineSnapshot( + `"npx create-typescript-app --base minimal"`, ); }); diff --git a/src/shared/options/args.ts b/src/shared/options/args.ts index d160720ec..ed3a88d28 100644 --- a/src/shared/options/args.ts +++ b/src/shared/options/args.ts @@ -26,7 +26,8 @@ export const allArgOptions = { • everything: that comes with the template (${chalk.cyanBright.bold( "recommended", )}) - • minimum: amounts of tooling, essentially opting out of everything + • common: additions to the minimal starters such as releases and tests + • minimal: amounts of tooling, essentially opting out of everything • prompt: for which portions to exclude`, docsSection: "core", type: "string", diff --git a/src/shared/options/augmentOptionsWithExcludes.test.ts b/src/shared/options/augmentOptionsWithExcludes.test.ts index c34dfddfb..63f2a7e25 100644 --- a/src/shared/options/augmentOptionsWithExcludes.test.ts +++ b/src/shared/options/augmentOptionsWithExcludes.test.ts @@ -27,6 +27,7 @@ const optionsBase = { npm: "npm@email.com", }, excludeAllContributors: undefined, + excludeBuild: undefined, excludeCompliance: undefined, excludeLintESLint: undefined, excludeLintJSDoc: undefined, @@ -84,6 +85,7 @@ describe("augmentOptionsWithExcludes", () => { ...optionsBase, base, excludeAllContributors: true, + excludeBuild: true, excludeCompliance: true, excludeLintESLint: true, excludeLintJSDoc: true, @@ -141,10 +143,10 @@ describe("augmentOptionsWithExcludes", () => { }); }); - it("uses the 'minimum' base without prompting when provided manually", async () => { + it("uses the 'minimal' base without prompting when provided manually", async () => { const options = { ...optionsBase, - base: "minimum", + base: "minimal", } satisfies Options; const actual = await augmentOptionsWithExcludes(options); diff --git a/src/shared/options/augmentOptionsWithExcludes.ts b/src/shared/options/augmentOptionsWithExcludes.ts index e9a415b66..c25b7bff9 100644 --- a/src/shared/options/augmentOptionsWithExcludes.ts +++ b/src/shared/options/augmentOptionsWithExcludes.ts @@ -47,10 +47,10 @@ export async function augmentOptionsWithExcludes( }, { label: makeLabel( - "minimum", + "minimal", "Just bare starter tooling: building, formatting, linting, and type checking.", ), - value: "minimum", + value: "minimal", }, { label: makeLabel("prompt", "(allow me to customize)"), @@ -64,8 +64,8 @@ export async function augmentOptionsWithExcludes( case undefined: return undefined; case "common": - case "minimum": case "everything": + case "minimal": return { ...options, base, diff --git a/src/shared/options/exclusionKeys.ts b/src/shared/options/exclusionKeys.ts index 1173899b8..47c3ea90d 100644 --- a/src/shared/options/exclusionKeys.ts +++ b/src/shared/options/exclusionKeys.ts @@ -5,7 +5,7 @@ export type ExclusionKey = `exclude${string}` & keyof Options; export interface ExclusionDescription { hint: string; label: string; - uncommon?: true; + level?: "common" | "minimal"; } export const exclusionDescriptions: Record = @@ -15,28 +15,33 @@ export const exclusionDescriptions: Record = label: "Add all-contributors to track contributions and display them in a README.md table.", }, + excludeBuild: { + hint: "--exclude-build", + label: "Add a tsup build step to generate built output files.", + level: "minimal", + }, excludeCompliance: { hint: "--exclude-compliance", label: "Add a GitHub Actions workflow to verify that PRs match an expected format.", - uncommon: true, + level: "common", }, excludeLintESLint: { hint: "--exclude-lint-eslint", label: "Include eslint-plugin-eslint-comment to enforce good practices around ESLint comment directives.", - uncommon: true, + level: "common", }, excludeLintJSDoc: { hint: "--exclude-lint-jsdoc", label: "Include eslint-plugin-jsdoc to enforce good practices around JSDoc comments.", - uncommon: true, + level: "common", }, excludeLintJson: { hint: "--exclude-lint-json", label: "Apply linting and sorting to *.json and *.jsonc files.", - uncommon: true, + level: "common", }, excludeLintKnip: { hint: "--exclude-lint-knip", @@ -45,53 +50,53 @@ export const exclusionDescriptions: Record = excludeLintMd: { hint: "--exclude-lint-md", label: "Apply linting to *.md files.", - uncommon: true, + level: "common", }, excludeLintPackageJson: { hint: "--exclude-lint-package-json", label: "Add eslint-plugin-package-json to lint for package.json correctness.", - uncommon: true, + level: "common", }, excludeLintPackages: { hint: "--exclude-lint-packages", label: "Add a pnpm dedupe workflow to ensure packages aren't duplicated unnecessarily.", - uncommon: true, + level: "common", }, excludeLintPerfectionist: { hint: "--exclude-lint-perfectionist", label: "Apply eslint-plugin-perfectionist to ensure imports, keys, and so on are in sorted order.", - uncommon: true, + level: "common", }, excludeLintRegex: { hint: "--exclude-lint-regex", label: "Include eslint-plugin-regex to enforce good practices around regular expressions.", - uncommon: true, + level: "common", }, excludeLintSpelling: { hint: "--exclude-lint-spelling", label: "Add cspell to spell check against dictionaries of known words.", - uncommon: true, + level: "common", }, excludeLintStrict: { hint: "--exclude-lint-strict", label: "Include strict logical lint rules such as typescript-eslint's strict config. ", - uncommon: true, + level: "common", }, excludeLintStylistic: { hint: "--exclude-lint-stylistic", label: "Include stylistic lint rules such as typescript-eslint's stylistic config.", - uncommon: true, + level: "common", }, excludeLintYml: { hint: "--exclude-lint-yml", label: "Apply linting and sorting to *.yaml and *.yml files.", - uncommon: true, + level: "common", }, excludeReleases: { hint: "--exclude-releases", @@ -122,20 +127,25 @@ export function getExclusions( return { ...Object.fromEntries( exclusionKeys - .filter((exclusion) => exclusionDescriptions[exclusion].uncommon) + .filter( + (exclusion) => + exclusionDescriptions[exclusion].level === "common", + ) .map((exclusion) => [exclusion, options[exclusion] ?? true]), ), }; - case "minimum": + case "minimal": return { ...Object.fromEntries( - exclusionKeys.map((exclusion) => [ - exclusion, - options[exclusion] ?? true, - ]), + exclusionKeys + .filter( + (exclusion) => + exclusionDescriptions[exclusion].level !== "minimal", + ) + .map((exclusion) => [exclusion, options[exclusion] ?? true]), ), }; - // We only really care about exclusions on the common and minimum bases + // We only really care about exclusions on the common and minimal bases default: return {}; } diff --git a/src/shared/options/getBase.test.ts b/src/shared/options/getBase.test.ts index b131d332c..9f50ce440 100644 --- a/src/shared/options/getBase.test.ts +++ b/src/shared/options/getBase.test.ts @@ -10,7 +10,7 @@ vi.mock("../packages.js", () => ({ })); describe("getBase", () => { - it("should return minimum with minimum scripts", async () => { + it("should return minimal with minimal scripts", async () => { mockReadPackageData.mockImplementationOnce(() => Promise.resolve({ scripts: { @@ -21,7 +21,7 @@ describe("getBase", () => { }), ); - expect(await getBase()).toBe("minimum"); + expect(await getBase()).toBe("minimal"); }); it("should return common with common scripts", async () => { diff --git a/src/shared/options/getBase.ts b/src/shared/options/getBase.ts index a09262640..af5e8bf6e 100644 --- a/src/shared/options/getBase.ts +++ b/src/shared/options/getBase.ts @@ -30,5 +30,5 @@ export async function getBase(): Promise { return "common"; } - return "minimum"; + return "minimal"; } diff --git a/src/shared/options/optionsSchema.ts b/src/shared/options/optionsSchema.ts index d144861f9..e6a097a18 100644 --- a/src/shared/options/optionsSchema.ts +++ b/src/shared/options/optionsSchema.ts @@ -8,7 +8,7 @@ export const optionsSchemaShape = { .union([ z.literal("common"), z.literal("everything"), - z.literal("minimum"), + z.literal("minimal"), z.literal("prompt"), ]) .optional(), @@ -22,6 +22,7 @@ export const optionsSchemaShape = { }) .optional(), excludeAllContributors: z.boolean().optional(), + excludeBuild: z.boolean().optional(), excludeCompliance: z.boolean().optional(), excludeLintESLint: z.boolean().optional(), excludeLintJSDoc: z.boolean().optional(), diff --git a/src/shared/options/readOptions.test.ts b/src/shared/options/readOptions.test.ts index c50b9a030..2be4a603c 100644 --- a/src/shared/options/readOptions.test.ts +++ b/src/shared/options/readOptions.test.ts @@ -588,7 +588,7 @@ describe("readOptions", () => { ...emptyOptions, ...mockOptions, access: "public", - base: "minimum", + base: "minimal", description: "mock", directory: "mock", email: { @@ -642,7 +642,7 @@ describe("readOptions", () => { ...emptyOptions, ...mockOptions, access: "public", - base: "minimum", + base: "minimal", description, directory: repository, email: { @@ -700,7 +700,7 @@ describe("readOptions", () => { ...mockOptions, access: "public", auto: true, - base: "minimum", + base: "minimal", description, directory: repository, email: { @@ -725,7 +725,7 @@ describe("readOptions", () => { "access": "public", "author": undefined, "auto": true, - "base": "minimum", + "base": "minimal", "bin": undefined, "description": "Test description.", "directory": "test-repository", diff --git a/src/shared/types.ts b/src/shared/types.ts index 795004424..781fab088 100644 --- a/src/shared/types.ts +++ b/src/shared/types.ts @@ -25,7 +25,7 @@ export interface PartialPackageData { export type OptionsAccess = "public" | "restricted"; -export type OptionsBase = "common" | "everything" | "minimum" | "prompt"; +export type OptionsBase = "common" | "everything" | "minimal" | "prompt"; export interface OptionsEmail { github: string; @@ -54,6 +54,7 @@ export interface Options { directory: string; email: OptionsEmail; excludeAllContributors?: boolean; + excludeBuild?: boolean; excludeCompliance?: boolean; excludeLintESLint?: boolean; excludeLintJSDoc?: boolean; diff --git a/src/steps/writing/creation/writePackageJson.test.ts b/src/steps/writing/creation/writePackageJson.test.ts index 9bb9219ba..cebb82693 100644 --- a/src/steps/writing/creation/writePackageJson.test.ts +++ b/src/steps/writing/creation/writePackageJson.test.ts @@ -123,6 +123,7 @@ describe("writePackageJson", () => { ...options, bin: "./bin/index.js", excludeAllContributors: true, + excludeBuild: true, excludeCompliance: true, excludeLintJson: true, excludeLintKnip: true, @@ -169,7 +170,6 @@ describe("writePackageJson", () => { "url": "https://github.com/test-owner/test-repository", }, "scripts": { - "build": "tsup", "format": "prettier .", "lint": "eslint . --max-warnings 0", "prepare": "husky", diff --git a/src/steps/writing/creation/writePackageJson.ts b/src/steps/writing/creation/writePackageJson.ts index a04b770d5..fdaf2c4eb 100644 --- a/src/steps/writing/creation/writePackageJson.ts +++ b/src/steps/writing/creation/writePackageJson.ts @@ -84,7 +84,9 @@ export async function writePackageJson(options: Options) { }, scripts: { ...existingPackageJson.scripts, - build: "tsup", + ...(!options.excludeBuild && { + build: "tsup", + }), format: "prettier .", lint: "eslint . --max-warnings 0", ...(!options.excludeLintKnip && {