From d478043ef5e39d2fbd0170386b005457149f5007 Mon Sep 17 00:00:00 2001 From: Ben Maurer Date: Fri, 29 May 2026 06:58:19 -0700 Subject: [PATCH 1/6] fix(dev-server): for HTTPS, support non-RSA TLS certs (#12065) Co-authored-by: sebastien --- packages/docusaurus/src/commands/cli.ts | 15 + .../docusaurus/src/commands/start/start.ts | 7 + .../docusaurus/src/commands/start/webpack.ts | 10 +- .../__fixtures__/getHttpsConfig/host-ec.crt | 11 + .../__fixtures__/getHttpsConfig/host-ec.key | 5 + .../__fixtures__/getHttpsConfig/other-ec.key | 5 + .../utils/__tests__/getHttpsConfig.test.ts | 313 ++++++++++++++++-- .../src/webpack/utils/getHttpsConfig.ts | 209 +++++++++--- 8 files changed, 498 insertions(+), 77 deletions(-) create mode 100644 packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/host-ec.crt create mode 100644 packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/host-ec.key create mode 100644 packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/other-ec.key diff --git a/packages/docusaurus/src/commands/cli.ts b/packages/docusaurus/src/commands/cli.ts index 3b9f765bd11e..2a1b1f897396 100755 --- a/packages/docusaurus/src/commands/cli.ts +++ b/packages/docusaurus/src/commands/cli.ts @@ -203,6 +203,21 @@ export async function createCLIProgram({ '--no-minify', 'build website without minimizing JS bundles (default: false)', ) + /* + TODO + .option( + '--https', + 'serve the dev site over HTTPS using a self-signed cert (default: false). Preferred over the HTTPS=true env var. Implied when both --ssl-cert and --ssl-key are provided.', + ) + .option( + '--ssl-cert ', + 'path to a TLS certificate file (implies HTTPS). Preferred over the SSL_CRT_FILE env var; CLI takes precedence if both are set.', + ) + .option( + '--ssl-key ', + 'path to a TLS private key file (implies HTTPS). Preferred over the SSL_KEY_FILE env var; CLI takes precedence if both are set.', + ) + */ .action(start); cli diff --git a/packages/docusaurus/src/commands/start/start.ts b/packages/docusaurus/src/commands/start/start.ts index 6cf7824b2ab6..10d7412abeac 100644 --- a/packages/docusaurus/src/commands/start/start.ts +++ b/packages/docusaurus/src/commands/start/start.ts @@ -19,6 +19,13 @@ export type StartCLIOptions = HostPortOptions & open?: boolean; poll?: boolean | number; minify?: boolean; + + /* + TODO Docusaurus v4: wire new CLI parameters + https?: true; + sslCert?: string; + sslKey?: string; + */ }; async function doStart( diff --git a/packages/docusaurus/src/commands/start/webpack.ts b/packages/docusaurus/src/commands/start/webpack.ts index 1dfd8f90250d..7082c75c168d 100644 --- a/packages/docusaurus/src/commands/start/webpack.ts +++ b/packages/docusaurus/src/commands/start/webpack.ts @@ -60,7 +60,15 @@ async function createDevServerConfig({ const pollingOptions = createPollingOptions(cliOptions); - const httpsConfig = await getHttpsConfig(); + const httpsConfig = await getHttpsConfig({ + /* + TODO Docusaurus v4: wire new CLI parameters + https: cliOptions.https, + sslCert: cliOptions.sslCert, + sslKey: cliOptions.sslKey, + + */ + }); // https://webpack.js.org/configuration/dev-server return { diff --git a/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/host-ec.crt b/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/host-ec.crt new file mode 100644 index 000000000000..f2c85f891f85 --- /dev/null +++ b/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/host-ec.crt @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBfzCCASWgAwIBAgIUVCZHpPiH1oRsTS2/guIgZLMs7iYwCgYIKoZIzj0EAwIw +FDESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTI2MDUyMzE5NDIwMloYDzIxMjYwNDI5 +MTk0MjAyWjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggqhkjO +PQMBBwNCAAS51eBSUOBuxt152Dz1HP+lqZhshKwdakVGu75fkQ7tTOHtM0bIwLEi +aTxyk3pELJP+CJCHiDQpoY99VE0SlNAZo1MwUTAdBgNVHQ4EFgQUenetYbu4Ic/0 +hH0xPr2SLpPMa+QwHwYDVR0jBBgwFoAUenetYbu4Ic/0hH0xPr2SLpPMa+QwDwYD +VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiBpZ/J5R7HDdHUrhudY0ELd ++FvKoc9NVLA3YWB5Nu9aCQIhAKcFeDg7QImUJGbdMq+b+B2VgDyJKZEr6v2yT5pN +LPbp +-----END CERTIFICATE----- diff --git a/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/host-ec.key b/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/host-ec.key new file mode 100644 index 000000000000..c03b7cd93840 --- /dev/null +++ b/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/host-ec.key @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIDugIoSHhghcP/iQaY1TICcZvfqOMOi+KCLl9ykkVb7moAoGCCqGSM49 +AwEHoUQDQgAEudXgUlDgbsbdedg89Rz/pamYbISsHWpFRru+X5EO7Uzh7TNGyMCx +Imk8cpN6RCyT/giQh4g0KaGPfVRNEpTQGQ== +-----END EC PRIVATE KEY----- diff --git a/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/other-ec.key b/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/other-ec.key new file mode 100644 index 000000000000..658a90071850 --- /dev/null +++ b/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/other-ec.key @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIKS1ePqiAg+m41OQ23weowY3XF6n5hd1DFY1pB0Rk9AroAoGCCqGSM49 +AwEHoUQDQgAEyVwSps8j6DfDs23Qc1MVAEz6DSXLub21L/wG8Vn+hbZrgtBLHktA +e3pVXbZu7Fo+cEUcWqtH++ndWfDuT4Hwzw== +-----END EC PRIVATE KEY----- diff --git a/packages/docusaurus/src/webpack/utils/__tests__/getHttpsConfig.test.ts b/packages/docusaurus/src/webpack/utils/__tests__/getHttpsConfig.test.ts index 8e7d4ab9eaff..259ed937cbb0 100644 --- a/packages/docusaurus/src/webpack/utils/__tests__/getHttpsConfig.test.ts +++ b/packages/docusaurus/src/webpack/utils/__tests__/getHttpsConfig.test.ts @@ -18,46 +18,299 @@ describe('getHttpsConfig', () => { vi.unstubAllEnvs(); }); - it('returns true for HTTPS not env', async () => { + const configMatcher = { + key: expect.any(Buffer), + cert: expect.any(Buffer), + }; + + it('returns false - empty config/env', async () => { await expect(getHttpsConfig()).resolves.toBe(false); }); - it('returns true for HTTPS in env', async () => { - vi.stubEnv('HTTPS', 'true'); - await expect(getHttpsConfig()).resolves.toBe(true); - }); + describe('env', () => { + it('returns false - !https', async () => { + vi.stubEnv('HTTPS', 'false'); + await expect(getHttpsConfig()).resolves.toBe(false); + }); + + it('returns true - https, !cert, !key', async () => { + vi.stubEnv('HTTPS', 'true'); + await expect(getHttpsConfig()).resolves.toBe(true); + }); - it('returns custom certs if they are in env', async () => { - vi.stubEnv('HTTPS', 'true'); - vi.stubEnv('SSL_CRT_FILE', getFixture('host.crt')); - vi.stubEnv('SSL_KEY_FILE', getFixture('host.key')); + it('returns config - !https, cert, key', async () => { + vi.stubEnv('HTTPS', 'false'); + vi.stubEnv('SSL_CRT_FILE', getFixture('host.crt')); + vi.stubEnv('SSL_KEY_FILE', getFixture('host.key')); + await expect(getHttpsConfig()).resolves.toEqual(false); + }); - await expect(getHttpsConfig()).resolves.toEqual({ - key: expect.any(Buffer), - cert: expect.any(Buffer), + it('returns config - -https, cert, key', async () => { + vi.stubEnv('SSL_CRT_FILE', getFixture('host.crt')); + vi.stubEnv('SSL_KEY_FILE', getFixture('host.key')); + await expect(getHttpsConfig()).resolves.toEqual(configMatcher); + }); + + it('returns config - https, cert, key', async () => { + vi.stubEnv('HTTPS', 'true'); + vi.stubEnv('SSL_CRT_FILE', getFixture('host.crt')); + vi.stubEnv('SSL_KEY_FILE', getFixture('host.key')); + await expect(getHttpsConfig()).resolves.toEqual(configMatcher); + }); + + it('returns config - https, ECDSA cert, ECDSA key', async () => { + vi.stubEnv('HTTPS', 'true'); + vi.stubEnv('SSL_CRT_FILE', getFixture('host-ec.crt')); + vi.stubEnv('SSL_KEY_FILE', getFixture('host-ec.key')); + await expect(getHttpsConfig()).resolves.toEqual(configMatcher); + }); + + it('throws for non-existent cert', async () => { + vi.stubEnv('HTTPS', 'true'); + vi.stubEnv('SSL_CRT_FILE', getFixture('nonexistent.crt')); + vi.stubEnv('SSL_KEY_FILE', getFixture('host.key')); + await expect(getHttpsConfig()).rejects.toThrowErrorMatchingInlineSnapshot( + `[Error: You specified env SSL_CRT_FILE, but file at path "/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/nonexistent.crt" can't be found.]`, + ); + }); + + it('throws for invalid cert', async () => { + vi.stubEnv('HTTPS', 'true'); + vi.stubEnv('SSL_CRT_FILE', getFixture('invalid.crt')); + vi.stubEnv('SSL_KEY_FILE', getFixture('host.key')); + await expect(getHttpsConfig()).rejects + .toThrowErrorMatchingInlineSnapshot(` + [Error: The certificate "/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/invalid.crt" is invalid.] + Cause: [Error: error:0480006C:PEM routines::no start line] + `); }); - }); - it("throws if file doesn't exist", async () => { - vi.stubEnv('HTTPS', 'true'); - vi.stubEnv('SSL_CRT_FILE', getFixture('nonexistent.crt')); - vi.stubEnv('SSL_KEY_FILE', getFixture('host.key')); - await expect(getHttpsConfig()).rejects.toThrowErrorMatchingInlineSnapshot( - `[Error: You specified SSL_CRT_FILE in your env, but the file "/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/nonexistent.crt" can't be found.]`, - ); + it('throws for non-existent key', async () => { + vi.stubEnv('HTTPS', 'true'); + vi.stubEnv('SSL_CRT_FILE', getFixture('host.crt')); + vi.stubEnv('SSL_KEY_FILE', getFixture('nonexistent.key')); + await expect(getHttpsConfig()).rejects.toThrowErrorMatchingInlineSnapshot( + `[Error: You specified env SSL_KEY_FILE, but file at path "/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/nonexistent.key" can't be found.]`, + ); + }); + + it('throws for invalid key', async () => { + vi.stubEnv('HTTPS', 'true'); + vi.stubEnv('SSL_CRT_FILE', getFixture('host.crt')); + vi.stubEnv('SSL_KEY_FILE', getFixture('invalid.key')); + await expect(getHttpsConfig()).rejects.toThrowErrorMatchingInlineSnapshot( + ` + [Error: The certificate key "/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/invalid.key" is invalid.] + Cause: [Error: error:1E08010C:DECODER routines::unsupported] + `, + ); + }); + + it('throws for cert without key', async () => { + vi.stubEnv('HTTPS', 'true'); + vi.stubEnv('SSL_CRT_FILE', getFixture('host.crt')); + await expect(getHttpsConfig()).rejects + .toThrowErrorMatchingInlineSnapshot(` + [Error: HTTPS support require proving a certificate and key at the same time. + You only provided a certificate (with env SSL_CRT_FILE) at path "/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/host.crt".] + `); + }); + + it('throws for key without cert', async () => { + vi.stubEnv('HTTPS', 'true'); + vi.stubEnv('SSL_KEY_FILE', getFixture('host.key')); + await expect(getHttpsConfig()).rejects + .toThrowErrorMatchingInlineSnapshot(` + [Error: HTTPS support require proving a certificate and key at the same time. + You only provided a key (with env SSL_KEY_FILE) at path "/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/host.key".] + `); + }); + + it('throws when cert and key do not match', async () => { + vi.stubEnv('HTTPS', 'true'); + vi.stubEnv('SSL_CRT_FILE', getFixture('host-ec.crt')); + vi.stubEnv('SSL_KEY_FILE', getFixture('other-ec.key')); + await expect(getHttpsConfig()).rejects.toMatchInlineSnapshot( + `[Error: The certificate "/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/host-ec.crt" and key "/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/other-ec.key" do not match.]`, + ); + }); }); - it('throws for invalid key', async () => { - vi.stubEnv('HTTPS', 'true'); - vi.stubEnv('SSL_CRT_FILE', getFixture('host.crt')); - vi.stubEnv('SSL_KEY_FILE', getFixture('invalid.key')); - await expect(getHttpsConfig()).rejects.toThrow(); + describe('options', () => { + it('returns false - !https', async () => { + await expect(getHttpsConfig({https: false})).resolves.toBe(false); + }); + + it('returns true - https, !cert, !key', async () => { + await expect(getHttpsConfig({https: true})).resolves.toBe(true); + }); + + it('returns config - !https, cert, key', async () => { + await expect( + getHttpsConfig({ + https: false, + sslCert: getFixture('host.crt'), + sslKey: getFixture('host.key'), + }), + ).resolves.toEqual(false); + }); + + it('returns config - -https, cert, key', async () => { + await expect( + getHttpsConfig({ + sslCert: getFixture('host.crt'), + sslKey: getFixture('host.key'), + }), + ).resolves.toEqual(configMatcher); + }); + + it('returns config - https, cert, key', async () => { + await expect( + getHttpsConfig({ + https: true, + sslCert: getFixture('host.crt'), + sslKey: getFixture('host.key'), + }), + ).resolves.toEqual(configMatcher); + }); + + it('returns config - https, ECDSA cert, ECDSA key', async () => { + await expect( + getHttpsConfig({ + https: true, + sslCert: getFixture('host-ec.crt'), + sslKey: getFixture('host-ec.key'), + }), + ).resolves.toEqual(configMatcher); + }); + + it('throws for non-existent cert', async () => { + await expect( + getHttpsConfig({ + https: true, + sslCert: getFixture('nonexistent.crt'), + sslKey: getFixture('host.key'), + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `[Error: You specified CLI arg --ssl-cert, but file at path "/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/nonexistent.crt" can't be found.]`, + ); + }); + + it('throws for invalid cert', async () => { + await expect( + getHttpsConfig({ + https: true, + sslCert: getFixture('invalid.crt'), + sslKey: getFixture('host.key'), + }), + ).rejects.toThrowErrorMatchingInlineSnapshot(` + [Error: The certificate "/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/invalid.crt" is invalid.] + Cause: [Error: error:0480006C:PEM routines::no start line] + `); + }); + + it('throws for non-existent key', async () => { + await expect( + getHttpsConfig({ + https: true, + sslCert: getFixture('host.crt'), + sslKey: getFixture('nonexistent.key'), + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `[Error: You specified CLI arg --ssl-key, but file at path "/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/nonexistent.key" can't be found.]`, + ); + }); + + it('throws for invalid key', async () => { + await expect( + getHttpsConfig({ + https: true, + sslCert: getFixture('host.crt'), + sslKey: getFixture('invalid.key'), + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + ` + [Error: The certificate key "/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/invalid.key" is invalid.] + Cause: [Error: error:1E08010C:DECODER routines::unsupported] + `, + ); + }); + + it('throws for cert without key', async () => { + await expect( + getHttpsConfig({ + https: true, + sslCert: getFixture('host.crt'), + }), + ).rejects.toThrowErrorMatchingInlineSnapshot(` + [Error: HTTPS support require proving a certificate and key at the same time. + You only provided a certificate (with CLI arg --ssl-cert) at path "/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/host.crt".] + `); + }); + + it('throws for key without cert', async () => { + await expect( + getHttpsConfig({ + https: true, + sslKey: getFixture('host.key'), + }), + ).rejects.toThrowErrorMatchingInlineSnapshot(` + [Error: HTTPS support require proving a certificate and key at the same time. + You only provided a key (with CLI arg --ssl-key) at path "/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/host.key".] + `); + }); + + it('throws when cert and key do not match', async () => { + await expect( + getHttpsConfig({ + https: true, + sslCert: getFixture('host-ec.crt'), + sslKey: getFixture('other-ec.key'), + }), + ).rejects.toMatchInlineSnapshot( + `[Error: The certificate "/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/host-ec.crt" and key "/packages/docusaurus/src/webpack/utils/__tests__/__fixtures__/getHttpsConfig/other-ec.key" do not match.]`, + ); + }); }); - it('throws for invalid cert', async () => { - vi.stubEnv('HTTPS', 'true'); - vi.stubEnv('SSL_CRT_FILE', getFixture('invalid.crt')); - vi.stubEnv('SSL_KEY_FILE', getFixture('host.key')); - await expect(getHttpsConfig()).rejects.toThrow(); + describe('mixed', () => { + it('cLI options take precedence over env vars', async () => { + vi.stubEnv('HTTPS', 'false'); + vi.stubEnv('SSL_CRT_FILE', getFixture('nonexistent.crt')); + vi.stubEnv('SSL_KEY_FILE', getFixture('invalid.key')); + // CLI override should succeed despite the broken env-var key pair. + await expect( + getHttpsConfig({ + https: true, + sslCert: getFixture('host-ec.crt'), + sslKey: getFixture('host-ec.key'), + }), + ).resolves.toEqual(configMatcher); + }); + + it('dOCUSAURUS_ prefixed env variables take precedence over unprefixed env vars', async () => { + vi.stubEnv('HTTPS', 'false'); + vi.stubEnv('DOCUSAURUS_HTTPS', 'true'); + + vi.stubEnv('SSL_CRT_FILE', getFixture('nonexistent.crt')); + vi.stubEnv('DOCUSAURUS_SSL_CRT_FILE', getFixture('host-ec.crt')); + + vi.stubEnv('SSL_KEY_FILE', getFixture('invalid.key')); + vi.stubEnv('DOCUSAURUS_SSL_KEY_FILE', getFixture('host-ec.key')); + // CLI override should succeed despite the broken env-var key pair. + await expect(getHttpsConfig()).resolves.toEqual(configMatcher); + }); + + it('supports mixing prefixed/unprefixed env vars and CLI options', async () => { + vi.stubEnv('HTTPS', 'true'); + + vi.stubEnv('DOCUSAURUS_SSL_CRT_FILE', getFixture('host-ec.crt')); + // CLI override should succeed despite the broken env-var key pair. + await expect( + getHttpsConfig({ + sslKey: getFixture('host-ec.key'), + }), + ).resolves.toEqual(configMatcher); + }); }); }); diff --git a/packages/docusaurus/src/webpack/utils/getHttpsConfig.ts b/packages/docusaurus/src/webpack/utils/getHttpsConfig.ts index 083614ceb889..5edfe281472c 100644 --- a/packages/docusaurus/src/webpack/utils/getHttpsConfig.ts +++ b/packages/docusaurus/src/webpack/utils/getHttpsConfig.ts @@ -11,65 +11,182 @@ import crypto from 'crypto'; import logger from '@docusaurus/logger'; // Ensure the certificate and key provided are valid and if not -// throw an easy to debug error -function validateKeyAndCerts({ - cert, - key, - keyFile, - crtFile, -}: { - cert: Buffer; - key: Buffer; - keyFile: string; - crtFile: string; -}) { - let encrypted: Buffer; +// throw an easy to debug error. +// +// Works for any key type (RSA, ECDSA, EdDSA, ...) — parses both PEMs and +// checks that the public key embedded in the cert matches the public key +// derived from the private key. +function validateKeyAndCerts({cert, key}: {cert: CryptoFile; key: CryptoFile}) { + let certPublicKey: crypto.KeyObject; try { - // publicEncrypt will throw an error with an invalid cert - encrypted = crypto.publicEncrypt(cert, Buffer.from('test')); - } catch (err) { - logger.error`The certificate path=${crtFile} is invalid.`; - throw err; + certPublicKey = new crypto.X509Certificate(cert.content).publicKey; + } catch (error) { + throw new Error( + logger.interpolate`The certificate path=${cert.path} is invalid.`, + {cause: error}, + ); + } + + let keyPublicKey: crypto.KeyObject; + try { + keyPublicKey = crypto.createPublicKey(crypto.createPrivateKey(key.content)); + } catch (error) { + throw new Error( + logger.interpolate`The certificate key path=${key.path} is invalid.`, + {cause: error}, + ); + } + + if (!certPublicKey.equals(keyPublicKey)) { + throw new Error( + logger.interpolate`The certificate path=${cert.path} and key path=${key.path} do not match.`, + ); } +} + +type HttpsConfigOptions = { + https: boolean; + sslCert: string; + sslKey: string; +}; + +function getExplicitHttps( + options: Partial, +): boolean | undefined { + return ( + options.https ?? + (typeof process.env.DOCUSAURUS_HTTPS !== 'undefined' + ? process.env.DOCUSAURUS_HTTPS == 'true' + : undefined) ?? + (typeof process.env.HTTPS !== 'undefined' + ? process.env.HTTPS == 'true' + : undefined) + ); +} + +type CryptoFile = { + path: string; + content: Buffer; + source: string; +}; +async function readCryptoFile( + filepath: string, + source: string, +): Promise { + if (!(await fs.pathExists(filepath))) { + throw new Error( + logger.interpolate`You specified ${source}, but file at path path=${filepath} can't be found.`, + ); + } try { - // privateDecrypt will throw an error with an invalid key - crypto.privateDecrypt(key, encrypted); - } catch (err) { - logger.error`The certificate key path=${keyFile} is invalid.`; - throw err; + return { + path: filepath, + source, + content: await fs.readFile(filepath), + }; + } catch (error) { + throw new Error( + logger.interpolate`You specified ${source}, but file at path path=${filepath} can't be read.`, + {cause: error}, + ); } } -// Read file and throw an error if it doesn't exist -async function readEnvFile(file: string, type: string) { - if (!(await fs.pathExists(file))) { +function getCert( + options: Partial, + cwd: string, +): Promise | null { + if (options.sslCert) { + return readCryptoFile( + path.resolve(cwd, options.sslCert), + 'CLI arg --ssl-cert', + ); + } + if (process.env.DOCUSAURUS_SSL_CRT_FILE) { + return readCryptoFile( + path.resolve(cwd, process.env.DOCUSAURUS_SSL_CRT_FILE), + 'env DOCUSAURUS_SSL_CRT_FILE', + ); + } + if (process.env.SSL_CRT_FILE) { + return readCryptoFile( + path.resolve(cwd, process.env.SSL_CRT_FILE), + 'env SSL_CRT_FILE', + ); + } + return null; +} + +function getKeyFile( + options: Partial, + cwd: string, +): Promise | null { + if (options.sslKey) { + return readCryptoFile( + path.resolve(cwd, options.sslKey), + 'CLI arg --ssl-key', + ); + } + if (process.env.DOCUSAURUS_SSL_KEY_FILE) { + return readCryptoFile( + path.resolve(cwd, process.env.DOCUSAURUS_SSL_KEY_FILE), + 'env DOCUSAURUS_SSL_KEY_FILE', + ); + } + if (process.env.SSL_KEY_FILE) { + return readCryptoFile( + path.resolve(cwd, process.env.SSL_KEY_FILE), + 'env SSL_KEY_FILE', + ); + } + return null; +} + +function ensureCertKeyBothProvided( + cert: CryptoFile | null, + key: CryptoFile | null, +) { + if ((cert || key) && !(cert && key)) { + const fileProvided = (cert ?? key)!; throw new Error( - `You specified ${type} in your env, but the file "${file}" can't be found.`, + logger.interpolate`HTTPS support require proving a certificate and key at the same time. +You only provided a ${cert ? 'certificate' : 'key'} (with ${fileProvided.source}) at path path=${fileProvided.path}.`, ); } - return fs.readFile(file); } // Get the https config -// Return cert files if provided in env, otherwise just true or false -export default async function getHttpsConfig(): Promise< - boolean | {cert: Buffer; key: Buffer} -> { - const appDirectory = await fs.realpath(process.cwd()); - const {SSL_CRT_FILE, SSL_KEY_FILE, HTTPS} = process.env; - const isHttps = HTTPS === 'true'; - - if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) { - const crtFile = path.resolve(appDirectory, SSL_CRT_FILE); - const keyFile = path.resolve(appDirectory, SSL_KEY_FILE); - const config = { - cert: await readEnvFile(crtFile, 'SSL_CRT_FILE'), - key: await readEnvFile(keyFile, 'SSL_KEY_FILE'), - }; +// Return cert files if provided via CLI or env, otherwise just true or false. +// CLI options take precedence over env vars. +export default async function getHttpsConfig( + options: Partial = {}, +): Promise { + const cwd = await fs.realpath(process.cwd()); - validateKeyAndCerts({...config, keyFile, crtFile}); - return config; + const [cert, key] = await Promise.all([ + getCert(options, cwd), + getKeyFile(options, cwd), + ]); + + // Providing both cert/key implies HTTPS + const inferredHttps = !!(cert && key); + const https = getExplicitHttps(options) ?? inferredHttps; + + if (https && cert && key) { + validateKeyAndCerts({ + cert, + key, + }); + return { + cert: cert.content, + key: key.content, + }; } - return isHttps; + + ensureCertKeyBothProvided(cert, key); + + // Apparently we can have https without cert/key (historical) + // although I don't know how this works 🤷‍♂️ + return https; } From a846a0fd7385e58d5bc36ac47457ec46702a00cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Fri, 29 May 2026 16:34:13 +0200 Subject: [PATCH 2/6] feat(dev-server): add dev-server CLI options for HTTPS support (#12082) --- packages/docusaurus/src/commands/cli.ts | 3 --- .../docusaurus/src/commands/start/start.ts | 4 ---- .../docusaurus/src/commands/start/webpack.ts | 4 ---- website/docs/cli.mdx | 19 ++++++++++++++++--- yarn.lock | 2 +- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/packages/docusaurus/src/commands/cli.ts b/packages/docusaurus/src/commands/cli.ts index 2a1b1f897396..cbce9944cfa1 100755 --- a/packages/docusaurus/src/commands/cli.ts +++ b/packages/docusaurus/src/commands/cli.ts @@ -203,8 +203,6 @@ export async function createCLIProgram({ '--no-minify', 'build website without minimizing JS bundles (default: false)', ) - /* - TODO .option( '--https', 'serve the dev site over HTTPS using a self-signed cert (default: false). Preferred over the HTTPS=true env var. Implied when both --ssl-cert and --ssl-key are provided.', @@ -217,7 +215,6 @@ export async function createCLIProgram({ '--ssl-key ', 'path to a TLS private key file (implies HTTPS). Preferred over the SSL_KEY_FILE env var; CLI takes precedence if both are set.', ) - */ .action(start); cli diff --git a/packages/docusaurus/src/commands/start/start.ts b/packages/docusaurus/src/commands/start/start.ts index 10d7412abeac..e98579d63283 100644 --- a/packages/docusaurus/src/commands/start/start.ts +++ b/packages/docusaurus/src/commands/start/start.ts @@ -19,13 +19,9 @@ export type StartCLIOptions = HostPortOptions & open?: boolean; poll?: boolean | number; minify?: boolean; - - /* - TODO Docusaurus v4: wire new CLI parameters https?: true; sslCert?: string; sslKey?: string; - */ }; async function doStart( diff --git a/packages/docusaurus/src/commands/start/webpack.ts b/packages/docusaurus/src/commands/start/webpack.ts index 7082c75c168d..fd349abaf9c8 100644 --- a/packages/docusaurus/src/commands/start/webpack.ts +++ b/packages/docusaurus/src/commands/start/webpack.ts @@ -61,13 +61,9 @@ async function createDevServerConfig({ const pollingOptions = createPollingOptions(cliOptions); const httpsConfig = await getHttpsConfig({ - /* - TODO Docusaurus v4: wire new CLI parameters https: cliOptions.https, sslCert: cliOptions.sslCert, sslKey: cliOptions.sslKey, - - */ }); // https://webpack.js.org/configuration/dev-server diff --git a/website/docs/cli.mdx b/website/docs/cli.mdx index 1541e41f983d..b294153e18b5 100644 --- a/website/docs/cli.mdx +++ b/website/docs/cli.mdx @@ -45,6 +45,9 @@ Builds and serves a preview of your site locally with [Webpack Dev Server](https | `--config` | `undefined` | Path to Docusaurus config file, default to `[siteDir]/docusaurus.config.js` | | `--poll [optionalIntervalMs]` | `false` | Use polling of files rather than watching for live reload as a fallback in environments where watching doesn't work. More information [here](https://webpack.js.org/configuration/watch/#watchoptionspoll). | | `--no-minify` | `false` | Build website without minimizing JS/CSS bundles. | +| `--https` | `false` | Serve the dev site over HTTPS using a self-signed certificate. Implied when both `--ssl-cert` and `--ssl-key` are provided. | +| `--ssl-cert` | `undefined` | Path to a TLS certificate file (implies HTTPS). | +| `--ssl-key` | `undefined` | Path to a TLS private key file (implies HTTPS). | :::info @@ -70,14 +73,24 @@ There are multiple ways to obtain a certificate. We will use [mkcert](https://gi 2. Run `mkcert -install` to install the cert in your trust store, and restart your browser -3. Start the app with Docusaurus HTTPS env variables: +3. Start the app with the Docusaurus HTTPS CLI options: -```bash -HTTPS=true SSL_CRT_FILE=localhost.pem SSL_KEY_FILE=localhost-key.pem yarn start +```bash npm2yarn +npm run start -- --ssl-cert localhost.pem --ssl-key localhost-key.pem ``` 4. Open `https://localhost:3000/` +:::tip Self-signed certificate + +Use the `--https` option to serve the dev site over HTTPS with an automatically generated self-signed certificate: + +```bash npm2yarn +npm run start -- --https +``` + +::: + ### `docusaurus build [siteDir]` {/* #docusaurus-build-sitedir */} Compiles your site for production. diff --git a/yarn.lock b/yarn.lock index 15fc0b9ed6fd..2389b92f8899 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4263,7 +4263,7 @@ resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.40.tgz#3563f7e8ce8708f5fda43eb8e0956ef11e0da320" integrity sha512-OXtKsLU1bVtInzzDEAY2sYiF/rl4tvAnLLLpuMp3HzAOQZ5A+i69AKDhA1YLQTaMAqO3vzyYNVAYVRMPtSYD4w== -"@swc/core@^1.15.32", "@swc/core@^1.15.40": +"@swc/core@^1.15.40": version "1.15.40" resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.15.40.tgz#941c949aa88c0d8d291f102f519f3c2c77701b90" integrity sha512-2kwzJikRvgtNAG7MwVZY2vEzZjTxKIq5jXOihuSV/8U+Hej8Va22t65aKnJZs3P+NwojZvR8Mf8kyM7O+V8sQg== From 98a605fe26345f5836ec4f3dd28dd66501189dd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Fri, 29 May 2026 17:17:24 +0200 Subject: [PATCH 3/6] chore: use modern Node APIs (AI-assisted) (#12083) --- packages/docusaurus-mdx-loader/src/loader.ts | 3 +-- packages/docusaurus-mdx-loader/src/options.ts | 1 - packages/docusaurus-mdx-loader/src/utils.ts | 17 ----------------- packages/docusaurus-utils/src/urlUtils.ts | 16 ++++++---------- packages/docusaurus-utils/src/vcs/gitUtils.ts | 6 +----- .../docusaurus/src/server/plugins/plugins.ts | 13 ++++--------- packages/docusaurus/src/ssg/ssgExecutor.ts | 6 +----- 7 files changed, 13 insertions(+), 49 deletions(-) diff --git a/packages/docusaurus-mdx-loader/src/loader.ts b/packages/docusaurus-mdx-loader/src/loader.ts index 3aa7fc35ba54..c4374a5ded67 100644 --- a/packages/docusaurus-mdx-loader/src/loader.ts +++ b/packages/docusaurus-mdx-loader/src/loader.ts @@ -17,7 +17,6 @@ import { compileToJSX, createAssetsExportCode, extractContentTitleData, - promiseWithResolvers, } from './utils'; import type {WebpackCompilerName} from '@docusaurus/utils'; import type {Options} from './options'; @@ -202,7 +201,7 @@ async function loadMDXWithCaching({ deleteCacheEntry(); return cacheEntry.promise; } else { - const {promise, resolve, reject} = promiseWithResolvers(); + const {promise, resolve, reject} = Promise.withResolvers(); crossCompilerCache.set(cacheKey, {promise, resolve, reject}); return promise; } diff --git a/packages/docusaurus-mdx-loader/src/options.ts b/packages/docusaurus-mdx-loader/src/options.ts index 5190953b0a0b..6fb712c1c0f0 100644 --- a/packages/docusaurus-mdx-loader/src/options.ts +++ b/packages/docusaurus-mdx-loader/src/options.ts @@ -8,7 +8,6 @@ import type {MDXOptions, SimpleProcessors} from './processor'; import type {MarkdownConfig} from '@docusaurus/types'; import type {ResolveMarkdownLink} from './remark/resolveMarkdownLinks'; -import type {PromiseWithResolvers} from './utils'; export type Options = Partial & { dependencies?: string[]; diff --git a/packages/docusaurus-mdx-loader/src/utils.ts b/packages/docusaurus-mdx-loader/src/utils.ts index 17a8ae9ffe1f..61baff46d581 100644 --- a/packages/docusaurus-mdx-loader/src/utils.ts +++ b/packages/docusaurus-mdx-loader/src/utils.ts @@ -132,20 +132,3 @@ export async function compileToJSX({ ); } } - -// TODO Docusaurus v4, remove temporary polyfill when upgrading to Node 22+ -export interface PromiseWithResolvers { - promise: Promise; - resolve: (value: T | PromiseLike) => void; - reject: (reason?: any) => void; -} -// TODO Docusaurus v4, remove temporary polyfill when upgrading to Node 22+ -export function promiseWithResolvers(): PromiseWithResolvers { - // @ts-expect-error: it's fine - const out: PromiseWithResolvers = {}; - out.promise = new Promise((resolve, reject) => { - out.resolve = resolve; - out.reject = reject; - }); - return out; -} diff --git a/packages/docusaurus-utils/src/urlUtils.ts b/packages/docusaurus-utils/src/urlUtils.ts index 98bf0123527a..3f3056abc8d3 100644 --- a/packages/docusaurus-utils/src/urlUtils.ts +++ b/packages/docusaurus-utils/src/urlUtils.ts @@ -165,17 +165,13 @@ export function isValidPathname(str: string): boolean { } export function parseURLOrPath(url: string, base?: string | URL): URL { - try { - // TODO Docusaurus v4: use URL.parse() - // Node 24 supports it, use URL.parse could be faster? - // see https://kilianvalkhof.com/2024/javascript/the-problem-with-new-url-and-how-url-parse-fixes-that/ - return new URL(url, base ?? 'https://example.com'); - } catch (e) { - throw new Error( - `Can't parse URL ${url}${base ? ` with base ${base}` : ''}`, - {cause: e}, - ); + const parsedURL = URL.parse(url, base ?? 'https://example.com'); + + if (parsedURL) { + return parsedURL; } + + throw new Error(`Can't parse URL ${url}${base ? ` with base ${base}` : ''}`); } export type URLPath = {pathname: string; search?: string; hash?: string}; diff --git a/packages/docusaurus-utils/src/vcs/gitUtils.ts b/packages/docusaurus-utils/src/vcs/gitUtils.ts index a1c13997401a..292cd12fc45c 100644 --- a/packages/docusaurus-utils/src/vcs/gitUtils.ts +++ b/packages/docusaurus-utils/src/vcs/gitUtils.ts @@ -15,11 +15,7 @@ import logger from '@docusaurus/logger'; // Quite high/conservative concurrency value (it was previously "Infinity") // See https://github.com/facebook/docusaurus/pull/10915 -const DefaultGitCommandConcurrency = - // TODO Docusaurus v4: bump node, availableParallelism() now always exists - (typeof os.availableParallelism === 'function' - ? os.availableParallelism() - : os.cpus().length) * 4; +const DefaultGitCommandConcurrency = os.availableParallelism() * 4; const GitCommandConcurrencyEnv = process.env.DOCUSAURUS_GIT_COMMAND_CONCURRENCY ? parseInt(process.env.DOCUSAURUS_GIT_COMMAND_CONCURRENCY, 10) diff --git a/packages/docusaurus/src/server/plugins/plugins.ts b/packages/docusaurus/src/server/plugins/plugins.ts index b697878624ff..86d6644aa846 100644 --- a/packages/docusaurus/src/server/plugins/plugins.ts +++ b/packages/docusaurus/src/server/plugins/plugins.ts @@ -317,15 +317,10 @@ export async function reloadPlugin({ context, }); - /* - // TODO Docusaurus v4 - upgrade to Node 20, use array.with() - const plugins = previousPlugins.with( - previousPlugins.indexOf(previousPlugin), - plugin, - ); - */ - const plugins = [...previousPlugins]; - plugins[previousPlugins.indexOf(previousPlugin)] = plugin; + const plugins = previousPlugins.with( + previousPlugins.indexOf(previousPlugin), + plugin, + ); const allContentLoadedResult = await executeAllPluginsAllContentLoaded({ plugins, diff --git a/packages/docusaurus/src/ssg/ssgExecutor.ts b/packages/docusaurus/src/ssg/ssgExecutor.ts index c329a635ca6d..ea929d2b51b9 100644 --- a/packages/docusaurus/src/ssg/ssgExecutor.ts +++ b/packages/docusaurus/src/ssg/ssgExecutor.ts @@ -83,11 +83,7 @@ function getNumberOfThreads(pathnames: string[]) { } // See also https://github.com/tinylibs/tinypool/pull/108 - const cpuCount = - // TODO Docusaurus v4: bump node, availableParallelism() now always exists - typeof os.availableParallelism === 'function' - ? os.availableParallelism() - : os.cpus().length; + const cpuCount = os.availableParallelism(); return inferNumberOfThreads({ pageCount: pathnames.length, From ff28bdf06237631a3a8022030688c94993fc7eaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Fri, 29 May 2026 17:24:18 +0200 Subject: [PATCH 4/6] chore: upgrade stylelint (#11992) --- .stylelintrc.js | 2 +- package.json | 5 +- .../assets/atom.css | 2 +- .../assets/rss.css | 2 +- .../website/build-snap/blog/atom.css | 2 +- .../website/build-snap/blog/rss.css | 2 +- .../src/theme/DebugLayout/styles.module.css | 2 +- .../theme/PwaReloadPopup/styles.module.css | 2 +- .../theme/AnnouncementBar/styles.module.css | 2 +- .../Header/Title/styles.module.css | 2 +- .../BlogSidebar/Desktop/styles.module.css | 2 +- .../styles.module.css | 2 +- .../theme/DocItem/Layout/styles.module.css | 2 +- .../DocItem/TOC/Mobile/styles.module.css | 2 +- .../DocRoot/Layout/Main/styles.module.css | 2 +- .../Sidebar/ExpandButton/styles.module.css | 2 +- .../DocRoot/Layout/Sidebar/styles.module.css | 2 +- .../Desktop/CollapseButton/styles.module.css | 2 +- .../Desktop/Content/styles.module.css | 3 +- .../DocSidebar/Desktop/styles.module.css | 2 +- .../DocSidebarItem/Html/styles.module.css | 2 +- .../src/theme/EditMetaRow/styles.module.css | 2 +- .../theme/Navbar/Content/styles.module.css | 2 +- .../src/theme/Navbar/Search/styles.module.css | 4 +- .../src/theme/TOC/styles.module.css | 2 +- .../src/theme/SearchPage/styles.module.css | 4 +- .../src/vcs/__tests__/gitUtils.test.ts | 3 +- packages/stylelint-copyright/package.json | 3 +- packages/stylelint-copyright/src/index.ts | 15 +- .../_dogfooding/_blog tests/custom-atom.css | 4 +- .../_dogfooding/_blog tests/custom-rss.css | 4 +- website/_dogfooding/dogfooding.css | 2 +- .../ShowcaseCarousel.module.css | 5 +- website/src/css/custom.css | 5 +- website/src/pages/styles.module.css | 24 +- yarn.lock | 417 ++++++++++-------- 36 files changed, 299 insertions(+), 243 deletions(-) diff --git a/.stylelintrc.js b/.stylelintrc.js index c081bd119c09..ce326e0d67a6 100644 --- a/.stylelintrc.js +++ b/.stylelintrc.js @@ -6,7 +6,7 @@ */ module.exports = { - extends: ['stylelint-config-standard', 'stylelint-config-prettier'], + extends: ['stylelint-config-standard'], plugins: ['stylelint-copyright'], rules: { 'docusaurus/copyright-header': [ diff --git a/package.json b/package.json index 2d284b5b1fa3..6f7d9b635872 100644 --- a/package.json +++ b/package.json @@ -125,9 +125,8 @@ "rimraf": "^3.0.2", "sharp": "^0.34.5", "strip-ansi": "^6.0.1", - "stylelint": "^14.16.1", - "stylelint-config-prettier": "^9.0.5", - "stylelint-config-standard": "^29.0.0", + "stylelint": "^17.12.0", + "stylelint-config-standard": "^40.0.0", "syncpack": "^14.3.1", "typescript": "~6.0.3", "typescript-eslint": "^8.59.3", diff --git a/packages/docusaurus-plugin-content-blog/assets/atom.css b/packages/docusaurus-plugin-content-blog/assets/atom.css index 34e60c0ba022..b529fe659de3 100644 --- a/packages/docusaurus-plugin-content-blog/assets/atom.css +++ b/packages/docusaurus-plugin-content-blog/assets/atom.css @@ -14,7 +14,7 @@ main { font-family: system-ui, -apple-system, - Segoe UI, + 'Segoe UI', Roboto, Ubuntu, Cantarell; diff --git a/packages/docusaurus-plugin-content-blog/assets/rss.css b/packages/docusaurus-plugin-content-blog/assets/rss.css index 34e60c0ba022..b529fe659de3 100644 --- a/packages/docusaurus-plugin-content-blog/assets/rss.css +++ b/packages/docusaurus-plugin-content-blog/assets/rss.css @@ -14,7 +14,7 @@ main { font-family: system-ui, -apple-system, - Segoe UI, + 'Segoe UI', Roboto, Ubuntu, Cantarell; diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website/build-snap/blog/atom.css b/packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website/build-snap/blog/atom.css index 34e60c0ba022..b529fe659de3 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website/build-snap/blog/atom.css +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website/build-snap/blog/atom.css @@ -14,7 +14,7 @@ main { font-family: system-ui, -apple-system, - Segoe UI, + 'Segoe UI', Roboto, Ubuntu, Cantarell; diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website/build-snap/blog/rss.css b/packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website/build-snap/blog/rss.css index 34e60c0ba022..b529fe659de3 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website/build-snap/blog/rss.css +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website/build-snap/blog/rss.css @@ -14,7 +14,7 @@ main { font-family: system-ui, -apple-system, - Segoe UI, + 'Segoe UI', Roboto, Ubuntu, Cantarell; diff --git a/packages/docusaurus-plugin-debug/src/theme/DebugLayout/styles.module.css b/packages/docusaurus-plugin-debug/src/theme/DebugLayout/styles.module.css index 40326effb3b0..ffbd44e8989a 100644 --- a/packages/docusaurus-plugin-debug/src/theme/DebugLayout/styles.module.css +++ b/packages/docusaurus-plugin-debug/src/theme/DebugLayout/styles.module.css @@ -48,7 +48,7 @@ background-color: #363739; } -@media screen and (min-width: 800px) { +@media screen and (width >= 800px) { .nav { flex-direction: column; justify-content: flex-start; diff --git a/packages/docusaurus-plugin-pwa/src/theme/PwaReloadPopup/styles.module.css b/packages/docusaurus-plugin-pwa/src/theme/PwaReloadPopup/styles.module.css index 1d341c114e17..dcfa918ef57b 100644 --- a/packages/docusaurus-plugin-pwa/src/theme/PwaReloadPopup/styles.module.css +++ b/packages/docusaurus-plugin-pwa/src/theme/PwaReloadPopup/styles.module.css @@ -20,7 +20,7 @@ margin: 0; } -@media screen and (max-width: 500px) { +@media screen and (width <= 500px) { .popup { width: 100%; bottom: 0; diff --git a/packages/docusaurus-theme-classic/src/theme/AnnouncementBar/styles.module.css b/packages/docusaurus-theme-classic/src/theme/AnnouncementBar/styles.module.css index b09a21721ff7..fa77f1dfeb01 100644 --- a/packages/docusaurus-theme-classic/src/theme/AnnouncementBar/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/AnnouncementBar/styles.module.css @@ -50,7 +50,7 @@ html[data-announcement-bar-initially-dismissed='true'] .announcementBar { } } -@media (min-width: 997px) { +@media (width >= 997px) { :root { --docusaurus-announcement-bar-height: 30px; } diff --git a/packages/docusaurus-theme-classic/src/theme/BlogPostItem/Header/Title/styles.module.css b/packages/docusaurus-theme-classic/src/theme/BlogPostItem/Header/Title/styles.module.css index 5ffc89f2432b..df79299fab0e 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogPostItem/Header/Title/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/BlogPostItem/Header/Title/styles.module.css @@ -12,7 +12,7 @@ /** Blog post title should be smaller on smaller devices **/ -@media (max-width: 576px) { +@media (width <= 576px) { .title { font-size: 2rem; } diff --git a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/styles.module.css b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/styles.module.css index 70781835456c..7c0ae6313d93 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/styles.module.css @@ -38,7 +38,7 @@ color: var(--ifm-color-primary) !important; } -@media (max-width: 996px) { +@media (width <= 996px) { .sidebar { display: none; } diff --git a/packages/docusaurus-theme-classic/src/theme/DocCategoryGeneratedIndexPage/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocCategoryGeneratedIndexPage/styles.module.css index 8ca9a8f47e2b..b1737abca349 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocCategoryGeneratedIndexPage/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocCategoryGeneratedIndexPage/styles.module.css @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -@media (min-width: 997px) { +@media (width >= 997px) { .generatedIndexPage { max-width: 75% !important; } diff --git a/packages/docusaurus-theme-classic/src/theme/DocItem/Layout/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocItem/Layout/styles.module.css index 784498f2e1fd..a3a1f8ac5087 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocItem/Layout/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocItem/Layout/styles.module.css @@ -10,7 +10,7 @@ margin-top: 0; } -@media (min-width: 997px) { +@media (width >= 997px) { .docItemCol { max-width: 75% !important; } diff --git a/packages/docusaurus-theme-classic/src/theme/DocItem/TOC/Mobile/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocItem/TOC/Mobile/styles.module.css index a298b5e3502e..03a8aa90fda2 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocItem/TOC/Mobile/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocItem/TOC/Mobile/styles.module.css @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -@media (min-width: 997px) { +@media (width >= 997px) { /* Prevent hydration FOUC, as the mobile TOC needs to be server-rendered */ .tocMobile { display: none; diff --git a/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Main/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Main/styles.module.css index 0754fce24b02..590fd2c8f14d 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Main/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Main/styles.module.css @@ -10,7 +10,7 @@ width: 100%; } -@media (min-width: 997px) { +@media (width >= 997px) { .docMainContainer { flex-grow: 1; max-width: calc(100% - var(--doc-sidebar-width)); diff --git a/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Sidebar/ExpandButton/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Sidebar/ExpandButton/styles.module.css index f5e58785e148..f3a8d310ccdf 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Sidebar/ExpandButton/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Sidebar/ExpandButton/styles.module.css @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -@media (min-width: 997px) { +@media (width >= 997px) { .expandButton { position: absolute; top: 0; diff --git a/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Sidebar/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Sidebar/styles.module.css index f821f3b60564..97903b7cec02 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Sidebar/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Sidebar/styles.module.css @@ -14,7 +14,7 @@ display: none; } -@media (min-width: 997px) { +@media (width >= 997px) { .docSidebarContainer { display: block; width: var(--doc-sidebar-width); diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebar/Desktop/CollapseButton/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocSidebar/Desktop/CollapseButton/styles.module.css index c5026e8bf154..578320cec545 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebar/Desktop/CollapseButton/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebar/Desktop/CollapseButton/styles.module.css @@ -15,7 +15,7 @@ --docusaurus-collapse-button-bg-hover: rgb(255 255 255 / 10%); } -@media (min-width: 997px) { +@media (width >= 997px) { .collapseSidebarButton { display: block !important; background-color: var(--docusaurus-collapse-button-bg); diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebar/Desktop/Content/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocSidebar/Desktop/Content/styles.module.css index 8d8c7e88cbe6..6e56ca8cdbb9 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebar/Desktop/Content/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebar/Desktop/Content/styles.module.css @@ -5,11 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -@media (min-width: 997px) { +@media (width >= 997px) { .menu { flex-grow: 1; padding: 0.5rem; } + @supports (scrollbar-gutter: stable) { .menu { padding: 0.5rem 0 0.5rem 0.5rem; diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebar/Desktop/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocSidebar/Desktop/styles.module.css index e4d472476a75..9556020a67f1 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebar/Desktop/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebar/Desktop/styles.module.css @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -@media (min-width: 997px) { +@media (width >= 997px) { .sidebar { display: flex; flex-direction: column; diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Html/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Html/styles.module.css index 2bb6934d33ee..c813c7420374 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Html/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Html/styles.module.css @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -@media (min-width: 997px) { +@media (width >= 997px) { .menuHtmlItem { padding: var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal); diff --git a/packages/docusaurus-theme-classic/src/theme/EditMetaRow/styles.module.css b/packages/docusaurus-theme-classic/src/theme/EditMetaRow/styles.module.css index 95f36d63c070..27616e053dc5 100644 --- a/packages/docusaurus-theme-classic/src/theme/EditMetaRow/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/EditMetaRow/styles.module.css @@ -11,7 +11,7 @@ margin-top: 0.2rem; } -@media (min-width: 997px) { +@media (width >= 997px) { .lastUpdated { text-align: right; } diff --git a/packages/docusaurus-theme-classic/src/theme/Navbar/Content/styles.module.css b/packages/docusaurus-theme-classic/src/theme/Navbar/Content/styles.module.css index eee2127b697c..109e0928bda9 100644 --- a/packages/docusaurus-theme-classic/src/theme/Navbar/Content/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/Navbar/Content/styles.module.css @@ -8,7 +8,7 @@ /* Hide color mode toggle in small viewports */ -@media (max-width: 996px) { +@media (width <= 996px) { .colorModeToggle { display: none; } diff --git a/packages/docusaurus-theme-classic/src/theme/Navbar/Search/styles.module.css b/packages/docusaurus-theme-classic/src/theme/Navbar/Search/styles.module.css index c58238dcf97e..e3703c17dc0c 100644 --- a/packages/docusaurus-theme-classic/src/theme/Navbar/Search/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/Navbar/Search/styles.module.css @@ -13,14 +13,14 @@ See https://github.com/facebook/docusaurus/pull/9385 display: none; } -@media (max-width: 996px) { +@media (width <= 996px) { .navbarSearchContainer { position: absolute; right: var(--ifm-navbar-padding-horizontal); } } -@media (min-width: 997px) { +@media (width >= 997px) { .navbarSearchContainer { padding: 0 var(--ifm-navbar-item-padding-horizontal); } diff --git a/packages/docusaurus-theme-classic/src/theme/TOC/styles.module.css b/packages/docusaurus-theme-classic/src/theme/TOC/styles.module.css index 4b6d2bcc657e..c0d85868d8df 100644 --- a/packages/docusaurus-theme-classic/src/theme/TOC/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/TOC/styles.module.css @@ -12,7 +12,7 @@ top: calc(var(--ifm-navbar-height) + 1rem); } -@media (max-width: 996px) { +@media (width <= 996px) { .tableOfContents { display: none; } diff --git a/packages/docusaurus-theme-search-algolia/src/theme/SearchPage/styles.module.css b/packages/docusaurus-theme-search-algolia/src/theme/SearchPage/styles.module.css index 29c4389f5514..53f100b46c7a 100644 --- a/packages/docusaurus-theme-search-algolia/src/theme/SearchPage/styles.module.css +++ b/packages/docusaurus-theme-search-algolia/src/theme/SearchPage/styles.module.css @@ -70,7 +70,7 @@ font-style: italic; } -@media only screen and (max-width: 996px) { +@media only screen and (width <= 996px) { .searchQueryColumn { max-width: 60% !important; } @@ -89,7 +89,7 @@ } } -@media screen and (max-width: 576px) { +@media screen and (width <= 576px) { .searchQueryColumn { max-width: 100% !important; } diff --git a/packages/docusaurus-utils/src/vcs/__tests__/gitUtils.test.ts b/packages/docusaurus-utils/src/vcs/__tests__/gitUtils.test.ts index fd817e579eae..71cbe1903a52 100644 --- a/packages/docusaurus-utils/src/vcs/__tests__/gitUtils.test.ts +++ b/packages/docusaurus-utils/src/vcs/__tests__/gitUtils.test.ts @@ -423,7 +423,8 @@ describe('getGitRepoRoot', () => { it('returns Docusaurus repo for cwd=__dirname', async () => { const cwd = __dirname; - await expect(getGitRepoRoot(cwd)).resolves.toMatch(/docusaurus$/); + const repoRoot = path.resolve(cwd, '..', '..', '..', '..', '..'); + await expect(getGitRepoRoot(cwd)).resolves.toEqual(repoRoot); }); it('rejects for cwd=repoDir/doesNotExist', async () => { diff --git a/packages/stylelint-copyright/package.json b/packages/stylelint-copyright/package.json index 5724c68cc971..4689d16e665e 100644 --- a/packages/stylelint-copyright/package.json +++ b/packages/stylelint-copyright/package.json @@ -3,6 +3,7 @@ "version": "3.10.1", "description": "Stylelint plugin to check CSS files for a copyright header.", "main": "lib/index.js", + "type": "module", "license": "MIT", "scripts": { "build": "tsc", @@ -14,7 +15,7 @@ "directory": "packages/stylelint-copyright" }, "dependencies": { - "stylelint": "^14.16.1", + "stylelint": "^17.12.0", "tslib": "^2.6.0" } } diff --git a/packages/stylelint-copyright/src/index.ts b/packages/stylelint-copyright/src/index.ts index ae77974fd905..fa6e333f376c 100644 --- a/packages/stylelint-copyright/src/index.ts +++ b/packages/stylelint-copyright/src/index.ts @@ -14,7 +14,7 @@ const messages = stylelint.utils.ruleMessages(ruleName, { type SecondaryOption = {header?: string}; -const rule: Rule = +const ruleFunction: Rule = (primaryOption, secondaryOption, context) => (root, result) => { stylelint.utils.validateOptions( result, @@ -53,9 +53,12 @@ const rule: Rule = }); }; -rule.ruleName = ruleName; -rule.messages = messages; +ruleFunction.ruleName = ruleName; +ruleFunction.messages = messages; +ruleFunction.meta = { + url: 'https://github.com/facebook/docusaurus/tree/main/packages/stylelint-copyright', + fixable: true, + deprecated: false, +}; -const plugin = stylelint.createPlugin(ruleName, rule); - -export default plugin; +export default stylelint.createPlugin(ruleName, ruleFunction); diff --git a/website/_dogfooding/_blog tests/custom-atom.css b/website/_dogfooding/_blog tests/custom-atom.css index ad5829c20101..0d8818492f2c 100644 --- a/website/_dogfooding/_blog tests/custom-atom.css +++ b/website/_dogfooding/_blog tests/custom-atom.css @@ -13,13 +13,13 @@ main { flex: 1 0 auto; width: 100%; margin: 4rem auto; - padding: 1.5 rem; + padding: 1.5rem; max-width: 800px; /* stylelint-disable-next-line font-family-name-quotes */ font-family: system-ui, -apple-system, - Segoe UI, + 'Segoe UI', Roboto, Ubuntu, Cantarell; diff --git a/website/_dogfooding/_blog tests/custom-rss.css b/website/_dogfooding/_blog tests/custom-rss.css index ad5829c20101..0d8818492f2c 100644 --- a/website/_dogfooding/_blog tests/custom-rss.css +++ b/website/_dogfooding/_blog tests/custom-rss.css @@ -13,13 +13,13 @@ main { flex: 1 0 auto; width: 100%; margin: 4rem auto; - padding: 1.5 rem; + padding: 1.5rem; max-width: 800px; /* stylelint-disable-next-line font-family-name-quotes */ font-family: system-ui, -apple-system, - Segoe UI, + 'Segoe UI', Roboto, Ubuntu, Cantarell; diff --git a/website/_dogfooding/dogfooding.css b/website/_dogfooding/dogfooding.css index 3ae643d6f197..6e20f680bfe6 100644 --- a/website/_dogfooding/dogfooding.css +++ b/website/_dogfooding/dogfooding.css @@ -6,7 +6,7 @@ */ html { - @media screen and (min-width: 1px) { + @media screen and (width >= 1px) { &.plugin-docs.plugin-id-docs-tests { .red > a { color: red; diff --git a/website/blog/2022/08-01-announcing-docusaurus-2.0/ShowcaseCarousel.module.css b/website/blog/2022/08-01-announcing-docusaurus-2.0/ShowcaseCarousel.module.css index 83b3eb90eab0..631f6c1c867d 100644 --- a/website/blog/2022/08-01-announcing-docusaurus-2.0/ShowcaseCarousel.module.css +++ b/website/blog/2022/08-01-announcing-docusaurus-2.0/ShowcaseCarousel.module.css @@ -11,8 +11,7 @@ .cssCarouselSlider { display: flex; - overflow-x: scroll; - overflow-y: hidden; + overflow: scroll hidden; scroll-snap-type: x mandatory; scrollbar-width: none; } @@ -85,7 +84,7 @@ --ifm-link-hover-decoration: none; } -@media only screen and (max-width: 768px) { +@media only screen and (width <= 768px) { .siteLink { font-size: 12px; padding: 0 8px; diff --git a/website/src/css/custom.css b/website/src/css/custom.css index 2284e1e2375c..f19f426cd1b4 100644 --- a/website/src/css/custom.css +++ b/website/src/css/custom.css @@ -175,7 +175,6 @@ html[data-theme='dark'] { .screen-reader-only { border: 0; - clip: rect(0 0 0 0); clip-path: polygon(0 0, 0 0, 0 0); height: 1px; margin: -1px; @@ -227,11 +226,11 @@ html[data-theme='dark'] { } [data-rmiz-modal-overlay='visible'] { - background-color: rgba(255 255 255 / 95%); + background-color: rgb(255 255 255 / 95%); } [data-theme='dark'] [data-rmiz-modal-overlay='visible'] { - background-color: rgba(0 0 0 / 95%); + background-color: rgb(0 0 0 / 95%); } html[data-navbar='false'] { diff --git a/website/src/pages/styles.module.css b/website/src/pages/styles.module.css index 9912eee6ae9d..81d1bec51615 100644 --- a/website/src/pages/styles.module.css +++ b/website/src/pages/styles.module.css @@ -65,19 +65,24 @@ font-size: 54px; font-weight: bold; margin-bottom: 0.4rem; - @media only screen and (max-width: 768px) { + + @media only screen and (width <= 768px) { font-size: 40px; } - @media only screen and (max-width: 768px) { + + @media only screen and (width <= 768px) { font-size: 40px; } - @media only screen and (max-width: 450px) { + + @media only screen and (width <= 450px) { font-size: 32px; } - @media only screen and (max-width: 350px) { + + @media only screen and (width <= 350px) { font-size: 24px; } - @media only screen and (max-width: 250px) { + + @media only screen and (width <= 250px) { font-size: 16px; } } @@ -112,7 +117,8 @@ html[data-theme='dark'] .topBannerTitleText { .topBannerDescription { font-size: 20px; } -@media only screen and (max-width: 768px) { + +@media only screen and (width <= 768px) { .topBannerDescription { font-size: 16px; white-space: normal; @@ -200,7 +206,7 @@ html[data-theme='dark'] .topBannerTitleText { color: var(--ifm-color-primary); } -@media only screen and (max-width: 768px) { +@media only screen and (width <= 768px) { .hero { padding-left: 20px; padding-right: 20px; @@ -238,13 +244,13 @@ html[data-theme='dark'] .topBannerTitleText { margin-bottom: 2rem; } -@media (max-width: 996px) { +@media (width <= 996px) { .tweetsSection > :global(.col:last-child) > *:last-child { margin-bottom: 0; } } -@media (min-width: 997px) { +@media (width >= 997px) { .tweetsSection > :global(.col) > *:last-child { margin-bottom: 0; } diff --git a/yarn.lock b/yarn.lock index 2389b92f8899..01a0bc2f3fa4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1234,6 +1234,24 @@ resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz#ca2035b0fefe956a8676ff0c69af73e605fcd81f" integrity sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA== +"@cacheable/memory@^2.0.8": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@cacheable/memory/-/memory-2.0.9.tgz#22168cd7781df081ac0b3569bfbe7b4fc2c4cecd" + integrity sha512-HdMx6DoGywB30vacDbBsITbIX4pgFqj1zsrV58jZBUw3klzkNoXhj7qOqAgledhxG7YZI5rBSJg7Zp8/VG0DuA== + dependencies: + "@cacheable/utils" "^2.4.1" + "@keyv/bigmap" "^1.3.1" + hookified "^1.15.1" + keyv "^5.6.0" + +"@cacheable/utils@^2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@cacheable/utils/-/utils-2.4.1.tgz#614ab46e4e2adf94785d8adaadbf40873d0eb12d" + integrity sha512-eiFgzCbIneyMlLOmNG4g9xzF7Hv3Mga4LjxjcSC/ues6VYq2+gUbQI8JqNuw/ZM8tJIeIaBGpswAsqV2V7ApgA== + dependencies: + hashery "^1.5.1" + keyv "^5.6.0" + "@chevrotain/types@~11.1.1": version "11.1.2" resolved "https://registry.yarnpkg.com/@chevrotain/types/-/types-11.1.2.tgz#e83a1a2704f0c5e49e7592b214031a0f4a34d7e5" @@ -1728,6 +1746,11 @@ resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz#e1c65dc09378b42f26a111fca7f7075fc2c26164" integrity sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w== +"@csstools/css-syntax-patches-for-csstree@^1.1.3": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.4.tgz#8f4e5e23574e8c76005588984308d2b216993720" + integrity sha512-wgsqt92b7C7tQhIdPNxj0n9zuUbQlvAuI1exyzeNrOKOi62SD7ren8zqszmpVREjAOqg8cD2FqYhQfAuKjk4sw== + "@csstools/css-tokenizer@^3.0.3": version "3.0.4" resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz#333fedabc3fd1a8e5d0100013731cf19e6a8c5d3" @@ -2104,11 +2127,6 @@ resolved "https://registry.yarnpkg.com/@csstools/selector-resolve-nested/-/selector-resolve-nested-4.0.0.tgz#ccc38c2cdc14c3ddd1d94647803facef654d47e2" integrity sha512-9vAPxmp+Dx3wQBIUwc1v7Mdisw1kbbaGqXUM8QLTgWg7SoPGYtXBsMXvsFs/0Bn5yoFhcktzxNZGNaUt0VjgjA== -"@csstools/selector-specificity@^2.0.2": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz#2cbcf822bf3764c9658c4d2e568bd0c0cb748016" - integrity sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw== - "@csstools/selector-specificity@^6.0.0": version "6.0.0" resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-6.0.0.tgz#ef28e27c1ded1d8e5c54879a9399e7055aed1920" @@ -2654,6 +2672,19 @@ "@jsonjoy.com/buffers" "^1.0.0" "@jsonjoy.com/codegen" "^1.0.0" +"@keyv/bigmap@^1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@keyv/bigmap/-/bigmap-1.3.1.tgz#fc82fa83947e7ff68c6798d08907db842771ef2c" + integrity sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ== + dependencies: + hashery "^1.4.0" + hookified "^1.15.0" + +"@keyv/serialize@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@keyv/serialize/-/serialize-1.1.1.tgz#0c01dd3a3483882af7cf3878d4e71d505c81fc4a" + integrity sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA== + "@leichtgewicht/ip-codec@^2.0.1": version "2.0.4" resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" @@ -4078,6 +4109,11 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-5.5.0.tgz#70af51f38ef3b624eb08eb02a2ed70f117fa19d7" integrity sha512-3rO1QIz6mL0MvFVTOxqhDJRVsLfG/vK2VSlKKPghALA6FhJqU7L+RUHnFvH5BP5HhkWiMQqq514i9ZFTcqoGCQ== +"@sindresorhus/merge-streams@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz#abb11d99aeb6d27f1b563c38147a72d50058e339" + integrity sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ== + "@slorber/remark-comment@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@slorber/remark-comment/-/remark-comment-1.0.0.tgz#2a020b3f4579c89dec0361673206c28d67e08f5a" @@ -5093,11 +5129,6 @@ resolved "https://registry.yarnpkg.com/@types/nprogress/-/nprogress-0.2.3.tgz#b2150b054a13622fabcba12cf6f0b54c48b14287" integrity sha512-k7kRA033QNtC+gLc4VPlfnue58CM1iQLgn1IMAU8VPHGOj7oIHPp9UlhedEnD/Gl8evoCjwkZjlBORtZ3JByUA== -"@types/parse-json@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" - integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== - "@types/picomatch@^2.3.0": version "2.3.4" resolved "https://registry.yarnpkg.com/@types/picomatch/-/picomatch-2.3.4.tgz#00c5b3eee51cd690f76b8213c625adc9bc4b9aa6" @@ -6295,11 +6326,6 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -balanced-match@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-2.0.0.tgz#dc70f920d78db8b858535795867bf48f820633d9" - integrity sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA== - balanced-match@^4.0.2: version "4.0.4" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-4.0.4.tgz#bfb10662feed8196a2c62e7c68e17720c274179a" @@ -6635,6 +6661,17 @@ cacheable-request@^10.2.8: normalize-url "^8.0.0" responselike "^3.0.0" +cacheable@^2.3.4: + version "2.3.5" + resolved "https://registry.yarnpkg.com/cacheable/-/cacheable-2.3.5.tgz#dc0c2a2713eef5c82f048237c5b267e25d78eaac" + integrity sha512-EQfaKe09tl615iNvq/TBRWTFf1AKJNXYQSsMx0Z3EI0nA+pVsVPS8wJhnRlkbdacKPh1d0qVIhwTc2zsQNFEEg== + dependencies: + "@cacheable/memory" "^2.0.8" + "@cacheable/utils" "^2.4.1" + hookified "^1.15.0" + keyv "^5.6.0" + qified "^0.10.1" + call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" @@ -7422,17 +7459,6 @@ cose-base@^2.2.0: dependencies: layout-base "^2.0.0" -cosmiconfig@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" - integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.2.1" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.10.0" - cosmiconfig@^8.1.3, cosmiconfig@^8.2.0: version "8.3.6" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3" @@ -7443,10 +7469,10 @@ cosmiconfig@^8.1.3, cosmiconfig@^8.2.0: parse-json "^5.2.0" path-type "^4.0.0" -cosmiconfig@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-9.0.0.tgz#34c3fc58287b915f3ae905ab6dc3de258b55ad9d" - integrity sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg== +cosmiconfig@^9.0.0, cosmiconfig@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-9.0.1.tgz#df110631a8547b5d1a98915271986f06e3011379" + integrity sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ== dependencies: env-paths "^2.2.1" import-fresh "^3.3.0" @@ -7620,10 +7646,10 @@ css-declaration-sorter@^7.2.0: resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz#6dec1c9523bc4a643e088aab8f09e67a54961024" integrity sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow== -css-functions-list@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.2.0.tgz#8290b7d064bf483f48d6559c10e98dc4d1ad19ee" - integrity sha512-d/jBMPyYybkkLVypgtGv12R+pIFw4/f/IHtCTxWpZc8ofTYOPigIgmA6vu5rMHartZC+WuXhBUHfnyNUIQSYrg== +css-functions-list@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.3.3.tgz#c4ab5008659de2e3baf3752c8fdef7662f3ffe23" + integrity sha512-8HFEBPKhOpJPEPu70wJJetjKta86Gw9+CCyCnB3sui2qQfOvRyqBy4IKLKKAwdMpWb2lHXWk9Wb4Z6AmaUT1Pg== css-has-pseudo@^8.0.0: version "8.0.0" @@ -7695,7 +7721,7 @@ css-tree@^2.3.1: mdn-data "2.0.30" source-map-js "^1.0.1" -css-tree@^3.0.1: +css-tree@^3.0.1, css-tree@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-3.2.1.tgz#86cac7011561272b30e6b1e042ba6ce047aa7518" integrity sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA== @@ -8212,7 +8238,7 @@ decamelize-keys@^1.1.0: decamelize "^1.1.0" map-obj "^1.0.0" -decamelize@^1.1.0, decamelize@^1.2.0: +decamelize@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== @@ -9393,16 +9419,16 @@ fast-folder-size@1.6.1: dependencies: unzipper "^0.10.11" -fast-glob@^3.2.12, fast-glob@^3.2.9, fast-glob@^3.3.1, fast-glob@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" - integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== +fast-glob@^3.2.9, fast-glob@^3.3.1, fast-glob@^3.3.2, fast-glob@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" glob-parent "^5.1.2" merge2 "^1.3.0" - micromatch "^4.0.4" + micromatch "^4.0.8" fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" @@ -9464,12 +9490,12 @@ figures@3.2.0, figures@^3.0.0: dependencies: escape-string-regexp "^1.0.5" -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== +file-entry-cache@^11.1.3: + version "11.1.3" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-11.1.3.tgz#f7be4d09f63889db1493ff23914199d6bfcf439e" + integrity sha512-oMbq0PD6VIiIwMF6LIa7MEwd/l9huKwmqRKXqmrkqIZv8CvRbfowL+L0ryAl8h//HfAS0zS+4SbYoRyAoA6BJA== dependencies: - flat-cache "^3.0.4" + flat-cache "^6.1.22" file-entry-cache@^8.0.0: version "8.0.0" @@ -9573,15 +9599,6 @@ find-yarn-workspace-root@^2.0.0: dependencies: micromatch "^4.0.2" -flat-cache@^3.0.4: - version "3.2.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" - integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== - dependencies: - flatted "^3.2.9" - keyv "^4.5.3" - rimraf "^3.0.2" - flat-cache@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" @@ -9598,12 +9615,21 @@ flat-cache@^5.0.0: flatted "^3.3.1" keyv "^4.5.4" +flat-cache@^6.1.22: + version "6.1.22" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-6.1.22.tgz#e9f31d567179bb5f0f2fc011e6f89af2cc94f918" + integrity sha512-N2dnzVJIphnNsjHcrxGW7DePckJ6haPrSFqpsBUhHYgwtKGVq4JrBGielEGD2fCVnsGm1zlBVZ8wGhkyuetgug== + dependencies: + cacheable "^2.3.4" + flatted "^3.4.2" + hookified "^1.15.0" + flat@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== -flatted@^3.2.9, flatted@^3.3.1: +flatted@^3.2.9, flatted@^3.3.1, flatted@^3.4.2: version "3.4.2" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.4.2.tgz#f5c23c107f0f37de8dbdf24f13722b3b98d52726" integrity sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA== @@ -10070,6 +10096,18 @@ globby@11.1.0, globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" +globby@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-16.2.0.tgz#6ab1351fbac1d9b9e47ed423814c2ad41af308ea" + integrity sha512-QrJia2qDf5BB/V6HYlDTs0I0lBahyjLzpGQg3KT7FnCdTonAyPy2RtY802m2k4ALx6Dp752f82WsOczEVr3l6Q== + dependencies: + "@sindresorhus/merge-streams" "^4.0.0" + fast-glob "^3.3.3" + ignore "^7.0.5" + is-path-inside "^4.0.0" + slash "^5.1.0" + unicorn-magic "^0.4.0" + globjoin@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" @@ -10166,6 +10204,11 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-flag@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-5.0.1.tgz#5483db2ae02a472d1d0691462fc587d1843cd940" + integrity sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA== + has-own-prop@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-own-prop/-/has-own-prop-2.0.0.tgz#f0f95d58f65804f5d218db32563bb85b8e0417af" @@ -10207,6 +10250,13 @@ has-yarn@^3.0.0: resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-3.0.0.tgz#c3c21e559730d1d3b57e28af1f30d06fac38147d" integrity sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA== +hashery@^1.4.0, hashery@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/hashery/-/hashery-1.5.1.tgz#4ba82ad54911ac617467870845d57a9fe508a400" + integrity sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ== + dependencies: + hookified "^1.15.0" + hasown@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" @@ -10434,6 +10484,16 @@ hoist-non-react-statics@^3.1.0: dependencies: react-is "^16.7.0" +hookified@^1.15.0, hookified@^1.15.1: + version "1.15.1" + resolved "https://registry.yarnpkg.com/hookified/-/hookified-1.15.1.tgz#b1fafeaa5489cdc29cb85546a8f837ed4ffbbcb6" + integrity sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg== + +hookified@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/hookified/-/hookified-2.2.0.tgz#1d024ac1668973dd5bcc4a96ab9ccdb7639ef8d4" + integrity sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA== + hosted-git-info@^2.1.4: version "2.8.9" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" @@ -10513,11 +10573,16 @@ html-minifier-terser@^7.2.0: relateurl "^0.2.7" terser "^5.15.1" -html-tags@^3.2.0, html-tags@^3.3.1: +html-tags@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.3.1.tgz#a04026a18c882e4bba8a01a3d39cfe465d40b5ce" integrity sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ== +html-tags@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-5.1.0.tgz#ec7214b57b3e50e2a4cec39414454338a94291f8" + integrity sha512-n6l5uca7/y5joxZ3LUePhzmBFUJ+U2YWzhMa8XUTecSeSlQiZdF5XAd/Q3/WUl0VsXgUwWi8I7CNIwdI5WN1SQ== + html-void-elements@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-3.0.0.tgz#fc9dbd84af9e747249034d4d62602def6517f1d7" @@ -10743,7 +10808,7 @@ ignore-walk@^6.0.0: dependencies: minimatch "^9.0.0" -ignore@^5.0.4, ignore@^5.2.0, ignore@^5.2.1, ignore@^5.3.1: +ignore@^5.0.4, ignore@^5.2.0, ignore@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== @@ -10779,10 +10844,10 @@ import-local@3.1.0: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" -import-meta-resolve@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz#f9db8bead9fafa61adb811db77a2bf22c5399706" - integrity sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw== +import-meta-resolve@^4.1.0, import-meta-resolve@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz#08cb85b5bd37ecc8eb1e0f670dc2767002d43734" + integrity sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg== imurmurhash@^0.1.4: version "0.1.4" @@ -11165,6 +11230,11 @@ is-path-inside@^3.0.2: resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== +is-path-inside@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-4.0.0.tgz#805aeb62c47c1b12fc3fd13bfb3ed1e7430071db" + integrity sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA== + is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" @@ -11664,13 +11734,20 @@ katex@^0.16.0, katex@^0.16.25: dependencies: commander "^8.3.0" -keyv@^4.5.2, keyv@^4.5.3, keyv@^4.5.4: +keyv@^4.5.2, keyv@^4.5.4: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: json-buffer "3.0.1" +keyv@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-5.6.0.tgz#03044074c6b4d072d0a62c7b9fa649537baf0105" + integrity sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw== + dependencies: + "@keyv/serialize" "^1.1.1" + khroma@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/khroma/-/khroma-2.1.0.tgz#45f2ce94ce231a437cf5b63c2e886e6eb42bbbb1" @@ -11693,11 +11770,6 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== -known-css-properties@^0.26.0: - version "0.26.0" - resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.26.0.tgz#008295115abddc045a9f4ed7e2a84dc8b3a77649" - integrity sha512-5FZRzrZzNTBruuurWpvZnvP9pum+fe0HcK8z/ooo+U+Hmp4vtbyp1/QDsqmufirXy4egGzbaH/y2uCZf+6W5Kg== - language-subtag-registry@^0.3.20: version "0.3.23" resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz#23529e04d9e3b74679d70142df3fd2eb6ec572e7" @@ -12309,10 +12381,10 @@ math-intrinsics@^1.1.0: resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== -mathml-tag-names@^2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" - integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== +mathml-tag-names@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-4.0.0.tgz#295494906312f849a9236e6cd9accc902814d477" + integrity sha512-aa6AU2Pcx0VP/XWnh8IGL0SYSgQHDT6Ucror2j2mXeFAlN3ahaNs8EZtG1YiticMkSLj3Gt6VPFfZogt7G5iFQ== mdast-util-directive@^3.0.0: version "3.0.0" @@ -12580,6 +12652,11 @@ memorystream@^0.3.1: resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw== +meow@^14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-14.1.0.tgz#3cd2d16ad534829ab12fcb5010fc2fdb89facd31" + integrity sha512-EDYo6VlmtnumlcBCbh1gLJ//9jvM/ndXHfVXIFrZVr6fGcwTUyCTFNTLCKuY3ffbK8L/+3Mzqnd58RojiZqHVw== + meow@^8.1.2: version "8.1.2" resolved "https://registry.yarnpkg.com/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" @@ -12597,24 +12674,6 @@ meow@^8.1.2: type-fest "^0.18.0" yargs-parser "^20.2.3" -meow@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-9.0.0.tgz#cd9510bc5cac9dee7d03c73ee1f9ad959f4ea364" - integrity sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ== - dependencies: - "@types/minimist" "^1.2.0" - camelcase-keys "^6.2.2" - decamelize "^1.2.0" - decamelize-keys "^1.1.0" - hard-rejection "^2.1.0" - minimist-options "4.1.0" - normalize-package-data "^3.0.0" - read-pkg-up "^7.0.1" - redent "^3.0.0" - trim-newlines "^3.0.0" - type-fest "^0.18.0" - yargs-parser "^20.2.3" - merge-descriptors@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" @@ -13093,7 +13152,7 @@ micromark@^4.0.0: micromark-util-symbol "^2.0.0" micromark-util-types "^2.0.0" -micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5, micromatch@^4.0.8: +micromatch@^4.0.2, micromatch@^4.0.5, micromatch@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== @@ -14753,11 +14812,6 @@ postcss-logical@^9.0.0: dependencies: postcss-value-parser "^4.2.0" -postcss-media-query-parser@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244" - integrity sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig== - postcss-merge-idents@^7.0.2: version "7.0.2" resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-7.0.2.tgz#92e06a267daff77e66da498f0b40ec96d9f81e27" @@ -15063,15 +15117,10 @@ postcss-replace-overflow-wrap@^4.0.0: resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz#d2df6bed10b477bf9c52fab28c568b4b29ca4319" integrity sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw== -postcss-resolve-nested-selector@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz#29ccbc7c37dedfac304e9fff0bf1596b3f6a0e4e" - integrity sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw== - -postcss-safe-parser@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz#bb4c29894171a94bc5c996b9a30317ef402adaa1" - integrity sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ== +postcss-safe-parser@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz#36e4f7e608111a0ca940fd9712ce034718c40ec0" + integrity sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A== postcss-selector-not@^9.0.0: version "9.0.0" @@ -15080,7 +15129,7 @@ postcss-selector-not@^9.0.0: dependencies: postcss-selector-parser "^7.1.1" -postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: +postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: version "6.1.2" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de" integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg== @@ -15128,7 +15177,7 @@ postcss-zindex@^7.0.2: resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-7.0.2.tgz#739ce60df05f5c6a9057b43674382ec6f56b8e58" integrity sha512-Vw8MG8FIxP97KBJ3bJkMcU1n8JUs9T3tHU7wI3RfRpf7FbThjb6Npt3ivJWN18RHMMXRt6OG4ak9U7h5tXHwRQ== -postcss@^8.2.x, postcss@^8.4.19, postcss@^8.4.21, postcss@^8.4.33, postcss@^8.4.40, postcss@^8.5.12, postcss@^8.5.14: +postcss@^8.2.x, postcss@^8.4.21, postcss@^8.4.33, postcss@^8.4.40, postcss@^8.5.12, postcss@^8.5.14: version "8.5.14" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.14.tgz#a66c2d7808fadf69ebb5b84a03f8bafd76c4919c" integrity sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg== @@ -15331,6 +15380,13 @@ pvutils@^1.1.3: resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.1.5.tgz#84b0dea4a5d670249aa9800511804ee0b7c2809c" integrity sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA== +qified@^0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/qified/-/qified-0.10.1.tgz#0640bf21bbe6ca540db290ad8f5fde4d870b8bda" + integrity sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA== + dependencies: + hookified "^2.1.1" + qs@6.13.0: version "6.13.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" @@ -16814,6 +16870,11 @@ slash@^2.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== +slash@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-5.1.0.tgz#be3adddcdf09ac38eebe8dcdc7b1a57a75b095ce" + integrity sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg== + slice-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" @@ -17159,7 +17220,7 @@ string-width@^7.0.0: get-east-asian-width "^1.0.0" strip-ansi "^7.1.0" -string-width@^8.2.0: +string-width@^8.2.0, string-width@^8.2.1: version "8.2.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-8.2.1.tgz#165089cfa527cc88fbc23dd73313f5e334af1ea1" integrity sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA== @@ -17347,11 +17408,6 @@ strong-log-transformer@2.1.0, strong-log-transformer@^2.1.0: minimist "^1.2.0" through "^2.3.4" -style-search@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" - integrity sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg== - style-to-object@^0.4.0: version "0.4.4" resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.4.4.tgz#266e3dfd56391a7eefb7770423612d043c3f33ec" @@ -17374,66 +17430,58 @@ stylehacks@^7.0.10: browserslist "^4.28.2" postcss-selector-parser "^7.1.1" -stylelint-config-prettier@^9.0.5: - version "9.0.5" - resolved "https://registry.yarnpkg.com/stylelint-config-prettier/-/stylelint-config-prettier-9.0.5.tgz#9f78bbf31c7307ca2df2dd60f42c7014ee9da56e" - integrity sha512-U44lELgLZhbAD/xy/vncZ2Pq8sh2TnpiPvo38Ifg9+zeioR+LAkHu0i6YORIOxFafZoVg0xqQwex6e6F25S5XA== +stylelint-config-recommended@^18.0.0: + version "18.0.0" + resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-18.0.0.tgz#1d86be73565c3cd5e6babb8abcc932012a86bd76" + integrity sha512-mxgT2XY6YZ3HWWe3Di8umG6aBmWmHTblTgu/f10rqFXnyWxjKWwNdjSWkgkwCtxIKnqjSJzvFmPT5yabVIRxZg== -stylelint-config-recommended@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-9.0.0.tgz#1c9e07536a8cd875405f8ecef7314916d94e7e40" - integrity sha512-9YQSrJq4NvvRuTbzDsWX3rrFOzOlYBmZP+o513BJN/yfEmGSr0AxdvrWs0P/ilSpVV/wisamAHu5XSk8Rcf4CQ== - -stylelint-config-standard@^29.0.0: - version "29.0.0" - resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-29.0.0.tgz#4cc0e0f05512a39bb8b8e97853247d3a95d66fa2" - integrity sha512-uy8tZLbfq6ZrXy4JKu3W+7lYLgRQBxYTUUB88vPgQ+ZzAxdrvcaSUW9hOMNLYBnwH+9Kkj19M2DHdZ4gKwI7tg== +stylelint-config-standard@^40.0.0: + version "40.0.0" + resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-40.0.0.tgz#6bb72b94f8be434cdf2902ba26b2167d572c5414" + integrity sha512-EznGJxOUhtWck2r6dJpbgAdPATIzvpLdK9+i5qPd4Lx70es66TkBPljSg4wN3Qnc6c4h2n+WbUrUynQ3fanjHw== dependencies: - stylelint-config-recommended "^9.0.0" + stylelint-config-recommended "^18.0.0" -stylelint@^14.16.1: - version "14.16.1" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.16.1.tgz#b911063530619a1bbe44c2b875fd8181ebdc742d" - integrity sha512-ErlzR/T3hhbV+a925/gbfc3f3Fep9/bnspMiJPorfGEmcBbXdS+oo6LrVtoUZ/w9fqD6o6k7PtUlCOsCRdjX/A== +stylelint@^17.12.0: + version "17.12.0" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-17.12.0.tgz#388d3fb56bebbb816f1043c8cc1c290bf5a889ab" + integrity sha512-KIlzWXMHUvgfPUR0R7TK3H80yCIi0uoivUwf+6Az4yrHJD1Q3c1qIkh/H5Z0i/K3QXgtq/UMEkWyBUSUwnpnOg== dependencies: - "@csstools/selector-specificity" "^2.0.2" - balanced-match "^2.0.0" + "@csstools/css-calc" "^3.2.0" + "@csstools/css-parser-algorithms" "^4.0.0" + "@csstools/css-syntax-patches-for-csstree" "^1.1.3" + "@csstools/css-tokenizer" "^4.0.0" + "@csstools/media-query-list-parser" "^5.0.0" + "@csstools/selector-resolve-nested" "^4.0.0" + "@csstools/selector-specificity" "^6.0.0" colord "^2.9.3" - cosmiconfig "^7.1.0" - css-functions-list "^3.1.0" - debug "^4.3.4" - fast-glob "^3.2.12" + cosmiconfig "^9.0.1" + css-functions-list "^3.3.3" + css-tree "^3.2.1" + debug "^4.4.3" + fast-glob "^3.3.3" fastest-levenshtein "^1.0.16" - file-entry-cache "^6.0.1" + file-entry-cache "^11.1.3" global-modules "^2.0.0" - globby "^11.1.0" + globby "^16.2.0" globjoin "^0.1.4" - html-tags "^3.2.0" - ignore "^5.2.1" - import-lazy "^4.0.0" - imurmurhash "^0.1.4" - is-plain-object "^5.0.0" - known-css-properties "^0.26.0" - mathml-tag-names "^2.1.3" - meow "^9.0.0" - micromatch "^4.0.5" + html-tags "^5.1.0" + ignore "^7.0.5" + import-meta-resolve "^4.2.0" + mathml-tag-names "^4.0.0" + meow "^14.1.0" + micromatch "^4.0.8" normalize-path "^3.0.0" - picocolors "^1.0.0" - postcss "^8.4.19" - postcss-media-query-parser "^0.2.3" - postcss-resolve-nested-selector "^0.1.1" - postcss-safe-parser "^6.0.0" - postcss-selector-parser "^6.0.11" + picocolors "^1.1.1" + postcss "^8.5.14" + postcss-safe-parser "^7.0.1" + postcss-selector-parser "^7.1.1" postcss-value-parser "^4.2.0" - resolve-from "^5.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - style-search "^0.1.0" - supports-hyperlinks "^2.3.0" + string-width "^8.2.1" + supports-hyperlinks "^4.4.0" svg-tags "^1.0.0" - table "^6.8.1" - v8-compile-cache "^2.3.0" - write-file-atomic "^4.0.2" + table "^6.9.0" + write-file-atomic "^7.0.1" stylis@^4.3.6: version "4.3.6" @@ -17465,7 +17513,7 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -supports-color@^7.0.0, supports-color@^7.1.0: +supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -17479,13 +17527,13 @@ supports-color@^8.0.0, supports-color@^8.1.1: dependencies: has-flag "^4.0.0" -supports-hyperlinks@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" - integrity sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA== +supports-hyperlinks@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-4.4.0.tgz#b25ed8e5ef67388d1ce1e83029c07df19d36b870" + integrity sha512-UKbpT93hN5Nr9go5UY7bopIB9YQlMz9nm/ct4IXt/irb5YRkn9WaqrOBJGZ5Pwvsd5FQzSVeYlGdXoCAPQZrPg== dependencies: - has-flag "^4.0.0" - supports-color "^7.0.0" + has-flag "^5.0.1" + supports-color "^10.2.2" supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" @@ -17602,10 +17650,10 @@ syncpack@^14.3.1: syncpack-windows-arm64 "14.3.1" syncpack-windows-x64 "14.3.1" -table@^6.8.1: - version "6.8.1" - resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf" - integrity sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA== +table@^6.9.0: + version "6.9.0" + resolved "https://registry.yarnpkg.com/table/-/table-6.9.0.tgz#50040afa6264141c7566b3b81d4d82c47a8668f5" + integrity sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A== dependencies: ajv "^8.0.1" lodash.truncate "^4.4.2" @@ -18203,6 +18251,11 @@ unicode-property-aliases-ecmascript@^2.0.0: resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== +unicorn-magic@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.4.0.tgz#78c6a090fd6d07abd2468b83b385603e00dfdb24" + integrity sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw== + unified@^11.0.0, unified@^11.0.3, unified@^11.0.4: version "11.0.5" resolved "https://registry.yarnpkg.com/unified/-/unified-11.0.5.tgz#f66677610a5c0a9ee90cab2b8d4d66037026d9e1" @@ -18480,7 +18533,7 @@ uuid@^9.0.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== -v8-compile-cache@2.3.0, v8-compile-cache@^2.3.0: +v8-compile-cache@2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== @@ -19202,13 +19255,12 @@ write-file-atomic@^3.0.3: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -write-file-atomic@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" - integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== +write-file-atomic@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-7.0.1.tgz#0e2a450ab5aa306bcfcd3aed61833b10cc4fb885" + integrity sha512-OTIk8iR8/aCRWBqvxrzxR0hgxWpnYBblY1S5hDWBQfk/VFmJwzmJgQFN3WsoUKHISv2eAwe+PpbUzyL1CKTLXg== dependencies: - imurmurhash "^0.1.4" - signal-exit "^3.0.7" + signal-exit "^4.0.1" write-json-file@^3.2.0: version "3.2.0" @@ -19300,11 +19352,6 @@ yallist@^5.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-5.0.0.tgz#00e2de443639ed0d78fd87de0d27469fbcffb533" integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== -yaml@^1.10.0: - version "1.10.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== - yaml@^2.2.2, yaml@^2.7.0, yaml@^2.8.4: version "2.8.4" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.4.tgz#4b5f411dd25f9544914d8673d4da7f29248e5e2e" From 34656d725ce6466bd965d4fe268765de2e6eb4be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Fri, 29 May 2026 17:25:09 +0200 Subject: [PATCH 5/6] break(core): Remove legacy `postBuild({head})` API and v4 future flag (#12084) --- packages/docusaurus-types/src/config.d.ts | 1 - packages/docusaurus-types/src/plugin.d.ts | 5 - .../docusaurus/src/client/serverEntry.tsx | 11 +- .../src/client/serverHelmetUtils.tsx | 1 - .../src/commands/build/buildLocale.ts | 5 - packages/docusaurus/src/common.d.ts | 11 +- .../__snapshots__/config.test.ts.snap | 10 -- .../__tests__/__snapshots__/site.test.ts.snap | 12 -- .../server/__tests__/configValidation.test.ts | 123 ++---------------- .../docusaurus/src/server/configValidation.ts | 22 ---- packages/docusaurus/src/ssg/ssgParams.ts | 6 - packages/docusaurus/src/ssg/ssgRenderer.ts | 7 +- website/docs/api/docusaurus.config.js.mdx | 4 +- 13 files changed, 17 insertions(+), 201 deletions(-) diff --git a/packages/docusaurus-types/src/config.d.ts b/packages/docusaurus-types/src/config.d.ts index 6f88b68dc6c6..bb64bdbe9218 100644 --- a/packages/docusaurus-types/src/config.d.ts +++ b/packages/docusaurus-types/src/config.d.ts @@ -37,7 +37,6 @@ export type FasterConfig = { }; export type FutureV4Config = { - removeLegacyPostBuildHeadAttribute: boolean; useCssCascadeLayers: boolean; siteStorageNamespacing: boolean; fasterByDefault: boolean; diff --git a/packages/docusaurus-types/src/plugin.d.ts b/packages/docusaurus-types/src/plugin.d.ts index b3378247a4fa..53b3c8a1a547 100644 --- a/packages/docusaurus-types/src/plugin.d.ts +++ b/packages/docusaurus-types/src/plugin.d.ts @@ -10,7 +10,6 @@ import type {RuleSetRule, Configuration as WebpackConfiguration} from 'webpack'; import type {CustomizeRuleString} from 'webpack-merge/dist/types'; import type {CommanderStatic} from 'commander'; import type Joi from 'joi'; -import type {HelmetServerState} from 'react-helmet-async'; import type {ThemeConfig} from './config'; import type {LoadContext, Props} from './context'; import type {SwizzleConfig} from './swizzle'; @@ -137,10 +136,6 @@ export type Plugin = { postBuild?: ( props: Props & { content: Content; - // TODO Docusaurus v4: remove old messy unserializable "head" API - // breaking change, replaced by routesBuildMetadata - // Reason: https://github.com/facebook/docusaurus/pull/10826 - head: {[location: string]: HelmetServerState}; routesBuildMetadata: {[location: string]: RouteBuildMetadata}; }, ) => Promise | void; diff --git a/packages/docusaurus/src/client/serverEntry.tsx b/packages/docusaurus/src/client/serverEntry.tsx index 161e512cb54f..1ca10a1d3826 100644 --- a/packages/docusaurus/src/client/serverEntry.tsx +++ b/packages/docusaurus/src/client/serverEntry.tsx @@ -19,10 +19,7 @@ import { import {toPageCollectedMetadataInternal} from './serverHelmetUtils'; import type {AppRenderer, PageCollectedDataInternal} from '../common'; -const render: AppRenderer['render'] = async ({ - pathname, - v4RemoveLegacyPostBuildHeadAttribute, -}) => { +const render: AppRenderer['render'] = async ({pathname}) => { await preload(pathname); const modules = new Set(); @@ -49,12 +46,6 @@ const render: AppRenderer['render'] = async ({ const metadata = toPageCollectedMetadataInternal({helmet}); - // TODO Docusaurus v4 remove with deprecated postBuild({head}) API - // the returned collectedData must be serializable to run in workers - if (v4RemoveLegacyPostBuildHeadAttribute) { - metadata.helmet = null; - } - const collectedData: PageCollectedDataInternal = { metadata, anchors: statefulBrokenLinks.getCollectedAnchors(), diff --git a/packages/docusaurus/src/client/serverHelmetUtils.tsx b/packages/docusaurus/src/client/serverHelmetUtils.tsx index 9ee582a23170..d6b0d4c8a895 100644 --- a/packages/docusaurus/src/client/serverHelmetUtils.tsx +++ b/packages/docusaurus/src/client/serverHelmetUtils.tsx @@ -39,7 +39,6 @@ export function toPageCollectedMetadataInternal({ const noIndex = tags.some(isNoIndexTag); return { - helmet, // TODO Docusaurus v4 remove public: { noIndex, }, diff --git a/packages/docusaurus/src/commands/build/buildLocale.ts b/packages/docusaurus/src/commands/build/buildLocale.ts index bb04fedd038c..ffee1006594b 100644 --- a/packages/docusaurus/src/commands/build/buildLocale.ts +++ b/packages/docusaurus/src/commands/build/buildLocale.ts @@ -158,10 +158,6 @@ async function executePluginsPostBuild({ props: Props; collectedData: SiteCollectedData; }) { - const head = props.siteConfig.future.v4.removeLegacyPostBuildHeadAttribute - ? {} - : _.mapValues(collectedData, (d) => d.metadata.helmet!); - const routesBuildMetadata = _.mapValues( collectedData, (d) => d.metadata.public, @@ -174,7 +170,6 @@ async function executePluginsPostBuild({ } await plugin.postBuild({ ...props, - head, routesBuildMetadata, content: plugin.content, }); diff --git a/packages/docusaurus/src/common.d.ts b/packages/docusaurus/src/common.d.ts index dc6892676dc5..3873ee6cca72 100644 --- a/packages/docusaurus/src/common.d.ts +++ b/packages/docusaurus/src/common.d.ts @@ -8,7 +8,6 @@ // This file is for types that are common between client/server // In particular the interface between SSG and serverEntry code -import type {HelmetServerState} from 'react-helmet-async'; import type {RouteBuildMetadata} from '@docusaurus/types'; export type AppRenderResult = { @@ -17,12 +16,7 @@ export type AppRenderResult = { }; export type AppRenderer = { - render: (params: { - pathname: string; - - // TODO Docusaurus v4: remove deprecated postBuild({head}) API - v4RemoveLegacyPostBuildHeadAttribute: boolean; - }) => Promise; + render: (params: {pathname: string}) => Promise; // It's important to shut down the app renderer // Otherwise Node.js require cache leaks memory @@ -42,9 +36,6 @@ export type RouteBuildMetadataInternal = { export type PageCollectedMetadata = { public: RouteBuildMetadata; - // TODO Docusaurus v4 remove legacy unserializable helmet data structure - // See https://github.com/facebook/docusaurus/pull/10850 - helmet: HelmetServerState | null; }; // This data structure must remain serializable! diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap index e440cf9e52dd..229eb8ecc9d4 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap @@ -28,7 +28,6 @@ exports[`loadSiteConfig > website with .cjs siteConfig 1`] = ` "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -116,7 +115,6 @@ exports[`loadSiteConfig > website with ts + js config 1`] = ` "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -204,7 +202,6 @@ exports[`loadSiteConfig > website with valid JS CJS config 1`] = ` "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -292,7 +289,6 @@ exports[`loadSiteConfig > website with valid JS ESM config 1`] = ` "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -380,7 +376,6 @@ exports[`loadSiteConfig > website with valid TypeScript CJS config 1`] = ` "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -468,7 +463,6 @@ exports[`loadSiteConfig > website with valid TypeScript ESM config 1`] = ` "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -556,7 +550,6 @@ exports[`loadSiteConfig > website with valid async config 1`] = ` "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -646,7 +639,6 @@ exports[`loadSiteConfig > website with valid async config creator function 1`] = "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -736,7 +728,6 @@ exports[`loadSiteConfig > website with valid config creator function 1`] = ` "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -829,7 +820,6 @@ exports[`loadSiteConfig > website with valid siteConfig 1`] = ` "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/site.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/site.test.ts.snap index 205c3da6e255..0cda8a64877a 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/site.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/site.test.ts.snap @@ -108,7 +108,6 @@ exports[`loadSite > custom-i18n-site > loads site 1`] = ` "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -284,7 +283,6 @@ exports[`loadSite > simple-site-with-baseUrl > loads site - custom config 1`] = "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -452,7 +450,6 @@ exports[`loadSite > simple-site-with-baseUrl > loads site - custom outDir 1`] = "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -620,7 +617,6 @@ exports[`loadSite > simple-site-with-baseUrl > loads site 1`] = ` "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -832,7 +828,6 @@ exports[`loadSite > simple-site-with-baseUrl-i18n > loads site - locale fr + cu "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -1066,7 +1061,6 @@ exports[`loadSite > simple-site-with-baseUrl-i18n > loads site - custom outDir 1 "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -1300,7 +1294,6 @@ exports[`loadSite > simple-site-with-baseUrl-i18n > loads site - locale de 1`] = "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -1534,7 +1527,6 @@ exports[`loadSite > simple-site-with-baseUrl-i18n > loads site - locale en 1`] = "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -1768,7 +1760,6 @@ exports[`loadSite > simple-site-with-baseUrl-i18n > loads site - locale es 1`] = "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -2002,7 +1993,6 @@ exports[`loadSite > simple-site-with-baseUrl-i18n > loads site - locale fr 1`] = "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -2236,7 +2226,6 @@ exports[`loadSite > simple-site-with-baseUrl-i18n > loads site - locale it 1`] = "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, @@ -2470,7 +2459,6 @@ exports[`loadSite > simple-site-with-baseUrl-i18n > loads site 1`] = ` "v4": { "fasterByDefault": false, "mdx1CompatDisabledByDefault": false, - "removeLegacyPostBuildHeadAttribute": false, "siteStorageNamespacing": false, "useCssCascadeLayers": false, }, diff --git a/packages/docusaurus/src/server/__tests__/configValidation.test.ts b/packages/docusaurus/src/server/__tests__/configValidation.test.ts index b09c915fd0ae..63dce02913f5 100644 --- a/packages/docusaurus/src/server/__tests__/configValidation.test.ts +++ b/packages/docusaurus/src/server/__tests__/configValidation.test.ts @@ -63,7 +63,6 @@ describe('normalizeConfig', () => { }, future: { v4: { - removeLegacyPostBuildHeadAttribute: true, useCssCascadeLayers: true, siteStorageNamespacing: true, fasterByDefault: true, @@ -1343,7 +1342,6 @@ describe('future', () => { it('accepts future - full', () => { const future: DocusaurusConfig['future'] = { v4: { - removeLegacyPostBuildHeadAttribute: true, useCssCascadeLayers: true, siteStorageNamespacing: true, fasterByDefault: true, @@ -1727,34 +1725,26 @@ describe('future', () => { ).toEqual(fasterContaining(DEFAULT_FASTER_CONFIG_TRUE)); }); - it('rejects faster - true (v4: false)', () => { - expect(() => + it('accepts faster - true (v4: false)', () => { + expect( normalizeConfig({ future: { v4: false, faster: true, }, }), - ).toThrowErrorMatchingInlineSnapshot(` - [Error: Docusaurus config \`future.faster.ssgWorkerThreads\` requires the future flag \`future.v4.removeLegacyPostBuildHeadAttribute\` to be turned on. - If you use Docusaurus Faster, we recommend that you also activate Docusaurus v4 future flags: \`{future: {v4: true}}\` - All the v4 future flags are documented here: https://docusaurus.io/docs/api/docusaurus-config#future] - `); + ).toEqual(fasterContaining(DEFAULT_FASTER_CONFIG_TRUE)); }); - it('rejects faster - true (v4: undefined)', () => { - expect(() => + it('accepts faster - true (v4: undefined)', () => { + expect( normalizeConfig({ future: { - v4: false, + v4: undefined, faster: true, }, }), - ).toThrowErrorMatchingInlineSnapshot(` - [Error: Docusaurus config \`future.faster.ssgWorkerThreads\` requires the future flag \`future.v4.removeLegacyPostBuildHeadAttribute\` to be turned on. - If you use Docusaurus Faster, we recommend that you also activate Docusaurus v4 future flags: \`{future: {v4: true}}\` - All the v4 future flags are documented here: https://docusaurus.io/docs/api/docusaurus-config#future] - `); + ).toEqual(fasterContaining(DEFAULT_FASTER_CONFIG_TRUE)); }); it('rejects faster - number', () => { @@ -2330,40 +2320,32 @@ describe('future', () => { ).toEqual(fasterContaining({ssgWorkerThreads: true})); }); - it('rejects - true (v4: false)', () => { + it('accepts - true (v4: false)', () => { const faster: Partial = { ssgWorkerThreads: true, }; - expect(() => + expect( normalizeConfig({ future: { v4: false, faster, }, }), - ).toThrowErrorMatchingInlineSnapshot(` - [Error: Docusaurus config \`future.faster.ssgWorkerThreads\` requires the future flag \`future.v4.removeLegacyPostBuildHeadAttribute\` to be turned on. - If you use Docusaurus Faster, we recommend that you also activate Docusaurus v4 future flags: \`{future: {v4: true}}\` - All the v4 future flags are documented here: https://docusaurus.io/docs/api/docusaurus-config#future] - `); + ).toEqual(fasterContaining({ssgWorkerThreads: true})); }); - it('rejects - true (v4: undefined)', () => { + it('accepts - true (v4: undefined)', () => { const faster: Partial = { ssgWorkerThreads: true, }; - expect(() => + expect( normalizeConfig({ future: { v4: undefined, faster, }, }), - ).toThrowErrorMatchingInlineSnapshot(` - [Error: Docusaurus config \`future.faster.ssgWorkerThreads\` requires the future flag \`future.v4.removeLegacyPostBuildHeadAttribute\` to be turned on. - If you use Docusaurus Faster, we recommend that you also activate Docusaurus v4 future flags: \`{future: {v4: true}}\` - All the v4 future flags are documented here: https://docusaurus.io/docs/api/docusaurus-config#future] - `); + ).toEqual(fasterContaining({ssgWorkerThreads: true})); }); it('accepts - false', () => { @@ -2497,7 +2479,6 @@ describe('future', () => { future: { v4: { fasterByDefault: true, - removeLegacyPostBuildHeadAttribute: true, }, }, }), @@ -2510,7 +2491,6 @@ describe('future', () => { future: { v4: { fasterByDefault: true, - removeLegacyPostBuildHeadAttribute: true, }, faster: {swcJsLoader: false}, }, @@ -2562,7 +2542,6 @@ describe('future', () => { it('accepts v4 - full', () => { const v4: FutureV4Config = { - removeLegacyPostBuildHeadAttribute: true, useCssCascadeLayers: true, siteStorageNamespacing: true, fasterByDefault: true, @@ -2608,81 +2587,6 @@ describe('future', () => { `); }); - describe('removeLegacyPostBuildHeadAttribute', () => { - it('accepts - undefined', () => { - const v4: Partial = { - removeLegacyPostBuildHeadAttribute: undefined, - }; - expect( - normalizeConfig({ - future: { - v4, - }, - }), - ).toEqual(v4Containing({removeLegacyPostBuildHeadAttribute: false})); - }); - - it('accepts - true', () => { - const v4: Partial = { - removeLegacyPostBuildHeadAttribute: true, - }; - expect( - normalizeConfig({ - future: { - v4, - }, - }), - ).toEqual(v4Containing({removeLegacyPostBuildHeadAttribute: true})); - }); - - it('accepts - false', () => { - const v4: Partial = { - removeLegacyPostBuildHeadAttribute: false, - }; - expect( - normalizeConfig({ - future: { - v4, - }, - }), - ).toEqual(v4Containing({removeLegacyPostBuildHeadAttribute: false})); - }); - - it('rejects - null', () => { - const v4: Partial = { - // @ts-expect-error: invalid - removeLegacyPostBuildHeadAttribute: 42, - }; - expect(() => - normalizeConfig({ - future: { - v4, - }, - }), - ).toThrowErrorMatchingInlineSnapshot(` - [Error: "future.v4.removeLegacyPostBuildHeadAttribute" must be a boolean - ] - `); - }); - - it('rejects - number', () => { - const v4: Partial = { - // @ts-expect-error: invalid - removeLegacyPostBuildHeadAttribute: 42, - }; - expect(() => - normalizeConfig({ - future: { - v4, - }, - }), - ).toThrowErrorMatchingInlineSnapshot(` - [Error: "future.v4.removeLegacyPostBuildHeadAttribute" must be a boolean - ] - `); - }); - }); - describe('useCssCascadeLayers', () => { it('accepts - undefined', () => { const v4: Partial = { @@ -2849,7 +2753,6 @@ describe('future', () => { it('accepts - true', () => { const v4: Partial = { fasterByDefault: true, - removeLegacyPostBuildHeadAttribute: true, }; expect( normalizeConfig({ diff --git a/packages/docusaurus/src/server/configValidation.ts b/packages/docusaurus/src/server/configValidation.ts index 724f4ea70cf2..462e5b2274d6 100644 --- a/packages/docusaurus/src/server/configValidation.ts +++ b/packages/docusaurus/src/server/configValidation.ts @@ -99,7 +99,6 @@ export const DEFAULT_FASTER_CONFIG_TRUE: FasterConfig = { }; export const DEFAULT_FUTURE_V4_CONFIG: FutureV4Config = { - removeLegacyPostBuildHeadAttribute: false, useCssCascadeLayers: false, siteStorageNamespacing: false, fasterByDefault: false, @@ -108,7 +107,6 @@ export const DEFAULT_FUTURE_V4_CONFIG: FutureV4Config = { // When using the "v4: true" shortcut export const DEFAULT_FUTURE_V4_CONFIG_TRUE: FutureV4Config = { - removeLegacyPostBuildHeadAttribute: true, useCssCascadeLayers: true, siteStorageNamespacing: true, fasterByDefault: true, @@ -315,9 +313,6 @@ const FASTER_CONFIG_SCHEMA = Joi.alternatives() const FUTURE_V4_SCHEMA = Joi.alternatives() .try( Joi.object({ - removeLegacyPostBuildHeadAttribute: Joi.boolean().default( - DEFAULT_FUTURE_V4_CONFIG.removeLegacyPostBuildHeadAttribute, - ), useCssCascadeLayers: Joi.boolean().default( DEFAULT_FUTURE_V4_CONFIG.useCssCascadeLayers, ), @@ -619,23 +614,6 @@ Please migrate and move this option to code=${'siteConfig.markdown.hooks.onBroke config.future.experimental_vcs = vcsConfig; } - if ( - config.future.faster.ssgWorkerThreads && - !config.future.v4.removeLegacyPostBuildHeadAttribute - ) { - throw new Error( - `Docusaurus config ${logger.code( - 'future.faster.ssgWorkerThreads', - )} requires the future flag ${logger.code( - 'future.v4.removeLegacyPostBuildHeadAttribute', - )} to be turned on. -If you use Docusaurus Faster, we recommend that you also activate Docusaurus v4 future flags: ${logger.code( - '{future: {v4: true}}', - )} -All the v4 future flags are documented here: https://docusaurus.io/docs/api/docusaurus-config#future`, - ); - } - if ( config.future.faster.rspackPersistentCache && !config.future.faster.rspackBundler diff --git a/packages/docusaurus/src/ssg/ssgParams.ts b/packages/docusaurus/src/ssg/ssgParams.ts index 7a11633e044e..9f32259922b7 100644 --- a/packages/docusaurus/src/ssg/ssgParams.ts +++ b/packages/docusaurus/src/ssg/ssgParams.ts @@ -30,9 +30,6 @@ export type SSGParams = { htmlMinifierType: HtmlMinifierType; serverBundlePath: string; ssgTemplateContent: string; - - // TODO Docusaurus v4: remove deprecated postBuild({head}) API - v4RemoveLegacyPostBuildHeadAttribute: boolean; }; export async function createSSGParams({ @@ -64,9 +61,6 @@ export async function createSSGParams({ htmlMinifierType: props.siteConfig.future.faster.swcHtmlMinimizer ? 'swc' : 'terser', - - v4RemoveLegacyPostBuildHeadAttribute: - props.siteConfig.future.v4.removeLegacyPostBuildHeadAttribute, }; // Useless but ensures that SSG params remain serializable diff --git a/packages/docusaurus/src/ssg/ssgRenderer.ts b/packages/docusaurus/src/ssg/ssgRenderer.ts index 0955f0367daa..f34206e636b5 100644 --- a/packages/docusaurus/src/ssg/ssgRenderer.ts +++ b/packages/docusaurus/src/ssg/ssgRenderer.ts @@ -162,7 +162,6 @@ function reduceCollectedData( anchors: pageCollectedData.anchors, metadata: { public: pageCollectedData.metadata.public, - helmet: pageCollectedData.metadata.helmet, }, links: pageCollectedData.links, }; @@ -183,11 +182,7 @@ async function generateStaticFile({ }): Promise { try { // This only renders the app HTML - const appRenderResult = await appRenderer.render({ - pathname, - v4RemoveLegacyPostBuildHeadAttribute: - params.v4RemoveLegacyPostBuildHeadAttribute, - }); + const appRenderResult = await appRenderer.render({pathname}); // This renders the full page HTML, including head tags... const fullPageHtml = renderSSGTemplate({ params, diff --git a/website/docs/api/docusaurus.config.js.mdx b/website/docs/api/docusaurus.config.js.mdx index 0443e4adc40c..414a4a1a0878 100644 --- a/website/docs/api/docusaurus.config.js.mdx +++ b/website/docs/api/docusaurus.config.js.mdx @@ -250,7 +250,6 @@ Example: export default { future: { v4: { - removeLegacyPostBuildHeadAttribute: true, useCssCascadeLayers: true, siteStorageNamespacing: true, fasterByDefault: true, @@ -272,7 +271,6 @@ export default { ``` - `v4`: Permits to opt-in for upcoming Docusaurus v4 breaking changes and features, to prepare your site in advance for this new version. Use `true` as a shorthand to enable all the flags. - - [`removeLegacyPostBuildHeadAttribute`](https://github.com/facebook/docusaurus/pull/10435): Removes the legacy `plugin.postBuild({head})` API that prevents us from applying useful SSG optimizations ([explanations](https://github.com/facebook/docusaurus/pull/10850)). - [`useCssCascadeLayers`](https://github.com/facebook/docusaurus/pull/11142): This enables the [Docusaurus CSS Cascade Layers plugin](./plugins/plugin-css-cascade-layers.mdx) with pre-configured layers that we plan to apply by default for Docusaurus v4. - [`siteStorageNamespacing`](https://github.com/facebook/docusaurus/pull/11797): Defaults the [`storage.namespace`](#storage) config to `true` instead of `false`. This enables automatic browser storage key namespacing, which avoids storage key conflicts when multiple Docusaurus sites are hosted under the same domain, or on localhost. - [`fasterByDefault`](https://github.com/facebook/docusaurus/pull/11802): Defaults all `future.faster` flags to `true` instead of `false`. This enables [Docusaurus Faster](https://github.com/facebook/docusaurus/issues/10556) features by default. Requires having `@docusaurus/faster` in your dependencies. If you explicitly set individual `faster` flags, those explicit values take precedence. @@ -285,7 +283,7 @@ export default { - [`rspackBundler`](https://github.com/facebook/docusaurus/pull/10402): Use [Rspack](https://rspack.dev/) to bundle your app (instead of [webpack](https://webpack.js.org/)). - [`rspackPersistentCache`](https://github.com/facebook/docusaurus/pull/10931): Use [Rspack Persistent Cache](https://rspack.dev/config/cache) to re-build your app faster on subsequent builds. Requires `rspackBundler: true`. Requires persisting `./node_modules/.cache` across rebuilds. - [`mdxCrossCompilerCache`](https://github.com/facebook/docusaurus/pull/10479): Compile MDX files only once for both browser/Node.js environments instead of twice. - - [`ssgWorkerThreads`](https://github.com/facebook/docusaurus/pull/10826): Using a Node.js worker thread pool to execute the static site generation phase faster. Requires `future.v4.removeLegacyPostBuildHeadAttribute` to be turned on. + - [`ssgWorkerThreads`](https://github.com/facebook/docusaurus/pull/10826): Using a Node.js worker thread pool to execute the static site generation phase faster. - [`gitEagerVcs`](https://github.com/facebook/docusaurus/pull/11512): Upgrades the default [VCS strategy](#vcs) to `default-v2`, that reads your whole Git repository at once instead of per-file, making Git operations faster on large repositories. - `experimental_router`: The router type to use. Possible values are `browser` and `hash`. Defaults to `browser`. The `hash` router is only useful for rare cases where you want to opt-out of static site generation, have a fully client-side app with a single `index.html` entrypoint file. This can be useful to distribute a Docusaurus site as a `.zip` archive that you can [browse locally without running a web server](https://github.com/facebook/docusaurus/issues/3825). - [`experimental_vcs`](#vcs): The Version Control System (VCS) implementation to use to read file info (creation/last update date/author). Read the [dedicated section](#vcs) below for details. From e35d0987dd2db9a09137e3fd97da4032075c9084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Fri, 29 May 2026 17:36:17 +0200 Subject: [PATCH 6/6] break(theme-common): Remove deprecated `useColorMode` APIs (AI-assisted) (#12085) --- .../src/contexts/colorMode.tsx | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/packages/docusaurus-theme-common/src/contexts/colorMode.tsx b/packages/docusaurus-theme-common/src/contexts/colorMode.tsx index 6f4def96b969..e4a171ba7d5b 100644 --- a/packages/docusaurus-theme-common/src/contexts/colorMode.tsx +++ b/packages/docusaurus-theme-common/src/contexts/colorMode.tsx @@ -55,12 +55,6 @@ type ContextValue = { readonly colorModeChoice: ColorModeChoice; /** Set new color mode. */ readonly setColorMode: (colorMode: ColorModeChoice) => void; - - // TODO Docusaurus v4 - // legacy APIs kept for retro-compatibility: deprecate them - readonly isDarkTheme: boolean; - readonly setLightTheme: () => void; - readonly setDarkTheme: () => void; }; const Context = React.createContext(undefined); @@ -237,30 +231,6 @@ function useContextValue(): ContextValue { colorMode, colorModeChoice, setColorMode, - get isDarkTheme() { - if (process.env.NODE_ENV === 'development') { - console.error( - '`useColorMode().isDarkTheme` is deprecated. Please use `useColorMode().colorMode === "dark"` instead.', - ); - } - return colorMode === 'dark'; - }, - setLightTheme() { - if (process.env.NODE_ENV === 'development') { - console.error( - '`useColorMode().setLightTheme` is deprecated. Please use `useColorMode().setColorMode("light")` instead.', - ); - } - setColorMode('light'); - }, - setDarkTheme() { - if (process.env.NODE_ENV === 'development') { - console.error( - '`useColorMode().setDarkTheme` is deprecated. Please use `useColorMode().setColorMode("dark")` instead.', - ); - } - setColorMode('dark'); - }, }), [colorMode, colorModeChoice, setColorMode], );