Skip to content

Commit 1399071

Browse files
feat: support package.json keywords (#886)
## PR Checklist - [x] Addresses an existing open issue: fixes #526 - [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 Adds `keywords` as an allowed arg. I set it to plural instead of the singular `keyword` because I expect I'll be specifying many, multiple, keywords.
1 parent 4486186 commit 1399071

File tree

8 files changed

+43
-8
lines changed

8 files changed

+43
-8
lines changed

docs/Options.md

+2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ The setup scripts also allow for optional overrides of the following inputs whos
5454
- `--email` _(`string`)_: Email address to be listed as the point of contact in docs and packages (e.g. `[email protected]`)
5555
- Optionally, `--email-github` _(`string`)_ and/or `--email-npm` _(`string`)_ may be provided to use different emails in `.md` files and `package.json`, respectively
5656
- `--funding` _(`string`)_: GitHub organization or username to mention in `funding.yml` (by default, `owner`)
57+
- `--keywords` _(`string[]`)_: Any number of keywords to include in `package.json` (by default, none)
58+
- This can be specified any number of times, like `--keywords apple --keywords "banana cherry"`
5759
- `--logo` _(`string`)_: Local image file in the repository to display near the top of the README.md as a logo
5860
- `--logo-alt` _(`string`)_: If `--logo` is provided or detected from an existing README.md, alt text that describes the image will be prompted for if not provided
5961

src/create/createRerunSuggestion.test.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const options = {
2828
excludeRenovate: undefined,
2929
excludeTests: undefined,
3030
funding: undefined,
31+
keywords: ["abc", "def ghi", "jkl mno pqr"],
3132
logo: undefined,
3233
mode: "create",
3334
owner: "TestOwner",
@@ -45,7 +46,7 @@ describe("createRerunSuggestion", () => {
4546
const actual = createRerunSuggestion(options);
4647

4748
expect(actual).toMatchInlineSnapshot(
48-
'"npx create-typescript-app --mode create --base everything --access public --author TestAuthor --create-repository true --description \\"Test description.\\" --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-package-json true --exclude-lint-perfectionist true --mode create --owner TestOwner --repository test-repository --skip-github-api true --skip-install true --skip-removal true --title \\"Test Title\\""',
49+
'"npx create-typescript-app --mode create --base everything --access public --author TestAuthor --create-repository true --description \\"Test description.\\" --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-package-json true --exclude-lint-perfectionist 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\\""',
4950
);
5051
});
5152

@@ -60,7 +61,7 @@ describe("createRerunSuggestion", () => {
6061
});
6162

6263
expect(actual).toMatchInlineSnapshot(
63-
'"npx create-typescript-app --mode initialize --base everything --access public --author TestAuthor --create-repository true --description \\"Test description.\\" --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-package-json true --exclude-lint-perfectionist true --logo test/src.png --logo-alt \\"Test alt.\\" --mode initialize --owner TestOwner --repository test-repository --skip-github-api true --skip-install true --skip-removal true --title \\"Test Title\\""',
64+
'"npx create-typescript-app --mode initialize --base everything --access public --author TestAuthor --create-repository true --description \\"Test description.\\" --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-package-json true --exclude-lint-perfectionist true --keywords \\"abc def ghi jkl mno pqr\\" --logo test/src.png --logo-alt \\"Test alt.\\" --mode initialize --owner TestOwner --repository test-repository --skip-github-api true --skip-install true --skip-removal true --title \\"Test Title\\""',
6465
);
6566
});
6667

@@ -74,7 +75,7 @@ describe("createRerunSuggestion", () => {
7475
});
7576

7677
expect(actual).toMatchInlineSnapshot(
77-
'"npx create-typescript-app --mode initialize --base everything --access public --author TestAuthor --create-repository true --description \\"Test description.\\" --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 --mode initialize --owner TestOwner --repository test-repository --skip-github-api true --skip-install true --skip-removal true --title \\"Test Title\\""',
78+
'"npx create-typescript-app --mode initialize --base everything --access public --author TestAuthor --create-repository true --description \\"Test description.\\" --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\\""',
7879
);
7980
});
8081
});

src/create/createRerunSuggestion.ts

+15-4
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,23 @@ export function createRerunSuggestion(options: Partial<Options>): string {
3131
)
3232
.filter(([, value]) => !!value)
3333
.map(([key, value]) => {
34-
const valueStringified = `${value}`;
35-
return `--${getFirstMatchingArg(key)} ${
36-
valueStringified.includes(" ") ? `"${value}"` : value
37-
}`;
34+
return `--${getFirstMatchingArg(key)} ${stringifyValue(value)}`;
3835
})
3936
.join(" ");
4037

4138
return `npx create-typescript-app --mode ${options.mode} ${args}`;
4239
}
40+
41+
function stringifyValue(
42+
value: boolean | string | string[] | undefined,
43+
): string {
44+
if (Array.isArray(value)) {
45+
return stringifyValue(value.join(" "));
46+
}
47+
48+
const valueStringified = `${value}`;
49+
50+
return valueStringified.includes(" ")
51+
? `"${valueStringified}"`
52+
: valueStringified;
53+
}

src/shared/options/args.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { ParseArgsConfig } from "node:util";
2+
13
export const allArgOptions = {
24
access: { type: "string" },
35
author: { type: "string" },
@@ -27,6 +29,7 @@ export const allArgOptions = {
2729
"exclude-renovate": { type: "boolean" },
2830
"exclude-tests": { type: "boolean" },
2931
funding: { type: "string" },
32+
keywords: { multiple: true, type: "string" },
3033
logo: { type: "string" },
3134
"logo-alt": { type: "string" },
3235
mode: { type: "string" },
@@ -40,4 +43,4 @@ export const allArgOptions = {
4043
"skip-restore": { type: "boolean" },
4144
"skip-uninstall": { type: "boolean" },
4245
title: { type: "string" },
43-
} as const;
46+
} as const satisfies ParseArgsConfig["options"];

src/shared/options/optionsSchema.ts

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export const optionsSchemaShape = {
3939
excludeRenovate: z.boolean().optional(),
4040
excludeTests: z.boolean().optional(),
4141
funding: z.string().optional(),
42+
keywords: z.array(z.string()).optional(),
4243
logo: z.string().optional(),
4344
logoAlt: z.string().optional(),
4445
mode: z

src/shared/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export interface Options {
6060
excludeRenovate?: boolean;
6161
excludeTests?: boolean;
6262
funding?: string;
63+
keywords?: string[];
6364
logo: OptionsLogo | undefined;
6465
mode: Mode;
6566
offline?: boolean;

src/steps/writing/creation/writePackageJson.test.ts

+13
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,19 @@ describe("writePackageJson", () => {
7070
);
7171
});
7272

73+
it("includes flattened keywords when they're specified", async () => {
74+
mockReadFileSafeAsJson.mockResolvedValue({});
75+
76+
const keywords = ["abc", "def ghi", "jkl mno pqr"];
77+
const packageJson = await writePackageJson({ ...options, keywords });
78+
79+
expect(JSON.parse(packageJson)).toEqual(
80+
expect.objectContaining({
81+
keywords: ["abc", "def", "ghi", "jkl", "mno", "pqr"],
82+
}),
83+
);
84+
});
85+
7386
it("includes all optional portions when no exclusions are enabled", async () => {
7487
mockReadFileSafeAsJson.mockResolvedValue({});
7588

src/steps/writing/creation/writePackageJson.ts

+3
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ export async function writePackageJson(options: Options) {
4040

4141
author: { email: options.email.npm, name: options.author },
4242
description: options.description,
43+
keywords: options.keywords?.length
44+
? options.keywords.flatMap((keyword) => keyword.split(/ /))
45+
: undefined,
4346

4447
// We copy all existing dev dependencies except those we know are not used anymore
4548
devDependencies: copyDevDependencies(existingPackageJson),

0 commit comments

Comments
 (0)