diff --git a/src/shared/options/createOptionDefaults/index.ts b/src/shared/options/createOptionDefaults/index.ts index 3e51daea2..369c0d864 100644 --- a/src/shared/options/createOptionDefaults/index.ts +++ b/src/shared/options/createOptionDefaults/index.ts @@ -10,9 +10,9 @@ import { tryCatchAsync } from "../../tryCatchAsync.js"; import { tryCatchLazyValueAsync } from "../../tryCatchLazyValueAsync.js"; import { PromptedOptions } from "../../types.js"; import { parsePackageAuthor } from "./parsePackageAuthor.js"; -import { readDefaultsFromDevelopment } from "./readDefaultsFromDevelopment.js"; import { readDefaultsFromReadme } from "./readDefaultsFromReadme.js"; -import { readGitHubEmail } from "./readGitHubEmail.js"; +import { readEmails } from "./readEmails.js"; +import { readGuide } from "./readGuide.js"; export function createOptionDefaults(promptedOptions?: PromptedOptions) { const gitDefaults = tryCatchLazyValueAsync(async () => @@ -34,24 +34,7 @@ export function createOptionDefaults(promptedOptions?: PromptedOptions) { (await packageAuthor()).author ?? (await npmDefaults())?.name, bin: async () => (await packageData()).bin, description: async () => (await packageData()).description, - email: async () => { - const githubEmail = - (await readGitHubEmail()) ?? - (await tryCatchAsync( - async () => (await $`git config --get user.email`).stdout, - )); - const npmEmail = - (await npmDefaults())?.email ?? (await packageAuthor()).email; - - /* eslint-disable @typescript-eslint/no-non-null-assertion */ - return githubEmail || npmEmail - ? { - github: (githubEmail || npmEmail)!, - npm: (npmEmail || githubEmail)!, - } - : undefined; - /* eslint-enable @typescript-eslint/no-non-null-assertion */ - }, + email: async () => readEmails(npmDefaults, packageAuthor), funding: async () => await tryCatchAsync(async () => (await fs.readFile(".github/FUNDING.yml")) @@ -59,13 +42,13 @@ export function createOptionDefaults(promptedOptions?: PromptedOptions) { .split(":")[1] ?.trim(), ), + guide: readGuide, owner: async () => (await gitDefaults())?.organization ?? (await packageAuthor()).author, repository: async () => promptedOptions?.repository ?? (await gitDefaults())?.name ?? (await packageData()).name, - ...readDefaultsFromDevelopment(), ...readDefaultsFromReadme(), }; } diff --git a/src/shared/options/createOptionDefaults/readDefaultsFromDevelopment.ts b/src/shared/options/createOptionDefaults/readDefaultsFromDevelopment.ts deleted file mode 100644 index b0ebe2605..000000000 --- a/src/shared/options/createOptionDefaults/readDefaultsFromDevelopment.ts +++ /dev/null @@ -1,22 +0,0 @@ -import lazyValue from "lazy-value"; - -import { readFileSafe } from "../../readFileSafe.js"; - -export function readDefaultsFromDevelopment() { - return { - guide: lazyValue(async () => { - const tag = /> .*guided walkthrough, see \[((?!\[).+)\]\((.+)\)/i.exec( - await readFileSafe(".github/DEVELOPMENT.md", ""), - ); - - if (!tag) { - return undefined; - } - - return { - href: tag[2], - title: tag[1], - }; - }), - }; -} diff --git a/src/shared/options/createOptionDefaults/readDefaultsFromReadme.ts b/src/shared/options/createOptionDefaults/readDefaultsFromReadme.ts index 68afdf5fa..2ae458776 100644 --- a/src/shared/options/createOptionDefaults/readDefaultsFromReadme.ts +++ b/src/shared/options/createOptionDefaults/readDefaultsFromReadme.ts @@ -30,8 +30,10 @@ export function readDefaultsFromReadme() { src, }; }, - title: async () => - (/^(.+)<\/h1>/.exec(await readme()) ?? - /^# (.+)/.exec(await readme()))?.[1], + title: async () => { + const text = await readme(); + return (/^(.+)<\/h1>/.exec(text) ?? + /^# (.+)/.exec(text))?.[1]; + }, }; } diff --git a/src/shared/options/createOptionDefaults/readEmails.ts b/src/shared/options/createOptionDefaults/readEmails.ts new file mode 100644 index 000000000..d26579e98 --- /dev/null +++ b/src/shared/options/createOptionDefaults/readEmails.ts @@ -0,0 +1,24 @@ +import { $ } from "execa"; +import { UserInfo } from "npm-user"; + +import { tryCatchAsync } from "../../tryCatchAsync.js"; +import { readGitHubEmail } from "./readGitHubEmail.js"; + +export async function readEmails( + npmDefaults: () => Promise, + packageAuthor: () => Promise<{ + author: string | undefined; + email: string | undefined; + }>, +) { + const github = + (await readGitHubEmail()) ?? + (await tryCatchAsync( + async () => (await $`git config --get user.email`).stdout, + )); + + const npm = + ((await npmDefaults())?.email ?? (await packageAuthor()).email) || github; + + return npm ? { github: github || npm, npm } : undefined; +} diff --git a/src/shared/options/createOptionDefaults/readFunding.ts b/src/shared/options/createOptionDefaults/readFunding.ts new file mode 100644 index 000000000..7de124697 --- /dev/null +++ b/src/shared/options/createOptionDefaults/readFunding.ts @@ -0,0 +1,9 @@ +import fs from "node:fs/promises"; + +import { tryCatchAsync } from "../../tryCatchAsync.js"; + +export async function readFunding() { + return await tryCatchAsync(async () => + (await fs.readFile(".github/FUNDING.yml")).toString().split(":")[1]?.trim(), + ); +} diff --git a/src/shared/options/createOptionDefaults/readDefaultsFromDevelopment.test.ts b/src/shared/options/createOptionDefaults/readGuide.test.ts similarity index 79% rename from src/shared/options/createOptionDefaults/readDefaultsFromDevelopment.test.ts rename to src/shared/options/createOptionDefaults/readGuide.test.ts index 1bb51c5bd..9a438babc 100644 --- a/src/shared/options/createOptionDefaults/readDefaultsFromDevelopment.test.ts +++ b/src/shared/options/createOptionDefaults/readGuide.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it, vi } from "vitest"; -import { readDefaultsFromDevelopment } from "./readDefaultsFromDevelopment.js"; +import { readGuide } from "./readGuide.js"; const mockReadFileSafe = vi.fn(); @@ -10,12 +10,12 @@ vi.mock("../../readFileSafe.js", () => ({ }, })); -describe("readDefaultsFromDevelopment", () => { +describe("readGuide", () => { describe("guide", () => { it("defaults to undefined when .github/DEVELOPMENT.md cannot be found", async () => { mockReadFileSafe.mockResolvedValue(""); - const guide = await readDefaultsFromDevelopment().guide(); + const guide = await readGuide(); expect(guide).toBeUndefined(); }); @@ -27,7 +27,7 @@ describe("readDefaultsFromDevelopment", () => { > It'll walk you through the common activities you'll need to contribute. `); - const guide = await readDefaultsFromDevelopment().guide(); + const guide = await readGuide(); expect(guide).toEqual({ href: "https://www.joshuakgoldberg.com/blog/contributing-to-a-create-typescript-app-repository", diff --git a/src/shared/options/createOptionDefaults/readGuide.ts b/src/shared/options/createOptionDefaults/readGuide.ts new file mode 100644 index 000000000..dbbf6ad03 --- /dev/null +++ b/src/shared/options/createOptionDefaults/readGuide.ts @@ -0,0 +1,17 @@ +import { readFileSafe } from "../../readFileSafe.js"; + +export async function readGuide() { + const development = await readFileSafe(".github/DEVELOPMENT.md", ""); + const tag = /> .*guided walkthrough, see \[((?!\[).+)\]\((.+)\)/i.exec( + development, + ); + + if (!tag) { + return undefined; + } + + return { + href: tag[2], + title: tag[1], + }; +}