@next/codemod 16.3.0-canary.50 → 16.3.0-canary.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/agents-md.js +28 -12
- package/lib/__tests__/agents-md-e2e.test.js +117 -0
- package/lib/agents-md.js +32 -0
- package/package.json +1 -1
package/bin/agents-md.js
CHANGED
|
@@ -59,8 +59,17 @@ async function runAgentsMd(options) {
|
|
|
59
59
|
targetFile = promptedOptions.targetFile;
|
|
60
60
|
}
|
|
61
61
|
const claudeMdPath = path_1.default.join(cwd, targetFile);
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
// Next.js >= 16.2.0 ships its docs inside the published package. When the
|
|
63
|
+
// installed version matches the requested one, index the bundled docs
|
|
64
|
+
// directly instead of downloading a copy into .next-docs.
|
|
65
|
+
const bundledDocs = (0, agents_md_1.getBundledDocsInfo)(cwd);
|
|
66
|
+
const useBundledDocs = bundledDocs !== null && bundledDocs.version === nextjsVersion;
|
|
67
|
+
const docsPath = useBundledDocs
|
|
68
|
+
? bundledDocs.docsPath
|
|
69
|
+
: path_1.default.join(cwd, DOCS_DIR_NAME);
|
|
70
|
+
const docsLinkPath = useBundledDocs
|
|
71
|
+
? (0, agents_md_1.getBundledDocsLinkPath)(cwd, bundledDocs.docsPath)
|
|
72
|
+
: `./${DOCS_DIR_NAME}`;
|
|
64
73
|
let sizeBefore = 0;
|
|
65
74
|
let isNewFile = true;
|
|
66
75
|
let existingContent = '';
|
|
@@ -69,14 +78,19 @@ async function runAgentsMd(options) {
|
|
|
69
78
|
sizeBefore = Buffer.byteLength(existingContent, 'utf-8');
|
|
70
79
|
isNewFile = false;
|
|
71
80
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
if (useBundledDocs) {
|
|
82
|
+
console.log(`\nUsing the docs bundled with Next.js ${picocolors_1.default.cyan(nextjsVersion)} at ${picocolors_1.default.cyan(docsLinkPath)} (no download needed).`);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
console.log(`\nDownloading Next.js ${picocolors_1.default.cyan(nextjsVersion)} documentation to ${picocolors_1.default.cyan(DOCS_DIR_NAME)}...`);
|
|
86
|
+
const pullResult = await (0, agents_md_1.pullDocs)({
|
|
87
|
+
cwd,
|
|
88
|
+
version: nextjsVersion,
|
|
89
|
+
docsDir: docsPath,
|
|
90
|
+
});
|
|
91
|
+
if (!pullResult.success) {
|
|
92
|
+
throw new shared_1.BadInput(`Failed to pull docs: ${pullResult.error}`);
|
|
93
|
+
}
|
|
80
94
|
}
|
|
81
95
|
const docFiles = (0, agents_md_1.collectDocFiles)(docsPath);
|
|
82
96
|
const sections = (0, agents_md_1.buildDocTree)(docFiles);
|
|
@@ -88,13 +102,15 @@ async function runAgentsMd(options) {
|
|
|
88
102
|
const newContent = (0, agents_md_1.injectIntoClaudeMd)(existingContent, indexContent);
|
|
89
103
|
fs_1.default.writeFileSync(claudeMdPath, newContent, 'utf-8');
|
|
90
104
|
const sizeAfter = Buffer.byteLength(newContent, 'utf-8');
|
|
91
|
-
|
|
105
|
+
// .next-docs only exists on the download path; bundled docs live in
|
|
106
|
+
// node_modules, which is already ignored.
|
|
107
|
+
const gitignoreResult = useBundledDocs ? null : (0, agents_md_1.ensureGitignoreEntry)(cwd);
|
|
92
108
|
const action = isNewFile ? 'Created' : 'Updated';
|
|
93
109
|
const sizeInfo = isNewFile
|
|
94
110
|
? formatSize(sizeAfter)
|
|
95
111
|
: `${formatSize(sizeBefore)} → ${formatSize(sizeAfter)}`;
|
|
96
112
|
console.log(`${picocolors_1.default.green('✓')} ${action} ${picocolors_1.default.bold(targetFile)} (${sizeInfo})`);
|
|
97
|
-
if (gitignoreResult
|
|
113
|
+
if (gitignoreResult?.updated) {
|
|
98
114
|
console.log(`${picocolors_1.default.green('✓')} Added ${picocolors_1.default.bold(DOCS_DIR_NAME)} to .gitignore`);
|
|
99
115
|
}
|
|
100
116
|
console.log('');
|
|
@@ -293,6 +293,123 @@ This is my project documentation.
|
|
|
293
293
|
}
|
|
294
294
|
}, 30000) // Increase timeout for git clone
|
|
295
295
|
|
|
296
|
+
describe('bundled docs (Next.js >= 16.2.0)', () => {
|
|
297
|
+
// Simulate an install of a Next.js version that ships docs inside the
|
|
298
|
+
// published package at node_modules/next/dist/docs.
|
|
299
|
+
function setupBundledNext(projectDir, version) {
|
|
300
|
+
const nextDir = path.join(projectDir, 'node_modules', 'next')
|
|
301
|
+
const gettingStartedDir = path.join(
|
|
302
|
+
nextDir,
|
|
303
|
+
'dist',
|
|
304
|
+
'docs',
|
|
305
|
+
'01-app',
|
|
306
|
+
'01-getting-started'
|
|
307
|
+
)
|
|
308
|
+
fs.mkdirSync(gettingStartedDir, { recursive: true })
|
|
309
|
+
fs.writeFileSync(
|
|
310
|
+
path.join(nextDir, 'package.json'),
|
|
311
|
+
JSON.stringify({ name: 'next', version })
|
|
312
|
+
)
|
|
313
|
+
fs.writeFileSync(
|
|
314
|
+
path.join(nextDir, 'dist', 'docs', 'index.md'),
|
|
315
|
+
'# Next.js Docs'
|
|
316
|
+
)
|
|
317
|
+
fs.writeFileSync(
|
|
318
|
+
path.join(gettingStartedDir, '01-installation.md'),
|
|
319
|
+
'# Installation'
|
|
320
|
+
)
|
|
321
|
+
fs.writeFileSync(
|
|
322
|
+
path.join(gettingStartedDir, '02-project-structure.md'),
|
|
323
|
+
'# Project Structure'
|
|
324
|
+
)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
it('indexes bundled docs instead of downloading when installed Next.js ships them', async () => {
|
|
328
|
+
setupBundledNext(testProjectDir, '16.2.0')
|
|
329
|
+
|
|
330
|
+
const originalCwd = process.cwd()
|
|
331
|
+
process.chdir(testProjectDir)
|
|
332
|
+
|
|
333
|
+
try {
|
|
334
|
+
await runAgentsMd({ output: 'CLAUDE.md' })
|
|
335
|
+
|
|
336
|
+
// No .next-docs copy and no .gitignore entry for it
|
|
337
|
+
expect(fs.existsSync(path.join(testProjectDir, '.next-docs'))).toBe(
|
|
338
|
+
false
|
|
339
|
+
)
|
|
340
|
+
expect(fs.existsSync(path.join(testProjectDir, '.gitignore'))).toBe(
|
|
341
|
+
false
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
const claudeMdContent = fs.readFileSync(
|
|
345
|
+
path.join(testProjectDir, 'CLAUDE.md'),
|
|
346
|
+
'utf-8'
|
|
347
|
+
)
|
|
348
|
+
expect(claudeMdContent).toContain(
|
|
349
|
+
'root: ./node_modules/next/dist/docs'
|
|
350
|
+
)
|
|
351
|
+
expect(claudeMdContent).toContain('01-installation.md')
|
|
352
|
+
|
|
353
|
+
const output = consoleOutput.join('\n')
|
|
354
|
+
expect(output).toContain('bundled with Next.js')
|
|
355
|
+
expect(output).not.toContain('Downloading')
|
|
356
|
+
} finally {
|
|
357
|
+
process.chdir(originalCwd)
|
|
358
|
+
}
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
it('uses bundled docs when --version matches the installed version', async () => {
|
|
362
|
+
setupBundledNext(testProjectDir, '16.2.0')
|
|
363
|
+
|
|
364
|
+
const originalCwd = process.cwd()
|
|
365
|
+
process.chdir(testProjectDir)
|
|
366
|
+
|
|
367
|
+
try {
|
|
368
|
+
await runAgentsMd({ version: '16.2.0', output: 'AGENTS.md' })
|
|
369
|
+
|
|
370
|
+
expect(fs.existsSync(path.join(testProjectDir, '.next-docs'))).toBe(
|
|
371
|
+
false
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
const agentsMdContent = fs.readFileSync(
|
|
375
|
+
path.join(testProjectDir, 'AGENTS.md'),
|
|
376
|
+
'utf-8'
|
|
377
|
+
)
|
|
378
|
+
expect(agentsMdContent).toContain(
|
|
379
|
+
'root: ./node_modules/next/dist/docs'
|
|
380
|
+
)
|
|
381
|
+
} finally {
|
|
382
|
+
process.chdir(originalCwd)
|
|
383
|
+
}
|
|
384
|
+
})
|
|
385
|
+
|
|
386
|
+
it('falls back to downloading when --version differs from the installed version', async () => {
|
|
387
|
+
setupBundledNext(testProjectDir, '16.2.0')
|
|
388
|
+
|
|
389
|
+
const originalCwd = process.cwd()
|
|
390
|
+
process.chdir(testProjectDir)
|
|
391
|
+
|
|
392
|
+
try {
|
|
393
|
+
await runAgentsMd({ version: '15.0.0', output: 'CLAUDE.md' })
|
|
394
|
+
|
|
395
|
+
expect(fs.existsSync(path.join(testProjectDir, '.next-docs'))).toBe(
|
|
396
|
+
true
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
const claudeMdContent = fs.readFileSync(
|
|
400
|
+
path.join(testProjectDir, 'CLAUDE.md'),
|
|
401
|
+
'utf-8'
|
|
402
|
+
)
|
|
403
|
+
expect(claudeMdContent).toContain('root: ./.next-docs')
|
|
404
|
+
|
|
405
|
+
const output = consoleOutput.join('\n')
|
|
406
|
+
expect(output).toContain('Downloading')
|
|
407
|
+
} finally {
|
|
408
|
+
process.chdir(originalCwd)
|
|
409
|
+
}
|
|
410
|
+
}, 30000) // Increase timeout for git clone
|
|
411
|
+
})
|
|
412
|
+
|
|
296
413
|
describe('getNextjsVersion', () => {
|
|
297
414
|
const fixturesDir = path.join(__dirname, 'fixtures/agents-md')
|
|
298
415
|
|
package/lib/agents-md.js
CHANGED
|
@@ -10,6 +10,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.getNextjsVersion = getNextjsVersion;
|
|
13
|
+
exports.getBundledDocsInfo = getBundledDocsInfo;
|
|
14
|
+
exports.getBundledDocsLinkPath = getBundledDocsLinkPath;
|
|
13
15
|
exports.pullDocs = pullDocs;
|
|
14
16
|
exports.collectDocFiles = collectDocFiles;
|
|
15
17
|
exports.buildDocTree = buildDocTree;
|
|
@@ -45,6 +47,36 @@ function getNextjsVersion(cwd) {
|
|
|
45
47
|
};
|
|
46
48
|
}
|
|
47
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Next.js ships its documentation inside the published package (at
|
|
52
|
+
* `dist/docs`) since 16.2.0. When the install resolved from `cwd` has
|
|
53
|
+
* bundled docs, the index can point at them directly instead of
|
|
54
|
+
* downloading a copy into `.next-docs`.
|
|
55
|
+
*/
|
|
56
|
+
function getBundledDocsInfo(cwd) {
|
|
57
|
+
try {
|
|
58
|
+
const nextPkgPath = require.resolve('next/package.json', { paths: [cwd] });
|
|
59
|
+
const pkg = JSON.parse(fs_1.default.readFileSync(nextPkgPath, 'utf-8'));
|
|
60
|
+
const docsPath = path_1.default.join(path_1.default.dirname(nextPkgPath), 'dist', 'docs');
|
|
61
|
+
if (!pkg.version || collectDocFiles(docsPath).length === 0) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
return { docsPath, version: pkg.version };
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function getBundledDocsLinkPath(cwd, docsPath) {
|
|
71
|
+
// Prefer the conventional path when it resolves from the project
|
|
72
|
+
// (covers hoisted installs; pnpm exposes next via a node_modules symlink).
|
|
73
|
+
const conventional = path_1.default.join(cwd, 'node_modules', 'next', 'dist', 'docs');
|
|
74
|
+
if (fs_1.default.existsSync(conventional)) {
|
|
75
|
+
return './node_modules/next/dist/docs';
|
|
76
|
+
}
|
|
77
|
+
const relative = path_1.default.relative(cwd, docsPath).replace(/\\/g, '/');
|
|
78
|
+
return relative.startsWith('.') ? relative : `./${relative}`;
|
|
79
|
+
}
|
|
48
80
|
function versionToGitHubTag(version) {
|
|
49
81
|
return version.startsWith('v') ? version : `v${version}`;
|
|
50
82
|
}
|