Skip to content

Commit 6105fc0

Browse files
SarahSoutoulwobsorianomanovotnyclaude
authored
chore(repo): Add logic to prevent duplication of legacy hooks Typedoc (#8074)
Co-authored-by: Robert Soriano <sorianorobertc@gmail.com> Co-authored-by: Michael Novotny <manovotny@gmail.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e00ec97 commit 6105fc0

3 files changed

Lines changed: 95 additions & 12 deletions

File tree

.changeset/short-apes-joke.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

.typedoc/__tests__/file-structure.test.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,16 @@ async function scanDirectory(type: 'file' | 'directory' = 'file') {
2626
return arr;
2727
}
2828

29+
function isTopLevelPath(filePath: string) {
30+
return !filePath.includes('/');
31+
}
32+
2933
describe('Typedoc output', () => {
3034
it('should only have these top-level folders', async () => {
3135
const folders = await scanDirectory('directory');
36+
const topLevelFolders = folders.filter(isTopLevelPath);
3237

33-
expect(folders).toMatchInlineSnapshot(`
38+
expect(topLevelFolders).toMatchInlineSnapshot(`
3439
[
3540
"backend",
3641
"nextjs",
@@ -40,6 +45,17 @@ describe('Typedoc output', () => {
4045
`);
4146
});
4247

48+
it('should only have these nested folders', async () => {
49+
const folders = await scanDirectory('directory');
50+
const nestedFolders = folders.filter(folder => !isTopLevelPath(folder));
51+
52+
expect(nestedFolders).toMatchInlineSnapshot(`
53+
[
54+
"react/legacy",
55+
]
56+
`);
57+
});
58+
4359
it('should only contain lowercase files', async () => {
4460
const files = await scanDirectory('file');
4561
const upperCaseFiles = files.filter(file => /[A-Z]/.test(file));

.typedoc/extract-returns-and-params.mjs

Lines changed: 76 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,33 @@ import { fileURLToPath } from 'node:url';
66
const __filename = fileURLToPath(import.meta.url);
77
const __dirname = path.dirname(__filename);
88

9+
const LEGACY_HOOK_NAMES = new Set(['use-sign-in-1', 'use-sign-up-1']);
10+
11+
/**
12+
* Returns legacy hook output info or null if not a legacy hook.
13+
* @param {string} filePath
14+
* @returns {{ outputDir: string; baseName: string } | null}
15+
*/
16+
function getLegacyHookTarget(filePath) {
17+
const fileName = path.basename(filePath, '.mdx');
18+
if (!LEGACY_HOOK_NAMES.has(fileName)) {
19+
return null;
20+
}
21+
const dirName = path.dirname(filePath);
22+
return {
23+
outputDir: path.join(dirName, 'legacy'),
24+
baseName: fileName.replace(/-1$/, ''),
25+
};
26+
}
27+
928
/**
1029
* Extracts the "## Returns" section from a markdown file and writes it to a separate file.
1130
* @param {string} filePath - The path to the markdown file
31+
* @param {string} content - The file content
32+
* @param {{ outputDir: string; baseName: string } | null} legacyTarget
1233
* @returns {boolean} True if a file was created
1334
*/
14-
function extractReturnsSection(filePath) {
15-
const content = fs.readFileSync(filePath, 'utf-8');
16-
35+
function extractReturnsSection(filePath, content, legacyTarget) {
1736
// Find the "## Returns" section
1837
const returnsStart = content.indexOf('## Returns');
1938

@@ -34,8 +53,15 @@ function extractReturnsSection(filePath) {
3453

3554
// Generate the new filename: use-auth.mdx -> use-auth-return.mdx
3655
const fileName = path.basename(filePath, '.mdx');
37-
const dirName = path.dirname(filePath);
38-
const newFilePath = path.join(dirName, `${fileName}-return.mdx`);
56+
let outputBaseName = `${fileName}-return`;
57+
let outputDir = path.dirname(filePath);
58+
// Legacy hooks: move into legacy/ and drop the -1
59+
if (legacyTarget) {
60+
outputBaseName = `${legacyTarget.baseName}-return`;
61+
outputDir = legacyTarget.outputDir;
62+
fs.mkdirSync(outputDir, { recursive: true });
63+
}
64+
const newFilePath = path.join(outputDir, `${outputBaseName}.mdx`);
3965

4066
// Write the extracted Returns section to the new file
4167
fs.writeFileSync(newFilePath, returnsContent, 'utf-8');
@@ -61,16 +87,25 @@ function replaceGenericTypesInParamsTable(content) {
6187
/**
6288
* Extracts the "## Parameters" section from a markdown file and writes it to a separate file.
6389
* @param {string} filePath - The path to the markdown file
90+
* @param {string} content - The file content
91+
* @param {{ outputDir: string; baseName: string } | null} legacyTarget
6492
* @returns {boolean} True if a file was created
6593
*/
66-
function extractParametersSection(filePath) {
67-
const content = fs.readFileSync(filePath, 'utf-8');
94+
function extractParametersSection(filePath, content, legacyTarget) {
6895
const fileName = path.basename(filePath, '.mdx');
6996
const dirName = path.dirname(filePath);
97+
let outputDir = dirName;
98+
let outputBaseName = fileName;
99+
100+
if (legacyTarget) {
101+
outputDir = legacyTarget.outputDir;
102+
outputBaseName = legacyTarget.baseName;
103+
fs.mkdirSync(outputDir, { recursive: true });
104+
}
70105

71106
// Always use -params suffix
72107
const suffix = '-params';
73-
const targetFileName = `${fileName}${suffix}.mdx`;
108+
const targetFileName = `${outputBaseName}${suffix}.mdx`;
74109
const propsFileName = `${fileName}-props.mdx`;
75110

76111
// Delete any existing -props file (TypeDoc-generated)
@@ -100,13 +135,37 @@ function extractParametersSection(filePath) {
100135
const processedParams = replaceGenericTypesInParamsTable(paramsContent);
101136

102137
// Write to new file
103-
const newFilePath = path.join(dirName, targetFileName);
138+
const newFilePath = path.join(outputDir, targetFileName);
104139
fs.writeFileSync(newFilePath, processedParams, 'utf-8');
105140

106141
console.log(`[extract-returns] Created ${path.relative(process.cwd(), newFilePath)}`);
107142
return true;
108143
}
109144

145+
/**
146+
* Moves legacy hook docs into a legacy/ folder and removes the -1 suffix
147+
* @param {string} filePath
148+
* @param {{ outputDir: string; baseName: string } | null} legacyTarget
149+
*/
150+
function moveLegacyHookDoc(filePath, legacyTarget) {
151+
if (!legacyTarget) {
152+
return;
153+
}
154+
155+
const legacyDir = legacyTarget.outputDir;
156+
fs.mkdirSync(legacyDir, { recursive: true });
157+
const legacyPath = path.join(legacyDir, `${legacyTarget.baseName}.mdx`);
158+
159+
if (fs.existsSync(legacyPath)) {
160+
fs.unlinkSync(legacyPath);
161+
}
162+
163+
fs.renameSync(filePath, legacyPath);
164+
console.log(
165+
`[extract-returns] Moved ${path.relative(process.cwd(), filePath)} -> ${path.relative(process.cwd(), legacyPath)}`,
166+
);
167+
}
168+
110169
/**
111170
* Recursively reads all .mdx files in a directory, excluding generated files
112171
* @param {string} dir - The directory to read
@@ -160,15 +219,21 @@ function main() {
160219
let paramsCount = 0;
161220

162221
for (const filePath of mdxFiles) {
222+
const content = fs.readFileSync(filePath, 'utf-8');
223+
const legacyTarget = getLegacyHookTarget(filePath);
224+
163225
// Extract Returns sections
164-
if (extractReturnsSection(filePath)) {
226+
if (extractReturnsSection(filePath, content, legacyTarget)) {
165227
returnsCount++;
166228
}
167229

168230
// Extract Parameters sections
169-
if (extractParametersSection(filePath)) {
231+
if (extractParametersSection(filePath, content, legacyTarget)) {
170232
paramsCount++;
171233
}
234+
235+
// Move legacy hook docs after extraction
236+
moveLegacyHookDoc(filePath, legacyTarget);
172237
}
173238

174239
console.log(`[extract-returns] Extracted ${returnsCount} Returns sections`);

0 commit comments

Comments
 (0)