Skip to content

Commit 777d413

Browse files
fix: lazily evaluate options.repository for options.usage (#1827)
## PR Checklist - [x] Addresses an existing open issue: fixes #1826 - [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 Moves `repository` into its own separate `lazyValue` that's then used for `usage`. Also allows `repository` to default to `options.directory`. 💖
1 parent ff5c1b1 commit 777d413

File tree

5 files changed

+83
-24
lines changed

5 files changed

+83
-24
lines changed

src/next/base.ts

+10-5
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,14 @@ export const base = createBase({
197197

198198
const version = lazyValue(async () => (await packageData()).version);
199199

200+
const repository = lazyValue(
201+
async () =>
202+
options.repository ??
203+
(await gitDefaults())?.name ??
204+
(await packageData()).name ??
205+
options.directory,
206+
);
207+
200208
return {
201209
access: "public" as const,
202210
author,
@@ -222,11 +230,8 @@ export const base = createBase({
222230
scripts: original.scripts,
223231
};
224232
},
225-
repository: async () =>
226-
options.repository ??
227-
(await gitDefaults())?.name ??
228-
(await packageData()).name,
229-
...readDefaultsFromReadme(readme, options.repository),
233+
repository,
234+
...readDefaultsFromReadme(readme, repository),
230235
version,
231236
};
232237
},

src/shared/options/createOptionDefaults/index.test.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -196,13 +196,23 @@ describe("createOptionDefaults", () => {
196196
expect(actual).toBe(name);
197197
});
198198

199-
it("returns the package name when it exists and promptedOptions.repository a Git name don't", async () => {
199+
it("returns the package name when it exists and promptedOptions.repository and Git name don't", async () => {
200200
const name = "test-package-name";
201201
mockReadPackageData.mockResolvedValueOnce({ name });
202202

203203
const actual = await createOptionDefaults().repository();
204204

205205
expect(actual).toBe(name);
206206
});
207+
208+
it("returns the directory when it exists and promptedOptions.repository, Git name, and package name don't", async () => {
209+
mockReadPackageData.mockResolvedValueOnce({});
210+
const directory = "test-prompted-directory";
211+
const promptedOptions = { directory };
212+
213+
const actual = await createOptionDefaults(promptedOptions).repository();
214+
215+
expect(actual).toBe(directory);
216+
});
207217
});
208218
});

src/shared/options/createOptionDefaults/index.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ export function createOptionDefaults(promptedOptions?: PromptedOptions) {
5252
repository: async () =>
5353
promptedOptions?.repository ??
5454
(await gitDefaults())?.name ??
55-
(await packageData()).name,
56-
...readDefaultsFromReadme(readme, promptedOptions?.repository),
55+
(await packageData()).name ??
56+
promptedOptions?.directory,
57+
...readDefaultsFromReadme(readme, () =>
58+
Promise.resolve(promptedOptions?.repository),
59+
),
5760
};
5861
}

src/shared/options/createOptionDefaults/readDefaultsFromReadme.test.ts

+54-13
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,20 @@ vi.mock("../readLogoSizing.js", () => ({
1010
},
1111
}));
1212

13+
const mockGetUsageFromReadme = vi.fn().mockResolvedValue({});
14+
15+
vi.mock("./getUsageFromReadme.js", () => ({
16+
get getUsageFromReadme() {
17+
return mockGetUsageFromReadme;
18+
},
19+
}));
20+
1321
describe("readDefaultsFromReadme", () => {
1422
describe("logo", () => {
1523
it("defaults to undefined when it cannot be found", async () => {
1624
const logo = await readDefaultsFromReadme(
1725
() => Promise.resolve(`nothing.`),
18-
undefined,
26+
() => Promise.resolve(undefined),
1927
).logo();
2028

2129
expect(logo).toBeUndefined();
@@ -26,7 +34,7 @@ describe("readDefaultsFromReadme", () => {
2634
() =>
2735
Promise.resolve(`
2836
<img src=abc/def.jpg/>`),
29-
undefined,
37+
() => Promise.resolve(undefined),
3038
).logo();
3139

3240
expect(logo).toEqual({
@@ -40,7 +48,7 @@ describe("readDefaultsFromReadme", () => {
4048
() =>
4149
Promise.resolve(`
4250
<img src='abc/def.jpg'/>`),
43-
undefined,
51+
() => Promise.resolve(undefined),
4452
).logo();
4553

4654
expect(logo).toEqual({
@@ -54,7 +62,7 @@ describe("readDefaultsFromReadme", () => {
5462
() =>
5563
Promise.resolve(`
5664
<img src="abc/def.jpg"/>`),
57-
undefined,
65+
() => Promise.resolve(undefined),
5866
).logo();
5967

6068
expect(logo).toEqual({
@@ -68,7 +76,7 @@ describe("readDefaultsFromReadme", () => {
6876
() =>
6977
Promise.resolve(`
7078
<img alt="Project logo: a fancy circle" src="abc/def.jpg"/>`),
71-
undefined,
79+
() => Promise.resolve(undefined),
7280
).logo();
7381

7482
expect(logo).toEqual({
@@ -82,7 +90,7 @@ describe("readDefaultsFromReadme", () => {
8290
() =>
8391
Promise.resolve(`
8492
<img alt='Project logo: a fancy circle' src='abc/def.jpg'/>`),
85-
undefined,
93+
() => Promise.resolve(undefined),
8694
).logo();
8795

8896
expect(logo).toEqual({
@@ -100,7 +108,7 @@ describe("readDefaultsFromReadme", () => {
100108
() =>
101109
Promise.resolve(`
102110
<img alt='Project logo: a fancy circle' src='abc/def.jpg'/>`),
103-
undefined,
111+
() => Promise.resolve(undefined),
104112
).logo();
105113

106114
expect(logo).toEqual({
@@ -117,7 +125,7 @@ describe("readDefaultsFromReadme", () => {
117125
<a href="#contributors" target="_blank"><img alt="👪 All Contributors: 48" src="https://img.shields.io/badge/%F0%9F%91%AA_all_contributors-48-21bb42.svg" /></a>
118126
<img src=abc/def.jpg/>
119127
`),
120-
undefined,
128+
() => Promise.resolve(undefined),
121129
).logo();
122130

123131
expect(logo).toEqual({
@@ -149,7 +157,7 @@ describe("readDefaultsFromReadme", () => {
149157
150158
<img align="right" alt="Project logo: the TypeScript blue square with rounded corners, but a plus sign instead of 'TS'" src="./docs/create-typescript-app.png">
151159
`),
152-
undefined,
160+
() => Promise.resolve(undefined),
153161
).logo();
154162

155163
expect(logo).toEqual({
@@ -163,7 +171,7 @@ describe("readDefaultsFromReadme", () => {
163171
it("defaults to undefined when it cannot be found", async () => {
164172
const title = await readDefaultsFromReadme(
165173
() => Promise.resolve(`nothing`),
166-
undefined,
174+
() => Promise.resolve(undefined),
167175
).title();
168176

169177
expect(title).toBeUndefined();
@@ -172,7 +180,7 @@ describe("readDefaultsFromReadme", () => {
172180
it('reads title as markdown from "README.md" when it exists', async () => {
173181
const title = await readDefaultsFromReadme(
174182
() => Promise.resolve(`# My Awesome Package`),
175-
undefined,
183+
() => Promise.resolve(undefined),
176184
).title();
177185

178186
expect(title).toBe("My Awesome Package");
@@ -181,7 +189,7 @@ describe("readDefaultsFromReadme", () => {
181189
it('reads title as HTML from "README.md" when it exists', async () => {
182190
const title = await readDefaultsFromReadme(
183191
() => Promise.resolve('<h1 align="center">My Awesome Package</h1>'),
184-
undefined,
192+
() => Promise.resolve(undefined),
185193
).title();
186194

187195
expect(title).toBe("My Awesome Package");
@@ -190,10 +198,43 @@ describe("readDefaultsFromReadme", () => {
190198
it("returns undefined when title does not exist", async () => {
191199
const title = await readDefaultsFromReadme(
192200
() => Promise.resolve(`Other text.`),
193-
undefined,
201+
() => Promise.resolve(undefined),
194202
).title();
195203

196204
expect(title).toBeUndefined();
197205
});
198206
});
207+
208+
describe("usage", () => {
209+
it("returns the existing usage when getUsageFromReadme provides one", async () => {
210+
const existing = "Use it.";
211+
212+
mockGetUsageFromReadme.mockReturnValueOnce(existing);
213+
214+
const usage = await readDefaultsFromReadme(
215+
() => Promise.resolve(""),
216+
() => Promise.resolve(undefined),
217+
).usage();
218+
219+
expect(usage).toBe(existing);
220+
});
221+
222+
it("returns sample usage when getUsageFromReadme doesn't provide usage", async () => {
223+
mockGetUsageFromReadme.mockReturnValueOnce(undefined);
224+
225+
const usage = await readDefaultsFromReadme(
226+
() => Promise.resolve(""),
227+
() => Promise.resolve("test-repository"),
228+
).usage();
229+
230+
expect(usage).toBe(`\`\`\`shell
231+
npm i test-repository
232+
\`\`\`
233+
\`\`\`ts
234+
import { greet } from "test-repository";
235+
236+
greet("Hello, world! 💖");
237+
\`\`\``);
238+
});
239+
});
199240
});

src/shared/options/createOptionDefaults/readDefaultsFromReadme.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { getUsageFromReadme } from "./getUsageFromReadme.js";
55

66
export function readDefaultsFromReadme(
77
readme: () => Promise<string>,
8-
repository: string | undefined,
8+
repository: () => Promise<string | undefined>,
99
) {
1010
const imageTag = lazyValue(
1111
async () => /\n<img.+src=.+>/.exec(await readme())?.[0],
@@ -43,10 +43,10 @@ export function readDefaultsFromReadme(
4343
return (
4444
getUsageFromReadme(await readme()) ??
4545
`\`\`\`shell
46-
npm i ${repository}
46+
npm i ${await repository()}
4747
\`\`\`
4848
\`\`\`ts
49-
import { greet } from "${repository}";
49+
import { greet } from "${await repository()}";
5050
5151
greet("Hello, world! 💖");
5252
\`\`\``

0 commit comments

Comments
 (0)