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

Issue:
🐛 Bug: Transition mode clobbers existing README.md content after badges if there is no Usage h2
### Bug Report Checklist

- [x] I have tried restarting my IDE and the issue persists.
- [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.

### Expected

Following #2127 -> #2128, running `npx create-typescript-app` in an existing repo shouldn't remove any content between badges and `## Usage`.

### Actual

https://github.com/JoshuaKGoldberg/prune-github-notifications/pull/201/files#r2028676849 shows sections being removed. Again. Ugh.

### Additional Info

🎁 

Pull request description:
fix: correct README.md parsing without an existing Usage h2
## PR Checklist

- [x] Addresses an existing open issue: fixes #2140
- [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

https://github.com/JoshuaKGoldberg/prune-github-notifications didn't have a `## Usage` in its README.md, and instead of allowing all content until the next relevant h2 or end-of-file, the option was defaulting to `undefined`.

This reminds me that `blockREADME` hardcodes a `## Usage` in there - that's not an assumption I want to keep. But removing that assumption can be a followup.

🎁 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9bc8e39..2662916 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
 # Changelog
 
+## [2.26.6](https://github.com/JoshuaKGoldberg/create-typescript-app/compare/2.26.5...2.26.6) (2025-04-04)
+
+### Bug Fixes
+
+- correct readme templated-by parsing for multiple indicators ([#2142](https://github.com/JoshuaKGoldberg/create-typescript-app/issues/2142)) ([c71dbbf](https://github.com/JoshuaKGoldberg/create-typescript-app/commit/c71dbbf7dae15f00098aeee3785e5234db1091ad)), closes [#2141](https://github.com/JoshuaKGoldberg/create-typescript-app/issues/2141)
+
 ## [2.26.5](https://github.com/JoshuaKGoldberg/create-typescript-app/compare/2.26.4...2.26.5) (2025-04-04)
 
 ### Bug Fixes
diff --git a/package.json b/package.json
index c86d24b..95dbbb4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "create-typescript-app",
-	"version": "2.26.5",
+	"version": "2.26.6",
 	"description": "Quickstart-friendly TypeScript template with comprehensive, configurable, opinionated tooling. 🎁",
 	"repository": {
 		"type": "git",
diff --git a/src/options/readReadmeExplainer.ts b/src/options/readReadmeExplainer.ts
index aff6a33..5f36fe0 100644
--- a/src/options/readReadmeExplainer.ts
+++ b/src/options/readReadmeExplainer.ts
@@ -1,24 +1,24 @@
+const lastTagMatchers = [`">`, "/p>", "/>"];
+
 export async function readReadmeExplainer(getReadme: () => Promise<string>) {
 	const readme = await getReadme();
 
-	const indexOfUsageH2 = /## Usage/.exec(readme)?.index ?? readme.indexOf("##");
-	if (indexOfUsageH2 === -1) {
-		return undefined;
-	}
-
-	const beforeUsageH2 = readme.slice(0, indexOfUsageH2);
-
-	const [indexOfLastTag, lastTagMatcher] = lastLastIndexOf(beforeUsageH2, [
-		`">`,
-		"/p>",
-		"/>",
-	]);
+	const indexOfFirstH2 = readme.indexOf("##");
+	const indexOfUsageH2 = /## Usage/.exec(readme)?.index;
+	const beforeH2s = readme.slice(0, indexOfUsageH2 ?? indexOfFirstH2);
+	const [indexOfLastTag, lastTagMatcher] = lastLastIndexOf(
+		beforeH2s,
+		lastTagMatchers,
+	);
 	if (!lastTagMatcher) {
 		return undefined;
 	}
 
+	const endingIndex =
+		indexOfUsageH2 ?? /## (?:Contrib|Develop)/.exec(readme)?.index;
+
 	return readme
-		.slice(indexOfLastTag + lastTagMatcher.length, indexOfUsageH2)
+		.slice(indexOfLastTag + lastTagMatcher.length, endingIndex)
 		.trim();
 }
 


Test patch:
diff --git a/src/options/readReadmeExplainer.test.ts b/src/options/readReadmeExplainer.test.ts
index d545d13..0beed93 100644
--- a/src/options/readReadmeExplainer.test.ts
+++ b/src/options/readReadmeExplainer.test.ts
@@ -37,7 +37,8 @@ describe(readReadmeExplainer, () => {
 This is my project.
 
 ## Usage
-					.`),
+
+...`),
 		);
 
 		expect(actual).toEqual("This is my project.");
@@ -52,7 +53,8 @@ This is my project.
 It is good.
 
 ## Usage
-					.`),
+
+...`),
 		);
 
 		expect(actual).toEqual("This is my project.\nIt is good.");
@@ -80,7 +82,8 @@ This is my project.
 It is good.
 
 ## Usage
-					.`),
+
+...`),
 		);
 
 		expect(actual).toEqual("This is my project.\nIt is good.");
@@ -108,7 +111,8 @@ This is my project.
 It is good.
 
 ## Usage
-					.`),
+
+...`),
 		);
 
 		expect(actual).toEqual("## What?\n\nThis is my project.\nIt is good.");
@@ -129,7 +133,8 @@ It is good.
 > See here.
 
 ## Usage
-					.`),
+
+...`),
 		);
 
 		expect(actual).toEqual(
@@ -152,7 +157,8 @@ This is my project.
 It is good.
 
 ## Usage
-					.`),
+
+...`),
 		);
 
 		expect(actual).toEqual("## What?\n\nThis is my project.\nIt is good.");
@@ -175,7 +181,57 @@ It is good.
 > See here.
 
 ## Usage
-					.`),
+
+...`),
+		);
+
+		expect(actual).toEqual(
+			"## What?\n\nThis is my project.\nIt is good.\n\n> See here.",
+		);
+	});
+
+	it("returns existing content before a non-Usage h2 when the Usage h2 does not exist", async () => {
+		const actual = await readReadmeExplainer(() =>
+			Promise.resolve(`
+	<a href="http://npmjs.com/package/create-typescript-app"><img alt="📦 npm version" src="https://img.shields.io/npm/v/create-typescript-app?color=21bb42&label=%F0%9F%93%A6%20npm" /></a>
+	<img alt="💪 TypeScript: Strict" src="https://img.shields.io/badge/%F0%9F%92%AA_typescript-strict-21bb42.svg" />
+</p>
+
+<img align="right" alt="Project logo: the TypeScript blue square with rounded corners, but a plus sign instead of 'TS'" height="128" src="./docs/create-typescript-app.png" width="128">
+
+## What?
+
+This is my project.
+It is good.
+
+> See here.
+
+## Contributing
+
+...`),
+		);
+
+		expect(actual).toEqual(
+			"## What?\n\nThis is my project.\nIt is good.\n\n> See here.",
+		);
+	});
+
+	it("returns existing content until the end of the file when no subsequent h2 exists", async () => {
+		const actual = await readReadmeExplainer(() =>
+			Promise.resolve(`
+	<a href="http://npmjs.com/package/create-typescript-app"><img alt="📦 npm version" src="https://img.shields.io/npm/v/create-typescript-app?color=21bb42&label=%F0%9F%93%A6%20npm" /></a>
+	<img alt="💪 TypeScript: Strict" src="https://img.shields.io/badge/%F0%9F%92%AA_typescript-strict-21bb42.svg" />
+</p>
+
+<img align="right" alt="Project logo: the TypeScript blue square with rounded corners, but a plus sign instead of 'TS'" height="128" src="./docs/create-typescript-app.png" width="128">
+
+## What?
+
+This is my project.
+It is good.
+
+> See here.
+`),
 		);
 
 		expect(actual).toEqual(