Repository: JoshuaKGoldberg/create-typescript-app (ts)

Issue:
🐛 Bug: Don't infer --description if it's the same as create-typescript-app's
### Bug Report Checklist

- [X] I have pulled the latest `main` branch of the repository.
- [X] I have [searched for related issues](https://github.com/JoshuaKGoldberg/create-typescript-app/issues?q=is%3Aissue) and found none that matched my issue.

### Overview

Right now, `--description` defaults to the `description` in a `package.json` file:

https://github.com/JoshuaKGoldberg/create-typescript-app/blob/dd4fc2989f6a441b7e834d9733ff3c26f992b8f1/src/shared/options/createOptionDefaults/index.ts#L34

...but, in a repository newly created from the template, that description will likely be the default create-typescript-app one:

```plaintext
┌  ✨ Welcome to create-typescript-app 1.57.8! ✨
│
│  ⚠️ This template is early stage, opinionated, and not endorsed by the TypeScript team. ⚠️
│  ⚠️ If any tooling it sets displeases you, you can always remove that portion manually. ⚠️
│
◇  What organization or user will the repository be under?
│  JoshuaKGoldberg
│
◇  What will the kebab-case name of the repository be?
│  github-notifications-prune
│
◇  ✅ Passed checking GitHub authentication.
│
◆  How would you describe the new package?
│  Quickstart-friendly TypeScript template with comprehensive, configurable, opinionated tooling. 💝
└
```


If the `package.json` description is the same default description as `create-typescript-app`'s as seen in that code block, then it's not likely a good suggestion for a newly created package. Let's have the logic also check the GitHub repository's _About_ as second thing:

![Screenshot of a GitHub repository's About: 'Prunes GitHub notifications you don't care about, such as automated dependency bumps. 🧹'](https://github.com/JoshuaKGoldberg/create-typescript-app/assets/3335181/d0105a85-18fa-461e-9e9b-0dc747089014)

...and don't include a suggestion if both are the default description.

### Additional Info

_No response_

Pull request:
fix: don't infer --description if it's the source default
## PR Checklist

- [x] Addresses an existing open issue: fixes #1363
- [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

Applies both in the legacy mode and new create mode.

💖 

Patch:
diff --git a/src/next/base.ts b/src/next/base.ts
index a1d7750..b212851 100644
--- a/src/next/base.ts
+++ b/src/next/base.ts
@@ -17,6 +17,7 @@ import { readGuide } from "../shared/options/createOptionDefaults/readGuide.js";
 import { readPackageData } from "../shared/packages.js";
 import { tryCatchLazyValueAsync } from "../shared/tryCatchLazyValueAsync.js";
 import { AllContributorsData } from "../shared/types.js";
+import { readDescription } from "./readDescription.js";
 import { readDocumentation } from "./readDocumentation.js";
 import { swallowError } from "./utils/swallowError.js";
 
@@ -193,7 +194,7 @@ export const base = createBase({
 			author,
 			bin: async () => (await packageData()).bin,
 			contributors: allContributors,
-			description: async () => (await packageData()).description,
+			description: async () => await readDescription(packageData),
 			documentation,
 			email: async () => readEmails(npmDefaults, packageAuthor),
 			funding: readFunding,
diff --git a/src/next/blocks/packageData.ts b/src/next/blocks/packageData.ts
index ed6bfc2..a72bf3a 100644
--- a/src/next/blocks/packageData.ts
+++ b/src/next/blocks/packageData.ts
@@ -1,10 +1,4 @@
-import { createRequire } from "node:module";
-
-const require = createRequire(import.meta.url);
-
-const packageData =
-	// Importing from above src/ would expand the TS build rootDir
-	require("../../../package.json") as typeof import("../../../package.json");
+import { sourcePackageJson } from "./sourcePackageJson.js";
 
 export function getPackageDependencies(...names: string[]) {
 	return Object.fromEntries(
@@ -32,7 +26,7 @@ function getPackageInner(
 	key: "dependencies" | "devDependencies",
 	name: string,
 ) {
-	const inner = packageData[key];
+	const inner = sourcePackageJson[key];
 
 	return inner[name as keyof typeof inner] as string | undefined;
 }
diff --git a/src/next/blocks/sourcePackageJson.ts b/src/next/blocks/sourcePackageJson.ts
new file mode 100644
index 0000000..75867f0
--- /dev/null
+++ b/src/next/blocks/sourcePackageJson.ts
@@ -0,0 +1,7 @@
+import { createRequire } from "node:module";
+
+const require = createRequire(import.meta.url);
+
+export const sourcePackageJson =
+	// Importing from above src/ would expand the TS build rootDir
+	require("../../../package.json") as typeof import("../../../package.json");
diff --git a/src/next/readDescription.ts b/src/next/readDescription.ts
new file mode 100644
index 0000000..f5a307e
--- /dev/null
+++ b/src/next/readDescription.ts
@@ -0,0 +1,11 @@
+import { PartialPackageData } from "../shared/types.js";
+import { sourcePackageJson } from "./blocks/sourcePackageJson.js";
+
+export async function readDescription(
+	getPackageData: () => Promise<PartialPackageData>,
+) {
+	const { description: inferred } = await getPackageData();
+	const { description: existing } = sourcePackageJson;
+
+	return existing === inferred ? undefined : inferred;
+}
diff --git a/src/shared/options/createOptionDefaults/index.ts b/src/shared/options/createOptionDefaults/index.ts
index 369c0d8..48a46fd 100644
--- a/src/shared/options/createOptionDefaults/index.ts
+++ b/src/shared/options/createOptionDefaults/index.ts
@@ -5,6 +5,7 @@ import lazyValue from "lazy-value";
 import * as fs from "node:fs/promises";
 import npmUser from "npm-user";
 
+import { readDescription } from "../../../next/readDescription.js";
 import { readPackageData } from "../../packages.js";
 import { tryCatchAsync } from "../../tryCatchAsync.js";
 import { tryCatchLazyValueAsync } from "../../tryCatchLazyValueAsync.js";
@@ -33,7 +34,7 @@ export function createOptionDefaults(promptedOptions?: PromptedOptions) {
 		author: async () =>
 			(await packageAuthor()).author ?? (await npmDefaults())?.name,
 		bin: async () => (await packageData()).bin,
-		description: async () => (await packageData()).description,
+		description: async () => await readDescription(packageData),
 		email: async () => readEmails(npmDefaults, packageAuthor),
 		funding: async () =>
 			await tryCatchAsync(async () =>


Test patch:
diff --git a/script/__snapshots__/migrate-test-e2e.ts.snap b/script/__snapshots__/migrate-test-e2e.ts.snap
index 6d87dfb..156d5ff 100644
--- a/script/__snapshots__/migrate-test-e2e.ts.snap
+++ b/script/__snapshots__/migrate-test-e2e.ts.snap
@@ -115,6 +115,14 @@ exports[`expected file changes > .prettierignore 1`] = `
 exports[`expected file changes > README.md 1`] = `
 "--- a/README.md
 +++ b/README.md
+@@ ... @@
+ <h1 align="center">Create TypeScript App</h1>
+ 
+-<p align="center">Quickstart-friendly TypeScript template with comprehensive, configurable, opinionated tooling. ❤️‍🔥</p>
++<p align="center">A very lovely package. Hooray!</p>
+ 
+ <p align="center">
+ 	<!-- prettier-ignore-start -->
 @@ ... @@ Thanks! 💖
  
  <!-- ALL-CONTRIBUTORS-LIST:END -->
@@ -225,6 +233,15 @@ exports[`expected file changes > knip.json 1`] = `
 exports[`expected file changes > package.json 1`] = `
 "--- a/package.json
 +++ b/package.json
+@@ ... @@
+ {
+ 	"name": "create-typescript-app",
+ 	"version": "1.78.0",
+-	"description": "Quickstart-friendly TypeScript template with comprehensive, configurable, opinionated tooling. ❤️‍🔥",
++	"description": "A very lovely package. Hooray!",
+ 	"repository": {
+ 		"type": "git",
+ 		"url": "https://github.com/JoshuaKGoldberg/create-typescript-app"
 @@ ... @@
  		"lint-staged": "15.2.11",
  		"markdownlint": "0.37.2",
diff --git a/src/next/readDescription.test.ts b/src/next/readDescription.test.ts
new file mode 100644
index 0000000..7d98e76
--- /dev/null
+++ b/src/next/readDescription.test.ts
@@ -0,0 +1,45 @@
+import { describe, expect, it, vi } from "vitest";
+
+import { readDescription } from "./readDescription.js";
+
+const mockSourcePackageJsonDescription = vi.fn<() => string>();
+
+vi.mock("./blocks/sourcePackageJson", () => ({
+	sourcePackageJson: {
+		get description() {
+			return mockSourcePackageJsonDescription();
+		},
+	},
+}));
+
+describe("finalize", () => {
+	it("returns undefined when the description matches the current package.json description", async () => {
+		const existing = "Same description.";
+
+		mockSourcePackageJsonDescription.mockReturnValueOnce(existing);
+
+		const documentation = await readDescription(() =>
+			Promise.resolve({
+				description: existing,
+			}),
+		);
+
+		expect(documentation).toBeUndefined();
+	});
+
+	it("filters known headings when .github/DEVELOPMENT.md exists", async () => {
+		const updated = "Updated description.";
+
+		mockSourcePackageJsonDescription.mockReturnValueOnce(
+			"Existing description",
+		);
+
+		const documentation = await readDescription(() =>
+			Promise.resolve({
+				description: updated,
+			}),
+		);
+
+		expect(documentation).toBe(updated);
+	});
+});