Skip to content

Commit

Permalink
fix: include base in rerun commands (#1301)
Browse files Browse the repository at this point in the history
## PR Checklist

- [x] Addresses an existing open issue: fixes #1276
- [x] That issue was marked as [`status: accepting
prs`](https://github.com/JoshuaKGoldberg/create-typescript-app/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+accepting+prs%22)
- [x] Steps in
[CONTRIBUTING.md](https://github.com/JoshuaKGoldberg/create-typescript-app/blob/main/.github/CONTRIBUTING.md)
were taken

## Overview

Attaches `base` the options returned during augmentation, so they can
get printed out later.

I noticed that the `exclusionKeys` stuff was exported from the
`augmentOptionsWithExcludes.ts` file but never used in its tests. So I
extracted it to a new `exclusionKeys.ts`.

Adds some unit tests, but doesn't do all of #699. There's still coverage
missing.

Co-authored-by: @niklas-wortmann
  • Loading branch information
JoshuaKGoldberg committed Feb 14, 2024
1 parent 8101b51 commit 2dfb7b5
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 149 deletions.
2 changes: 1 addition & 1 deletion src/create/createRerunSuggestion.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";

import { getExclusions } from "../shared/options/augmentOptionsWithExcludes.js";
import { getExclusions } from "../shared/options/exclusionKeys.js";
import { Options } from "../shared/types.js";
import { createRerunSuggestion } from "./createRerunSuggestion.js";

Expand Down
2 changes: 1 addition & 1 deletion src/create/createRerunSuggestion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { allArgOptions } from "../shared/options/args.js";
import {
ExclusionKey,
getExclusions,
} from "../shared/options/augmentOptionsWithExcludes.js";
} from "../shared/options/exclusionKeys.js";
import { Options } from "../shared/types.js";

function getFirstMatchingArg(key: string) {
Expand Down
65 changes: 62 additions & 3 deletions src/shared/options/augmentOptionsWithExcludes.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
import { describe, expect, it } from "vitest";
import { describe, expect, it, vi } from "vitest";

import { Options } from "../types.js";
import { augmentOptionsWithExcludes } from "./augmentOptionsWithExcludes.js";

const mockMultiselect = vi.fn();
const mockSelect = vi.fn();

vi.mock("@clack/prompts", () => ({
isCancel: () => false,
get multiselect() {
return mockMultiselect;
},
get select() {
return mockSelect;
},
}));

const optionsBase = {
access: "public",
author: undefined,
base: "everything",
base: undefined,
description: "",
directory: ".",
email: {
Expand Down Expand Up @@ -47,7 +60,53 @@ const optionsBase = {
} satisfies Options;

describe("augmentOptionsWithExcludes", () => {
it("returns options without exclusions and skips prompting when exclusions are provided manually", async () => {
it("returns options directly when no exclusions are provided and 'base' is provided for the prompt", async () => {
const base = "everything";

mockSelect.mockResolvedValueOnce(base);

const actual = await augmentOptionsWithExcludes(optionsBase);

expect(actual).toEqual({
...optionsBase,
base,
});
});

it("returns options based on the select when no exclusions are provided and 'prompt' is provided for the prompt", async () => {
const base = "prompt";

mockSelect.mockResolvedValueOnce(base);
mockMultiselect.mockResolvedValue([]);

const actual = await augmentOptionsWithExcludes(optionsBase);

expect(actual).toEqual({
...optionsBase,
base,
excludeAllContributors: true,
excludeCompliance: true,
excludeLintDeprecation: true,
excludeLintESLint: true,
excludeLintJSDoc: true,
excludeLintJson: true,
excludeLintKnip: true,
excludeLintMd: true,
excludeLintPackageJson: true,
excludeLintPackages: true,
excludeLintPerfectionist: true,
excludeLintRegex: true,
excludeLintSpelling: true,
excludeLintStrict: true,
excludeLintStylistic: true,
excludeLintYml: true,
excludeReleases: true,
excludeRenovate: true,
excludeTests: true,
});
});

it("skips prompting returns options directly when exclusions are provided manually", async () => {
const options = {
...optionsBase,
excludeCompliance: true,
Expand Down
152 changes: 8 additions & 144 deletions src/shared/options/augmentOptionsWithExcludes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,150 +3,12 @@ import chalk from "chalk";

import { filterPromptCancel } from "../prompts.js";
import { Options, OptionsBase } from "../types.js";

interface ExclusionDescription {
hint: string;
label: string;
uncommon?: true;
}

export type ExclusionKey = keyof Options & `exclude${string}`;

const exclusionDescriptions: Record<ExclusionKey, ExclusionDescription> = {
excludeAllContributors: {
hint: "--exclude-all-contributors",
label:
"Add all-contributors to track contributions and display them in a README.md table.",
},
excludeCompliance: {
hint: "--exclude-compliance",
label:
"Add a GitHub Actions workflow to verify that PRs match an expected format.",
uncommon: true,
},
excludeLintDeprecation: {
hint: "--exclude-lint-deprecation",
label:
"Include an eslint-plugin-deprecation to reports on usage of code marked as @deprecated.",
uncommon: true,
},
excludeLintESLint: {
hint: "--exclude-lint-eslint",
label:
"Include eslint-plugin-eslint-comment to enforce good practices around ESLint comment directives.",
uncommon: true,
},
excludeLintJSDoc: {
hint: "--exclude-lint-jsdoc",
label:
"Include eslint-plugin-jsdoc to enforce good practices around JSDoc comments.",
uncommon: true,
},
excludeLintJson: {
hint: "--exclude-lint-json",
label: "Apply linting and sorting to *.json and *.jsonc files.",
uncommon: true,
},
excludeLintKnip: {
hint: "--exclude-lint-knip",
label: "Add Knip to detect unused files, dependencies, and code exports.",
},
excludeLintMd: {
hint: "--exclude-lint-md",
label: "Apply linting to *.md files.",
uncommon: true,
},
excludeLintPackageJson: {
hint: "--exclude-lint-package-json",
label:
"Add eslint-plugin-package-json to lint for package.json correctness.",
uncommon: true,
},
excludeLintPackages: {
hint: "--exclude-lint-packages",
label:
"Add a pnpm dedupe workflow to ensure packages aren't duplicated unnecessarily.",
uncommon: true,
},
excludeLintPerfectionist: {
hint: "--exclude-lint-perfectionist",
label:
"Apply eslint-plugin-perfectionist to ensure imports, keys, and so on are in sorted order.",
uncommon: true,
},
excludeLintRegex: {
hint: "--exclude-lint-regex",
label:
"Include eslint-plugin-regex to enforce good practices around regular expressions.",
uncommon: true,
},
excludeLintSpelling: {
hint: "--exclude-lint-spelling",
label: "Add cspell to spell check against dictionaries of known words.",
uncommon: true,
},
excludeLintStrict: {
hint: "--exclude-lint-strict",
label:
"Include strict logical lint rules such as typescript-eslint's strict config. ",
uncommon: true,
},
excludeLintStylistic: {
hint: "--exclude-lint-stylistic",
label:
"Include stylistic lint rules such as typescript-eslint's stylistic config.",
uncommon: true,
},
excludeLintYml: {
hint: "--exclude-lint-yml",
label: "Apply linting and sorting to *.yaml and *.yml files.",
uncommon: true,
},
excludeReleases: {
hint: "--exclude-releases",
label:
"Add release-it to generate changelogs, package bumps, and publishes based on conventional commits.",
},
excludeRenovate: {
hint: "--exclude-renovate",
label: "Add a Renovate config to keep dependencies up-to-date with PRs.",
},
excludeTests: {
hint: "--exclude-tests",
label:
"Add Vitest tooling for fast unit tests, configured with coverage tracking.",
},
};

const exclusionKeys = Object.keys(exclusionDescriptions) as ExclusionKey[];

export function getExclusions(
options: Partial<Options>,
base?: OptionsBase,
): Partial<Options> {
switch (base) {
case "common":
return {
...Object.fromEntries(
exclusionKeys
.filter((exclusion) => exclusionDescriptions[exclusion].uncommon)
.map((exclusion) => [exclusion, options[exclusion] ?? true]),
),
};
case "minimum":
return {
...Object.fromEntries(
exclusionKeys.map((exclusion) => [
exclusion,
options[exclusion] ?? true,
]),
),
};
// We only really care about exclusions on the common and minimum bases
default:
return {};
}
}
import {
ExclusionKey,
exclusionDescriptions,
exclusionKeys,
getExclusions,
} from "./exclusionKeys.js";

export async function augmentOptionsWithExcludes(
options: Options,
Expand Down Expand Up @@ -206,6 +68,7 @@ export async function augmentOptionsWithExcludes(
case "everything":
return {
...options,
base,
...getExclusions(options, base),
};
case "prompt":
Expand All @@ -228,6 +91,7 @@ export async function augmentOptionsWithExcludes(

return {
...options,
base,
...Object.fromEntries(
exclusionKeys.map(
(exclusionKey) =>
Expand Down

0 comments on commit 2dfb7b5

Please sign in to comment.