From e677256915c37c830e9c1863404253b557158e50 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Wed, 18 May 2022 22:07:59 +0300 Subject: [PATCH 01/35] docs: add custom plugin for tabs --- docs/MockFunctionAPI.md | 114 ++++------------------------ website/docusaurus.config.js | 1 + website/package.json | 3 +- website/src/remark/tabs-plugin.js | 120 ++++++++++++++++++++++++++++++ yarn.lock | 1 + 5 files changed, 140 insertions(+), 99 deletions(-) create mode 100644 website/src/remark/tabs-plugin.js diff --git a/docs/MockFunctionAPI.md b/docs/MockFunctionAPI.md index 0ac4de121f65..cedd8d50d7b4 100644 --- a/docs/MockFunctionAPI.md +++ b/docs/MockFunctionAPI.md @@ -17,8 +17,6 @@ import {jest} from '@jest/globals'; ## Methods -import TOCInline from '@theme/TOCInline'; - --- @@ -159,10 +157,7 @@ Accepts a function that should be used as the implementation of the mock. The mo ::: - - - -```js +```js tab const mockFn = jest.fn(scalar => 42 + scalar); mockFn(0); // 42 @@ -174,11 +169,7 @@ mockFn(2); // 38 mockFn(3); // 39 ``` - - - - -```js +```ts tab const mockFn = jest.fn((scalar: number) => 42 + scalar); mockFn(0); // 42 @@ -190,9 +181,6 @@ mockFn(2); // 38 mockFn(3); // 39 ``` - - - `.mockImplementation()` can also be used to mock class constructors: @@ -257,10 +245,7 @@ console.log('Calls to method: ', mockMethod.mock.calls); Accepts a function that will be used as an implementation of the mock for one call to the mocked function. Can be chained so that multiple function calls produce different results. - - - -```js +```js tab const mockFn = jest .fn() .mockImplementationOnce(cb => cb(null, true)) @@ -270,11 +255,7 @@ mockFn((err, val) => console.log(val)); // true mockFn((err, val) => console.log(val)); // false ``` - - - - -```ts +```ts tab const mockFn = jest .fn<(cb: (a: null, b: boolean) => void) => void>() .mockImplementationOnce(cb => cb(null, true)) @@ -284,9 +265,6 @@ mockFn((err, val) => console.log(val)); // true mockFn((err, val) => console.log(val)); // false ``` - - - When the mocked function runs out of implementations defined with `.mockImplementationOnce()`, it will execute the default implementation set with `jest.fn(() => defaultValue)` or `.mockImplementation(() => defaultValue)` if they were called: ```js @@ -336,10 +314,7 @@ jest.fn(function () { Accepts a value that will be returned whenever the mock function is called. - - - -```js +```js tab const mock = jest.fn(); mock.mockReturnValue(42); @@ -349,11 +324,7 @@ mock.mockReturnValue(43); mock(); // 43 ``` - - - - -```ts +```ts tab const mock = jest.fn<() => number>(); mock.mockReturnValue(42); @@ -363,17 +334,11 @@ mock.mockReturnValue(43); mock(); // 43 ``` - - - ### `mockFn.mockReturnValueOnce(value)` Accepts a value that will be returned for one call to the mock function. Can be chained so that successive calls to the mock function return different values. When there are no more `mockReturnValueOnce` values to use, calls will return a value specified by `mockReturnValue`. - - - -```js +```js tab const mockFn = jest .fn() .mockReturnValue('default') @@ -386,11 +351,7 @@ mockFn(); // 'default' mockFn(); // 'default' ``` - - - - -```ts +```ts tab const mockFn = jest .fn<() => string>() .mockReturnValue('default') @@ -403,9 +364,6 @@ mockFn(); // 'default' mockFn(); // 'default' ``` - - - ### `mockFn.mockResolvedValue(value)` Syntactic sugar function for: @@ -416,10 +374,7 @@ jest.fn().mockImplementation(() => Promise.resolve(value)); Useful to mock async functions in async tests: - - - -```js +```js tab test('async test', async () => { const asyncMock = jest.fn().mockResolvedValue(43); @@ -427,11 +382,7 @@ test('async test', async () => { }); ``` - - - - -```ts +```ts tab test('async test', async () => { const asyncMock = jest.fn<() => Promise>().mockResolvedValue(43); @@ -439,9 +390,6 @@ test('async test', async () => { }); ``` - - - ### `mockFn.mockResolvedValueOnce(value)` Syntactic sugar function for: @@ -452,10 +400,7 @@ jest.fn().mockImplementationOnce(() => Promise.resolve(value)); Useful to resolve different values over multiple async calls: - - - -```js +```js tab test('async test', async () => { const asyncMock = jest .fn() @@ -470,11 +415,7 @@ test('async test', async () => { }); ``` - - - - -```ts +```ts tab test('async test', async () => { const asyncMock = jest .fn<() => Promise>() @@ -489,9 +430,6 @@ test('async test', async () => { }); ``` - - - ### `mockFn.mockRejectedValue(value)` Syntactic sugar function for: @@ -502,10 +440,7 @@ jest.fn().mockImplementation(() => Promise.reject(value)); Useful to create async mock functions that will always reject: - - - -```js +```js tab test('async test', async () => { const asyncMock = jest .fn() @@ -515,11 +450,7 @@ test('async test', async () => { }); ``` - - - - -```ts +```ts tab test('async test', async () => { const asyncMock = jest .fn<() => Promise>() @@ -529,9 +460,6 @@ test('async test', async () => { }); ``` - - - ### `mockFn.mockRejectedValueOnce(value)` Syntactic sugar function for: @@ -542,10 +470,7 @@ jest.fn().mockImplementationOnce(() => Promise.reject(value)); Useful together with `.mockResolvedValueOnce()` or to reject with different exceptions over multiple async calls: - - - -```js +```js tab test('async test', async () => { const asyncMock = jest .fn() @@ -557,11 +482,7 @@ test('async test', async () => { }); ``` - - - - -```ts +```ts tab test('async test', async () => { const asyncMock = jest .fn<() => Promise>() @@ -573,9 +494,6 @@ test('async test', async () => { }); ``` - - - ## TypeScript Usage :::tip diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 8d57541950c8..c920c648e78e 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -56,6 +56,7 @@ module.exports = { sidebarPath: path.resolve(__dirname, './sidebars.json'), remarkPlugins: [ [require('@docusaurus/remark-plugin-npm2yarn'), {sync: true}], + require('./src/remark/tabs-plugin'), ], }, blog: { diff --git a/website/package.json b/website/package.json index a64446b8fdce..cdc12b5fbd20 100644 --- a/website/package.json +++ b/website/package.json @@ -40,7 +40,8 @@ "react-dom": "^17.0.1", "react-github-btn": "^1.2.0", "react-lite-youtube-embed": "^2.2.1-a", - "react-markdown": "^8.0.0" + "react-markdown": "^8.0.0", + "unist-util-visit": "^2.0.3" }, "devDependencies": { "@babel/core": "^7.11.6", diff --git a/website/src/remark/tabs-plugin.js b/website/src/remark/tabs-plugin.js new file mode 100644 index 000000000000..dcdb7d53b6c6 --- /dev/null +++ b/website/src/remark/tabs-plugin.js @@ -0,0 +1,120 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const visit = require('unist-util-visit'); + +const transformFirstTabNode = node => [ + { + type: 'jsx', + value: `\n`, + }, + { + type: node.type, + lang: node.lang, + value: node.value, + }, + { + type: 'jsx', + value: '', + }, +]; + +const transformLastTabNode = node => [ + { + type: 'jsx', + value: ``, + }, + { + type: node.type, + lang: node.lang, + value: node.value, + }, + { + type: 'jsx', + value: '\n', + }, +]; + +const isImport = node => node.type === 'import'; +const isParent = node => Array.isArray(node.children); +const isTab = node => node.type === 'code' && node.meta === 'tab'; + +const isFirstTab = (node, index, parent) => { + if (!isTab(node)) { + return false; + } + + const nextChild = parent.children[index + 1]; + const previousChild = parent.children[index - 1]; + + const isNextChildTab = nextChild ? isTab(nextChild) : false; + const isPreviousChildTab = previousChild ? isTab(previousChild) : false; + + return isNextChildTab && !isPreviousChildTab; +}; + +const isLastTab = (node, index, parent) => { + if (!isTab(node)) { + return false; + } + + const nextChild = parent.children[index + 1]; + const previousChild = parent.children[index - 1]; + + const isNextChildTab = nextChild ? isTab(nextChild) : false; + // it should be already transformed + const isPreviousChildTab = + previousChild?.type === 'jsx' && previousChild?.value === ''; + + return !isNextChildTab && isPreviousChildTab; +}; + +const importTabsNode = { + type: 'import', + value: + "import Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';", +}; + +const tabsPlugin = () => root => { + let hasTabs = false; + let hasImportTabsNode = false; + + visit(root, node => { + if (isImport(node) && node.value.includes('@theme/Tabs')) { + hasImportTabsNode = true; + } + + if (isParent(node)) { + let index = 0; + while (index < node.children.length) { + const child = node.children[index]; + + if (isFirstTab(child, index, node)) { + const result = transformFirstTabNode(child); + node.children.splice(index, 1, ...result); + + index += result.length; + hasTabs = true; + } else if (isLastTab(child, index, node)) { + const result = transformLastTabNode(child); + node.children.splice(index, 1, ...result); + + index += result.length; + hasTabs = true; + } else { + index += 1; + } + } + } + }); + + if (hasTabs && !hasImportTabsNode) { + root.children.unshift(importTabsNode); + } +}; + +module.exports = tabsPlugin; diff --git a/yarn.lock b/yarn.lock index 050470a7b40c..ea4040612246 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13721,6 +13721,7 @@ __metadata: react-github-btn: ^1.2.0 react-lite-youtube-embed: ^2.2.1-a react-markdown: ^8.0.0 + unist-util-visit: ^2.0.3 languageName: unknown linkType: soft From 587ce12e4ec98baac850e8259a158c9206281107 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Wed, 18 May 2022 22:14:14 +0300 Subject: [PATCH 02/35] ups.. bring back TOC --- docs/MockFunctionAPI.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/MockFunctionAPI.md b/docs/MockFunctionAPI.md index cedd8d50d7b4..a68233a07c8e 100644 --- a/docs/MockFunctionAPI.md +++ b/docs/MockFunctionAPI.md @@ -17,15 +17,14 @@ import {jest} from '@jest/globals'; ## Methods +import TOCInline from '@theme/TOCInline'; + --- ## Reference -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - ### `mockFn.getMockName()` Returns the mock name string set by calling `mockFn.mockName(value)`. From 24037f024139fcf591015620b365aa1c706b16b4 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Wed, 18 May 2022 22:19:31 +0300 Subject: [PATCH 03/35] copyright --- website/src/remark/tabs-plugin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/remark/tabs-plugin.js b/website/src/remark/tabs-plugin.js index dcdb7d53b6c6..9a2faa9cdb64 100644 --- a/website/src/remark/tabs-plugin.js +++ b/website/src/remark/tabs-plugin.js @@ -1,5 +1,5 @@ /** - * Copyright (c) Facebook, Inc. and its affiliates. + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. From 513c98ec9d7859d487493274a275c742d5eaae3e Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Wed, 18 May 2022 22:21:10 +0300 Subject: [PATCH 04/35] versioned docs --- .../version-28.0/MockFunctionAPI.md | 115 +++--------------- .../version-28.1/MockFunctionAPI.md | 115 +++--------------- 2 files changed, 32 insertions(+), 198 deletions(-) diff --git a/website/versioned_docs/version-28.0/MockFunctionAPI.md b/website/versioned_docs/version-28.0/MockFunctionAPI.md index 0ac4de121f65..a68233a07c8e 100644 --- a/website/versioned_docs/version-28.0/MockFunctionAPI.md +++ b/website/versioned_docs/version-28.0/MockFunctionAPI.md @@ -25,9 +25,6 @@ import TOCInline from '@theme/TOCInline'; ## Reference -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - ### `mockFn.getMockName()` Returns the mock name string set by calling `mockFn.mockName(value)`. @@ -159,10 +156,7 @@ Accepts a function that should be used as the implementation of the mock. The mo ::: - - - -```js +```js tab const mockFn = jest.fn(scalar => 42 + scalar); mockFn(0); // 42 @@ -174,11 +168,7 @@ mockFn(2); // 38 mockFn(3); // 39 ``` - - - - -```js +```ts tab const mockFn = jest.fn((scalar: number) => 42 + scalar); mockFn(0); // 42 @@ -190,9 +180,6 @@ mockFn(2); // 38 mockFn(3); // 39 ``` - - - `.mockImplementation()` can also be used to mock class constructors: @@ -257,10 +244,7 @@ console.log('Calls to method: ', mockMethod.mock.calls); Accepts a function that will be used as an implementation of the mock for one call to the mocked function. Can be chained so that multiple function calls produce different results. - - - -```js +```js tab const mockFn = jest .fn() .mockImplementationOnce(cb => cb(null, true)) @@ -270,11 +254,7 @@ mockFn((err, val) => console.log(val)); // true mockFn((err, val) => console.log(val)); // false ``` - - - - -```ts +```ts tab const mockFn = jest .fn<(cb: (a: null, b: boolean) => void) => void>() .mockImplementationOnce(cb => cb(null, true)) @@ -284,9 +264,6 @@ mockFn((err, val) => console.log(val)); // true mockFn((err, val) => console.log(val)); // false ``` - - - When the mocked function runs out of implementations defined with `.mockImplementationOnce()`, it will execute the default implementation set with `jest.fn(() => defaultValue)` or `.mockImplementation(() => defaultValue)` if they were called: ```js @@ -336,10 +313,7 @@ jest.fn(function () { Accepts a value that will be returned whenever the mock function is called. - - - -```js +```js tab const mock = jest.fn(); mock.mockReturnValue(42); @@ -349,11 +323,7 @@ mock.mockReturnValue(43); mock(); // 43 ``` - - - - -```ts +```ts tab const mock = jest.fn<() => number>(); mock.mockReturnValue(42); @@ -363,17 +333,11 @@ mock.mockReturnValue(43); mock(); // 43 ``` - - - ### `mockFn.mockReturnValueOnce(value)` Accepts a value that will be returned for one call to the mock function. Can be chained so that successive calls to the mock function return different values. When there are no more `mockReturnValueOnce` values to use, calls will return a value specified by `mockReturnValue`. - - - -```js +```js tab const mockFn = jest .fn() .mockReturnValue('default') @@ -386,11 +350,7 @@ mockFn(); // 'default' mockFn(); // 'default' ``` - - - - -```ts +```ts tab const mockFn = jest .fn<() => string>() .mockReturnValue('default') @@ -403,9 +363,6 @@ mockFn(); // 'default' mockFn(); // 'default' ``` - - - ### `mockFn.mockResolvedValue(value)` Syntactic sugar function for: @@ -416,10 +373,7 @@ jest.fn().mockImplementation(() => Promise.resolve(value)); Useful to mock async functions in async tests: - - - -```js +```js tab test('async test', async () => { const asyncMock = jest.fn().mockResolvedValue(43); @@ -427,11 +381,7 @@ test('async test', async () => { }); ``` - - - - -```ts +```ts tab test('async test', async () => { const asyncMock = jest.fn<() => Promise>().mockResolvedValue(43); @@ -439,9 +389,6 @@ test('async test', async () => { }); ``` - - - ### `mockFn.mockResolvedValueOnce(value)` Syntactic sugar function for: @@ -452,10 +399,7 @@ jest.fn().mockImplementationOnce(() => Promise.resolve(value)); Useful to resolve different values over multiple async calls: - - - -```js +```js tab test('async test', async () => { const asyncMock = jest .fn() @@ -470,11 +414,7 @@ test('async test', async () => { }); ``` - - - - -```ts +```ts tab test('async test', async () => { const asyncMock = jest .fn<() => Promise>() @@ -489,9 +429,6 @@ test('async test', async () => { }); ``` - - - ### `mockFn.mockRejectedValue(value)` Syntactic sugar function for: @@ -502,10 +439,7 @@ jest.fn().mockImplementation(() => Promise.reject(value)); Useful to create async mock functions that will always reject: - - - -```js +```js tab test('async test', async () => { const asyncMock = jest .fn() @@ -515,11 +449,7 @@ test('async test', async () => { }); ``` - - - - -```ts +```ts tab test('async test', async () => { const asyncMock = jest .fn<() => Promise>() @@ -529,9 +459,6 @@ test('async test', async () => { }); ``` - - - ### `mockFn.mockRejectedValueOnce(value)` Syntactic sugar function for: @@ -542,10 +469,7 @@ jest.fn().mockImplementationOnce(() => Promise.reject(value)); Useful together with `.mockResolvedValueOnce()` or to reject with different exceptions over multiple async calls: - - - -```js +```js tab test('async test', async () => { const asyncMock = jest .fn() @@ -557,11 +481,7 @@ test('async test', async () => { }); ``` - - - - -```ts +```ts tab test('async test', async () => { const asyncMock = jest .fn<() => Promise>() @@ -573,9 +493,6 @@ test('async test', async () => { }); ``` - - - ## TypeScript Usage :::tip diff --git a/website/versioned_docs/version-28.1/MockFunctionAPI.md b/website/versioned_docs/version-28.1/MockFunctionAPI.md index 0ac4de121f65..a68233a07c8e 100644 --- a/website/versioned_docs/version-28.1/MockFunctionAPI.md +++ b/website/versioned_docs/version-28.1/MockFunctionAPI.md @@ -25,9 +25,6 @@ import TOCInline from '@theme/TOCInline'; ## Reference -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - ### `mockFn.getMockName()` Returns the mock name string set by calling `mockFn.mockName(value)`. @@ -159,10 +156,7 @@ Accepts a function that should be used as the implementation of the mock. The mo ::: - - - -```js +```js tab const mockFn = jest.fn(scalar => 42 + scalar); mockFn(0); // 42 @@ -174,11 +168,7 @@ mockFn(2); // 38 mockFn(3); // 39 ``` - - - - -```js +```ts tab const mockFn = jest.fn((scalar: number) => 42 + scalar); mockFn(0); // 42 @@ -190,9 +180,6 @@ mockFn(2); // 38 mockFn(3); // 39 ``` - - - `.mockImplementation()` can also be used to mock class constructors: @@ -257,10 +244,7 @@ console.log('Calls to method: ', mockMethod.mock.calls); Accepts a function that will be used as an implementation of the mock for one call to the mocked function. Can be chained so that multiple function calls produce different results. - - - -```js +```js tab const mockFn = jest .fn() .mockImplementationOnce(cb => cb(null, true)) @@ -270,11 +254,7 @@ mockFn((err, val) => console.log(val)); // true mockFn((err, val) => console.log(val)); // false ``` - - - - -```ts +```ts tab const mockFn = jest .fn<(cb: (a: null, b: boolean) => void) => void>() .mockImplementationOnce(cb => cb(null, true)) @@ -284,9 +264,6 @@ mockFn((err, val) => console.log(val)); // true mockFn((err, val) => console.log(val)); // false ``` - - - When the mocked function runs out of implementations defined with `.mockImplementationOnce()`, it will execute the default implementation set with `jest.fn(() => defaultValue)` or `.mockImplementation(() => defaultValue)` if they were called: ```js @@ -336,10 +313,7 @@ jest.fn(function () { Accepts a value that will be returned whenever the mock function is called. - - - -```js +```js tab const mock = jest.fn(); mock.mockReturnValue(42); @@ -349,11 +323,7 @@ mock.mockReturnValue(43); mock(); // 43 ``` - - - - -```ts +```ts tab const mock = jest.fn<() => number>(); mock.mockReturnValue(42); @@ -363,17 +333,11 @@ mock.mockReturnValue(43); mock(); // 43 ``` - - - ### `mockFn.mockReturnValueOnce(value)` Accepts a value that will be returned for one call to the mock function. Can be chained so that successive calls to the mock function return different values. When there are no more `mockReturnValueOnce` values to use, calls will return a value specified by `mockReturnValue`. - - - -```js +```js tab const mockFn = jest .fn() .mockReturnValue('default') @@ -386,11 +350,7 @@ mockFn(); // 'default' mockFn(); // 'default' ``` - - - - -```ts +```ts tab const mockFn = jest .fn<() => string>() .mockReturnValue('default') @@ -403,9 +363,6 @@ mockFn(); // 'default' mockFn(); // 'default' ``` - - - ### `mockFn.mockResolvedValue(value)` Syntactic sugar function for: @@ -416,10 +373,7 @@ jest.fn().mockImplementation(() => Promise.resolve(value)); Useful to mock async functions in async tests: - - - -```js +```js tab test('async test', async () => { const asyncMock = jest.fn().mockResolvedValue(43); @@ -427,11 +381,7 @@ test('async test', async () => { }); ``` - - - - -```ts +```ts tab test('async test', async () => { const asyncMock = jest.fn<() => Promise>().mockResolvedValue(43); @@ -439,9 +389,6 @@ test('async test', async () => { }); ``` - - - ### `mockFn.mockResolvedValueOnce(value)` Syntactic sugar function for: @@ -452,10 +399,7 @@ jest.fn().mockImplementationOnce(() => Promise.resolve(value)); Useful to resolve different values over multiple async calls: - - - -```js +```js tab test('async test', async () => { const asyncMock = jest .fn() @@ -470,11 +414,7 @@ test('async test', async () => { }); ``` - - - - -```ts +```ts tab test('async test', async () => { const asyncMock = jest .fn<() => Promise>() @@ -489,9 +429,6 @@ test('async test', async () => { }); ``` - - - ### `mockFn.mockRejectedValue(value)` Syntactic sugar function for: @@ -502,10 +439,7 @@ jest.fn().mockImplementation(() => Promise.reject(value)); Useful to create async mock functions that will always reject: - - - -```js +```js tab test('async test', async () => { const asyncMock = jest .fn() @@ -515,11 +449,7 @@ test('async test', async () => { }); ``` - - - - -```ts +```ts tab test('async test', async () => { const asyncMock = jest .fn<() => Promise>() @@ -529,9 +459,6 @@ test('async test', async () => { }); ``` - - - ### `mockFn.mockRejectedValueOnce(value)` Syntactic sugar function for: @@ -542,10 +469,7 @@ jest.fn().mockImplementationOnce(() => Promise.reject(value)); Useful together with `.mockResolvedValueOnce()` or to reject with different exceptions over multiple async calls: - - - -```js +```js tab test('async test', async () => { const asyncMock = jest .fn() @@ -557,11 +481,7 @@ test('async test', async () => { }); ``` - - - - -```ts +```ts tab test('async test', async () => { const asyncMock = jest .fn<() => Promise>() @@ -573,9 +493,6 @@ test('async test', async () => { }); ``` - - - ## TypeScript Usage :::tip From fcdd6721bbbba1fb9076c455ba8085cb70d3cfcb Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Wed, 18 May 2022 22:27:04 +0300 Subject: [PATCH 05/35] restart CI From a91f1a4638f7467c09f9bea5633b3a56533beb87 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Thu, 19 May 2022 12:32:32 +0300 Subject: [PATCH 06/35] rework Configuration.md --- docs/Configuration.md | 535 ++++++------------------------------------ 1 file changed, 76 insertions(+), 459 deletions(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index 26769132330e..389169ccc708 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -3,9 +3,6 @@ id: configuration title: Configuring Jest --- -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - The Jest philosophy is to work great by default, but sometimes you just need more configuration power. It is recommended to define the configuration in a dedicated JavaScript, TypeScript or JSON file. The file will be discovered automatically, if it is named `jest.config.js|ts|mjs|cjs|json`. You can use [`--config`](CLI.md#--configpath) flag to pass an explicit path to the file. @@ -18,10 +15,7 @@ Keep in mind that the resulting configuration object must always be JSON-seriali The configuration file should simply export an object: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { verbose: true, @@ -30,11 +24,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -44,15 +34,9 @@ const config: Config = { export default config; ``` - - - Or a function returning an object: - - - -```js +```js tab /** @returns {Promise} */ module.exports = async () => { return { @@ -61,11 +45,7 @@ module.exports = async () => { }; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; export default async (): Promise => { @@ -75,9 +55,6 @@ export default async (): Promise => { }; ``` - - - :::tip To read TypeScript configuration files Jest requires [`ts-node`](https://npmjs.com/package/ts-node). Make sure it is installed in your project. @@ -110,10 +87,7 @@ Alternatively Jest's configuration can be defined through the `"jest"` key in th You can retrieve Jest's defaults from `jest-config` to extend them if needed: - - - -```js +```js tab const {defaults} = require('jest-config'); /** @type {import('jest').Config} */ @@ -124,11 +98,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; import {defaults} from 'jest-config'; @@ -139,9 +109,6 @@ const config: Config = { export default config; ``` - - - ::: import TOCInline from '@theme/TOCInline'; @@ -233,10 +200,7 @@ Default: `undefined` An array of [glob patterns](https://github.com/micromatch/micromatch) indicating a set of files for which coverage information should be collected. If a file matches the specified glob pattern, coverage information will be collected for it even if no tests exist for this file and it's never required in the test suite. - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { collectCoverageFrom: [ @@ -249,11 +213,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -267,9 +227,6 @@ const config: Config = { export default config; ``` - - - This will collect coverage information for all the files inside the project's `rootDir`, except the ones that match `**/node_modules/**` or `**/vendor/**`. :::tip @@ -336,10 +293,7 @@ Setting this option overwrites the default values. Add `"text"` or `"text-summar Additional options can be passed using the tuple form. For example, you may hide coverage report lines for all fully-covered files: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { coverageReporters: ['clover', 'json', 'lcov', ['text', {skipFull: true}]], @@ -348,11 +302,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -362,9 +312,6 @@ const config: Config = { export default config; ``` - - - For more information about the options object shape refer to `CoverageReporterWithOptions` type in the [type definitions](https://github.com/facebook/jest/tree/main/packages/jest-types/src/Config.ts). ### `coverageThreshold` \[object] @@ -375,10 +322,7 @@ This will be used to configure minimum threshold enforcement for coverage result For example, with the following configuration jest will fail if there is less than 80% branch, line, and function coverage, or if there are more than 10 uncovered statements: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { coverageThreshold: { @@ -394,11 +338,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -415,17 +355,11 @@ const config: Config = { export default config; ``` - - - If globs or paths are specified alongside `global`, coverage data for matching paths will be subtracted from overall coverage and thresholds will be applied independently. Thresholds for globs are applied to all files matching the glob. If the file specified by path is not found, an error is returned. For example, with the following configuration: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { coverageThreshold: { @@ -454,11 +388,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -488,9 +418,6 @@ const config: Config = { export default config; ``` - - - Jest will fail if: - The `./src/components` directory has less than 40% branch or statement coverage. @@ -533,10 +460,7 @@ default: `undefined` Allows for a label to be printed alongside a test while it is running. This becomes more useful in multi-project repositories where there can be many jest configuration files. This visually tells which project a test belongs to. - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { displayName: 'CLIENT', @@ -545,11 +469,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -559,15 +479,9 @@ const config: Config = { export default config; ``` - - - Alternatively, an object with the properties `name` and `color` can be passed. This allows for a custom configuration of the background color of the displayName. `displayName` defaults to white when its value is a string. Jest uses [`chalk`](https://github.com/chalk/chalk) to provide the color. As such, all of the valid options for colors supported by `chalk` are also supported by Jest. - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { displayName: { @@ -579,11 +493,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -596,9 +506,6 @@ const config: Config = { export default config; ``` - - - ### `errorOnDeprecated` \[boolean] Default: `false` @@ -611,10 +518,7 @@ Default: `[]` Jest will run `.mjs` and `.js` files with nearest `package.json`'s `type` field set to `module` as ECMAScript Modules. If you have any other files that should run with native ESM, you need to specify their file extension here. - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { extensionsToTreatAsEsm: ['.ts'], @@ -623,11 +527,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -637,9 +537,6 @@ const config: Config = { export default config; ``` - - - :::caution Jest's ESM support is still experimental, see [its docs for more details](ECMAScriptModules.md). @@ -654,10 +551,7 @@ The fake timers may be useful when a piece of code sets a long timeout that we d This option provides the default configuration of fake timers for all tests. Calling `jest.useFakeTimers()` in a test file will use these options or will override them if a configuration object is passed. For example, you can tell Jest to keep the original implementation of `process.nextTick()` and adjust the limit of recursive timers that will be run: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { fakeTimers: { @@ -669,11 +563,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -686,9 +576,6 @@ const config: Config = { export default config; ``` - - - ```js title="fakeTime.test.js" // install fake timers for this file using the options from Jest configuration jest.useFakeTimers(); @@ -703,10 +590,7 @@ test('increase the limit of recursive timers for this and following tests', () = Instead of including `jest.useFakeTimers()` in each test file, you can enable fake timers globally for all tests in your Jest configuration: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { fakeTimers: { @@ -717,11 +601,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -733,9 +613,6 @@ const config: Config = { export default config; ``` - - - ::: Configuration options: @@ -788,10 +665,7 @@ type ModernFakeTimersConfig = { For some reason you might have to use legacy implementation of fake timers. Here is how to enable it globally (additional options are not supported): - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { fakeTimers: { @@ -803,11 +677,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -820,9 +690,6 @@ const config: Config = { export default config; ``` - - - ::: ### `forceCoverageMatch` \[array<string>] @@ -847,10 +714,7 @@ if (process.env.NODE_ENV === 'test') { You can collect coverage from those files with setting `forceCoverageMatch`. - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { forceCoverageMatch: ['**/*.t.js'], @@ -859,11 +723,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -873,9 +733,6 @@ const config: Config = { export default config; ``` - - - ### `globals` \[object] Default: `{}` @@ -884,10 +741,7 @@ A set of global variables that need to be available in all test environments. For example, the following would create a global `__DEV__` variable set to `true` in all test environments: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { globals: { @@ -898,11 +752,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -914,9 +764,6 @@ const config: Config = { export default config; ``` - - - Note that, if you specify a global reference value (like an object or array) here, and some code mutates that value in the midst of running a test, that mutation will _not_ be persisted across test runs for other test files. In addition, the `globals` object must be json-serializable, so it can't be used to specify global functions. For that, you should use `setupFiles`. ### `globalSetup` \[string] @@ -1035,10 +882,7 @@ Specifies the maximum number of workers the worker-pool will spawn for running t For environments with variable CPUs available, you can use percentage based configuration: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { maxWorkers: '50%', @@ -1047,11 +891,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -1061,19 +901,13 @@ const config: Config = { export default config; ``` - - - ### `moduleDirectories` \[array<string>] Default: `["node_modules"]` An array of directory names to be searched recursively up from the requiring module's location. Setting this option will _override_ the default, if you wish to still search `node_modules` for packages include it along with any other options: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { moduleDirectories: ['node_modules', 'bower_components'], @@ -1082,11 +916,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -1096,9 +926,6 @@ const config: Config = { export default config; ``` - - - ### `moduleFileExtensions` \[array<string>] Default: `["js", "mjs", "cjs", "jsx", "ts", "tsx", "json", "node"]` @@ -1119,10 +946,7 @@ Use `` string token to refer to [`rootDir`](#rootdir-string) value if y Additionally, you can substitute captured regex groups using numbered backreferences. - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { moduleNameMapper: { @@ -1140,11 +964,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -1163,9 +983,6 @@ const config: Config = { export default config; ``` - - - The order in which the mappings are defined matters. Patterns are checked one by one until one fits. The most specific rule should be listed first. This is true for arrays of module names as well. :::info @@ -1182,10 +999,7 @@ An array of regexp pattern strings that are matched against all module paths bef These pattern strings match against the full path. Use the `` string token to include the path to your project's root directory to prevent it from accidentally ignoring all of your files in different environments that may have different root directories. - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { modulePathIgnorePatterns: ['/build/'], @@ -1194,11 +1008,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -1208,19 +1018,13 @@ const config: Config = { export default config; ``` - - - ### `modulePaths` \[array<string>] Default: `[]` An alternative API to setting the `NODE_PATH` env variable, `modulePaths` is an array of absolute paths to additional locations to search when resolving modules. Use the `` string token to include the path to your project's root directory. - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { modulePaths: ['/app/'], @@ -1229,11 +1033,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -1243,9 +1043,6 @@ const config: Config = { export default config; ``` - - - ### `notify` \[boolean] Default: `false` @@ -1287,10 +1084,7 @@ A preset that is used as a base for Jest's configuration. A preset should point For example, this preset `foo-bar/jest-preset.js` will be configured as follows: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { preset: 'foo-bar', @@ -1299,11 +1093,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -1313,15 +1103,9 @@ const config: Config = { export default config; ``` - - - Presets may also be relative to filesystem paths: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { preset: './node_modules/foo-bar/jest-preset.js', @@ -1330,11 +1114,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -1344,9 +1124,6 @@ const config: Config = { export default config; ``` - - - :::info Note that if you also have specified [`rootDir`](#rootdir-string) that the resolution of this file will be relative to that root directory. @@ -1365,10 +1142,7 @@ Default: `undefined` When the `projects` configuration is provided with an array of paths or glob patterns, Jest will run tests in all of the specified projects at the same time. This is great for monorepos or when working on multiple projects at the same time. - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { projects: ['', '/examples/*'], @@ -1377,11 +1151,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -1391,17 +1161,11 @@ const config: Config = { export default config; ``` - - - This example configuration will run Jest in the root directory as well as in every folder in the examples directory. You can have an unlimited amount of projects running in the same Jest instance. The projects feature can also be used to run multiple configurations or multiple [runners](#runner-string). For this purpose, you can pass an array of configuration objects. For example, to run both tests and ESLint (via [jest-runner-eslint](https://github.com/jest-community/jest-runner-eslint)) in the same invocation of Jest: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { projects: [ @@ -1419,11 +1183,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -1442,9 +1202,6 @@ const config: Config = { export default config; ``` - - - :::tip When using multi-project runner, it's recommended to add a `displayName` for each project. This will show the `displayName` of a project next to its tests. @@ -1457,10 +1214,7 @@ Default: `undefined` Use this configuration option to add reporters to Jest. It must be a list of reporter names, additional options can be passed to a reporter using the tuple form: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { reporters: [ @@ -1472,11 +1226,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -1489,17 +1239,11 @@ const config: Config = { export default config; ``` - - - #### Default Reporter If custom reporters are specified, the default Jest reporter will be overridden. If you wish to keep it, `'default'` must be passed as a reporters name: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { reporters: [ @@ -1511,11 +1255,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -1528,17 +1268,11 @@ const config: Config = { export default config; ``` - - - #### GitHub Actions Reporter If included in the list, the built-in GitHub Actions Reporter will annotate changed files with test failure messages: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { reporters: ['default', 'github-actions'], @@ -1547,11 +1281,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -1561,17 +1291,11 @@ const config: Config = { export default config; ``` - - - #### Summary Reporter Summary reporter prints out summary of all tests. It is a part of default reporter, hence it will be enabled if `'default'` is included in the list. For instance, you might want to use it as stand-alone reporter instead of the default one, or together with [Silent Reporter](https://github.com/rickhanlonii/jest-silent-reporter): - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { reporters: ['jest-silent-reporter', 'summary'], @@ -1580,11 +1304,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -1594,9 +1314,6 @@ const config: Config = { export default config; ``` - - - #### Custom Reporters :::tip @@ -1696,10 +1413,7 @@ module.exports = browserResolve.sync; And add it to Jest configuration: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { resolver: '/resolver.js', @@ -1708,11 +1422,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -1722,9 +1432,6 @@ const config: Config = { export default config; ``` - - - By combining `defaultResolver` and `packageFilter` we can implement a `package.json` "pre-processor" that allows us to change how the default resolver will resolve modules. For example, imagine we want to use the field `"module"` if it is present, otherwise fallback to `"main"`: ```js @@ -1826,10 +1533,7 @@ Test files run inside a [vm](https://nodejs.org/api/vm.html), which slows calls For example, if your tests call `Math` often, you can pass it by setting `sandboxInjectedGlobals`. - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { sandboxInjectedGlobals: ['Math'], @@ -1838,11 +1542,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -1852,9 +1552,6 @@ const config: Config = { export default config; ``` - - - :::note This option has no effect if you use [native ESM](ECMAScriptModules.md). @@ -1890,10 +1587,7 @@ afterEach(() => { }); ``` - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { setupFilesAfterEnv: ['/setup-jest.js'], @@ -1902,11 +1596,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -1916,9 +1606,6 @@ const config: Config = { export default config; ``` - - - ### `slowTestThreshold` \[number] Default: `5` @@ -1931,10 +1618,7 @@ Default: `undefined` Allows overriding specific snapshot formatting options documented in the [pretty-format readme](https://www.npmjs.com/package/pretty-format#usage-with-options), with the exceptions of `compareKeys` and `plugins`. For example, this config would have the snapshot formatter not print a prefix for "Object" and "Array": - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { snapshotFormat: { @@ -1945,11 +1629,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -1961,9 +1641,6 @@ const config: Config = { export default config; ``` - - - ```js title="some.test.js" test('does not show prototypes for object and array inline', () => { const object = { @@ -2028,10 +1705,7 @@ module.exports = { Add `custom-serializer` to your Jest configuration: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { snapshotSerializers: ['path/to/custom-serializer.js'], @@ -2040,11 +1714,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -2054,9 +1724,6 @@ const config: Config = { export default config; ``` - - - Finally tests would look as follows: ```js @@ -2390,10 +2057,7 @@ module.exports = CustomSequencer; Add `custom-sequencer` to your Jest configuration: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { testSequencer: 'path/to/custom-sequencer.js', @@ -2402,11 +2066,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -2416,9 +2076,6 @@ const config: Config = { export default config; ``` - - - ### `testTimeout` \[number] Default: `5000` @@ -2441,10 +2098,7 @@ Keep in mind that a transformer only runs once per file unless the file has chan Remember to include the default `babel-jest` transformer explicitly, if you wish to use it alongside with additional code preprocessors: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { transform: { @@ -2456,11 +2110,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -2473,9 +2123,6 @@ const config: Config = { export default config; ``` - - - ::: ### `transformIgnorePatterns` \[array<string>] @@ -2486,10 +2133,7 @@ An array of regexp pattern strings that are matched against all source file path Providing regexp patterns that overlap with each other may result in files not being transformed that you expected to be transformed. For example: - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { transformIgnorePatterns: ['/node_modules/(?!(foo|bar)/)', '/bar/'], @@ -2498,11 +2142,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -2512,19 +2152,13 @@ const config: Config = { export default config; ``` - - - The first pattern will match (and therefore not transform) files inside `/node_modules` except for those in `/node_modules/foo/` and `/node_modules/bar/`. The second pattern will match (and therefore not transform) files inside any path with `/bar/` in it. With the two together, files in `/node_modules/bar/` will not be transformed because it does match the second pattern, even though it was excluded by the first. Sometimes it happens (especially in React Native or TypeScript projects) that 3rd party modules are published as untranspiled code. Since all files inside `node_modules` are not transformed by default, Jest will not understand the code in these modules, resulting in syntax errors. To overcome this, you may use `transformIgnorePatterns` to allow transpiling such modules. You'll find a good example of this use case in [React Native Guide](/docs/tutorial-react-native#transformignorepatterns-customization). These pattern strings match against the full path. Use the `` string token to include the path to your project's root directory to prevent it from accidentally ignoring all of your files in different environments that may have different root directories. - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { transformIgnorePatterns: [ @@ -2536,11 +2170,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -2553,9 +2183,6 @@ const config: Config = { export default config; ``` - - - ### `unmockedModulePathPatterns` \[array<string>] Default: `[]` @@ -2582,10 +2209,7 @@ These patterns match against the full path. Use the `` string token to Even if nothing is specified here, the watcher will ignore changes to the version control folders (.git, .hg). Other hidden files and directories, i.e. those that begin with a dot (`.`), are watched by default. Remember to escape the dot when you add them to `watchPathIgnorePatterns` as it is a special RegExp character. - - - -```js +```js tab /** @type {import('jest').Config} */ const config = { watchPathIgnorePatterns: ['/\\.tmp/', '/bar/'], @@ -2594,11 +2218,7 @@ const config = { module.exports = config; ``` - - - - -```ts +```ts tab import type {Config} from 'jest'; const config: Config = { @@ -2608,9 +2228,6 @@ const config: Config = { export default config; ``` - - - ### `watchPlugins` \[array<string | \[string, Object]>] Default: `[]` From 81806d95d79749469744db328cd912a1e887a452 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Thu, 19 May 2022 12:32:43 +0300 Subject: [PATCH 07/35] rename plugin --- website/docusaurus.config.js | 2 +- website/src/remark/{tabs-plugin.js => code-tabs-plugin.js} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename website/src/remark/{tabs-plugin.js => code-tabs-plugin.js} (100%) diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index c920c648e78e..d8ca300cdac5 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -56,7 +56,7 @@ module.exports = { sidebarPath: path.resolve(__dirname, './sidebars.json'), remarkPlugins: [ [require('@docusaurus/remark-plugin-npm2yarn'), {sync: true}], - require('./src/remark/tabs-plugin'), + require('./src/remark/code-tabs-plugin'), ], }, blog: { diff --git a/website/src/remark/tabs-plugin.js b/website/src/remark/code-tabs-plugin.js similarity index 100% rename from website/src/remark/tabs-plugin.js rename to website/src/remark/code-tabs-plugin.js From 442ff2338c450be00115f860f9a2cf5ba27b0977 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Thu, 19 May 2022 12:56:39 +0300 Subject: [PATCH 08/35] less code --- website/src/remark/code-tabs-plugin.js | 55 +++++++++++--------------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/website/src/remark/code-tabs-plugin.js b/website/src/remark/code-tabs-plugin.js index 9a2faa9cdb64..182e1777fd5e 100644 --- a/website/src/remark/code-tabs-plugin.js +++ b/website/src/remark/code-tabs-plugin.js @@ -7,37 +7,26 @@ const visit = require('unist-util-visit'); -const transformFirstTabNode = node => [ - { - type: 'jsx', - value: `\n`, - }, - { - type: node.type, - lang: node.lang, - value: node.value, - }, - { - type: 'jsx', - value: '', - }, -]; - -const transformLastTabNode = node => [ - { - type: 'jsx', - value: ``, - }, - { - type: node.type, - lang: node.lang, - value: node.value, - }, - { - type: 'jsx', - value: '\n', - }, -]; +const transformTabNode = (node, options) => { + const labels = { + js: 'JavaScript', + ts: 'TypeScript', + }; + + return [ + { + type: 'jsx', + value: `${ + options.first ? '\n' : '' + }`, + }, + node, + { + type: 'jsx', + value: `${options.last ? '\n' : ''}`, + }, + ]; +}; const isImport = node => node.type === 'import'; const isParent = node => Array.isArray(node.children); @@ -94,13 +83,13 @@ const tabsPlugin = () => root => { const child = node.children[index]; if (isFirstTab(child, index, node)) { - const result = transformFirstTabNode(child); + const result = transformTabNode(child, {first: true}); node.children.splice(index, 1, ...result); index += result.length; hasTabs = true; } else if (isLastTab(child, index, node)) { - const result = transformLastTabNode(child); + const result = transformTabNode(child, {last: true}); node.children.splice(index, 1, ...result); index += result.length; From 1ec1602baba8a09460a9ce6105d4d2c1e702fb66 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Sun, 22 May 2022 08:51:20 +0300 Subject: [PATCH 09/35] support title --- website/babel.config.js | 3 + website/package.json | 5 +- .../src/remark/__fixtures__/base-example.md | 7 + website/src/remark/__fixtures__/file-title.md | 17 ++ .../src/remark/__fixtures__/full-example.md | 63 +++++ .../remark/__fixtures__/import-tabs-above.md | 11 + .../remark/__fixtures__/import-tabs-below.md | 11 + .../remark/__fixtures__/inside-admonition.md | 36 +++ .../code-tabs-plugin.test.js.snap | 252 ++++++++++++++++++ website/src/remark/code-tabs-plugin.js | 14 +- website/src/remark/code-tabs-plugin.test.js | 61 +++++ yarn.lock | 106 +++++++- 12 files changed, 576 insertions(+), 10 deletions(-) create mode 100644 website/babel.config.js create mode 100644 website/src/remark/__fixtures__/base-example.md create mode 100644 website/src/remark/__fixtures__/file-title.md create mode 100644 website/src/remark/__fixtures__/full-example.md create mode 100644 website/src/remark/__fixtures__/import-tabs-above.md create mode 100644 website/src/remark/__fixtures__/import-tabs-below.md create mode 100644 website/src/remark/__fixtures__/inside-admonition.md create mode 100644 website/src/remark/__snapshots__/code-tabs-plugin.test.js.snap create mode 100644 website/src/remark/code-tabs-plugin.test.js diff --git a/website/babel.config.js b/website/babel.config.js new file mode 100644 index 000000000000..8283743ee3a2 --- /dev/null +++ b/website/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: [['@babel/preset-env', {targets: {node: 'current'}}]], +}; diff --git a/website/package.json b/website/package.json index cdc12b5fbd20..7eb87b9163d9 100644 --- a/website/package.json +++ b/website/package.json @@ -49,6 +49,9 @@ "@types/react": "^17.0.3", "graphql": "^16.3.0", "graphql-request": "^4.0.0", - "js-yaml": "^4.1.0" + "jest": "workspace:*", + "js-yaml": "^4.1.0", + "remark": "^12.0.1", + "remark-mdx": "^1.6.21" } } diff --git a/website/src/remark/__fixtures__/base-example.md b/website/src/remark/__fixtures__/base-example.md new file mode 100644 index 000000000000..682e4073b4ba --- /dev/null +++ b/website/src/remark/__fixtures__/base-example.md @@ -0,0 +1,7 @@ +```js tab +console.log('this is JS'); +``` + +```ts tab +console.log('this is TS'); +``` diff --git a/website/src/remark/__fixtures__/file-title.md b/website/src/remark/__fixtures__/file-title.md new file mode 100644 index 000000000000..889bd4ce276b --- /dev/null +++ b/website/src/remark/__fixtures__/file-title.md @@ -0,0 +1,17 @@ +`.mockImplementation()` can also be used to mock class constructors: + +```js tab title="SomeClass.js" +module.exports = class SomeClass { + method(a, b) {} +}; +``` + +```ts tab title="SomeClass.ts" +export class SomeClass { + method(a: string, b: string): void {} +} +``` + +### `mockFn.mockImplementationOnce(fn)` + +Accepts a function that will be used as an implementation of the mock for one call to the mocked function. Can be chained so that multiple function calls produce different results. diff --git a/website/src/remark/__fixtures__/full-example.md b/website/src/remark/__fixtures__/full-example.md new file mode 100644 index 000000000000..9b8e17bf5621 --- /dev/null +++ b/website/src/remark/__fixtures__/full-example.md @@ -0,0 +1,63 @@ +### `displayName` \[string, object] + +Default: `undefined` + +Allows for a label to be printed alongside a test while it is running. This becomes more useful in multi-project repositories where there can be many jest configuration files. This visually tells which project a test belongs to. + +```js tab +/** @type {import('jest').Config} */ +const config = { + displayName: 'CLIENT', +}; + +module.exports = config; +``` + +```ts tab +import type {Config} from 'jest'; + +const config: Config = { + displayName: 'CLIENT', +}; + +export default config; +``` + +Alternatively, an object with the properties `name` and `color` can be passed. + +### `fakeTimers` \[object] + +Default: `{}` + +The fake timers may be useful when a piece of code sets a long timeout that we don't want to wait for in a test. + +:::tip + +Instead of including `jest.useFakeTimers()` in each test file, you can enable fake timers globally for all tests in your Jest configuration: + +```js tab +/** @type {import('jest').Config} */ +const config = { + fakeTimers: { + enableGlobally: true, + }, +}; + +module.exports = config; +``` + +```ts tab +import type {Config} from 'jest'; + +const config: Config = { + fakeTimers: { + enableGlobally: true, + }, +}; + +export default config; +``` + +::: + +Configuration options: diff --git a/website/src/remark/__fixtures__/import-tabs-above.md b/website/src/remark/__fixtures__/import-tabs-above.md new file mode 100644 index 000000000000..008636d605b2 --- /dev/null +++ b/website/src/remark/__fixtures__/import-tabs-above.md @@ -0,0 +1,11 @@ +import Tabs from '@theme/Tabs'; + +import TabItem from '@theme/TabItem'; + +```js tab +console.log('this is JS'); +``` + +```ts tab +console.log('this is TS'); +``` diff --git a/website/src/remark/__fixtures__/import-tabs-below.md b/website/src/remark/__fixtures__/import-tabs-below.md new file mode 100644 index 000000000000..0672b0fc272f --- /dev/null +++ b/website/src/remark/__fixtures__/import-tabs-below.md @@ -0,0 +1,11 @@ +```js tab +console.log('this is JS'); +``` + +```ts tab +console.log('this is TS'); +``` + +import Tabs from '@theme/Tabs'; + +import TabItem from '@theme/TabItem'; diff --git a/website/src/remark/__fixtures__/inside-admonition.md b/website/src/remark/__fixtures__/inside-admonition.md new file mode 100644 index 000000000000..a78555bf0fca --- /dev/null +++ b/website/src/remark/__fixtures__/inside-admonition.md @@ -0,0 +1,36 @@ +### `fakeTimers` \[object] + +Default: `{}` + +The fake timers may be useful when a piece of code sets a long timeout that we don't want to wait for in a test. + +:::tip + +Instead of including `jest.useFakeTimers()` in each test file, you can enable fake timers globally for all tests in your Jest configuration: + +```js tab +/** @type {import('jest').Config} */ +const config = { + fakeTimers: { + enableGlobally: true, + }, +}; + +module.exports = config; +``` + +```ts tab +import type {Config} from 'jest'; + +const config: Config = { + fakeTimers: { + enableGlobally: true, + }, +}; + +export default config; +``` + +::: + +Configuration options: diff --git a/website/src/remark/__snapshots__/code-tabs-plugin.test.js.snap b/website/src/remark/__snapshots__/code-tabs-plugin.test.js.snap new file mode 100644 index 000000000000..284dd979b35d --- /dev/null +++ b/website/src/remark/__snapshots__/code-tabs-plugin.test.js.snap @@ -0,0 +1,252 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`code tabs plugin base example 1`] = ` +"import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + +\`\`\`js tab +console.log('this is JS'); +\`\`\` + + + + + +\`\`\`ts tab +console.log('this is TS'); +\`\`\` + + + +" +`; + +exports[`code tabs plugin can be nested inside an admonition 1`] = ` +"import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +### \`fakeTimers\` \\\\[object] + +Default: \`{}\` + +The fake timers may be useful when a piece of code sets a long timeout that we don't want to wait for in a test. + +:::tip + +Instead of including \`jest.useFakeTimers()\` in each test file, you can enable fake timers globally for all tests in your Jest configuration: + + + + +\`\`\`js tab +/** @type {import('jest').Config} */ +const config = { + fakeTimers: { + enableGlobally: true, + }, +}; + +module.exports = config; +\`\`\` + + + + + +\`\`\`ts tab +import type {Config} from 'jest'; + +const config: Config = { + fakeTimers: { + enableGlobally: true, + }, +}; + +export default config; +\`\`\` + + + + +::: + +Configuration options: +" +`; + +exports[`code tabs plugin does not re-import tabs components when already imported above 1`] = ` +"import Tabs from '@theme/Tabs'; + +import TabItem from '@theme/TabItem'; + + + + +\`\`\`js tab +console.log('this is JS'); +\`\`\` + + + + + +\`\`\`ts tab +console.log('this is TS'); +\`\`\` + + + +" +`; + +exports[`code tabs plugin does not re-import tabs components when already imported below 1`] = ` +" + + +\`\`\`js tab +console.log('this is JS'); +\`\`\` + + + + + +\`\`\`ts tab +console.log('this is TS'); +\`\`\` + + + + +import Tabs from '@theme/Tabs'; + +import TabItem from '@theme/TabItem'; +" +`; + +exports[`code tabs plugin full example 1`] = ` +"import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +### \`displayName\` \\\\[string, object] + +Default: \`undefined\` + +Allows for a label to be printed alongside a test while it is running. This becomes more useful in multi-project repositories where there can be many jest configuration files. This visually tells which project a test belongs to. + + + + +\`\`\`js tab +/** @type {import('jest').Config} */ +const config = { + displayName: 'CLIENT', +}; + +module.exports = config; +\`\`\` + + + + + +\`\`\`ts tab +import type {Config} from 'jest'; + +const config: Config = { + displayName: 'CLIENT', +}; + +export default config; +\`\`\` + + + + +Alternatively, an object with the properties \`name\` and \`color\` can be passed. + +### \`fakeTimers\` \\\\[object] + +Default: \`{}\` + +The fake timers may be useful when a piece of code sets a long timeout that we don't want to wait for in a test. + +:::tip + +Instead of including \`jest.useFakeTimers()\` in each test file, you can enable fake timers globally for all tests in your Jest configuration: + + + + +\`\`\`js tab +/** @type {import('jest').Config} */ +const config = { + fakeTimers: { + enableGlobally: true, + }, +}; + +module.exports = config; +\`\`\` + + + + + +\`\`\`ts tab +import type {Config} from 'jest'; + +const config: Config = { + fakeTimers: { + enableGlobally: true, + }, +}; + +export default config; +\`\`\` + + + + +::: + +Configuration options: +" +`; + +exports[`code tabs plugin respects file title 1`] = ` +"import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +\`.mockImplementation()\` can also be used to mock class constructors: + + + + +\`\`\`js tab title=\\"SomeClass.js\\" +module.exports = class SomeClass { + method(a, b) {} +}; +\`\`\` + + + + + +\`\`\`ts tab title=\\"SomeClass.ts\\" +export class SomeClass { + method(a: string, b: string): void {} +} +\`\`\` + + + + +### \`mockFn.mockImplementationOnce(fn)\` + +Accepts a function that will be used as an implementation of the mock for one call to the mocked function. Can be chained so that multiple function calls produce different results. +" +`; diff --git a/website/src/remark/code-tabs-plugin.js b/website/src/remark/code-tabs-plugin.js index 182e1777fd5e..e7a9d55ebe04 100644 --- a/website/src/remark/code-tabs-plugin.js +++ b/website/src/remark/code-tabs-plugin.js @@ -8,17 +8,17 @@ const visit = require('unist-util-visit'); const transformTabNode = (node, options) => { - const labels = { - js: 'JavaScript', - ts: 'TypeScript', - }; + const label = new Map([ + ['js', 'JavaScript'], + ['ts', 'TypeScript'], + ]); return [ { type: 'jsx', value: `${ options.first ? '\n' : '' - }`, + }`, }, node, { @@ -30,7 +30,9 @@ const transformTabNode = (node, options) => { const isImport = node => node.type === 'import'; const isParent = node => Array.isArray(node.children); -const isTab = node => node.type === 'code' && node.meta === 'tab'; +const isTab = node => + node.type === 'code' && + node.meta.split(' ').some(tag => tag.startsWith('tab')); const isFirstTab = (node, index, parent) => { if (!isTab(node)) { diff --git a/website/src/remark/code-tabs-plugin.test.js b/website/src/remark/code-tabs-plugin.test.js new file mode 100644 index 000000000000..808e0b45262c --- /dev/null +++ b/website/src/remark/code-tabs-plugin.test.js @@ -0,0 +1,61 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import path from 'path'; +import fs from 'graceful-fs'; +import remarkMdx from 'remark-mdx'; +import remark from 'remark'; +import codeTabsPlugin from './code-tabs-plugin'; + +const processFixture = async name => { + const filePath = path.join(__dirname, '__fixtures__', `${name}.md`); + const file = fs.readFileSync(filePath); + const result = await remark() + .use(remarkMdx) + .use(codeTabsPlugin) + .process(file); + + return result.toString(); +}; + +describe('code tabs plugin', () => { + test('base example', async () => { + const result = await processFixture('base-example'); + + expect(result).toMatchSnapshot(); + }); + + test('full example', async () => { + const result = await processFixture('full-example'); + + expect(result).toMatchSnapshot(); + }); + + test('can be nested inside an admonition', async () => { + const result = await processFixture('inside-admonition'); + + expect(result).toMatchSnapshot(); + }); + + test('respects file title', async () => { + const result = await processFixture('file-title'); + + expect(result).toMatchSnapshot(); + }); + + test('does not re-import tabs components when already imported above', async () => { + const result = await processFixture('import-tabs-above'); + + expect(result).toMatchSnapshot(); + }); + + test('does not re-import tabs components when already imported below', async () => { + const result = await processFixture('import-tabs-below'); + + expect(result).toMatchSnapshot(); + }); +}); diff --git a/yarn.lock b/yarn.lock index 7824366462fe..56eacd4f5034 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7471,6 +7471,13 @@ __metadata: languageName: node linkType: hard +"character-entities-html4@npm:^1.0.0": + version: 1.1.4 + resolution: "character-entities-html4@npm:1.1.4" + checksum: 22536aba07a378a2326420423ceadd65c0121032c527f80e84dfc648381992ed5aa666d7c2b267cd269864b3682d5b0315fc2f03a9e7c017d1a96d24ec292d5f + languageName: node + linkType: hard + "character-entities-legacy@npm:^1.0.0": version: 1.1.4 resolution: "character-entities-legacy@npm:1.1.4" @@ -12345,6 +12352,13 @@ __metadata: languageName: node linkType: hard +"is-alphanumeric@npm:^1.0.0": + version: 1.0.0 + resolution: "is-alphanumeric@npm:1.0.0" + checksum: 2f4f4f227fe4cae977529f628021655edc172e1e5debfb3c30efd547f32e8d390c9bb7a71f3e9fea4187fe6598980072323d5a1b1abd3368379e33ba6504558c + languageName: node + linkType: hard + "is-alphanumerical@npm:^1.0.0": version: 1.0.4 resolution: "is-alphanumerical@npm:1.0.4" @@ -13715,12 +13729,15 @@ __metadata: globby: ^11.0.1 graphql: ^16.3.0 graphql-request: ^4.0.0 + jest: "workspace:*" js-yaml: ^4.1.0 react: 17.0.2 react-dom: ^17.0.1 react-github-btn: ^1.2.0 react-lite-youtube-embed: ^2.2.1-a react-markdown: ^8.0.0 + remark: ^12.0.1 + remark-mdx: ^1.6.21 unist-util-visit: ^2.0.3 languageName: unknown linkType: soft @@ -14614,6 +14631,13 @@ __metadata: languageName: node linkType: hard +"longest-streak@npm:^2.0.1": + version: 2.0.4 + resolution: "longest-streak@npm:2.0.4" + checksum: 28b8234a14963002c5c71035dee13a0a11e9e9d18ffa320fdc8796ed7437399204495702ed69cd2a7087b0af041a2a8b562829b7c1e2042e73a3374d1ecf6580 + languageName: node + linkType: hard + "loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.2.0, loose-envify@npm:^1.3.1, loose-envify@npm:^1.4.0": version: 1.4.0 resolution: "loose-envify@npm:1.4.0" @@ -14801,6 +14825,15 @@ __metadata: languageName: node linkType: hard +"markdown-table@npm:^2.0.0": + version: 2.0.0 + resolution: "markdown-table@npm:2.0.0" + dependencies: + repeat-string: ^1.0.0 + checksum: 9bb634a9300016cbb41216c1eab44c74b6b7083ac07872e296f900a29449cf0e260ece03fa10c3e9784ab94c61664d1d147da0315f95e1336e2bdcc025615c90 + languageName: node + linkType: hard + "md5-file@npm:^5.0.0": version: 5.0.0 resolution: "md5-file@npm:5.0.0" @@ -14819,6 +14852,15 @@ __metadata: languageName: node linkType: hard +"mdast-util-compact@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-compact@npm:2.0.1" + dependencies: + unist-util-visit: ^2.0.0 + checksum: 750cc76e46223d2dadf86835d415d4954566572e6af5a8df5577065e5f863dda46c30767e12e29c4ec53cf2e7040863b0279d44af357e8b36f5983d78a73dceb + languageName: node + linkType: hard + "mdast-util-definitions@npm:^4.0.0": version: 4.0.0 resolution: "mdast-util-definitions@npm:4.0.0" @@ -19144,7 +19186,7 @@ __metadata: languageName: node linkType: hard -"remark-mdx@npm:1.6.22": +"remark-mdx@npm:1.6.22, remark-mdx@npm:^1.6.21": version: 1.6.22 resolution: "remark-mdx@npm:1.6.22" dependencies: @@ -19160,7 +19202,7 @@ __metadata: languageName: node linkType: hard -"remark-parse@npm:8.0.3": +"remark-parse@npm:8.0.3, remark-parse@npm:^8.0.0": version: 8.0.3 resolution: "remark-parse@npm:8.0.3" dependencies: @@ -19216,6 +19258,39 @@ __metadata: languageName: node linkType: hard +"remark-stringify@npm:^8.0.0": + version: 8.1.1 + resolution: "remark-stringify@npm:8.1.1" + dependencies: + ccount: ^1.0.0 + is-alphanumeric: ^1.0.0 + is-decimal: ^1.0.0 + is-whitespace-character: ^1.0.0 + longest-streak: ^2.0.1 + markdown-escapes: ^1.0.0 + markdown-table: ^2.0.0 + mdast-util-compact: ^2.0.0 + parse-entities: ^2.0.0 + repeat-string: ^1.5.4 + state-toggle: ^1.0.0 + stringify-entities: ^3.0.0 + unherit: ^1.0.4 + xtend: ^4.0.1 + checksum: 9a556e5a0dc26db151694a5d0a1dcd0f21bd7e619b3934d677876a633ad01a03e38f5cf174ff5468ec755d5a9398f4fbccac4788e04f5bcab8bb2583eddbc1b3 + languageName: node + linkType: hard + +"remark@npm:^12.0.1": + version: 12.0.1 + resolution: "remark@npm:12.0.1" + dependencies: + remark-parse: ^8.0.0 + remark-stringify: ^8.0.0 + unified: ^9.0.0 + checksum: 1ce7a264c19b3d0b915b0c08c9b84c053b03ecd65086ca25ac54e1ce5a685a1153403da870ec8e43f7b98c47fc6e7f0a12eb4d16481facc88131c1dbd4af01a1 + languageName: node + linkType: hard + "renderkid@npm:^3.0.0": version: 3.0.0 resolution: "renderkid@npm:3.0.0" @@ -19236,7 +19311,7 @@ __metadata: languageName: node linkType: hard -"repeat-string@npm:^1.5.4, repeat-string@npm:^1.6.1": +"repeat-string@npm:^1.0.0, repeat-string@npm:^1.5.4, repeat-string@npm:^1.6.1": version: 1.6.1 resolution: "repeat-string@npm:1.6.1" checksum: 1b809fc6db97decdc68f5b12c4d1a671c8e3f65ec4a40c238bc5200e44e85bcc52a54f78268ab9c29fcf5fe4f1343e805420056d1f30fa9a9ee4c2d93e3cc6c0 @@ -20700,6 +20775,17 @@ __metadata: languageName: node linkType: hard +"stringify-entities@npm:^3.0.0": + version: 3.1.0 + resolution: "stringify-entities@npm:3.1.0" + dependencies: + character-entities-html4: ^1.0.0 + character-entities-legacy: ^1.0.0 + xtend: ^4.0.0 + checksum: 5b6212e2985101ddb8197d999a6c01abb610f2ba6efd6f8f7d7ec763b61cb08b55735b03febdf501c2091f484df16bc82412419ef35ee21135548f6a15881044 + languageName: node + linkType: hard + "stringify-object@npm:^3.3.0": version: 3.3.0 resolution: "stringify-object@npm:3.3.0" @@ -21748,6 +21834,20 @@ __metadata: languageName: node linkType: hard +"unified@npm:^9.0.0": + version: 9.2.2 + resolution: "unified@npm:9.2.2" + dependencies: + bail: ^1.0.0 + extend: ^3.0.0 + is-buffer: ^2.0.0 + is-plain-obj: ^2.0.0 + trough: ^1.0.0 + vfile: ^4.0.0 + checksum: 7c24461be7de4145939739ce50d18227c5fbdf9b3bc5a29dabb1ce26dd3e8bd4a1c385865f6f825f3b49230953ee8b591f23beab3bb3643e3e9dc37aa8a089d5 + languageName: node + linkType: hard + "union-value@npm:^1.0.0": version: 1.0.1 resolution: "union-value@npm:1.0.1" From cbd10184e4b0b4b33cdf21722acbd5421925f8d9 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Sun, 22 May 2022 09:00:27 +0300 Subject: [PATCH 10/35] fix copyright headers --- website/babel.config.js | 7 +++++++ website/src/remark/code-tabs-plugin.test.js | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/website/babel.config.js b/website/babel.config.js index 8283743ee3a2..11e322797498 100644 --- a/website/babel.config.js +++ b/website/babel.config.js @@ -1,3 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + module.exports = { presets: [['@babel/preset-env', {targets: {node: 'current'}}]], }; diff --git a/website/src/remark/code-tabs-plugin.test.js b/website/src/remark/code-tabs-plugin.test.js index 808e0b45262c..cd4dcdbfd4b3 100644 --- a/website/src/remark/code-tabs-plugin.test.js +++ b/website/src/remark/code-tabs-plugin.test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) Facebook, Inc. and its affiliates. + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. From 92302ab47d92f21fa92b12f69d5f90b557846d57 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Sun, 22 May 2022 09:06:52 +0300 Subject: [PATCH 11/35] babel? --- website/babel.config.js | 5 +++- website/package.json | 1 + yarn.lock | 60 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/website/babel.config.js b/website/babel.config.js index 11e322797498..fda7b9b8b37a 100644 --- a/website/babel.config.js +++ b/website/babel.config.js @@ -6,5 +6,8 @@ */ module.exports = { - presets: [['@babel/preset-env', {targets: {node: 'current'}}]], + presets: [ + ['@babel/preset-env', {targets: {node: 'current'}}], + '@babel/preset-react', + ], }; diff --git a/website/package.json b/website/package.json index 7eb87b9163d9..7e73bcc3fe69 100644 --- a/website/package.json +++ b/website/package.json @@ -45,6 +45,7 @@ }, "devDependencies": { "@babel/core": "^7.11.6", + "@babel/preset-react": "^7.17.12", "@crowdin/cli": "^3.5.2", "@types/react": "^17.0.3", "graphql": "^16.3.0", diff --git a/yarn.lock b/yarn.lock index 56eacd4f5034..fd94de5f6954 100644 --- a/yarn.lock +++ b/yarn.lock @@ -519,6 +519,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-plugin-utils@npm:^7.17.12": + version: 7.17.12 + resolution: "@babel/helper-plugin-utils@npm:7.17.12" + checksum: 4813cf0ddb0f143de032cb88d4207024a2334951db330f8216d6fa253ea320c02c9b2667429ef1a34b5e95d4cfbd085f6cb72d418999751c31d0baf2422cc61d + languageName: node + linkType: hard + "@babel/helper-remap-async-to-generator@npm:^7.16.8": version: 7.16.8 resolution: "@babel/helper-remap-async-to-generator@npm:7.16.8" @@ -1023,6 +1030,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-jsx@npm:^7.17.12": + version: 7.17.12 + resolution: "@babel/plugin-syntax-jsx@npm:7.17.12" + dependencies: + "@babel/helper-plugin-utils": ^7.17.12 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 6acd0bbca8c3e0100ad61f3b7d0b0111cd241a0710b120b298c4aa0e07be02eccbcca61ede1e7678ade1783a0979f20305b62263df6767fa3fbf658670d82af5 + languageName: node + linkType: hard + "@babel/plugin-syntax-logical-assignment-operators@npm:^7.10.4, @babel/plugin-syntax-logical-assignment-operators@npm:^7.8.3": version: 7.10.4 resolution: "@babel/plugin-syntax-logical-assignment-operators@npm:7.10.4" @@ -1492,6 +1510,21 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-react-jsx@npm:^7.17.12": + version: 7.17.12 + resolution: "@babel/plugin-transform-react-jsx@npm:7.17.12" + dependencies: + "@babel/helper-annotate-as-pure": ^7.16.7 + "@babel/helper-module-imports": ^7.16.7 + "@babel/helper-plugin-utils": ^7.17.12 + "@babel/plugin-syntax-jsx": ^7.17.12 + "@babel/types": ^7.17.12 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 02e9974d14821173bb8e84db4bdfccd546bfdbf445d91d6345f953591f16306cf5741861d72e0d0910f3ffa7d4084fafed99cedf736e7ba8bed0cf64320c2ea6 + languageName: node + linkType: hard + "@babel/plugin-transform-react-pure-annotations@npm:^7.16.7": version: 7.16.7 resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.16.7" @@ -1762,6 +1795,22 @@ __metadata: languageName: node linkType: hard +"@babel/preset-react@npm:^7.17.12": + version: 7.17.12 + resolution: "@babel/preset-react@npm:7.17.12" + dependencies: + "@babel/helper-plugin-utils": ^7.17.12 + "@babel/helper-validator-option": ^7.16.7 + "@babel/plugin-transform-react-display-name": ^7.16.7 + "@babel/plugin-transform-react-jsx": ^7.17.12 + "@babel/plugin-transform-react-jsx-development": ^7.16.7 + "@babel/plugin-transform-react-pure-annotations": ^7.16.7 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 369712150d6a152720069db8d024320f3d9d2a6611e9b0be4aa03dcab8502fa0e9efc0693c93ba2d818d5243c9d03b015163d76efe65df600f15b9b0a206f674 + languageName: node + linkType: hard + "@babel/preset-typescript@npm:^7.0.0, @babel/preset-typescript@npm:^7.13.0, @babel/preset-typescript@npm:^7.15.0, @babel/preset-typescript@npm:^7.16.7": version: 7.16.7 resolution: "@babel/preset-typescript@npm:7.16.7" @@ -1848,6 +1897,16 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.17.12": + version: 7.18.0 + resolution: "@babel/types@npm:7.18.0" + dependencies: + "@babel/helper-validator-identifier": ^7.16.7 + to-fast-properties: ^2.0.0 + checksum: 151485f94c929171fd6539430c0ae519e8bb67fbc0d856b285328f5e6ecbaf4237b52d7a581b413f5e7b6268d31a4db6ca9bc01372b284b2966aa473fc902f27 + languageName: node + linkType: hard + "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" @@ -13718,6 +13777,7 @@ __metadata: resolution: "jest-website@workspace:website" dependencies: "@babel/core": ^7.11.6 + "@babel/preset-react": ^7.17.12 "@crowdin/cli": ^3.5.2 "@docusaurus/core": ^2.0.0-beta.17 "@docusaurus/plugin-client-redirects": ^2.0.0-beta.17 From 686dfd6aac10f7a851054721cb9d31b92c19aa47 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Sun, 22 May 2022 09:21:05 +0300 Subject: [PATCH 12/35] babel again --- website/babel.config.js | 5 +- website/package.json | 2 - website/src/remark/code-tabs-plugin.test.js | 10 ++-- yarn.lock | 61 --------------------- 4 files changed, 6 insertions(+), 72 deletions(-) diff --git a/website/babel.config.js b/website/babel.config.js index fda7b9b8b37a..5488564d3f2f 100644 --- a/website/babel.config.js +++ b/website/babel.config.js @@ -6,8 +6,5 @@ */ module.exports = { - presets: [ - ['@babel/preset-env', {targets: {node: 'current'}}], - '@babel/preset-react', - ], + presets: [require.resolve('@docusaurus/core/lib/babel/preset')], }; diff --git a/website/package.json b/website/package.json index 7e73bcc3fe69..f0c7c39a5804 100644 --- a/website/package.json +++ b/website/package.json @@ -44,8 +44,6 @@ "unist-util-visit": "^2.0.3" }, "devDependencies": { - "@babel/core": "^7.11.6", - "@babel/preset-react": "^7.17.12", "@crowdin/cli": "^3.5.2", "@types/react": "^17.0.3", "graphql": "^16.3.0", diff --git a/website/src/remark/code-tabs-plugin.test.js b/website/src/remark/code-tabs-plugin.test.js index cd4dcdbfd4b3..5a82c1e45f61 100644 --- a/website/src/remark/code-tabs-plugin.test.js +++ b/website/src/remark/code-tabs-plugin.test.js @@ -5,11 +5,11 @@ * LICENSE file in the root directory of this source tree. */ -import path from 'path'; -import fs from 'graceful-fs'; -import remarkMdx from 'remark-mdx'; -import remark from 'remark'; -import codeTabsPlugin from './code-tabs-plugin'; +const path = require('node:path'); +const fs = require('graceful-fs'); +const remarkMdx = require('remark-mdx'); +const remark = require('remark'); +const codeTabsPlugin = require('./code-tabs-plugin'); const processFixture = async name => { const filePath = path.join(__dirname, '__fixtures__', `${name}.md`); diff --git a/yarn.lock b/yarn.lock index fd94de5f6954..0d4e5e2ab2aa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -519,13 +519,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.17.12": - version: 7.17.12 - resolution: "@babel/helper-plugin-utils@npm:7.17.12" - checksum: 4813cf0ddb0f143de032cb88d4207024a2334951db330f8216d6fa253ea320c02c9b2667429ef1a34b5e95d4cfbd085f6cb72d418999751c31d0baf2422cc61d - languageName: node - linkType: hard - "@babel/helper-remap-async-to-generator@npm:^7.16.8": version: 7.16.8 resolution: "@babel/helper-remap-async-to-generator@npm:7.16.8" @@ -1030,17 +1023,6 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-jsx@npm:^7.17.12": - version: 7.17.12 - resolution: "@babel/plugin-syntax-jsx@npm:7.17.12" - dependencies: - "@babel/helper-plugin-utils": ^7.17.12 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 6acd0bbca8c3e0100ad61f3b7d0b0111cd241a0710b120b298c4aa0e07be02eccbcca61ede1e7678ade1783a0979f20305b62263df6767fa3fbf658670d82af5 - languageName: node - linkType: hard - "@babel/plugin-syntax-logical-assignment-operators@npm:^7.10.4, @babel/plugin-syntax-logical-assignment-operators@npm:^7.8.3": version: 7.10.4 resolution: "@babel/plugin-syntax-logical-assignment-operators@npm:7.10.4" @@ -1510,21 +1492,6 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-react-jsx@npm:^7.17.12": - version: 7.17.12 - resolution: "@babel/plugin-transform-react-jsx@npm:7.17.12" - dependencies: - "@babel/helper-annotate-as-pure": ^7.16.7 - "@babel/helper-module-imports": ^7.16.7 - "@babel/helper-plugin-utils": ^7.17.12 - "@babel/plugin-syntax-jsx": ^7.17.12 - "@babel/types": ^7.17.12 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 02e9974d14821173bb8e84db4bdfccd546bfdbf445d91d6345f953591f16306cf5741861d72e0d0910f3ffa7d4084fafed99cedf736e7ba8bed0cf64320c2ea6 - languageName: node - linkType: hard - "@babel/plugin-transform-react-pure-annotations@npm:^7.16.7": version: 7.16.7 resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.16.7" @@ -1795,22 +1762,6 @@ __metadata: languageName: node linkType: hard -"@babel/preset-react@npm:^7.17.12": - version: 7.17.12 - resolution: "@babel/preset-react@npm:7.17.12" - dependencies: - "@babel/helper-plugin-utils": ^7.17.12 - "@babel/helper-validator-option": ^7.16.7 - "@babel/plugin-transform-react-display-name": ^7.16.7 - "@babel/plugin-transform-react-jsx": ^7.17.12 - "@babel/plugin-transform-react-jsx-development": ^7.16.7 - "@babel/plugin-transform-react-pure-annotations": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 369712150d6a152720069db8d024320f3d9d2a6611e9b0be4aa03dcab8502fa0e9efc0693c93ba2d818d5243c9d03b015163d76efe65df600f15b9b0a206f674 - languageName: node - linkType: hard - "@babel/preset-typescript@npm:^7.0.0, @babel/preset-typescript@npm:^7.13.0, @babel/preset-typescript@npm:^7.15.0, @babel/preset-typescript@npm:^7.16.7": version: 7.16.7 resolution: "@babel/preset-typescript@npm:7.16.7" @@ -1897,16 +1848,6 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.17.12": - version: 7.18.0 - resolution: "@babel/types@npm:7.18.0" - dependencies: - "@babel/helper-validator-identifier": ^7.16.7 - to-fast-properties: ^2.0.0 - checksum: 151485f94c929171fd6539430c0ae519e8bb67fbc0d856b285328f5e6ecbaf4237b52d7a581b413f5e7b6268d31a4db6ca9bc01372b284b2966aa473fc902f27 - languageName: node - linkType: hard - "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" @@ -13776,8 +13717,6 @@ __metadata: version: 0.0.0-use.local resolution: "jest-website@workspace:website" dependencies: - "@babel/core": ^7.11.6 - "@babel/preset-react": ^7.17.12 "@crowdin/cli": ^3.5.2 "@docusaurus/core": ^2.0.0-beta.17 "@docusaurus/plugin-client-redirects": ^2.0.0-beta.17 From 7e6a2f7bc78fc9cae356d6e07c46eccacfd2fec2 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Sun, 22 May 2022 10:16:24 +0300 Subject: [PATCH 13/35] fix babel --- website/babel.config.js | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 website/babel.config.js diff --git a/website/babel.config.js b/website/babel.config.js deleted file mode 100644 index 5488564d3f2f..000000000000 --- a/website/babel.config.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -module.exports = { - presets: [require.resolve('@docusaurus/core/lib/babel/preset')], -}; From 29e6505e4fe3769148c8e07f79f94c1f04f34cd8 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Sun, 22 May 2022 10:17:11 +0300 Subject: [PATCH 14/35] fix meta check --- website/src/remark/code-tabs-plugin.js | 1 + 1 file changed, 1 insertion(+) diff --git a/website/src/remark/code-tabs-plugin.js b/website/src/remark/code-tabs-plugin.js index e7a9d55ebe04..d55489939f21 100644 --- a/website/src/remark/code-tabs-plugin.js +++ b/website/src/remark/code-tabs-plugin.js @@ -32,6 +32,7 @@ const isImport = node => node.type === 'import'; const isParent = node => Array.isArray(node.children); const isTab = node => node.type === 'code' && + typeof node.meta === 'string' && node.meta.split(' ').some(tag => tag.startsWith('tab')); const isFirstTab = (node, index, parent) => { From 39eeb8b6b71b0c887999f830c391c20f109d3e9a Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Sun, 22 May 2022 10:18:17 +0300 Subject: [PATCH 15/35] tweak processFixture --- website/src/remark/code-tabs-plugin.test.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/website/src/remark/code-tabs-plugin.test.js b/website/src/remark/code-tabs-plugin.test.js index 5a82c1e45f61..17d0af9d6da3 100644 --- a/website/src/remark/code-tabs-plugin.test.js +++ b/website/src/remark/code-tabs-plugin.test.js @@ -11,16 +11,17 @@ const remarkMdx = require('remark-mdx'); const remark = require('remark'); const codeTabsPlugin = require('./code-tabs-plugin'); -const processFixture = async name => { - const filePath = path.join(__dirname, '__fixtures__', `${name}.md`); +async function processFixture(fixture) { + const filePath = path.join(__dirname, '__fixtures__', `${fixture}.md`); const file = fs.readFileSync(filePath); + const result = await remark() .use(remarkMdx) .use(codeTabsPlugin) .process(file); return result.toString(); -}; +} describe('code tabs plugin', () => { test('base example', async () => { From aa36069c25be9244830369b00eeeb158aac6ff3a Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Sun, 22 May 2022 10:21:24 +0300 Subject: [PATCH 16/35] deploy? --- website/src/remark/__fixtures__/full-example.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/remark/__fixtures__/full-example.md b/website/src/remark/__fixtures__/full-example.md index 9b8e17bf5621..7bd46e0bd636 100644 --- a/website/src/remark/__fixtures__/full-example.md +++ b/website/src/remark/__fixtures__/full-example.md @@ -60,4 +60,4 @@ export default config; ::: -Configuration options: +Configuration options. From b66022ad903ef6ce4bf3180263eea6d29544c8e6 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Mon, 23 May 2022 15:59:54 +0300 Subject: [PATCH 17/35] rework logic --- website/package.json | 2 + .../__fixtures__/{base-example.md => base.md} | 0 .../src/remark/__fixtures__/full-example.md | 2 +- website/src/remark/__fixtures__/span.md | 25 +++ .../code-tabs-plugin.test.js.snap | 18 ++ website/src/remark/code-tabs-plugin.js | 159 +++++++++--------- website/src/remark/code-tabs-plugin.test.js | 10 +- yarn.lock | 6 +- 8 files changed, 138 insertions(+), 84 deletions(-) rename website/src/remark/__fixtures__/{base-example.md => base.md} (100%) create mode 100644 website/src/remark/__fixtures__/span.md diff --git a/website/package.json b/website/package.json index f0c7c39a5804..9e8cf91cae9d 100644 --- a/website/package.json +++ b/website/package.json @@ -41,10 +41,12 @@ "react-github-btn": "^1.2.0", "react-lite-youtube-embed": "^2.2.1-a", "react-markdown": "^8.0.0", + "unist-util-is": "^4.1.0", "unist-util-visit": "^2.0.3" }, "devDependencies": { "@crowdin/cli": "^3.5.2", + "@types/mdast": "^3.0.10", "@types/react": "^17.0.3", "graphql": "^16.3.0", "graphql-request": "^4.0.0", diff --git a/website/src/remark/__fixtures__/base-example.md b/website/src/remark/__fixtures__/base.md similarity index 100% rename from website/src/remark/__fixtures__/base-example.md rename to website/src/remark/__fixtures__/base.md diff --git a/website/src/remark/__fixtures__/full-example.md b/website/src/remark/__fixtures__/full-example.md index 7bd46e0bd636..9b8e17bf5621 100644 --- a/website/src/remark/__fixtures__/full-example.md +++ b/website/src/remark/__fixtures__/full-example.md @@ -60,4 +60,4 @@ export default config; ::: -Configuration options. +Configuration options: diff --git a/website/src/remark/__fixtures__/span.md b/website/src/remark/__fixtures__/span.md new file mode 100644 index 000000000000..2972584194e1 --- /dev/null +++ b/website/src/remark/__fixtures__/span.md @@ -0,0 +1,25 @@ +```js tab={"span":2} +console.log('this is first JS codeblock in a tab'); +``` + +```js tab +console.log('this is second JS codeblock in a tab'); +``` + +```ts tab={"span":2} +console.log('this is first TS codeblock in a tab'); +``` + +```ts tab +console.log('this is second TS codeblock in a tab'); +``` + +import Tabs from '@theme/Tabs'; + +import TabItem from '@theme/TabItem'; + +Some text + +```ts title="justfile.ts" +console.log('this is just code'); +``` diff --git a/website/src/remark/__snapshots__/code-tabs-plugin.test.js.snap b/website/src/remark/__snapshots__/code-tabs-plugin.test.js.snap index 284dd979b35d..5c082c052d59 100644 --- a/website/src/remark/__snapshots__/code-tabs-plugin.test.js.snap +++ b/website/src/remark/__snapshots__/code-tabs-plugin.test.js.snap @@ -2,9 +2,11 @@ exports[`code tabs plugin base example 1`] = ` "import Tabs from '@theme/Tabs'; + import TabItem from '@theme/TabItem'; + \`\`\`js tab @@ -20,12 +22,14 @@ console.log('this is TS'); \`\`\` + " `; exports[`code tabs plugin can be nested inside an admonition 1`] = ` "import Tabs from '@theme/Tabs'; + import TabItem from '@theme/TabItem'; ### \`fakeTimers\` \\\\[object] @@ -39,6 +43,7 @@ The fake timers may be useful when a piece of code sets a long timeout that we d Instead of including \`jest.useFakeTimers()\` in each test file, you can enable fake timers globally for all tests in your Jest configuration: + \`\`\`js tab @@ -69,6 +74,7 @@ export default config; \`\`\` + ::: @@ -83,6 +89,7 @@ exports[`code tabs plugin does not re-import tabs components when already import import TabItem from '@theme/TabItem'; + \`\`\`js tab @@ -98,12 +105,14 @@ console.log('this is TS'); \`\`\` + " `; exports[`code tabs plugin does not re-import tabs components when already imported below 1`] = ` " + \`\`\`js tab @@ -119,6 +128,7 @@ console.log('this is TS'); \`\`\` + import Tabs from '@theme/Tabs'; @@ -129,6 +139,7 @@ import TabItem from '@theme/TabItem'; exports[`code tabs plugin full example 1`] = ` "import Tabs from '@theme/Tabs'; + import TabItem from '@theme/TabItem'; ### \`displayName\` \\\\[string, object] @@ -138,6 +149,7 @@ Default: \`undefined\` Allows for a label to be printed alongside a test while it is running. This becomes more useful in multi-project repositories where there can be many jest configuration files. This visually tells which project a test belongs to. + \`\`\`js tab @@ -164,6 +176,7 @@ export default config; \`\`\` + Alternatively, an object with the properties \`name\` and \`color\` can be passed. @@ -179,6 +192,7 @@ The fake timers may be useful when a piece of code sets a long timeout that we d Instead of including \`jest.useFakeTimers()\` in each test file, you can enable fake timers globally for all tests in your Jest configuration: + \`\`\`js tab @@ -209,6 +223,7 @@ export default config; \`\`\` + ::: @@ -219,11 +234,13 @@ Configuration options: exports[`code tabs plugin respects file title 1`] = ` "import Tabs from '@theme/Tabs'; + import TabItem from '@theme/TabItem'; \`.mockImplementation()\` can also be used to mock class constructors: + \`\`\`js tab title=\\"SomeClass.js\\" @@ -243,6 +260,7 @@ export class SomeClass { \`\`\` + ### \`mockFn.mockImplementationOnce(fn)\` diff --git a/website/src/remark/code-tabs-plugin.js b/website/src/remark/code-tabs-plugin.js index d55489939f21..7493537785e7 100644 --- a/website/src/remark/code-tabs-plugin.js +++ b/website/src/remark/code-tabs-plugin.js @@ -6,107 +6,106 @@ */ const visit = require('unist-util-visit'); - -const transformTabNode = (node, options) => { - const label = new Map([ - ['js', 'JavaScript'], - ['ts', 'TypeScript'], - ]); - +const is = require('unist-util-is'); + +const importNodes = [ + { + type: 'import', + value: "import Tabs from '@theme/Tabs';", + }, + { + type: 'import', + value: "import TabItem from '@theme/TabItem';", + }, +]; + +function parseTabMeta(nodeMeta) { + const tabTag = nodeMeta.split(' ').filter(tag => tag.startsWith('tab')); + if (tabTag.length < 1) return null; + + const tabMeta = tabTag[0].split('=')[1] || '{}'; + + return JSON.parse(tabMeta); +} + +const labels = new Map([ + ['js', 'JavaScript'], + ['ts', 'TypeScript'], +]); + +function createTabItem(node) { return [ { type: 'jsx', - value: `${ - options.first ? '\n' : '' - }`, + value: ``, }, node, { type: 'jsx', - value: `${options.last ? '\n' : ''}`, + value: '', }, ]; -}; - -const isImport = node => node.type === 'import'; -const isParent = node => Array.isArray(node.children); -const isTab = node => - node.type === 'code' && - typeof node.meta === 'string' && - node.meta.split(' ').some(tag => tag.startsWith('tab')); - -const isFirstTab = (node, index, parent) => { - if (!isTab(node)) { - return false; - } +} - const nextChild = parent.children[index + 1]; - const previousChild = parent.children[index - 1]; +function createTabs(node, index, parent, meta) { + let tabsCount = 1; + const tabsNode = [ + { + type: 'jsx', + value: '', + }, + ...createTabItem(node), + ]; - const isNextChildTab = nextChild ? isTab(nextChild) : false; - const isPreviousChildTab = previousChild ? isTab(previousChild) : false; + while (index + tabsCount <= parent.children.length) { + const nextNode = parent.children[index + tabsCount]; - return isNextChildTab && !isPreviousChildTab; -}; + if (is(nextNode, 'code') && typeof node.meta === 'string') { + const nextTabMeta = parseTabMeta(nextNode.meta); + if (!nextTabMeta) break; -const isLastTab = (node, index, parent) => { - if (!isTab(node)) { - return false; + tabsCount += 1; + tabsNode.push(...createTabItem(nextNode)); + } else { + break; + } } - const nextChild = parent.children[index + 1]; - const previousChild = parent.children[index - 1]; + if (tabsCount === 1) return null; - const isNextChildTab = nextChild ? isTab(nextChild) : false; - // it should be already transformed - const isPreviousChildTab = - previousChild?.type === 'jsx' && previousChild?.value === ''; + tabsNode.push({ + type: 'jsx', + value: '', + }); - return !isNextChildTab && isPreviousChildTab; -}; + return {tabsNode, tabsCount}; +} -const importTabsNode = { - type: 'import', - value: - "import Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';", -}; +module.exports = function tabsPlugin() { + /** @param {import('@types/mdast').Root tree} */ + return tree => { + let hasTabs = false; + let includesImportTabs = false; -const tabsPlugin = () => root => { - let hasTabs = false; - let hasImportTabsNode = false; + visit(tree, ['code', 'import'], (node, index, parent) => { + if (is(node, 'import') && node.value.includes('@theme/Tabs')) { + includesImportTabs = true; + } - visit(root, node => { - if (isImport(node) && node.value.includes('@theme/Tabs')) { - hasImportTabsNode = true; - } + if (is(node, 'code') && typeof node.meta === 'string') { + const tabMeta = parseTabMeta(node.meta); + if (!tabMeta) return; + + const result = createTabs(node, index, parent, {...tabMeta}); + if (!result) return; - if (isParent(node)) { - let index = 0; - while (index < node.children.length) { - const child = node.children[index]; - - if (isFirstTab(child, index, node)) { - const result = transformTabNode(child, {first: true}); - node.children.splice(index, 1, ...result); - - index += result.length; - hasTabs = true; - } else if (isLastTab(child, index, node)) { - const result = transformTabNode(child, {last: true}); - node.children.splice(index, 1, ...result); - - index += result.length; - hasTabs = true; - } else { - index += 1; - } + hasTabs = true; + parent.children.splice(index, result.tabsCount, ...result.tabsNode); } - } - }); + }); - if (hasTabs && !hasImportTabsNode) { - root.children.unshift(importTabsNode); - } + if (hasTabs && !includesImportTabs) { + tree.children.unshift(...importNodes); + } + }; }; - -module.exports = tabsPlugin; diff --git a/website/src/remark/code-tabs-plugin.test.js b/website/src/remark/code-tabs-plugin.test.js index 17d0af9d6da3..980bc0a74882 100644 --- a/website/src/remark/code-tabs-plugin.test.js +++ b/website/src/remark/code-tabs-plugin.test.js @@ -25,7 +25,7 @@ async function processFixture(fixture) { describe('code tabs plugin', () => { test('base example', async () => { - const result = await processFixture('base-example'); + const result = await processFixture('base'); expect(result).toMatchSnapshot(); }); @@ -48,6 +48,14 @@ describe('code tabs plugin', () => { expect(result).toMatchSnapshot(); }); + test('supports span', async () => { + const result = await processFixture('span'); + + console.log(result); + + // expect(result).toMatchSnapshot(); + }); + test('does not re-import tabs components when already imported above', async () => { const result = await processFixture('import-tabs-above'); diff --git a/yarn.lock b/yarn.lock index 0d4e5e2ab2aa..4dc227e524a6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5120,7 +5120,7 @@ __metadata: languageName: node linkType: hard -"@types/mdast@npm:^3.0.0": +"@types/mdast@npm:^3.0.0, @types/mdast@npm:^3.0.10": version: 3.0.10 resolution: "@types/mdast@npm:3.0.10" dependencies: @@ -13723,6 +13723,7 @@ __metadata: "@docusaurus/plugin-pwa": ^2.0.0-beta.17 "@docusaurus/preset-classic": ^2.0.0-beta.17 "@docusaurus/remark-plugin-npm2yarn": ^2.0.0-beta.17 + "@types/mdast": ^3.0.10 "@types/react": ^17.0.3 clsx: ^1.1.1 globby: ^11.0.1 @@ -13737,6 +13738,7 @@ __metadata: react-markdown: ^8.0.0 remark: ^12.0.1 remark-mdx: ^1.6.21 + unist-util-is: ^4.1.0 unist-util-visit: ^2.0.3 languageName: unknown linkType: soft @@ -21916,7 +21918,7 @@ __metadata: languageName: node linkType: hard -"unist-util-is@npm:^4.0.0": +"unist-util-is@npm:^4.0.0, unist-util-is@npm:^4.1.0": version: 4.1.0 resolution: "unist-util-is@npm:4.1.0" checksum: 726484cd2adc9be75a939aeedd48720f88294899c2e4a3143da413ae593f2b28037570730d5cf5fd910ff41f3bc1501e3d636b6814c478d71126581ef695f7ea From d7f454ce42754bd94fa3500791880e69442bb065 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Mon, 23 May 2022 16:28:40 +0300 Subject: [PATCH 18/35] do not travers transformed nodes --- website/src/remark/code-tabs-plugin.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/website/src/remark/code-tabs-plugin.js b/website/src/remark/code-tabs-plugin.js index 7493537785e7..b1e8c7a1a2f2 100644 --- a/website/src/remark/code-tabs-plugin.js +++ b/website/src/remark/code-tabs-plugin.js @@ -101,6 +101,9 @@ module.exports = function tabsPlugin() { hasTabs = true; parent.children.splice(index, result.tabsCount, ...result.tabsNode); + + // eslint-disable-next-line consistent-return + return index + result.tabsNode.length; } }); From b22c274af8bf77e8d141518713486cc3b1653c57 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 24 May 2022 07:10:28 +0300 Subject: [PATCH 19/35] clean up --- website/src/remark/code-tabs-plugin.js | 51 ++++++++++++++------------ 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/website/src/remark/code-tabs-plugin.js b/website/src/remark/code-tabs-plugin.js index b1e8c7a1a2f2..62b90d65d83f 100644 --- a/website/src/remark/code-tabs-plugin.js +++ b/website/src/remark/code-tabs-plugin.js @@ -33,52 +33,53 @@ const labels = new Map([ ['ts', 'TypeScript'], ]); -function createTabItem(node) { +function createTabs(nodes) { return [ { type: 'jsx', - value: ``, + value: '', }, - node, + ...nodes, { type: 'jsx', - value: '', + value: '', }, ]; } -function createTabs(node, index, parent, meta) { - let tabsCount = 1; - const tabsNode = [ +function createTabItem(node) { + return [ { type: 'jsx', - value: '', + value: ``, + }, + node, + { + type: 'jsx', + value: '', }, - ...createTabItem(node), ]; +} + +function formatTabItems(node, index, parent) { + const tabItems = [createTabItem(node)]; - while (index + tabsCount <= parent.children.length) { - const nextNode = parent.children[index + tabsCount]; + while (index + tabItems.length <= parent.children.length) { + const nextNode = parent.children[index + tabItems.length]; if (is(nextNode, 'code') && typeof node.meta === 'string') { const nextTabMeta = parseTabMeta(nextNode.meta); if (!nextTabMeta) break; - tabsCount += 1; - tabsNode.push(...createTabItem(nextNode)); + tabItems.push(createTabItem(nextNode)); } else { break; } } - if (tabsCount === 1) return null; + if (tabItems.length === 1) return null; - tabsNode.push({ - type: 'jsx', - value: '', - }); - - return {tabsNode, tabsCount}; + return tabItems; } module.exports = function tabsPlugin() { @@ -96,14 +97,16 @@ module.exports = function tabsPlugin() { const tabMeta = parseTabMeta(node.meta); if (!tabMeta) return; - const result = createTabs(node, index, parent, {...tabMeta}); - if (!result) return; + const tabItems = formatTabItems(node, index, parent); + if (!tabItems) return; + + const tabs = createTabs(tabItems.flat()); hasTabs = true; - parent.children.splice(index, result.tabsCount, ...result.tabsNode); + parent.children.splice(index, tabItems.length, ...tabs); // eslint-disable-next-line consistent-return - return index + result.tabsNode.length; + return index + tabs.length; } }); From b44faa3d0490a557e56f2ee473ae7292124b5d72 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 24 May 2022 10:13:37 +0300 Subject: [PATCH 20/35] add span support --- .../src/remark/__fixtures__/full-example.md | 50 ++++++++- website/src/remark/__fixtures__/span.md | 10 +- .../__fixtures__/{file-title.md => title.md} | 0 .../code-tabs-plugin.test.js.snap | 105 +++++++++++++++++- website/src/remark/code-tabs-plugin.js | 66 +++++------ website/src/remark/code-tabs-plugin.test.js | 10 +- 6 files changed, 193 insertions(+), 48 deletions(-) rename website/src/remark/__fixtures__/{file-title.md => title.md} (100%) diff --git a/website/src/remark/__fixtures__/full-example.md b/website/src/remark/__fixtures__/full-example.md index 9b8e17bf5621..fe50ba8878ac 100644 --- a/website/src/remark/__fixtures__/full-example.md +++ b/website/src/remark/__fixtures__/full-example.md @@ -60,4 +60,52 @@ export default config; ::: -Configuration options: +`.mockImplementation()` can also be used to mock class constructors: + +```js tab={"span":2} title="SomeClass.js" +module.exports = class SomeClass { + method(a, b) {} +}; +``` + +```js title="SomeClass.test.js" +const SomeClass = require('./SomeClass'); + +jest.mock('./SomeClass'); // this happens automatically with automocking + +const mockMethod = jest.fn(); +SomeClass.mockImplementation(() => { + return { + method: mockMethod, + }; +}); + +const some = new SomeClass(); +some.method('a', 'b'); + +console.log('Calls to method: ', mockMethod.mock.calls); +``` + +```ts tab={"span":2} title="SomeClass.ts" +export class SomeClass { + method(a: string, b: string): void {} +} +``` + +```ts title="SomeClass.test.ts" +import {SomeClass} from './SomeClass'; + +jest.mock('./SomeClass'); // this happens automatically with automocking + +const mockMethod = jest.fn<(a: string, b: string) => void>(); +SomeClass.mockImplementation(() => { + return { + method: mockMethod, + }; +}); + +const some = new SomeClass(); +some.method('a', 'b'); + +console.log('Calls to method: ', mockMethod.mock.calls); +``` diff --git a/website/src/remark/__fixtures__/span.md b/website/src/remark/__fixtures__/span.md index 2972584194e1..bfda2911151a 100644 --- a/website/src/remark/__fixtures__/span.md +++ b/website/src/remark/__fixtures__/span.md @@ -2,7 +2,7 @@ console.log('this is first JS codeblock in a tab'); ``` -```js tab +```js console.log('this is second JS codeblock in a tab'); ``` @@ -10,16 +10,12 @@ console.log('this is second JS codeblock in a tab'); console.log('this is first TS codeblock in a tab'); ``` -```ts tab +```ts console.log('this is second TS codeblock in a tab'); ``` -import Tabs from '@theme/Tabs'; - -import TabItem from '@theme/TabItem'; - Some text -```ts title="justfile.ts" +```ts title="some-file.ts" console.log('this is just code'); ``` diff --git a/website/src/remark/__fixtures__/file-title.md b/website/src/remark/__fixtures__/title.md similarity index 100% rename from website/src/remark/__fixtures__/file-title.md rename to website/src/remark/__fixtures__/title.md diff --git a/website/src/remark/__snapshots__/code-tabs-plugin.test.js.snap b/website/src/remark/__snapshots__/code-tabs-plugin.test.js.snap index 5c082c052d59..072e5b0a0c0f 100644 --- a/website/src/remark/__snapshots__/code-tabs-plugin.test.js.snap +++ b/website/src/remark/__snapshots__/code-tabs-plugin.test.js.snap @@ -228,11 +228,71 @@ export default config; ::: -Configuration options: +\`.mockImplementation()\` can also be used to mock class constructors: + + + + + +\`\`\`js tab={\\"span\\":2} title=\\"SomeClass.js\\" +module.exports = class SomeClass { + method(a, b) {} +}; +\`\`\` + +\`\`\`js title=\\"SomeClass.test.js\\" +const SomeClass = require('./SomeClass'); + +jest.mock('./SomeClass'); // this happens automatically with automocking + +const mockMethod = jest.fn(); +SomeClass.mockImplementation(() => { + return { + method: mockMethod, + }; +}); + +const some = new SomeClass(); +some.method('a', 'b'); + +console.log('Calls to method: ', mockMethod.mock.calls); +\`\`\` + + + + + +\`\`\`ts tab={\\"span\\":2} title=\\"SomeClass.ts\\" +export class SomeClass { + method(a: string, b: string): void {} +} +\`\`\` + +\`\`\`ts title=\\"SomeClass.test.ts\\" +import {SomeClass} from './SomeClass'; + +jest.mock('./SomeClass'); // this happens automatically with automocking + +const mockMethod = jest.fn<(a: string, b: string) => void>(); +SomeClass.mockImplementation(() => { + return { + method: mockMethod, + }; +}); + +const some = new SomeClass(); +some.method('a', 'b'); + +console.log('Calls to method: ', mockMethod.mock.calls); +\`\`\` + + + + " `; -exports[`code tabs plugin respects file title 1`] = ` +exports[`code tabs plugin respects title meta 1`] = ` "import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; @@ -268,3 +328,44 @@ export class SomeClass { Accepts a function that will be used as an implementation of the mock for one call to the mocked function. Can be chained so that multiple function calls produce different results. " `; + +exports[`code tabs plugin supports span meta 1`] = ` +"import Tabs from '@theme/Tabs'; + +import TabItem from '@theme/TabItem'; + + + + + +\`\`\`js tab={\\"span\\":2} +console.log('this is first JS codeblock in a tab'); +\`\`\` + +\`\`\`js +console.log('this is second JS codeblock in a tab'); +\`\`\` + + + + + +\`\`\`ts tab={\\"span\\":2} +console.log('this is first TS codeblock in a tab'); +\`\`\` + +\`\`\`ts +console.log('this is second TS codeblock in a tab'); +\`\`\` + + + + + +Some text + +\`\`\`ts title=\\"some-file.ts\\" +console.log('this is just code'); +\`\`\` +" +`; diff --git a/website/src/remark/code-tabs-plugin.js b/website/src/remark/code-tabs-plugin.js index 62b90d65d83f..7a4c5f5160e5 100644 --- a/website/src/remark/code-tabs-plugin.js +++ b/website/src/remark/code-tabs-plugin.js @@ -25,7 +25,7 @@ function parseTabMeta(nodeMeta) { const tabMeta = tabTag[0].split('=')[1] || '{}'; - return JSON.parse(tabMeta); + return {span: 1, ...JSON.parse(tabMeta)}; } const labels = new Map([ @@ -33,53 +33,57 @@ const labels = new Map([ ['ts', 'TypeScript'], ]); -function createTabs(nodes) { +function formatTabItem(nodes) { return [ { type: 'jsx', - value: '', + value: ``, }, ...nodes, { type: 'jsx', - value: '', + value: '', }, ]; } -function createTabItem(node) { +function formatTabs(tabNodes) { return [ { type: 'jsx', - value: ``, + value: '', }, - node, + ...tabNodes.map(node => formatTabItem(node)), { type: 'jsx', - value: '', + value: '', }, - ]; + ].flat(); } -function formatTabItems(node, index, parent) { - const tabItems = [createTabItem(node)]; +function collectTabNodes(parent, index) { + let nodeIndex = index; + const tabNodes = []; - while (index + tabItems.length <= parent.children.length) { - const nextNode = parent.children[index + tabItems.length]; + do { + const node = parent.children[nodeIndex]; - if (is(nextNode, 'code') && typeof node.meta === 'string') { - const nextTabMeta = parseTabMeta(nextNode.meta); - if (!nextTabMeta) break; + if (is(node, 'code') && typeof node.meta === 'string') { + const tabMeta = parseTabMeta(node.meta); + if (!tabMeta) break; - tabItems.push(createTabItem(nextNode)); + tabNodes.push(parent.children.slice(nodeIndex, nodeIndex + tabMeta.span)); + nodeIndex += tabMeta.span; } else { break; } - } + } while (nodeIndex <= parent.children.length); - if (tabItems.length === 1) return null; + if (tabNodes.length <= 1) return null; - return tabItems; + return tabNodes; } module.exports = function tabsPlugin() { @@ -93,21 +97,19 @@ module.exports = function tabsPlugin() { includesImportTabs = true; } - if (is(node, 'code') && typeof node.meta === 'string') { - const tabMeta = parseTabMeta(node.meta); - if (!tabMeta) return; + const tabNodes = collectTabNodes(parent, index); + if (!tabNodes) return; - const tabItems = formatTabItems(node, index, parent); - if (!tabItems) return; + hasTabs = true; - const tabs = createTabs(tabItems.flat()); + parent.children.splice( + index, + tabNodes.flat().length, + ...formatTabs(tabNodes) + ); - hasTabs = true; - parent.children.splice(index, tabItems.length, ...tabs); - - // eslint-disable-next-line consistent-return - return index + tabs.length; - } + // eslint-disable-next-line consistent-return + return index + tabNodes.flat().length; }); if (hasTabs && !includesImportTabs) { diff --git a/website/src/remark/code-tabs-plugin.test.js b/website/src/remark/code-tabs-plugin.test.js index 980bc0a74882..7bd46205fb7e 100644 --- a/website/src/remark/code-tabs-plugin.test.js +++ b/website/src/remark/code-tabs-plugin.test.js @@ -42,18 +42,16 @@ describe('code tabs plugin', () => { expect(result).toMatchSnapshot(); }); - test('respects file title', async () => { - const result = await processFixture('file-title'); + test('respects title meta', async () => { + const result = await processFixture('title'); expect(result).toMatchSnapshot(); }); - test('supports span', async () => { + test('supports span meta', async () => { const result = await processFixture('span'); - console.log(result); - - // expect(result).toMatchSnapshot(); + expect(result).toMatchSnapshot(); }); test('does not re-import tabs components when already imported above', async () => { From ef6e70c6d94ba4b363af35cb6490b13b2a018544 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 24 May 2022 10:13:56 +0300 Subject: [PATCH 21/35] use span in docs --- docs/MockFunctionAPI.md | 14 ++------------ .../versioned_docs/version-28.0/MockFunctionAPI.md | 14 ++------------ .../versioned_docs/version-28.1/MockFunctionAPI.md | 14 ++------------ 3 files changed, 6 insertions(+), 36 deletions(-) diff --git a/docs/MockFunctionAPI.md b/docs/MockFunctionAPI.md index a68233a07c8e..b7ba592c6009 100644 --- a/docs/MockFunctionAPI.md +++ b/docs/MockFunctionAPI.md @@ -182,10 +182,7 @@ mockFn(3); // 39 `.mockImplementation()` can also be used to mock class constructors: - - - -```js title="SomeClass.js" +```js tab={"span":2} title="SomeClass.js" module.exports = class SomeClass { method(a, b) {} }; @@ -209,11 +206,7 @@ some.method('a', 'b'); console.log('Calls to method: ', mockMethod.mock.calls); ``` - - - - -```ts title="SomeClass.ts" +```ts tab={"span":2} title="SomeClass.ts" export class SomeClass { method(a: string, b: string): void {} } @@ -237,9 +230,6 @@ some.method('a', 'b'); console.log('Calls to method: ', mockMethod.mock.calls); ``` - - - ### `mockFn.mockImplementationOnce(fn)` Accepts a function that will be used as an implementation of the mock for one call to the mocked function. Can be chained so that multiple function calls produce different results. diff --git a/website/versioned_docs/version-28.0/MockFunctionAPI.md b/website/versioned_docs/version-28.0/MockFunctionAPI.md index a68233a07c8e..b7ba592c6009 100644 --- a/website/versioned_docs/version-28.0/MockFunctionAPI.md +++ b/website/versioned_docs/version-28.0/MockFunctionAPI.md @@ -182,10 +182,7 @@ mockFn(3); // 39 `.mockImplementation()` can also be used to mock class constructors: - - - -```js title="SomeClass.js" +```js tab={"span":2} title="SomeClass.js" module.exports = class SomeClass { method(a, b) {} }; @@ -209,11 +206,7 @@ some.method('a', 'b'); console.log('Calls to method: ', mockMethod.mock.calls); ``` - - - - -```ts title="SomeClass.ts" +```ts tab={"span":2} title="SomeClass.ts" export class SomeClass { method(a: string, b: string): void {} } @@ -237,9 +230,6 @@ some.method('a', 'b'); console.log('Calls to method: ', mockMethod.mock.calls); ``` - - - ### `mockFn.mockImplementationOnce(fn)` Accepts a function that will be used as an implementation of the mock for one call to the mocked function. Can be chained so that multiple function calls produce different results. diff --git a/website/versioned_docs/version-28.1/MockFunctionAPI.md b/website/versioned_docs/version-28.1/MockFunctionAPI.md index a68233a07c8e..b7ba592c6009 100644 --- a/website/versioned_docs/version-28.1/MockFunctionAPI.md +++ b/website/versioned_docs/version-28.1/MockFunctionAPI.md @@ -182,10 +182,7 @@ mockFn(3); // 39 `.mockImplementation()` can also be used to mock class constructors: - - - -```js title="SomeClass.js" +```js tab={"span":2} title="SomeClass.js" module.exports = class SomeClass { method(a, b) {} }; @@ -209,11 +206,7 @@ some.method('a', 'b'); console.log('Calls to method: ', mockMethod.mock.calls); ``` - - - - -```ts title="SomeClass.ts" +```ts tab={"span":2} title="SomeClass.ts" export class SomeClass { method(a: string, b: string): void {} } @@ -237,9 +230,6 @@ some.method('a', 'b'); console.log('Calls to method: ', mockMethod.mock.calls); ``` - - - ### `mockFn.mockImplementationOnce(fn)` Accepts a function that will be used as an implementation of the mock for one call to the mocked function. Can be chained so that multiple function calls produce different results. From 834351743131ef3152688f8259e61d95f7805378 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 24 May 2022 10:20:47 +0300 Subject: [PATCH 22/35] fix node count --- website/src/remark/code-tabs-plugin.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/website/src/remark/code-tabs-plugin.js b/website/src/remark/code-tabs-plugin.js index 7a4c5f5160e5..481743e037ea 100644 --- a/website/src/remark/code-tabs-plugin.js +++ b/website/src/remark/code-tabs-plugin.js @@ -101,15 +101,12 @@ module.exports = function tabsPlugin() { if (!tabNodes) return; hasTabs = true; + const tabs = formatTabs(tabNodes); - parent.children.splice( - index, - tabNodes.flat().length, - ...formatTabs(tabNodes) - ); + parent.children.splice(index, tabNodes.flat().length, ...tabs); // eslint-disable-next-line consistent-return - return index + tabNodes.flat().length; + return index + tabs.length; }); if (hasTabs && !includesImportTabs) { From 3733213c061f6eec36fed39882c21c6c3f6c9e6e Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 24 May 2022 10:22:17 +0300 Subject: [PATCH 23/35] run tests before deploy --- website/package.json | 5 +++-- website/src/remark/{ => __tests__}/__fixtures__/base.md | 0 .../src/remark/{ => __tests__}/__fixtures__/full-example.md | 0 .../remark/{ => __tests__}/__fixtures__/import-tabs-above.md | 0 .../remark/{ => __tests__}/__fixtures__/import-tabs-below.md | 0 .../remark/{ => __tests__}/__fixtures__/inside-admonition.md | 0 website/src/remark/{ => __tests__}/__fixtures__/span.md | 0 website/src/remark/{ => __tests__}/__fixtures__/title.md | 0 .../__snapshots__/code-tabs-plugin.test.js.snap | 0 website/src/remark/{ => __tests__}/code-tabs-plugin.test.js | 2 +- 10 files changed, 4 insertions(+), 3 deletions(-) rename website/src/remark/{ => __tests__}/__fixtures__/base.md (100%) rename website/src/remark/{ => __tests__}/__fixtures__/full-example.md (100%) rename website/src/remark/{ => __tests__}/__fixtures__/import-tabs-above.md (100%) rename website/src/remark/{ => __tests__}/__fixtures__/import-tabs-below.md (100%) rename website/src/remark/{ => __tests__}/__fixtures__/inside-admonition.md (100%) rename website/src/remark/{ => __tests__}/__fixtures__/span.md (100%) rename website/src/remark/{ => __tests__}/__fixtures__/title.md (100%) rename website/src/remark/{ => __tests__}/__snapshots__/code-tabs-plugin.test.js.snap (100%) rename website/src/remark/{ => __tests__}/code-tabs-plugin.test.js (97%) diff --git a/website/package.json b/website/package.json index 9e8cf91cae9d..07d745131bde 100644 --- a/website/package.json +++ b/website/package.json @@ -11,8 +11,9 @@ "serve": "docusaurus serve", "write-translations": "docusaurus write-translations", "fetchSupporters": "node fetchSupporters.js", - "netlify:ci:production": "yarn netlify:prepare && yarn netlify:crowdin && yarn build", - "netlify:ci:deployPreview": "yarn netlify:prepare && yarn build -l en", + "test": "yarn jest", + "netlify:ci:production": "yarn test && yarn netlify:prepare && yarn netlify:crowdin && yarn build", + "netlify:ci:deployPreview": "yarn test && yarn netlify:prepare && yarn build -l en", "netlify:prepare": "yarn fetchSupporters && yarn build:js", "netlify:crowdin": "yarn write-translations && yarn crowdin:upload && yarn crowdin:download" }, diff --git a/website/src/remark/__fixtures__/base.md b/website/src/remark/__tests__/__fixtures__/base.md similarity index 100% rename from website/src/remark/__fixtures__/base.md rename to website/src/remark/__tests__/__fixtures__/base.md diff --git a/website/src/remark/__fixtures__/full-example.md b/website/src/remark/__tests__/__fixtures__/full-example.md similarity index 100% rename from website/src/remark/__fixtures__/full-example.md rename to website/src/remark/__tests__/__fixtures__/full-example.md diff --git a/website/src/remark/__fixtures__/import-tabs-above.md b/website/src/remark/__tests__/__fixtures__/import-tabs-above.md similarity index 100% rename from website/src/remark/__fixtures__/import-tabs-above.md rename to website/src/remark/__tests__/__fixtures__/import-tabs-above.md diff --git a/website/src/remark/__fixtures__/import-tabs-below.md b/website/src/remark/__tests__/__fixtures__/import-tabs-below.md similarity index 100% rename from website/src/remark/__fixtures__/import-tabs-below.md rename to website/src/remark/__tests__/__fixtures__/import-tabs-below.md diff --git a/website/src/remark/__fixtures__/inside-admonition.md b/website/src/remark/__tests__/__fixtures__/inside-admonition.md similarity index 100% rename from website/src/remark/__fixtures__/inside-admonition.md rename to website/src/remark/__tests__/__fixtures__/inside-admonition.md diff --git a/website/src/remark/__fixtures__/span.md b/website/src/remark/__tests__/__fixtures__/span.md similarity index 100% rename from website/src/remark/__fixtures__/span.md rename to website/src/remark/__tests__/__fixtures__/span.md diff --git a/website/src/remark/__fixtures__/title.md b/website/src/remark/__tests__/__fixtures__/title.md similarity index 100% rename from website/src/remark/__fixtures__/title.md rename to website/src/remark/__tests__/__fixtures__/title.md diff --git a/website/src/remark/__snapshots__/code-tabs-plugin.test.js.snap b/website/src/remark/__tests__/__snapshots__/code-tabs-plugin.test.js.snap similarity index 100% rename from website/src/remark/__snapshots__/code-tabs-plugin.test.js.snap rename to website/src/remark/__tests__/__snapshots__/code-tabs-plugin.test.js.snap diff --git a/website/src/remark/code-tabs-plugin.test.js b/website/src/remark/__tests__/code-tabs-plugin.test.js similarity index 97% rename from website/src/remark/code-tabs-plugin.test.js rename to website/src/remark/__tests__/code-tabs-plugin.test.js index 7bd46205fb7e..0d0a2e4e2869 100644 --- a/website/src/remark/code-tabs-plugin.test.js +++ b/website/src/remark/__tests__/code-tabs-plugin.test.js @@ -9,7 +9,7 @@ const path = require('node:path'); const fs = require('graceful-fs'); const remarkMdx = require('remark-mdx'); const remark = require('remark'); -const codeTabsPlugin = require('./code-tabs-plugin'); +const codeTabsPlugin = require('../code-tabs-plugin'); async function processFixture(fixture) { const filePath = path.join(__dirname, '__fixtures__', `${fixture}.md`); From b6fe5c6ed3c740302d43a92b890327b955b47a9d Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 24 May 2022 10:28:53 +0300 Subject: [PATCH 24/35] hm.. --- website/package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/website/package.json b/website/package.json index 07d745131bde..9a480014d455 100644 --- a/website/package.json +++ b/website/package.json @@ -11,7 +11,7 @@ "serve": "docusaurus serve", "write-translations": "docusaurus write-translations", "fetchSupporters": "node fetchSupporters.js", - "test": "yarn jest", + "jest": "node ../packages/jest-cli/bin/jest.js", "netlify:ci:production": "yarn test && yarn netlify:prepare && yarn netlify:crowdin && yarn build", "netlify:ci:deployPreview": "yarn test && yarn netlify:prepare && yarn build -l en", "netlify:prepare": "yarn fetchSupporters && yarn build:js", @@ -51,7 +51,6 @@ "@types/react": "^17.0.3", "graphql": "^16.3.0", "graphql-request": "^4.0.0", - "jest": "workspace:*", "js-yaml": "^4.1.0", "remark": "^12.0.1", "remark-mdx": "^1.6.21" From fd09543d790b615cd1a6d4b203ee2d0f7e405240 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 24 May 2022 10:30:24 +0300 Subject: [PATCH 25/35] lock --- yarn.lock | 1 - 1 file changed, 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index 4dc227e524a6..12aeea0e46db 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13729,7 +13729,6 @@ __metadata: globby: ^11.0.1 graphql: ^16.3.0 graphql-request: ^4.0.0 - jest: "workspace:*" js-yaml: ^4.1.0 react: 17.0.2 react-dom: ^17.0.1 From cd98e665da29eedcbe706e420f310841f13a2983 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 24 May 2022 10:33:34 +0300 Subject: [PATCH 26/35] fix scripts --- website/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/package.json b/website/package.json index 9a480014d455..e5ae5657dc44 100644 --- a/website/package.json +++ b/website/package.json @@ -12,8 +12,8 @@ "write-translations": "docusaurus write-translations", "fetchSupporters": "node fetchSupporters.js", "jest": "node ../packages/jest-cli/bin/jest.js", - "netlify:ci:production": "yarn test && yarn netlify:prepare && yarn netlify:crowdin && yarn build", - "netlify:ci:deployPreview": "yarn test && yarn netlify:prepare && yarn build -l en", + "netlify:ci:production": "yarn netlify:prepare && yarn jest && yarn netlify:crowdin && yarn build", + "netlify:ci:deployPreview": "yarn netlify:prepare && yarn jest && yarn build -l en", "netlify:prepare": "yarn fetchSupporters && yarn build:js", "netlify:crowdin": "yarn write-translations && yarn crowdin:upload && yarn crowdin:download" }, From c1985d3ebf5099650e11eabebb5ae862775d699d Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 24 May 2022 10:41:07 +0300 Subject: [PATCH 27/35] add changelog entry --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f5e645f4dfb..cef4943dfc54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,8 +13,10 @@ ### Chore & Maintenance - `[docs]` Updated docs to indicate that `jest-environment-jsdom` is a separate package [#12828](https://github.com/facebook/jest/issues/12828) -- `[jest-haste-map]` Bump `walker` version ([#12324](https://github.com/facebook/jest/pull/12324)) - `[docs]` Document the comments used by coverage providers [#12835](https://github.com/facebook/jest/issues/12835) +- `[docs]` Fix typo in `--shard` CLI docs ([#12761](https://github.com/facebook/jest/pull/12761)) +- `[docs]` Use custom Remark plugin to format tabs with code examples ([#12859](https://github.com/facebook/jest/pull/12859)) +- `[jest-haste-map]` Bump `walker` version ([#12324](https://github.com/facebook/jest/pull/12324)) ### Performance From 6a4a028b36c3c02bf9faa794e9c70719a5444d48 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 24 May 2022 10:46:29 +0300 Subject: [PATCH 28/35] clean up --- website/package.json | 1 - yarn.lock | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/website/package.json b/website/package.json index e5ae5657dc44..7631c5ae2ad1 100644 --- a/website/package.json +++ b/website/package.json @@ -47,7 +47,6 @@ }, "devDependencies": { "@crowdin/cli": "^3.5.2", - "@types/mdast": "^3.0.10", "@types/react": "^17.0.3", "graphql": "^16.3.0", "graphql-request": "^4.0.0", diff --git a/yarn.lock b/yarn.lock index 12aeea0e46db..c59dfc12fe4d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5120,7 +5120,7 @@ __metadata: languageName: node linkType: hard -"@types/mdast@npm:^3.0.0, @types/mdast@npm:^3.0.10": +"@types/mdast@npm:^3.0.0": version: 3.0.10 resolution: "@types/mdast@npm:3.0.10" dependencies: @@ -13723,7 +13723,6 @@ __metadata: "@docusaurus/plugin-pwa": ^2.0.0-beta.17 "@docusaurus/preset-classic": ^2.0.0-beta.17 "@docusaurus/remark-plugin-npm2yarn": ^2.0.0-beta.17 - "@types/mdast": ^3.0.10 "@types/react": ^17.0.3 clsx: ^1.1.1 globby: ^11.0.1 From 359bb9cb9db535608cb56736afb993ee6e014351 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 24 May 2022 10:47:21 +0300 Subject: [PATCH 29/35] revert babel --- website/package.json | 1 + yarn.lock | 1 + 2 files changed, 2 insertions(+) diff --git a/website/package.json b/website/package.json index 7631c5ae2ad1..d86664e3111e 100644 --- a/website/package.json +++ b/website/package.json @@ -46,6 +46,7 @@ "unist-util-visit": "^2.0.3" }, "devDependencies": { + "@babel/core": "^7.11.6", "@crowdin/cli": "^3.5.2", "@types/react": "^17.0.3", "graphql": "^16.3.0", diff --git a/yarn.lock b/yarn.lock index c59dfc12fe4d..2d2737167cd7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13717,6 +13717,7 @@ __metadata: version: 0.0.0-use.local resolution: "jest-website@workspace:website" dependencies: + "@babel/core": ^7.11.6 "@crowdin/cli": ^3.5.2 "@docusaurus/core": ^2.0.0-beta.17 "@docusaurus/plugin-client-redirects": ^2.0.0-beta.17 From 8ab524bb2a2b29acec711ec834434296dc0b3ec6 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 24 May 2022 11:27:51 +0300 Subject: [PATCH 30/35] deps --- website/package.json | 4 ++-- yarn.lock | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/website/package.json b/website/package.json index d86664e3111e..0251eab77761 100644 --- a/website/package.json +++ b/website/package.json @@ -42,8 +42,8 @@ "react-github-btn": "^1.2.0", "react-lite-youtube-embed": "^2.2.1-a", "react-markdown": "^8.0.0", - "unist-util-is": "^4.1.0", - "unist-util-visit": "^2.0.3" + "unist-util-is": "^4.0.0", + "unist-util-visit": "^2.0.0" }, "devDependencies": { "@babel/core": "^7.11.6", diff --git a/yarn.lock b/yarn.lock index 2d2737167cd7..dc971387bfa3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13737,8 +13737,8 @@ __metadata: react-markdown: ^8.0.0 remark: ^12.0.1 remark-mdx: ^1.6.21 - unist-util-is: ^4.1.0 - unist-util-visit: ^2.0.3 + unist-util-is: ^4.0.0 + unist-util-visit: ^2.0.0 languageName: unknown linkType: soft @@ -21917,7 +21917,7 @@ __metadata: languageName: node linkType: hard -"unist-util-is@npm:^4.0.0, unist-util-is@npm:^4.1.0": +"unist-util-is@npm:^4.0.0": version: 4.1.0 resolution: "unist-util-is@npm:4.1.0" checksum: 726484cd2adc9be75a939aeedd48720f88294899c2e4a3143da413ae593f2b28037570730d5cf5fd910ff41f3bc1501e3d636b6814c478d71126581ef695f7ea From 6e6ae7ead2871dc79095a0d5f1db63218a055d08 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 24 May 2022 11:29:11 +0300 Subject: [PATCH 31/35] deps --- website/package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/website/package.json b/website/package.json index 0251eab77761..b04108abb1b2 100644 --- a/website/package.json +++ b/website/package.json @@ -53,6 +53,6 @@ "graphql-request": "^4.0.0", "js-yaml": "^4.1.0", "remark": "^12.0.1", - "remark-mdx": "^1.6.21" + "remark-mdx": "^1.6.22" } } diff --git a/yarn.lock b/yarn.lock index dc971387bfa3..6596fb25e062 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13736,7 +13736,7 @@ __metadata: react-lite-youtube-embed: ^2.2.1-a react-markdown: ^8.0.0 remark: ^12.0.1 - remark-mdx: ^1.6.21 + remark-mdx: ^1.6.22 unist-util-is: ^4.0.0 unist-util-visit: ^2.0.0 languageName: unknown @@ -19186,7 +19186,7 @@ __metadata: languageName: node linkType: hard -"remark-mdx@npm:1.6.22, remark-mdx@npm:^1.6.21": +"remark-mdx@npm:1.6.22, remark-mdx@npm:^1.6.22": version: 1.6.22 resolution: "remark-mdx@npm:1.6.22" dependencies: From 7137bae6cc1e4e85d40e69e0ea569d5d17a19087 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 24 May 2022 11:47:56 +0300 Subject: [PATCH 32/35] ignore incomplete spans --- .../__tests__/__fixtures__/span-incomplete.md | 21 ++++++++++++++++ .../code-tabs-plugin.test.js.snap | 25 +++++++++++++++++++ .../remark/__tests__/code-tabs-plugin.test.js | 6 +++++ website/src/remark/code-tabs-plugin.js | 12 ++++++++- 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 website/src/remark/__tests__/__fixtures__/span-incomplete.md diff --git a/website/src/remark/__tests__/__fixtures__/span-incomplete.md b/website/src/remark/__tests__/__fixtures__/span-incomplete.md new file mode 100644 index 000000000000..d7a97f961852 --- /dev/null +++ b/website/src/remark/__tests__/__fixtures__/span-incomplete.md @@ -0,0 +1,21 @@ +```js tab={"span":2} +console.log('this is first a codeblock'); +``` + +```js +console.log('this is second a codeblock'); +``` + +```js tab={"span":3} +console.log('this is first a codeblock'); +``` + +```js +console.log('this is second a codeblock'); +``` + +Third codeblock went missing. + +```ts tab={"span":2} +console.log('this is a code '); +``` diff --git a/website/src/remark/__tests__/__snapshots__/code-tabs-plugin.test.js.snap b/website/src/remark/__tests__/__snapshots__/code-tabs-plugin.test.js.snap index 072e5b0a0c0f..5b7cf6551ffa 100644 --- a/website/src/remark/__tests__/__snapshots__/code-tabs-plugin.test.js.snap +++ b/website/src/remark/__tests__/__snapshots__/code-tabs-plugin.test.js.snap @@ -292,6 +292,31 @@ console.log('Calls to method: ', mockMethod.mock.calls); " `; +exports[`code tabs plugin ignores incomplete spans 1`] = ` +"\`\`\`js tab={\\"span\\":2} +console.log('this is first a codeblock'); +\`\`\` + +\`\`\`js +console.log('this is second a codeblock'); +\`\`\` + +\`\`\`js tab={\\"span\\":3} +console.log('this is first a codeblock'); +\`\`\` + +\`\`\`js +console.log('this is second a codeblock'); +\`\`\` + +Third codeblock went missing. + +\`\`\`ts tab={\\"span\\":2} +console.log('this is a code '); +\`\`\` +" +`; + exports[`code tabs plugin respects title meta 1`] = ` "import Tabs from '@theme/Tabs'; diff --git a/website/src/remark/__tests__/code-tabs-plugin.test.js b/website/src/remark/__tests__/code-tabs-plugin.test.js index 0d0a2e4e2869..c184b5f94062 100644 --- a/website/src/remark/__tests__/code-tabs-plugin.test.js +++ b/website/src/remark/__tests__/code-tabs-plugin.test.js @@ -54,6 +54,12 @@ describe('code tabs plugin', () => { expect(result).toMatchSnapshot(); }); + test('ignores incomplete spans', async () => { + const result = await processFixture('span-incomplete'); + + expect(result).toMatchSnapshot(); + }); + test('does not re-import tabs components when already imported above', async () => { const result = await processFixture('import-tabs-above'); diff --git a/website/src/remark/code-tabs-plugin.js b/website/src/remark/code-tabs-plugin.js index 481743e037ea..22b154771e9e 100644 --- a/website/src/remark/code-tabs-plugin.js +++ b/website/src/remark/code-tabs-plugin.js @@ -74,7 +74,17 @@ function collectTabNodes(parent, index) { const tabMeta = parseTabMeta(node.meta); if (!tabMeta) break; - tabNodes.push(parent.children.slice(nodeIndex, nodeIndex + tabMeta.span)); + const nodes = parent.children.slice(nodeIndex, nodeIndex + tabMeta.span); + + if ( + nodes.length === tabMeta.span && + nodes.every(node => is(node, 'code')) + ) { + tabNodes.push(nodes); + } else { + break; + } + nodeIndex += tabMeta.span; } else { break; From d15f3feec3ec65c5cc8a66a7da29e5d822cf6461 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 24 May 2022 12:07:31 +0300 Subject: [PATCH 33/35] clean up --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cef4943dfc54..a1163dcc4759 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,6 @@ - `[docs]` Updated docs to indicate that `jest-environment-jsdom` is a separate package [#12828](https://github.com/facebook/jest/issues/12828) - `[docs]` Document the comments used by coverage providers [#12835](https://github.com/facebook/jest/issues/12835) -- `[docs]` Fix typo in `--shard` CLI docs ([#12761](https://github.com/facebook/jest/pull/12761)) - `[docs]` Use custom Remark plugin to format tabs with code examples ([#12859](https://github.com/facebook/jest/pull/12859)) - `[jest-haste-map]` Bump `walker` version ([#12324](https://github.com/facebook/jest/pull/12324)) From 8c2539397b7c4011430983de0a530c30573d5bab Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Mon, 30 May 2022 18:33:10 +0300 Subject: [PATCH 34/35] use docusaurus-remark-plugin-tab-blocks --- CHANGELOG.md | 2 +- website/docusaurus.config.js | 2 +- website/package.json | 14 +- .../src/remark/__tests__/__fixtures__/base.md | 7 - .../__tests__/__fixtures__/full-example.md | 111 ----- .../__fixtures__/import-tabs-above.md | 11 - .../__fixtures__/import-tabs-below.md | 11 - .../__fixtures__/inside-admonition.md | 36 -- .../__tests__/__fixtures__/span-incomplete.md | 21 - .../src/remark/__tests__/__fixtures__/span.md | 21 - .../remark/__tests__/__fixtures__/title.md | 17 - .../code-tabs-plugin.test.js.snap | 396 ------------------ .../remark/__tests__/code-tabs-plugin.test.js | 74 ---- website/src/remark/code-tabs-plugin.js | 126 ------ yarn.lock | 118 +----- 15 files changed, 21 insertions(+), 946 deletions(-) delete mode 100644 website/src/remark/__tests__/__fixtures__/base.md delete mode 100644 website/src/remark/__tests__/__fixtures__/full-example.md delete mode 100644 website/src/remark/__tests__/__fixtures__/import-tabs-above.md delete mode 100644 website/src/remark/__tests__/__fixtures__/import-tabs-below.md delete mode 100644 website/src/remark/__tests__/__fixtures__/inside-admonition.md delete mode 100644 website/src/remark/__tests__/__fixtures__/span-incomplete.md delete mode 100644 website/src/remark/__tests__/__fixtures__/span.md delete mode 100644 website/src/remark/__tests__/__fixtures__/title.md delete mode 100644 website/src/remark/__tests__/__snapshots__/code-tabs-plugin.test.js.snap delete mode 100644 website/src/remark/__tests__/code-tabs-plugin.test.js delete mode 100644 website/src/remark/code-tabs-plugin.js diff --git a/CHANGELOG.md b/CHANGELOG.md index a1163dcc4759..4cff3ea6efa0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ - `[docs]` Updated docs to indicate that `jest-environment-jsdom` is a separate package [#12828](https://github.com/facebook/jest/issues/12828) - `[docs]` Document the comments used by coverage providers [#12835](https://github.com/facebook/jest/issues/12835) -- `[docs]` Use custom Remark plugin to format tabs with code examples ([#12859](https://github.com/facebook/jest/pull/12859)) +- `[docs]` Use `docusaurus-remark-plugin-tab-blocks` to format tabs with code examples ([#12859](https://github.com/facebook/jest/pull/12859)) - `[jest-haste-map]` Bump `walker` version ([#12324](https://github.com/facebook/jest/pull/12324)) ### Performance diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index d8ca300cdac5..66e88609525a 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -56,7 +56,7 @@ module.exports = { sidebarPath: path.resolve(__dirname, './sidebars.json'), remarkPlugins: [ [require('@docusaurus/remark-plugin-npm2yarn'), {sync: true}], - require('./src/remark/code-tabs-plugin'), + require('docusaurus-remark-plugin-tab-blocks'), ], }, blog: { diff --git a/website/package.json b/website/package.json index b04108abb1b2..c6e2b9569e9a 100644 --- a/website/package.json +++ b/website/package.json @@ -11,9 +11,8 @@ "serve": "docusaurus serve", "write-translations": "docusaurus write-translations", "fetchSupporters": "node fetchSupporters.js", - "jest": "node ../packages/jest-cli/bin/jest.js", - "netlify:ci:production": "yarn netlify:prepare && yarn jest && yarn netlify:crowdin && yarn build", - "netlify:ci:deployPreview": "yarn netlify:prepare && yarn jest && yarn build -l en", + "netlify:ci:production": "yarn netlify:prepare && yarn netlify:crowdin && yarn build", + "netlify:ci:deployPreview": "yarn netlify:prepare && yarn build -l en", "netlify:prepare": "yarn fetchSupporters && yarn build:js", "netlify:crowdin": "yarn write-translations && yarn crowdin:upload && yarn crowdin:download" }, @@ -36,14 +35,13 @@ "@docusaurus/preset-classic": "^2.0.0-beta.17", "@docusaurus/remark-plugin-npm2yarn": "^2.0.0-beta.17", "clsx": "^1.1.1", + "docusaurus-remark-plugin-tab-blocks": "^1.0.0", "globby": "^11.0.1", "react": "17.0.2", "react-dom": "^17.0.1", "react-github-btn": "^1.2.0", "react-lite-youtube-embed": "^2.2.1-a", - "react-markdown": "^8.0.0", - "unist-util-is": "^4.0.0", - "unist-util-visit": "^2.0.0" + "react-markdown": "^8.0.0" }, "devDependencies": { "@babel/core": "^7.11.6", @@ -51,8 +49,6 @@ "@types/react": "^17.0.3", "graphql": "^16.3.0", "graphql-request": "^4.0.0", - "js-yaml": "^4.1.0", - "remark": "^12.0.1", - "remark-mdx": "^1.6.22" + "js-yaml": "^4.1.0" } } diff --git a/website/src/remark/__tests__/__fixtures__/base.md b/website/src/remark/__tests__/__fixtures__/base.md deleted file mode 100644 index 682e4073b4ba..000000000000 --- a/website/src/remark/__tests__/__fixtures__/base.md +++ /dev/null @@ -1,7 +0,0 @@ -```js tab -console.log('this is JS'); -``` - -```ts tab -console.log('this is TS'); -``` diff --git a/website/src/remark/__tests__/__fixtures__/full-example.md b/website/src/remark/__tests__/__fixtures__/full-example.md deleted file mode 100644 index fe50ba8878ac..000000000000 --- a/website/src/remark/__tests__/__fixtures__/full-example.md +++ /dev/null @@ -1,111 +0,0 @@ -### `displayName` \[string, object] - -Default: `undefined` - -Allows for a label to be printed alongside a test while it is running. This becomes more useful in multi-project repositories where there can be many jest configuration files. This visually tells which project a test belongs to. - -```js tab -/** @type {import('jest').Config} */ -const config = { - displayName: 'CLIENT', -}; - -module.exports = config; -``` - -```ts tab -import type {Config} from 'jest'; - -const config: Config = { - displayName: 'CLIENT', -}; - -export default config; -``` - -Alternatively, an object with the properties `name` and `color` can be passed. - -### `fakeTimers` \[object] - -Default: `{}` - -The fake timers may be useful when a piece of code sets a long timeout that we don't want to wait for in a test. - -:::tip - -Instead of including `jest.useFakeTimers()` in each test file, you can enable fake timers globally for all tests in your Jest configuration: - -```js tab -/** @type {import('jest').Config} */ -const config = { - fakeTimers: { - enableGlobally: true, - }, -}; - -module.exports = config; -``` - -```ts tab -import type {Config} from 'jest'; - -const config: Config = { - fakeTimers: { - enableGlobally: true, - }, -}; - -export default config; -``` - -::: - -`.mockImplementation()` can also be used to mock class constructors: - -```js tab={"span":2} title="SomeClass.js" -module.exports = class SomeClass { - method(a, b) {} -}; -``` - -```js title="SomeClass.test.js" -const SomeClass = require('./SomeClass'); - -jest.mock('./SomeClass'); // this happens automatically with automocking - -const mockMethod = jest.fn(); -SomeClass.mockImplementation(() => { - return { - method: mockMethod, - }; -}); - -const some = new SomeClass(); -some.method('a', 'b'); - -console.log('Calls to method: ', mockMethod.mock.calls); -``` - -```ts tab={"span":2} title="SomeClass.ts" -export class SomeClass { - method(a: string, b: string): void {} -} -``` - -```ts title="SomeClass.test.ts" -import {SomeClass} from './SomeClass'; - -jest.mock('./SomeClass'); // this happens automatically with automocking - -const mockMethod = jest.fn<(a: string, b: string) => void>(); -SomeClass.mockImplementation(() => { - return { - method: mockMethod, - }; -}); - -const some = new SomeClass(); -some.method('a', 'b'); - -console.log('Calls to method: ', mockMethod.mock.calls); -``` diff --git a/website/src/remark/__tests__/__fixtures__/import-tabs-above.md b/website/src/remark/__tests__/__fixtures__/import-tabs-above.md deleted file mode 100644 index 008636d605b2..000000000000 --- a/website/src/remark/__tests__/__fixtures__/import-tabs-above.md +++ /dev/null @@ -1,11 +0,0 @@ -import Tabs from '@theme/Tabs'; - -import TabItem from '@theme/TabItem'; - -```js tab -console.log('this is JS'); -``` - -```ts tab -console.log('this is TS'); -``` diff --git a/website/src/remark/__tests__/__fixtures__/import-tabs-below.md b/website/src/remark/__tests__/__fixtures__/import-tabs-below.md deleted file mode 100644 index 0672b0fc272f..000000000000 --- a/website/src/remark/__tests__/__fixtures__/import-tabs-below.md +++ /dev/null @@ -1,11 +0,0 @@ -```js tab -console.log('this is JS'); -``` - -```ts tab -console.log('this is TS'); -``` - -import Tabs from '@theme/Tabs'; - -import TabItem from '@theme/TabItem'; diff --git a/website/src/remark/__tests__/__fixtures__/inside-admonition.md b/website/src/remark/__tests__/__fixtures__/inside-admonition.md deleted file mode 100644 index a78555bf0fca..000000000000 --- a/website/src/remark/__tests__/__fixtures__/inside-admonition.md +++ /dev/null @@ -1,36 +0,0 @@ -### `fakeTimers` \[object] - -Default: `{}` - -The fake timers may be useful when a piece of code sets a long timeout that we don't want to wait for in a test. - -:::tip - -Instead of including `jest.useFakeTimers()` in each test file, you can enable fake timers globally for all tests in your Jest configuration: - -```js tab -/** @type {import('jest').Config} */ -const config = { - fakeTimers: { - enableGlobally: true, - }, -}; - -module.exports = config; -``` - -```ts tab -import type {Config} from 'jest'; - -const config: Config = { - fakeTimers: { - enableGlobally: true, - }, -}; - -export default config; -``` - -::: - -Configuration options: diff --git a/website/src/remark/__tests__/__fixtures__/span-incomplete.md b/website/src/remark/__tests__/__fixtures__/span-incomplete.md deleted file mode 100644 index d7a97f961852..000000000000 --- a/website/src/remark/__tests__/__fixtures__/span-incomplete.md +++ /dev/null @@ -1,21 +0,0 @@ -```js tab={"span":2} -console.log('this is first a codeblock'); -``` - -```js -console.log('this is second a codeblock'); -``` - -```js tab={"span":3} -console.log('this is first a codeblock'); -``` - -```js -console.log('this is second a codeblock'); -``` - -Third codeblock went missing. - -```ts tab={"span":2} -console.log('this is a code '); -``` diff --git a/website/src/remark/__tests__/__fixtures__/span.md b/website/src/remark/__tests__/__fixtures__/span.md deleted file mode 100644 index bfda2911151a..000000000000 --- a/website/src/remark/__tests__/__fixtures__/span.md +++ /dev/null @@ -1,21 +0,0 @@ -```js tab={"span":2} -console.log('this is first JS codeblock in a tab'); -``` - -```js -console.log('this is second JS codeblock in a tab'); -``` - -```ts tab={"span":2} -console.log('this is first TS codeblock in a tab'); -``` - -```ts -console.log('this is second TS codeblock in a tab'); -``` - -Some text - -```ts title="some-file.ts" -console.log('this is just code'); -``` diff --git a/website/src/remark/__tests__/__fixtures__/title.md b/website/src/remark/__tests__/__fixtures__/title.md deleted file mode 100644 index 889bd4ce276b..000000000000 --- a/website/src/remark/__tests__/__fixtures__/title.md +++ /dev/null @@ -1,17 +0,0 @@ -`.mockImplementation()` can also be used to mock class constructors: - -```js tab title="SomeClass.js" -module.exports = class SomeClass { - method(a, b) {} -}; -``` - -```ts tab title="SomeClass.ts" -export class SomeClass { - method(a: string, b: string): void {} -} -``` - -### `mockFn.mockImplementationOnce(fn)` - -Accepts a function that will be used as an implementation of the mock for one call to the mocked function. Can be chained so that multiple function calls produce different results. diff --git a/website/src/remark/__tests__/__snapshots__/code-tabs-plugin.test.js.snap b/website/src/remark/__tests__/__snapshots__/code-tabs-plugin.test.js.snap deleted file mode 100644 index 5b7cf6551ffa..000000000000 --- a/website/src/remark/__tests__/__snapshots__/code-tabs-plugin.test.js.snap +++ /dev/null @@ -1,396 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`code tabs plugin base example 1`] = ` -"import Tabs from '@theme/Tabs'; - -import TabItem from '@theme/TabItem'; - - - - - -\`\`\`js tab -console.log('this is JS'); -\`\`\` - - - - - -\`\`\`ts tab -console.log('this is TS'); -\`\`\` - - - - -" -`; - -exports[`code tabs plugin can be nested inside an admonition 1`] = ` -"import Tabs from '@theme/Tabs'; - -import TabItem from '@theme/TabItem'; - -### \`fakeTimers\` \\\\[object] - -Default: \`{}\` - -The fake timers may be useful when a piece of code sets a long timeout that we don't want to wait for in a test. - -:::tip - -Instead of including \`jest.useFakeTimers()\` in each test file, you can enable fake timers globally for all tests in your Jest configuration: - - - - - -\`\`\`js tab -/** @type {import('jest').Config} */ -const config = { - fakeTimers: { - enableGlobally: true, - }, -}; - -module.exports = config; -\`\`\` - - - - - -\`\`\`ts tab -import type {Config} from 'jest'; - -const config: Config = { - fakeTimers: { - enableGlobally: true, - }, -}; - -export default config; -\`\`\` - - - - - -::: - -Configuration options: -" -`; - -exports[`code tabs plugin does not re-import tabs components when already imported above 1`] = ` -"import Tabs from '@theme/Tabs'; - -import TabItem from '@theme/TabItem'; - - - - - -\`\`\`js tab -console.log('this is JS'); -\`\`\` - - - - - -\`\`\`ts tab -console.log('this is TS'); -\`\`\` - - - - -" -`; - -exports[`code tabs plugin does not re-import tabs components when already imported below 1`] = ` -" - - - -\`\`\`js tab -console.log('this is JS'); -\`\`\` - - - - - -\`\`\`ts tab -console.log('this is TS'); -\`\`\` - - - - - -import Tabs from '@theme/Tabs'; - -import TabItem from '@theme/TabItem'; -" -`; - -exports[`code tabs plugin full example 1`] = ` -"import Tabs from '@theme/Tabs'; - -import TabItem from '@theme/TabItem'; - -### \`displayName\` \\\\[string, object] - -Default: \`undefined\` - -Allows for a label to be printed alongside a test while it is running. This becomes more useful in multi-project repositories where there can be many jest configuration files. This visually tells which project a test belongs to. - - - - - -\`\`\`js tab -/** @type {import('jest').Config} */ -const config = { - displayName: 'CLIENT', -}; - -module.exports = config; -\`\`\` - - - - - -\`\`\`ts tab -import type {Config} from 'jest'; - -const config: Config = { - displayName: 'CLIENT', -}; - -export default config; -\`\`\` - - - - - -Alternatively, an object with the properties \`name\` and \`color\` can be passed. - -### \`fakeTimers\` \\\\[object] - -Default: \`{}\` - -The fake timers may be useful when a piece of code sets a long timeout that we don't want to wait for in a test. - -:::tip - -Instead of including \`jest.useFakeTimers()\` in each test file, you can enable fake timers globally for all tests in your Jest configuration: - - - - - -\`\`\`js tab -/** @type {import('jest').Config} */ -const config = { - fakeTimers: { - enableGlobally: true, - }, -}; - -module.exports = config; -\`\`\` - - - - - -\`\`\`ts tab -import type {Config} from 'jest'; - -const config: Config = { - fakeTimers: { - enableGlobally: true, - }, -}; - -export default config; -\`\`\` - - - - - -::: - -\`.mockImplementation()\` can also be used to mock class constructors: - - - - - -\`\`\`js tab={\\"span\\":2} title=\\"SomeClass.js\\" -module.exports = class SomeClass { - method(a, b) {} -}; -\`\`\` - -\`\`\`js title=\\"SomeClass.test.js\\" -const SomeClass = require('./SomeClass'); - -jest.mock('./SomeClass'); // this happens automatically with automocking - -const mockMethod = jest.fn(); -SomeClass.mockImplementation(() => { - return { - method: mockMethod, - }; -}); - -const some = new SomeClass(); -some.method('a', 'b'); - -console.log('Calls to method: ', mockMethod.mock.calls); -\`\`\` - - - - - -\`\`\`ts tab={\\"span\\":2} title=\\"SomeClass.ts\\" -export class SomeClass { - method(a: string, b: string): void {} -} -\`\`\` - -\`\`\`ts title=\\"SomeClass.test.ts\\" -import {SomeClass} from './SomeClass'; - -jest.mock('./SomeClass'); // this happens automatically with automocking - -const mockMethod = jest.fn<(a: string, b: string) => void>(); -SomeClass.mockImplementation(() => { - return { - method: mockMethod, - }; -}); - -const some = new SomeClass(); -some.method('a', 'b'); - -console.log('Calls to method: ', mockMethod.mock.calls); -\`\`\` - - - - -" -`; - -exports[`code tabs plugin ignores incomplete spans 1`] = ` -"\`\`\`js tab={\\"span\\":2} -console.log('this is first a codeblock'); -\`\`\` - -\`\`\`js -console.log('this is second a codeblock'); -\`\`\` - -\`\`\`js tab={\\"span\\":3} -console.log('this is first a codeblock'); -\`\`\` - -\`\`\`js -console.log('this is second a codeblock'); -\`\`\` - -Third codeblock went missing. - -\`\`\`ts tab={\\"span\\":2} -console.log('this is a code '); -\`\`\` -" -`; - -exports[`code tabs plugin respects title meta 1`] = ` -"import Tabs from '@theme/Tabs'; - -import TabItem from '@theme/TabItem'; - -\`.mockImplementation()\` can also be used to mock class constructors: - - - - - -\`\`\`js tab title=\\"SomeClass.js\\" -module.exports = class SomeClass { - method(a, b) {} -}; -\`\`\` - - - - - -\`\`\`ts tab title=\\"SomeClass.ts\\" -export class SomeClass { - method(a: string, b: string): void {} -} -\`\`\` - - - - - -### \`mockFn.mockImplementationOnce(fn)\` - -Accepts a function that will be used as an implementation of the mock for one call to the mocked function. Can be chained so that multiple function calls produce different results. -" -`; - -exports[`code tabs plugin supports span meta 1`] = ` -"import Tabs from '@theme/Tabs'; - -import TabItem from '@theme/TabItem'; - - - - - -\`\`\`js tab={\\"span\\":2} -console.log('this is first JS codeblock in a tab'); -\`\`\` - -\`\`\`js -console.log('this is second JS codeblock in a tab'); -\`\`\` - - - - - -\`\`\`ts tab={\\"span\\":2} -console.log('this is first TS codeblock in a tab'); -\`\`\` - -\`\`\`ts -console.log('this is second TS codeblock in a tab'); -\`\`\` - - - - - -Some text - -\`\`\`ts title=\\"some-file.ts\\" -console.log('this is just code'); -\`\`\` -" -`; diff --git a/website/src/remark/__tests__/code-tabs-plugin.test.js b/website/src/remark/__tests__/code-tabs-plugin.test.js deleted file mode 100644 index c184b5f94062..000000000000 --- a/website/src/remark/__tests__/code-tabs-plugin.test.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -const path = require('node:path'); -const fs = require('graceful-fs'); -const remarkMdx = require('remark-mdx'); -const remark = require('remark'); -const codeTabsPlugin = require('../code-tabs-plugin'); - -async function processFixture(fixture) { - const filePath = path.join(__dirname, '__fixtures__', `${fixture}.md`); - const file = fs.readFileSync(filePath); - - const result = await remark() - .use(remarkMdx) - .use(codeTabsPlugin) - .process(file); - - return result.toString(); -} - -describe('code tabs plugin', () => { - test('base example', async () => { - const result = await processFixture('base'); - - expect(result).toMatchSnapshot(); - }); - - test('full example', async () => { - const result = await processFixture('full-example'); - - expect(result).toMatchSnapshot(); - }); - - test('can be nested inside an admonition', async () => { - const result = await processFixture('inside-admonition'); - - expect(result).toMatchSnapshot(); - }); - - test('respects title meta', async () => { - const result = await processFixture('title'); - - expect(result).toMatchSnapshot(); - }); - - test('supports span meta', async () => { - const result = await processFixture('span'); - - expect(result).toMatchSnapshot(); - }); - - test('ignores incomplete spans', async () => { - const result = await processFixture('span-incomplete'); - - expect(result).toMatchSnapshot(); - }); - - test('does not re-import tabs components when already imported above', async () => { - const result = await processFixture('import-tabs-above'); - - expect(result).toMatchSnapshot(); - }); - - test('does not re-import tabs components when already imported below', async () => { - const result = await processFixture('import-tabs-below'); - - expect(result).toMatchSnapshot(); - }); -}); diff --git a/website/src/remark/code-tabs-plugin.js b/website/src/remark/code-tabs-plugin.js deleted file mode 100644 index 22b154771e9e..000000000000 --- a/website/src/remark/code-tabs-plugin.js +++ /dev/null @@ -1,126 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -const visit = require('unist-util-visit'); -const is = require('unist-util-is'); - -const importNodes = [ - { - type: 'import', - value: "import Tabs from '@theme/Tabs';", - }, - { - type: 'import', - value: "import TabItem from '@theme/TabItem';", - }, -]; - -function parseTabMeta(nodeMeta) { - const tabTag = nodeMeta.split(' ').filter(tag => tag.startsWith('tab')); - if (tabTag.length < 1) return null; - - const tabMeta = tabTag[0].split('=')[1] || '{}'; - - return {span: 1, ...JSON.parse(tabMeta)}; -} - -const labels = new Map([ - ['js', 'JavaScript'], - ['ts', 'TypeScript'], -]); - -function formatTabItem(nodes) { - return [ - { - type: 'jsx', - value: ``, - }, - ...nodes, - { - type: 'jsx', - value: '', - }, - ]; -} - -function formatTabs(tabNodes) { - return [ - { - type: 'jsx', - value: '', - }, - ...tabNodes.map(node => formatTabItem(node)), - { - type: 'jsx', - value: '', - }, - ].flat(); -} - -function collectTabNodes(parent, index) { - let nodeIndex = index; - const tabNodes = []; - - do { - const node = parent.children[nodeIndex]; - - if (is(node, 'code') && typeof node.meta === 'string') { - const tabMeta = parseTabMeta(node.meta); - if (!tabMeta) break; - - const nodes = parent.children.slice(nodeIndex, nodeIndex + tabMeta.span); - - if ( - nodes.length === tabMeta.span && - nodes.every(node => is(node, 'code')) - ) { - tabNodes.push(nodes); - } else { - break; - } - - nodeIndex += tabMeta.span; - } else { - break; - } - } while (nodeIndex <= parent.children.length); - - if (tabNodes.length <= 1) return null; - - return tabNodes; -} - -module.exports = function tabsPlugin() { - /** @param {import('@types/mdast').Root tree} */ - return tree => { - let hasTabs = false; - let includesImportTabs = false; - - visit(tree, ['code', 'import'], (node, index, parent) => { - if (is(node, 'import') && node.value.includes('@theme/Tabs')) { - includesImportTabs = true; - } - - const tabNodes = collectTabNodes(parent, index); - if (!tabNodes) return; - - hasTabs = true; - const tabs = formatTabs(tabNodes); - - parent.children.splice(index, tabNodes.flat().length, ...tabs); - - // eslint-disable-next-line consistent-return - return index + tabs.length; - }); - - if (hasTabs && !includesImportTabs) { - tree.children.unshift(...importNodes); - } - }; -}; diff --git a/yarn.lock b/yarn.lock index 6596fb25e062..c083ae337ba2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7471,13 +7471,6 @@ __metadata: languageName: node linkType: hard -"character-entities-html4@npm:^1.0.0": - version: 1.1.4 - resolution: "character-entities-html4@npm:1.1.4" - checksum: 22536aba07a378a2326420423ceadd65c0121032c527f80e84dfc648381992ed5aa666d7c2b267cd269864b3682d5b0315fc2f03a9e7c017d1a96d24ec292d5f - languageName: node - linkType: hard - "character-entities-legacy@npm:^1.0.0": version: 1.1.4 resolution: "character-entities-legacy@npm:1.1.4" @@ -9135,6 +9128,16 @@ __metadata: languageName: node linkType: hard +"docusaurus-remark-plugin-tab-blocks@npm:^1.0.0": + version: 1.0.0 + resolution: "docusaurus-remark-plugin-tab-blocks@npm:1.0.0" + dependencies: + unist-util-is: ^4.0.0 + unist-util-visit: ^2.0.0 + checksum: 3c6877b1b66f7dab70991c3707165e8bfd73bc3255fb7a66af52a926ea9b7c20e8a82cc112737a27b5afaecd7c0868c2684d86a68c8a442d17ef36192b7cc6bc + languageName: node + linkType: hard + "dom-accessibility-api@npm:^0.5.9": version: 0.5.13 resolution: "dom-accessibility-api@npm:0.5.13" @@ -12352,13 +12355,6 @@ __metadata: languageName: node linkType: hard -"is-alphanumeric@npm:^1.0.0": - version: 1.0.0 - resolution: "is-alphanumeric@npm:1.0.0" - checksum: 2f4f4f227fe4cae977529f628021655edc172e1e5debfb3c30efd547f32e8d390c9bb7a71f3e9fea4187fe6598980072323d5a1b1abd3368379e33ba6504558c - languageName: node - linkType: hard - "is-alphanumerical@npm:^1.0.0": version: 1.0.4 resolution: "is-alphanumerical@npm:1.0.4" @@ -13726,6 +13722,7 @@ __metadata: "@docusaurus/remark-plugin-npm2yarn": ^2.0.0-beta.17 "@types/react": ^17.0.3 clsx: ^1.1.1 + docusaurus-remark-plugin-tab-blocks: ^1.0.0 globby: ^11.0.1 graphql: ^16.3.0 graphql-request: ^4.0.0 @@ -13735,10 +13732,6 @@ __metadata: react-github-btn: ^1.2.0 react-lite-youtube-embed: ^2.2.1-a react-markdown: ^8.0.0 - remark: ^12.0.1 - remark-mdx: ^1.6.22 - unist-util-is: ^4.0.0 - unist-util-visit: ^2.0.0 languageName: unknown linkType: soft @@ -14631,13 +14624,6 @@ __metadata: languageName: node linkType: hard -"longest-streak@npm:^2.0.1": - version: 2.0.4 - resolution: "longest-streak@npm:2.0.4" - checksum: 28b8234a14963002c5c71035dee13a0a11e9e9d18ffa320fdc8796ed7437399204495702ed69cd2a7087b0af041a2a8b562829b7c1e2042e73a3374d1ecf6580 - languageName: node - linkType: hard - "loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.2.0, loose-envify@npm:^1.3.1, loose-envify@npm:^1.4.0": version: 1.4.0 resolution: "loose-envify@npm:1.4.0" @@ -14825,15 +14811,6 @@ __metadata: languageName: node linkType: hard -"markdown-table@npm:^2.0.0": - version: 2.0.0 - resolution: "markdown-table@npm:2.0.0" - dependencies: - repeat-string: ^1.0.0 - checksum: 9bb634a9300016cbb41216c1eab44c74b6b7083ac07872e296f900a29449cf0e260ece03fa10c3e9784ab94c61664d1d147da0315f95e1336e2bdcc025615c90 - languageName: node - linkType: hard - "md5-file@npm:^5.0.0": version: 5.0.0 resolution: "md5-file@npm:5.0.0" @@ -14852,15 +14829,6 @@ __metadata: languageName: node linkType: hard -"mdast-util-compact@npm:^2.0.0": - version: 2.0.1 - resolution: "mdast-util-compact@npm:2.0.1" - dependencies: - unist-util-visit: ^2.0.0 - checksum: 750cc76e46223d2dadf86835d415d4954566572e6af5a8df5577065e5f863dda46c30767e12e29c4ec53cf2e7040863b0279d44af357e8b36f5983d78a73dceb - languageName: node - linkType: hard - "mdast-util-definitions@npm:^4.0.0": version: 4.0.0 resolution: "mdast-util-definitions@npm:4.0.0" @@ -19186,7 +19154,7 @@ __metadata: languageName: node linkType: hard -"remark-mdx@npm:1.6.22, remark-mdx@npm:^1.6.22": +"remark-mdx@npm:1.6.22": version: 1.6.22 resolution: "remark-mdx@npm:1.6.22" dependencies: @@ -19202,7 +19170,7 @@ __metadata: languageName: node linkType: hard -"remark-parse@npm:8.0.3, remark-parse@npm:^8.0.0": +"remark-parse@npm:8.0.3": version: 8.0.3 resolution: "remark-parse@npm:8.0.3" dependencies: @@ -19258,39 +19226,6 @@ __metadata: languageName: node linkType: hard -"remark-stringify@npm:^8.0.0": - version: 8.1.1 - resolution: "remark-stringify@npm:8.1.1" - dependencies: - ccount: ^1.0.0 - is-alphanumeric: ^1.0.0 - is-decimal: ^1.0.0 - is-whitespace-character: ^1.0.0 - longest-streak: ^2.0.1 - markdown-escapes: ^1.0.0 - markdown-table: ^2.0.0 - mdast-util-compact: ^2.0.0 - parse-entities: ^2.0.0 - repeat-string: ^1.5.4 - state-toggle: ^1.0.0 - stringify-entities: ^3.0.0 - unherit: ^1.0.4 - xtend: ^4.0.1 - checksum: 9a556e5a0dc26db151694a5d0a1dcd0f21bd7e619b3934d677876a633ad01a03e38f5cf174ff5468ec755d5a9398f4fbccac4788e04f5bcab8bb2583eddbc1b3 - languageName: node - linkType: hard - -"remark@npm:^12.0.1": - version: 12.0.1 - resolution: "remark@npm:12.0.1" - dependencies: - remark-parse: ^8.0.0 - remark-stringify: ^8.0.0 - unified: ^9.0.0 - checksum: 1ce7a264c19b3d0b915b0c08c9b84c053b03ecd65086ca25ac54e1ce5a685a1153403da870ec8e43f7b98c47fc6e7f0a12eb4d16481facc88131c1dbd4af01a1 - languageName: node - linkType: hard - "renderkid@npm:^3.0.0": version: 3.0.0 resolution: "renderkid@npm:3.0.0" @@ -19311,7 +19246,7 @@ __metadata: languageName: node linkType: hard -"repeat-string@npm:^1.0.0, repeat-string@npm:^1.5.4, repeat-string@npm:^1.6.1": +"repeat-string@npm:^1.5.4, repeat-string@npm:^1.6.1": version: 1.6.1 resolution: "repeat-string@npm:1.6.1" checksum: 1b809fc6db97decdc68f5b12c4d1a671c8e3f65ec4a40c238bc5200e44e85bcc52a54f78268ab9c29fcf5fe4f1343e805420056d1f30fa9a9ee4c2d93e3cc6c0 @@ -20775,17 +20710,6 @@ __metadata: languageName: node linkType: hard -"stringify-entities@npm:^3.0.0": - version: 3.1.0 - resolution: "stringify-entities@npm:3.1.0" - dependencies: - character-entities-html4: ^1.0.0 - character-entities-legacy: ^1.0.0 - xtend: ^4.0.0 - checksum: 5b6212e2985101ddb8197d999a6c01abb610f2ba6efd6f8f7d7ec763b61cb08b55735b03febdf501c2091f484df16bc82412419ef35ee21135548f6a15881044 - languageName: node - linkType: hard - "stringify-object@npm:^3.3.0": version: 3.3.0 resolution: "stringify-object@npm:3.3.0" @@ -21834,20 +21758,6 @@ __metadata: languageName: node linkType: hard -"unified@npm:^9.0.0": - version: 9.2.2 - resolution: "unified@npm:9.2.2" - dependencies: - bail: ^1.0.0 - extend: ^3.0.0 - is-buffer: ^2.0.0 - is-plain-obj: ^2.0.0 - trough: ^1.0.0 - vfile: ^4.0.0 - checksum: 7c24461be7de4145939739ce50d18227c5fbdf9b3bc5a29dabb1ce26dd3e8bd4a1c385865f6f825f3b49230953ee8b591f23beab3bb3643e3e9dc37aa8a089d5 - languageName: node - linkType: hard - "union-value@npm:^1.0.0": version: 1.0.1 resolution: "union-value@npm:1.0.1" From 62695325dce68299041752cf7e2220a3d69ce5b5 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Mon, 30 May 2022 18:46:31 +0300 Subject: [PATCH 35/35] restart CI