From bb6ba9aec841f4f02089adcbd342c755e1054c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20O=E2=80=99Shannessy?= Date: Thu, 21 May 2026 06:49:39 -0700 Subject: [PATCH 1/6] chore: Migrate CodeQL config to GitHub settings (#12027) Migrate CodeQL config to GitHub settings This was reporting some issues so decided it would be better to just start using the UI-configured options. --- .github/workflows/codeql-analysis.yml | 44 --------------------------- 1 file changed, 44 deletions(-) delete mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 740bbcfbb883..000000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: CodeQL - -on: - push: - branches: - - main - - docusaurus-v** - pull_request: - branches: - - main - - docusaurus-v** - schedule: - - cron: 25 22 * * 3 - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: - - javascript - - steps: - - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Initialize CodeQL - uses: github/codeql-action/init@4e94bd11f71e507f7f87df81788dff88d1dacbfb # 4.31.0 - with: - languages: ${{ matrix.language }} - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@4e94bd11f71e507f7f87df81788dff88d1dacbfb # 4.31.0 From 0e9fe019836a9b660c62131eb826c9028227169e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20O=E2=80=99Shannessy?= Date: Thu, 21 May 2026 07:39:22 -0700 Subject: [PATCH 2/6] Use cross-spawn types instead of raw types from Node (#12029) Co-authored-by: sebastien --- packages/create-docusaurus/package.json | 1 + packages/create-docusaurus/src/utils.ts | 9 +++++---- yarn.lock | 7 +++++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/create-docusaurus/package.json b/packages/create-docusaurus/package.json index afc064496409..f271ce1bf460 100755 --- a/packages/create-docusaurus/package.json +++ b/packages/create-docusaurus/package.json @@ -31,6 +31,7 @@ "tslib": "^2.6.0" }, "devDependencies": { + "@types/cross-spawn": "^6.0.6", "@types/supports-color": "^10.0.0" }, "engines": { diff --git a/packages/create-docusaurus/src/utils.ts b/packages/create-docusaurus/src/utils.ts index a98402cf163b..33164479ff80 100644 --- a/packages/create-docusaurus/src/utils.ts +++ b/packages/create-docusaurus/src/utils.ts @@ -5,14 +5,15 @@ * LICENSE file in the root directory of this source tree. */ -// @ts-expect-error: no types, but same as spawn() -import CrossSpawn from 'cross-spawn'; -import type {spawn, SpawnOptions} from 'node:child_process'; +import crossSpawn from 'cross-spawn'; + +// This is the same as node's child_process.SpawnOptions type, but extract from +// cross-spawn directly to ensure direct compatibility. +type SpawnOptions = NonNullable[2]>; // We use cross-spawn instead of spawn because of Windows compatibility issues. // For example, "yarn" doesn't work on Windows, it requires "yarn.cmd" // Tools like execa() use cross-spawn under the hood, and "resolve" the command -const crossSpawn: typeof spawn = CrossSpawn; /** * Run a command, similar to execa(cmd,args) but simpler diff --git a/yarn.lock b/yarn.lock index 29b8e8fd2c88..8260f9cc7755 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4617,6 +4617,13 @@ dependencies: "@types/node" "*" +"@types/cross-spawn@^6.0.6": + version "6.0.6" + resolved "https://registry.yarnpkg.com/@types/cross-spawn/-/cross-spawn-6.0.6.tgz#0163d0b79a6f85409e0decb8dcca17147f81fd22" + integrity sha512-fXRhhUkG4H3TQk5dBhQ7m/JDdSNHKwR2BBia62lhwEIq9xGiQKLxd6LymNhn47SjXhsUEPmxi+PKw2OkW4LLjA== + dependencies: + "@types/node" "*" + "@types/d3-array@*": version "3.2.1" resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.2.1.tgz#1f6658e3d2006c4fceac53fde464166859f8b8c5" From b43766d86e11df751decd5c13b330e7f3c6de8bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Thu, 21 May 2026 17:31:27 +0200 Subject: [PATCH 3/6] refactor(create-docusaurus): simplify/refactor/split create-docusaurus internal logic (#12050) --- .oxfmtrc.json | 2 + packages/create-docusaurus/src/commands.ts | 115 ++++++++++++ packages/create-docusaurus/src/constants.ts | 53 ++++++ packages/create-docusaurus/src/index.ts | 195 +++++--------------- packages/create-docusaurus/src/prompts.ts | 17 ++ packages/create-docusaurus/src/types.ts | 8 - packages/create-docusaurus/src/utils.ts | 100 ++++++---- 7 files changed, 290 insertions(+), 200 deletions(-) create mode 100644 packages/create-docusaurus/src/commands.ts create mode 100644 packages/create-docusaurus/src/constants.ts delete mode 100644 packages/create-docusaurus/src/types.ts diff --git a/.oxfmtrc.json b/.oxfmtrc.json index c23c781a341c..4c663c06ad87 100644 --- a/.oxfmtrc.json +++ b/.oxfmtrc.json @@ -20,6 +20,8 @@ "packages/docusaurus-*/lib/*", "packages/create-docusaurus/lib/*", + "!packages/create-docusaurus/src/**", + "!packages/docusaurus-*/lib/theme/**", "packages/create-docusaurus/templates/*/docusaurus.config.js", diff --git a/packages/create-docusaurus/src/commands.ts b/packages/create-docusaurus/src/commands.ts new file mode 100644 index 000000000000..1e582e599f99 --- /dev/null +++ b/packages/create-docusaurus/src/commands.ts @@ -0,0 +1,115 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// We use cross-spawn instead of spawn because of Windows compatibility issues. +// For example, "yarn" doesn't work on Windows, it requires "yarn.cmd" +// Tools like execa() use cross-spawn under the hood, and "resolve" the command +import crossSpawn from 'cross-spawn'; +import supportsColor from 'supports-color'; +import { + PackageManagers, + type PackageManager, + type GitCloneStrategy, + type Source, +} from './constants.js'; +import {askForCustomGitCloneCommand} from './prompts.js'; + +// This is the same as node's child_process.SpawnOptions type, but extract from +// cross-spawn directly to ensure direct compatibility. +type SpawnOptions = NonNullable[2]>; + +/** + * Run a command, similar to execa(cmd,args) but simpler + * @param command + * @param args + * @param options + * @returns the command exit code + */ +async function runCommand( + command: string, + args: string[] = [], + options: SpawnOptions = {}, +): Promise { + // This does something similar to execa.command() + // we split a string command (with optional args) into command+args + // this way it's compatible with spawn() + const [realCommand, ...baseArgs] = command.split(' '); + const allArgs = [...baseArgs, ...args]; + if (!realCommand) { + throw new Error(`Invalid command: ${command}`); + } + + return new Promise((resolve, reject) => { + const p = crossSpawn(realCommand, allArgs, {stdio: 'ignore', ...options}); + p.on('error', reject); + p.on('close', (exitCode) => + exitCode !== null + ? resolve(exitCode) + : reject(new Error(`No exit code for command ${command}`)), + ); + }); +} + +async function hasPackageManager( + packageManager: PackageManager, +): Promise { + return (await runCommand(packageManager, ['--version'])) === 0; +} + +export async function getAvailablePackageManagers(): Promise { + const list = await Promise.all( + PackageManagers.map(async (name) => { + return (await hasPackageManager(name)) ? name : null; + }), + ); + return list.filter((item) => item !== null); +} + +export async function runPackageManagerInstallCommand( + pkgManager: PackageManager, +): Promise { + const installCommand = + pkgManager === 'yarn' + ? 'yarn' + : pkgManager === 'bun' + ? 'bun install' + : `${pkgManager} install --color always`; + + return ( + (await runCommand(installCommand, [], { + env: { + ...process.env, + // Force coloring the output + ...(supportsColor.stdout ? {FORCE_COLOR: '1'} : {}), + }, + })) === 0 + ); +} + +async function getGitCloneCommand( + gitStrategy: GitCloneStrategy, +): Promise { + switch (gitStrategy) { + case 'shallow': + case 'copy': + return 'git clone --recursive --depth 1'; + case 'custom': { + return askForCustomGitCloneCommand(); + } + case 'deep': + default: + return 'git clone'; + } +} + +export async function runGitCloneCommand( + source: Source & {type: 'git'}, + dest: string, +): Promise { + const gitCommand = await getGitCloneCommand(source.strategy); + return (await runCommand(gitCommand, [source.url, dest])) === 0; +} diff --git a/packages/create-docusaurus/src/constants.ts b/packages/create-docusaurus/src/constants.ts new file mode 100644 index 000000000000..683b77792ae3 --- /dev/null +++ b/packages/create-docusaurus/src/constants.ts @@ -0,0 +1,53 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// Only used in the rare, rare case of running globally installed create + +// using --skip-install. We need a default name to show the tip text +export const DefaultPackageManager = 'npm'; + +// Order matters +export const LockfileNames = { + npm: 'package-lock.json', + yarn: 'yarn.lock', + pnpm: 'pnpm-lock.yaml', + bun: 'bun.lockb', +}; + +export type PackageManager = keyof typeof LockfileNames; + +export const PackageManagers = Object.keys(LockfileNames) as PackageManager[]; + +export const GitCloneStrategies = [ + 'deep', + 'shallow', + 'copy', + 'custom', +] as const; + +export type GitCloneStrategy = (typeof GitCloneStrategies)[number]; + +export type Template = { + name: string; + path: string; + tsVariantPath: string | undefined; +}; + +export type Source = + | { + type: 'template'; + template: Template; + language: 'javascript' | 'typescript'; + } + | { + type: 'git'; + url: string; + strategy: GitCloneStrategy; + } + | { + type: 'local'; + path: string; + }; diff --git a/packages/create-docusaurus/src/index.ts b/packages/create-docusaurus/src/index.ts index 266f96d7220b..9f0db27f9f29 100755 --- a/packages/create-docusaurus/src/index.ts +++ b/packages/create-docusaurus/src/index.ts @@ -15,9 +15,27 @@ import path from 'node:path'; // TODO try to remove these third-party dependencies if possible import {logger} from '@docusaurus/logger'; import prompts, {type Choice} from 'prompts'; -import supportsColor from 'supports-color'; - -import {runCommand, siteNameToPackageName} from './utils.js'; +import { + LockfileNames, + PackageManagers, + DefaultPackageManager, + GitCloneStrategies, + type PackageManager, + type GitCloneStrategy, + type Source, + type Template, +} from './constants.js'; +import { + getAvailablePackageManagers, + runGitCloneCommand, + runPackageManagerInstallCommand, +} from './commands.js'; +import { + siteNameToPackageName, + updatePkg, + pathExists, + printPackageManagerHelp, +} from './utils.js'; import {askPreferredLanguage} from './prompts.js'; type LanguagesOptions = { @@ -28,7 +46,7 @@ type LanguagesOptions = { type CLIOptions = LanguagesOptions & { packageManager?: PackageManager; skipInstall?: boolean; - gitStrategy?: GitStrategy; + gitStrategy?: GitCloneStrategy; }; async function getLanguage(options: LanguagesOptions) { @@ -41,32 +59,11 @@ async function getLanguage(options: LanguagesOptions) { return askPreferredLanguage(); } -// Only used in the rare, rare case of running globally installed create + -// using --skip-install. We need a default name to show the tip text -const defaultPackageManager = 'npm'; - -const lockfileNames = { - npm: 'package-lock.json', - yarn: 'yarn.lock', - pnpm: 'pnpm-lock.yaml', - bun: 'bun.lockb', -}; - -type PackageManager = keyof typeof lockfileNames; - -const packageManagers = Object.keys(lockfileNames) as PackageManager[]; - -function pathExists(filePath: string): Promise { - return fs - .access(filePath, fs.constants.F_OK) - .then(() => true) - .catch(() => false); -} async function findPackageManagerFromLockFile( rootDir: string, ): Promise { - for (const packageManager of packageManagers) { - const lockFilePath = path.join(rootDir, lockfileNames[packageManager]); + for (const packageManager of PackageManagers) { + const lockFilePath = path.join(rootDir, LockfileNames[packageManager]); if (await pathExists(lockFilePath)) { return packageManager; } @@ -75,23 +72,22 @@ async function findPackageManagerFromLockFile( } function findPackageManagerFromUserAgent(): PackageManager | undefined { - return packageManagers.find((packageManager) => + return PackageManagers.find((packageManager) => process.env.npm_config_user_agent?.startsWith(packageManager), ); } async function askForPackageManagerChoice(): Promise { - const hasYarn = (await runCommand('yarn --version')) === 0; - const hasPnpm = (await runCommand('pnpm --version')) === 0; - const hasBun = (await runCommand('bun --version')) === 0; - - if (!hasYarn && !hasPnpm && !hasBun) { - return 'npm'; + const packageManagers = await getAvailablePackageManagers(); + if (packageManagers.length === 0) { + logger.warn`No package maintainer available? Trying with name=${DefaultPackageManager}`; + return DefaultPackageManager; + } + if (packageManagers.length === 1) { + return packageManagers[0]!; } - const choices = ['npm', hasYarn && 'yarn', hasPnpm && 'pnpm', hasBun && 'bun'] - .filter((p): p is string => Boolean(p)) - .map((p) => ({title: p, value: p})); + const choices = packageManagers.map((p) => ({title: p, value: p})); return ( ( (await prompts( @@ -103,11 +99,11 @@ async function askForPackageManagerChoice(): Promise { }, { onCancel() { - logger.info`Falling back to name=${defaultPackageManager}`; + logger.info`Falling back to name=${DefaultPackageManager}`; }, }, )) as {packageManager?: PackageManager} - ).packageManager ?? defaultPackageManager + ).packageManager ?? DefaultPackageManager ); } @@ -115,9 +111,9 @@ async function getPackageManager( dest: string, {packageManager, skipInstall}: CLIOptions, ): Promise { - if (packageManager && !packageManagers.includes(packageManager)) { + if (packageManager && !PackageManagers.includes(packageManager)) { throw new Error( - `Invalid package manager choice ${packageManager}. Must be one of ${packageManagers.join( + `Invalid package manager choice ${packageManager}. Must be one of ${PackageManagers.join( ', ', )}`, ); @@ -131,7 +127,7 @@ async function getPackageManager( (await findPackageManagerFromLockFile('.')) ?? findPackageManagerFromUserAgent() ?? // This only happens if the user has a global installation in PATH - (skipInstall ? defaultPackageManager : askForPackageManagerChoice()) + (skipInstall ? DefaultPackageManager : await askForPackageManagerChoice()) ); } @@ -139,12 +135,6 @@ const recommendedTemplate = 'classic'; const typeScriptTemplateSuffix = '-typescript'; const templatesDir = fileURLToPath(new URL('../templates', import.meta.url)); -type Template = { - name: string; - path: string; - tsVariantPath: string | undefined; -}; - async function readTemplates(): Promise { const dirContents = await fs.readdir(templatesDir); const templates = await Promise.all( @@ -253,36 +243,6 @@ function isValidGitRepoUrl(gitRepoUrl: string): boolean { return ['https://', 'git@'].some((item) => gitRepoUrl.startsWith(item)); } -const gitStrategies = ['deep', 'shallow', 'copy', 'custom'] as const; -type GitStrategy = (typeof gitStrategies)[number]; - -async function getGitCommand(gitStrategy: GitStrategy): Promise { - switch (gitStrategy) { - case 'shallow': - case 'copy': - return 'git clone --recursive --depth 1'; - case 'custom': { - const {command} = (await prompts( - { - type: 'text', - name: 'command', - message: - 'Write your own git clone command. The repository URL and destination directory will be supplied. E.g. "git clone --depth 10"', - }, - { - onCancel() { - logger.info`Falling back to code=${'git clone'}`; - }, - }, - )) as {command?: string}; - return command ?? 'git clone'; - } - case 'deep': - default: - return 'git clone'; - } -} - async function getSiteName( reqName: string | undefined, rootDir: string, @@ -325,22 +285,6 @@ async function getSiteName( return siteName; } -type Source = - | { - type: 'template'; - template: Template; - language: 'javascript' | 'typescript'; - } - | { - type: 'git'; - url: string; - strategy: GitStrategy; - } - | { - type: 'local'; - path: string; - }; - async function createTemplateSource({ template, cliOptions, @@ -390,11 +334,11 @@ async function getUserProvidedSource({ if (isValidGitRepoUrl(reqTemplate)) { if ( cliOptions.gitStrategy && - !gitStrategies.includes(cliOptions.gitStrategy) + !GitCloneStrategies.includes(cliOptions.gitStrategy) ) { logger.error`Invalid git strategy: name=${ cliOptions.gitStrategy - }. Value must be one of ${gitStrategies.join(', ')}.`; + }. Value must be one of ${GitCloneStrategies.join(', ')}.`; process.exit(1); } return { @@ -466,7 +410,7 @@ async function askGitRepositorySource({ logger.info`Falling back to name=${'deep'}`; }, }, - )) as {strategy?: GitStrategy}); + )) as {strategy?: GitCloneStrategy}); } return { type: 'git', @@ -530,16 +474,6 @@ async function getSource( }); } -async function updatePkg(pkgPath: string, obj: {[key: string]: unknown}) { - const pkg = JSON.parse(await fs.readFile(pkgPath, 'utf8')) as { - [key: string]: unknown; - }; - const newPkg = Object.assign(pkg, obj); - - await fs.mkdir(path.dirname(pkgPath), {recursive: true}); - await fs.writeFile(pkgPath, `${JSON.stringify(newPkg, null, 2)}\n`); -} - export default async function init( rootDir: string, reqName?: string, @@ -557,8 +491,7 @@ export default async function init( logger.info('Creating new Docusaurus project...'); if (source.type === 'git') { - const gitCommand = await getGitCommand(source.strategy); - if ((await runCommand(gitCommand, [source.url, dest])) !== 0) { + if (!(await runGitCloneCommand(source, dest))) { logger.error`Cloning Git template failed!`; process.exit(1); } @@ -621,23 +554,7 @@ export default async function init( logger.info`Installing dependencies with name=${pkgManager}...`; // ... - if ( - (await runCommand( - pkgManager === 'yarn' - ? 'yarn' - : pkgManager === 'bun' - ? 'bun install' - : `${pkgManager} install --color always`, - [], - { - env: { - ...process.env, - // Force coloring the output - ...(supportsColor.stdout ? {FORCE_COLOR: '1'} : {}), - }, - }, - )) !== 0 - ) { + if (!(await runPackageManagerInstallCommand(pkgManager))) { logger.error('Dependency installation failed.'); logger.info`The site directory has already been created, and you can retry by typing: @@ -647,29 +564,5 @@ export default async function init( } } - const useNpm = pkgManager === 'npm'; - const useBun = pkgManager === 'bun'; - const useRunCommand = useNpm || useBun; - logger.success`Created name=${cdpath}.`; - logger.info`Inside that directory, you can run several commands: - - code=${`${pkgManager} start`} - Starts the development server. - - code=${`${pkgManager} ${useRunCommand ? 'run ' : ''}build`} - Bundles your website into static files for production. - - code=${`${pkgManager} ${useRunCommand ? 'run ' : ''}serve`} - Serves the built website locally. - - code=${`${pkgManager} ${useRunCommand ? 'run ' : ''}deploy`} - Publishes the website to GitHub pages. - -We recommend that you begin by typing: - - code=${`cd ${cdpath}`} - code=${`${pkgManager} start`} - -Happy building awesome websites! -`; + printPackageManagerHelp({pkgManager, cdpath}); } diff --git a/packages/create-docusaurus/src/prompts.ts b/packages/create-docusaurus/src/prompts.ts index fcbf00f13d2b..fa6bbbfb6606 100644 --- a/packages/create-docusaurus/src/prompts.ts +++ b/packages/create-docusaurus/src/prompts.ts @@ -25,3 +25,20 @@ export async function askPreferredLanguage(): Promise< } return language; } + +export async function askForCustomGitCloneCommand(): Promise { + const {command} = (await prompts( + { + type: 'text', + name: 'command', + message: + 'Write your own git clone command. The repository URL and destination directory will be supplied. E.g. "git clone --depth 10"', + }, + { + onCancel() { + logger.info`Falling back to code=${'git clone'}`; + }, + }, + )) as {command?: string}; + return command ?? 'git clone'; +} diff --git a/packages/create-docusaurus/src/types.ts b/packages/create-docusaurus/src/types.ts deleted file mode 100644 index 2a7d45e07784..000000000000 --- a/packages/create-docusaurus/src/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -export type PackageManager = 'npm' | 'yarn' | 'pnpm' | 'bun'; diff --git a/packages/create-docusaurus/src/utils.ts b/packages/create-docusaurus/src/utils.ts index 33164479ff80..fcad45d854af 100644 --- a/packages/create-docusaurus/src/utils.ts +++ b/packages/create-docusaurus/src/utils.ts @@ -5,47 +5,10 @@ * LICENSE file in the root directory of this source tree. */ -import crossSpawn from 'cross-spawn'; - -// This is the same as node's child_process.SpawnOptions type, but extract from -// cross-spawn directly to ensure direct compatibility. -type SpawnOptions = NonNullable[2]>; - -// We use cross-spawn instead of spawn because of Windows compatibility issues. -// For example, "yarn" doesn't work on Windows, it requires "yarn.cmd" -// Tools like execa() use cross-spawn under the hood, and "resolve" the command - -/** - * Run a command, similar to execa(cmd,args) but simpler - * @param command - * @param args - * @param options - * @returns the command exit code - */ -export async function runCommand( - command: string, - args: string[] = [], - options: SpawnOptions = {}, -): Promise { - // This does something similar to execa.command() - // we split a string command (with optional args) into command+args - // this way it's compatible with spawn() - const [realCommand, ...baseArgs] = command.split(' '); - const allArgs = [...baseArgs, ...args]; - if (!realCommand) { - throw new Error(`Invalid command: ${command}`); - } - - return new Promise((resolve, reject) => { - const p = crossSpawn(realCommand, allArgs, {stdio: 'ignore', ...options}); - p.on('error', reject); - p.on('close', (exitCode) => - exitCode !== null - ? resolve(exitCode) - : reject(new Error(`No exit code for command ${command}`)), - ); - }); -} +import fs from 'node:fs/promises'; +import path from 'node:path'; +import {logger} from '@docusaurus/logger'; +import {type PackageManager} from './constants.js'; /** * We use a simple kebab-case-like conversion @@ -63,3 +26,58 @@ export function siteNameToPackageName(siteName: string): string { } return siteName; } + +export async function updatePkg( + pkgPath: string, + obj: {[key: string]: unknown}, +): Promise { + const pkg = JSON.parse(await fs.readFile(pkgPath, 'utf8')) as { + [key: string]: unknown; + }; + const newPkg = Object.assign(pkg, obj); + + await fs.mkdir(path.dirname(pkgPath), {recursive: true}); + await fs.writeFile(pkgPath, `${JSON.stringify(newPkg, null, 2)}\n`); +} + +// No need for fs-extra dependency +export async function pathExists(filePath: string): Promise { + return fs + .access(filePath, fs.constants.F_OK) + .then(() => true) + .catch(() => false); +} + +export function printPackageManagerHelp({ + pkgManager, + cdpath, +}: { + pkgManager: PackageManager; + cdpath: string; +}) { + const useNpm = pkgManager === 'npm'; + const useBun = pkgManager === 'bun'; + const run = useNpm || useBun ? 'run ' : ''; + logger.success`Created name=${cdpath}.`; + logger.info`Inside that directory, you can run several commands: + + code=${`${pkgManager} start`} + Starts the development server. + + code=${`${pkgManager} ${run}build`} + Bundles your website into static files for production. + + code=${`${pkgManager} ${run}serve`} + Serves the built website locally. + + code=${`${pkgManager} ${run}deploy`} + Publishes the website to GitHub pages. + +We recommend that you begin by typing: + + code=${`cd ${cdpath}`} + code=${`${pkgManager} start`} + +Happy building awesome websites! +`; +} From 2fec1c709e4d0012fe365a2cf909ab3039af72b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Thu, 21 May 2026 18:03:33 +0200 Subject: [PATCH 4/6] chore(ci): add missing workflow permissions (#12051) --- .github/workflows/argos.yml | 3 +++ .github/workflows/continuous-releases.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/argos.yml b/.github/workflows/argos.yml index ba7c052d9964..b89ec760483b 100644 --- a/.github/workflows/argos.yml +++ b/.github/workflows/argos.yml @@ -14,6 +14,9 @@ on: # We want trigger workflow on labeled too! - labeled +permissions: + contents: read + concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true diff --git a/.github/workflows/continuous-releases.yml b/.github/workflows/continuous-releases.yml index 0a919209f1d7..3076ff7ab379 100644 --- a/.github/workflows/continuous-releases.yml +++ b/.github/workflows/continuous-releases.yml @@ -7,6 +7,9 @@ on: - docusaurus-v** pull_request: +permissions: + contents: read + concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true From a86383d504ef2ee3bbe67aa0b4dd381a24434ba5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 May 2026 18:26:55 +0200 Subject: [PATCH 5/6] chore(deps): bump github-slugger, remove useless `@types/github-slugger` (#11987) * chore(deps): bump github-slugger and @types/github-slugger Bumps [github-slugger](https://github.com/Flet/github-slugger) and [@types/github-slugger](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/github-slugger). These dependencies needed to be updated together. Updates `github-slugger` from 1.5.0 to 2.0.0 - [Release notes](https://github.com/Flet/github-slugger/releases) - [Changelog](https://github.com/Flet/github-slugger/blob/master/CHANGELOG.md) - [Commits](https://github.com/Flet/github-slugger/compare/v1.5.0...2.0.0) Updates `@types/github-slugger` from 1.3.0 to 2.0.0 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/github-slugger) --- updated-dependencies: - dependency-name: "@types/github-slugger" dependency-version: 2.0.0 dependency-type: direct:development update-type: version-update:semver-major - dependency-name: github-slugger dependency-version: 2.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * remove useless types --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: sebastien --- packages/docusaurus-utils/package.json | 3 +-- yarn.lock | 32 +++++++++++--------------- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/packages/docusaurus-utils/package.json b/packages/docusaurus-utils/package.json index 459c1bde3de3..9e005e8aa277 100644 --- a/packages/docusaurus-utils/package.json +++ b/packages/docusaurus-utils/package.json @@ -25,7 +25,7 @@ "execa": "^5.1.1", "file-loader": "^6.2.0", "fs-extra": "^11.2.0", - "github-slugger": "^1.5.0", + "github-slugger": "^2.0.0", "globby": "^11.1.0", "gray-matter": "^4.0.3", "jiti": "^2.7.0", @@ -45,7 +45,6 @@ }, "devDependencies": { "@types/dedent": "^0.7.0", - "@types/github-slugger": "^1.3.0", "@types/micromatch": "^4.0.10", "@types/react-dom": "^19.2.3", "dedent": "^0.7.0", diff --git a/yarn.lock b/yarn.lock index 8260f9cc7755..1e32b7e2b408 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4959,11 +4959,6 @@ resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.16.tgz#8ebe53d69efada7044454e3305c19017d97ced2a" integrity sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg== -"@types/github-slugger@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@types/github-slugger/-/github-slugger-1.3.0.tgz#16ab393b30d8ae2a111ac748a015ac05a1fc5524" - integrity sha512-J/rMZa7RqiH/rT29TEVZO4nBoDP9XJOjnbbIofg7GQKs4JIduEO3WLpte+6WeUz/TcrXKlY+bM7FYrp8yFB+3g== - "@types/glob@~7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" @@ -6255,12 +6250,13 @@ axe-core@^4.10.0: integrity sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w== axios@1.14.0, axios@^1.0.0, axios@^1.15.2, axios@^1.5.0, axios@^1.7.7: - version "1.15.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.15.2.tgz#eb8fb6d30349abace6ade5b4cb4d9e8a0dc23e5b" - integrity sha512-wLrXxPtcrPTsNlJmKjkPnNPK2Ihe0hn0wGSaTEiHRPxwjvJwT3hKmXF4dpqxmPO9SoNb2FsYXj/xEo0gHN+D5A== + version "1.16.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.16.1.tgz#517e29291d19d6e8cf919ff264f4fe157261ba12" + integrity sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A== dependencies: - follow-redirects "^1.15.11" + follow-redirects "^1.16.0" form-data "^4.0.5" + https-proxy-agent "^5.0.1" proxy-from-env "^2.1.0" axobject-query@^4.1.0: @@ -9655,7 +9651,7 @@ flatted@^3.2.9, flatted@^3.3.1: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.4.2.tgz#f5c23c107f0f37de8dbdf24f13722b3b98d52726" integrity sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA== -follow-redirects@^1.0.0, follow-redirects@^1.15.11: +follow-redirects@^1.0.0, follow-redirects@^1.16.0: version "1.16.0" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.16.0.tgz#28474a159d3b9d11ef62050a14ed60e4df6d61bc" integrity sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw== @@ -9959,10 +9955,10 @@ github-from-package@0.0.0: resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== -github-slugger@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-1.5.0.tgz#17891bbc73232051474d68bd867a34625c955f7d" - integrity sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw== +github-slugger@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-2.0.0.tgz#52cf2f9279a21eb6c59dd385b410f0c0adda8f1a" + integrity sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw== glob-parent@5.1.2, glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" @@ -10702,7 +10698,7 @@ http2-wrapper@^2.1.10: quick-lru "^5.1.1" resolve-alpn "^1.2.0" -https-proxy-agent@^5.0.0: +https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== @@ -15537,9 +15533,9 @@ react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0: integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== react-is@^17.0.1, react-is@^18.0.0, react-is@^19.2.0: - version "19.2.5" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.2.5.tgz#7e7b54143e9313fed787b23fd4295d5a23872ad9" - integrity sha512-Dn0t8IQhCmeIT3wu+Apm1/YVsJXsGWi6k4sPdnBIdqMVtHtv0IGi6dcpNpNkNac0zB2uUAqNX3MHzN8c+z2rwQ== + version "19.2.6" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.2.6.tgz#aeee6159b159eb7f520d672cffcc69e7052d288f" + integrity sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw== react-json-view-lite@^2.3.0: version "2.5.0" From 282a098673793f517122130ae2b8c50b4b0d91bc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 May 2026 18:43:13 +0200 Subject: [PATCH 6/6] chore(deps): bump ws from 7.5.10 to 8.20.1 (#12041) Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 1e32b7e2b408..934a4bf9cb2e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19312,9 +19312,9 @@ ws@^7.3.1: integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== ws@^8.18.0, ws@^8.19.0: - version "8.20.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.20.0.tgz#4cd9532358eba60bc863aad1623dfb045a4d4af8" - integrity sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA== + version "8.20.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.20.1.tgz#91a9ae2b312ccf98e0a85ec499b48cef45ab0ddb" + integrity sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w== ws@~8.17.1: version "8.17.1"