Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: account for base when suggesting rerun cmd #992

Merged
30 changes: 30 additions & 0 deletions src/create/createRerunSuggestion.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { describe, expect, it } from "vitest";

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

Expand Down Expand Up @@ -41,6 +42,11 @@ const options = {
title: "Test Title",
} satisfies Options;

const opts = {
JoshuaKGoldberg marked this conversation as resolved.
Show resolved Hide resolved
...options,
excludeLintKnip: undefined,
};

describe("createRerunSuggestion", () => {
it("includes key-value pairs with mixed truthy and falsy values", () => {
const actual = createRerunSuggestion(options);
Expand Down Expand Up @@ -93,4 +99,28 @@ describe("createRerunSuggestion", () => {
'"npx create-typescript-app --mode initialize --base everything --access public --author TestAuthor --description \\"Test description.\\" --directory . --email-github [email protected] --email-npm [email protected] --exclude-all-contributors true --exclude-compliance true --exclude-lint-jsdoc true --exclude-lint-json true --exclude-lint-knip true --exclude-lint-md true --exclude-lint-package-json true --exclude-lint-perfectionist true --exclude-lint-spelling true --keywords \\"abc def ghi jkl mno pqr\\" --mode initialize --owner TestOwner --repository test-repository --skip-github-api true --skip-install true --skip-removal true --title \\"Test Title\\""',
);
});

it("does not list all excludes when using common base", () => {
const common = createRerunSuggestion({
...opts,
base: "common",
...getExclusions(options, "common"),
});

expect(common).toMatchInlineSnapshot(
'"npx create-typescript-app --mode create --base common --access public --author TestAuthor --description \\"Test description.\\" --directory . --email-github [email protected] --email-npm [email protected] --exclude-all-contributors true --keywords \\"abc def ghi jkl mno pqr\\" --mode create --owner TestOwner --repository test-repository --skip-github-api true --skip-install true --skip-removal true --title \\"Test Title\\""',
);
});

it("does not list all excludes when using minimum base", () => {
const minimum = createRerunSuggestion({
...opts,
base: "minimum",
...getExclusions(options, "minimum"),
});

expect(minimum).toMatchInlineSnapshot(
GV14982 marked this conversation as resolved.
Show resolved Hide resolved
'"npx create-typescript-app --mode create --base minimum --access public --author TestAuthor --description \\"Test description.\\" --directory . --email-github [email protected] --email-npm [email protected] --keywords \\"abc def ghi jkl mno pqr\\" --mode create --owner TestOwner --repository test-repository --skip-github-api true --skip-install true --skip-removal true --title \\"Test Title\\""',
);
});
});
12 changes: 11 additions & 1 deletion src/create/createRerunSuggestion.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { allArgOptions } from "../shared/options/args.js";
import {
ExclusionKey,
getExclusions,
} from "../shared/options/augmentOptionsWithExcludes.js";
import { Options } from "../shared/types.js";

function getFirstMatchingArg(key: string) {
Expand Down Expand Up @@ -30,10 +34,16 @@ export function createRerunSuggestion(options: Partial<Options>): string {
};

const args = Object.entries(optionsNormalized)
// Sort so the base is first, then the rest are sorted alphabetically
.sort(([a], [b]) =>
a === "base" ? -1 : b === "base" ? 1 : a.localeCompare(b),
)
.filter(([, value]) => !!value)
// Filter out all entries that have a key in the excluded object or have a falsy value
.filter(
([key, value]) =>
getExclusions(options, optionsNormalized.base)[key as ExclusionKey] ==
undefined && !!value,
)
.map(([key, value]) => {
return `--${getFirstMatchingArg(key)} ${stringifyValue(value)}`;
})
Expand Down
2 changes: 1 addition & 1 deletion src/shared/options/augmentOptionsWithExcludes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,6 @@ describe("augmentOptionsWithExcludes", () => {

const actual = await augmentOptionsWithExcludes(options);

expect(actual).toBe(options);
expect(actual).toStrictEqual(options);
});
});
52 changes: 31 additions & 21 deletions src/shared/options/augmentOptionsWithExcludes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface ExclusionDescription {
uncommon?: true;
}

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

const exclusionDescriptions: Record<ExclusionKey, ExclusionDescription> = {
excludeAllContributors: {
Expand Down Expand Up @@ -119,6 +119,34 @@ const exclusionDescriptions: Record<ExclusionKey, ExclusionDescription> = {

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 {};
}
}

export async function augmentOptionsWithExcludes(
options: Options,
): Promise<Options | undefined> {
Expand Down Expand Up @@ -172,31 +200,13 @@ export async function augmentOptionsWithExcludes(
switch (base) {
case undefined:
return undefined;

case "common":
return {
...options,
...Object.fromEntries(
exclusionKeys
.filter((exclusion) => exclusionDescriptions[exclusion].uncommon)
.map((exclusion) => [exclusion, options[exclusion] ?? true]),
),
};

case "everything":
return options;

case "minimum":
case "everything":
return {
...options,
...Object.fromEntries(
exclusionKeys.map((exclusion) => [
exclusion,
options[exclusion] ?? true,
]),
),
...getExclusions(options, base),
};

case "prompt":
const exclusionsNotEnabled = new Set(
filterPromptCancel(
Expand Down
Loading