chore: add eslint-plugin-react-compiler (#10969)

* install ESLint plugin

* fix eslint CodeBlockLine error

* eslint

* eslint

* eslint

* refactor: apply lint autofix

* empty

---------

Co-authored-by: slorber <749374+slorber@users.noreply.github.com>
This commit is contained in:
Sébastien Lorber 2025-03-07 18:04:40 +01:00 committed by GitHub
parent d33004da1e
commit 15b0ef6d13
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 133 additions and 58 deletions

2
.eslintrc.js vendored
View file

@ -60,6 +60,7 @@ module.exports = {
},
reportUnusedDisableDirectives: true,
plugins: [
'react-compiler',
'react-hooks',
'header',
'jest',
@ -68,6 +69,7 @@ module.exports = {
'@docusaurus',
],
rules: {
'react-compiler/react-compiler': ERROR,
'react/jsx-uses-react': OFF, // JSX runtime: automatic
'react/react-in-jsx-scope': OFF, // JSX runtime: automatic
'array-callback-return': WARNING,

View file

@ -98,6 +98,7 @@
"eslint-plugin-jest": "^27.2.3",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-compiler": "^19.0.0-beta-40c6c23-20250301",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-regexp": "^1.15.0",
"husky": "^8.0.3",

View file

@ -11,16 +11,29 @@ import type {Props} from '@theme/CodeBlock/Line';
import styles from './styles.module.css';
type Token = Props['line'][number];
// Replaces '\n' by ''
// Historical code, not sure why we even need this :/
function fixLineBreak(line: Token[]) {
const singleLineBreakToken =
line.length === 1 && line[0]!.content === '\n' ? line[0] : undefined;
if (singleLineBreakToken) {
return [{...singleLineBreakToken, content: ''}];
}
return line;
}
export default function CodeBlockLine({
line,
line: lineProp,
classNames,
showLineNumbers,
getLineProps,
getTokenProps,
}: Props): ReactNode {
if (line.length === 1 && line[0]!.content === '\n') {
line[0]!.content = '';
}
const line = fixLineBreak(lineProp);
const lineProps = getLineProps({
line,

View file

@ -123,6 +123,7 @@ function useCollapseAnimation({
return undefined;
}
// eslint-disable-next-line react-compiler/react-compiler
el.style.willChange = 'height';
function startAnimation() {

View file

@ -33,7 +33,7 @@ export function useDocsPreferredVersion(...args: unknown[]): unknown {
export function useContextualSearchFilters() {
const {i18n} = useDocusaurusContext();
const docsTags =
// eslint-disable-next-line @typescript-eslint/no-var-requires
// eslint-disable-next-line @typescript-eslint/no-var-requires, react-compiler/react-compiler
require('@docusaurus/plugin-content-docs/client').useDocsContextualSearchTags();
const tags = [DEFAULT_SEARCH_TAG, ...docsTags];
return {locale: i18n.currentLocale, tags};

View file

@ -50,6 +50,9 @@ export function usePrevious<T>(value: T): T | undefined {
ref.current = value;
});
// TODO need to fix this React Compiler lint error
// probably requires changing the API though
// eslint-disable-next-line react-compiler/react-compiler
return ref.current;
}
@ -81,7 +84,7 @@ export function useShallowMemoObject<O extends object>(obj: O): O {
const deps = Object.entries(obj);
// Sort by keys to make it order-insensitive
deps.sort((a, b) => a[0].localeCompare(b[0]));
// eslint-disable-next-line react-hooks/exhaustive-deps
// eslint-disable-next-line react-compiler/react-compiler,react-hooks/exhaustive-deps
return useMemo(() => obj, deps.flat());
}

View file

@ -124,6 +124,7 @@ export function useScrollPosition(
window.addEventListener('scroll', handleScroll, opts);
return () => window.removeEventListener('scroll', handleScroll, opts);
// eslint-disable-next-line react-compiler/react-compiler
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dynamicEffect, scrollEventsEnabledRef, ...deps]);
}

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {useCallback, useRef, useSyncExternalStore} from 'react';
import {useCallback, useState, useSyncExternalStore} from 'react';
import SiteStorage from '@generated/site-storage';
export type StorageType = (typeof SiteStorage)['type'] | 'none';
@ -208,12 +208,12 @@ export function useStorageSlot(
options?: {persistence?: StorageType},
): [string | null, StorageSlot] {
// Not ideal but good enough: assumes storage slot config is constant
const storageSlot = useRef(() => {
const [storageSlot] = useState(() => {
if (key === null) {
return NoopStorageSlot;
}
return createStorageSlot(key, options);
}).current();
});
const listen: StorageSlot['listen'] = useCallback(
(onChange) => {

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {useState, useEffect, useMemo, useRef} from 'react';
import {useState, useEffect, useMemo} from 'react';
import {useColorMode, useThemeConfig} from '@docusaurus/theme-common';
import mermaid from 'mermaid';
import type {RenderResult, MermaidConfig} from 'mermaid';
@ -36,8 +36,12 @@ function useMermaidId(): string {
Random client-only id, we don't care much but mermaid want an id so...
Note: Mermaid doesn't like values provided by Rect.useId() and throws
*/
// TODO 2025-2026: check if useId() now works
// It could work thanks to https://github.com/facebook/react/pull/32001
// return useId(); // tried that, doesn't work ('#d:re:' is not a valid selector.)
return useRef(`mermaid-svg-${Math.round(Math.random() * 10000000)}`).current!;
return useState(`mermaid-svg-${Math.round(Math.random() * 10000000)}`)[0];
}
async function renderMermaid({

View file

@ -269,6 +269,8 @@ function DocSearch({externalUrlRegex, ...props}: DocSearchProps) {
{isOpen &&
DocSearchModal &&
// TODO need to fix this React Compiler lint error
// eslint-disable-next-line react-compiler/react-compiler
searchContainer.current &&
createPortal(
<DocSearchModal
@ -287,6 +289,8 @@ function DocSearch({externalUrlRegex, ...props}: DocSearchProps) {
translations={props.translations?.modal ?? translations.modal}
searchParameters={searchParameters}
/>,
// TODO need to fix this React Compiler lint error
// eslint-disable-next-line react-compiler/react-compiler
searchContainer.current,
)}
</>

View file

@ -292,6 +292,8 @@ function SearchPageContent(): ReactNode {
const observer = useRef(
ExecutionEnvironment.canUseIntersectionObserver &&
new IntersectionObserver(
// TODO need to fix this React Compiler lint error
// eslint-disable-next-line react-compiler/react-compiler
(entries) => {
const {
isIntersecting,

138
yarn.lock
View file

@ -222,12 +222,13 @@
"@babel/highlight" "^7.25.7"
picocolors "^1.0.0"
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.25.9.tgz#895b6c7e04a7271a0cbfd575d2e8131751914cc7"
integrity sha512-z88xeGxnzehn2sqZ8UdGQEvYErF1odv2CftxInpSYJt6uHuPe9YjahKZITGs3l5LeI9d2ROG+obuDAoSlqbNfQ==
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.2":
version "7.26.2"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85"
integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==
dependencies:
"@babel/highlight" "^7.25.9"
"@babel/helper-validator-identifier" "^7.25.9"
js-tokens "^4.0.0"
picocolors "^1.0.0"
"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.25.9":
@ -256,12 +257,13 @@
json5 "^2.2.3"
semver "^6.3.1"
"@babel/generator@^7.25.9", "@babel/generator@^7.7.2":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.9.tgz#c7e828ebe0c2baba103b712924699c9e8a6e32f0"
integrity sha512-omlUGkr5EaoIJrhLf9CJ0TvjBRpd9+AXRG//0GEQ9THSo8wPiTlbpy1/Ow8ZTrbXpjd9FHXfbFQx32I04ht0FA==
"@babel/generator@^7.25.9", "@babel/generator@^7.26.9", "@babel/generator@^7.7.2":
version "7.26.9"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.9.tgz#75a9482ad3d0cc7188a537aa4910bc59db67cbca"
integrity sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==
dependencies:
"@babel/types" "^7.25.9"
"@babel/parser" "^7.26.9"
"@babel/types" "^7.26.9"
"@jridgewell/gen-mapping" "^0.3.5"
"@jridgewell/trace-mapping" "^0.3.25"
jsesc "^3.0.2"
@ -292,17 +294,17 @@
lru-cache "^5.1.1"
semver "^6.3.1"
"@babel/helper-create-class-features-plugin@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz#7644147706bb90ff613297d49ed5266bde729f83"
integrity sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==
"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.25.9":
version "7.26.9"
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.26.9.tgz#d6f83e3039547fbb39967e78043cd3c8b7820c71"
integrity sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg==
dependencies:
"@babel/helper-annotate-as-pure" "^7.25.9"
"@babel/helper-member-expression-to-functions" "^7.25.9"
"@babel/helper-optimise-call-expression" "^7.25.9"
"@babel/helper-replace-supers" "^7.25.9"
"@babel/helper-replace-supers" "^7.26.5"
"@babel/helper-skip-transparent-expression-wrappers" "^7.25.9"
"@babel/traverse" "^7.25.9"
"@babel/traverse" "^7.26.9"
semver "^6.3.1"
"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.25.9":
@ -372,14 +374,14 @@
"@babel/helper-wrap-function" "^7.25.9"
"@babel/traverse" "^7.25.9"
"@babel/helper-replace-supers@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz#ba447224798c3da3f8713fc272b145e33da6a5c5"
integrity sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==
"@babel/helper-replace-supers@^7.25.9", "@babel/helper-replace-supers@^7.26.5":
version "7.26.5"
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz#6cb04e82ae291dae8e72335dfe438b0725f14c8d"
integrity sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==
dependencies:
"@babel/helper-member-expression-to-functions" "^7.25.9"
"@babel/helper-optimise-call-expression" "^7.25.9"
"@babel/traverse" "^7.25.9"
"@babel/traverse" "^7.26.5"
"@babel/helper-simple-access@^7.25.9":
version "7.25.9"
@ -429,7 +431,7 @@
"@babel/template" "^7.25.9"
"@babel/types" "^7.25.9"
"@babel/highlight@^7.25.7", "@babel/highlight@^7.25.9":
"@babel/highlight@^7.25.7":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.25.9.tgz#8141ce68fc73757946f983b343f1231f4691acc6"
integrity sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==
@ -439,12 +441,12 @@
js-tokens "^4.0.0"
picocolors "^1.0.0"
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.9.tgz#8fcaa079ac7458facfddc5cd705cc8005e4d3817"
integrity sha512-aI3jjAAO1fh7vY/pBGsn1i9LDbRP43+asrRlkPuTXW5yHXtd1NgTEMudbBoDDxrf1daEEfPJqR+JBMakzrR4Dg==
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.4", "@babel/parser@^7.25.9", "@babel/parser@^7.26.9":
version "7.26.9"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.9.tgz#d9e78bee6dc80f9efd8f2349dcfbbcdace280fd5"
integrity sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==
dependencies:
"@babel/types" "^7.25.9"
"@babel/types" "^7.26.9"
"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.9":
version "7.25.9"
@ -485,6 +487,14 @@
"@babel/helper-plugin-utils" "^7.25.9"
"@babel/traverse" "^7.25.9"
"@babel/plugin-proposal-private-methods@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz#5209de7d213457548a98436fa2882f52f4be6bea"
integrity sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==
dependencies:
"@babel/helper-create-class-features-plugin" "^7.18.6"
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2":
version "7.21.0-placeholder-for-preset-env.2"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703"
@ -1182,32 +1192,32 @@
dependencies:
regenerator-runtime "^0.14.0"
"@babel/template@^7.25.9", "@babel/template@^7.3.3":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.9.tgz#ecb62d81a8a6f5dc5fe8abfc3901fc52ddf15016"
integrity sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==
"@babel/template@^7.25.9", "@babel/template@^7.26.9", "@babel/template@^7.3.3":
version "7.26.9"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.26.9.tgz#4577ad3ddf43d194528cff4e1fa6b232fa609bb2"
integrity sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==
dependencies:
"@babel/code-frame" "^7.25.9"
"@babel/parser" "^7.25.9"
"@babel/types" "^7.25.9"
"@babel/code-frame" "^7.26.2"
"@babel/parser" "^7.26.9"
"@babel/types" "^7.26.9"
"@babel/traverse@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.9.tgz#a50f8fe49e7f69f53de5bea7e413cd35c5e13c84"
integrity sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==
"@babel/traverse@^7.25.9", "@babel/traverse@^7.26.5", "@babel/traverse@^7.26.9":
version "7.26.9"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.9.tgz#4398f2394ba66d05d988b2ad13c219a2c857461a"
integrity sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==
dependencies:
"@babel/code-frame" "^7.25.9"
"@babel/generator" "^7.25.9"
"@babel/parser" "^7.25.9"
"@babel/template" "^7.25.9"
"@babel/types" "^7.25.9"
"@babel/code-frame" "^7.26.2"
"@babel/generator" "^7.26.9"
"@babel/parser" "^7.26.9"
"@babel/template" "^7.26.9"
"@babel/types" "^7.26.9"
debug "^4.3.1"
globals "^11.1.0"
"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.21.3", "@babel/types@^7.25.9", "@babel/types@^7.3.3", "@babel/types@^7.4.4":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.9.tgz#620f35ea1f4233df529ec9a2668d2db26574deee"
integrity sha512-OwS2CM5KocvQ/k7dFJa8i5bNGJP0hXWfVCfDkqRFP1IreH1JDC7wG6eCYCi0+McbfT8OR/kNqsI0UU0xP9H6PQ==
"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.21.3", "@babel/types@^7.25.9", "@babel/types@^7.26.9", "@babel/types@^7.3.3", "@babel/types@^7.4.4":
version "7.26.9"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.9.tgz#08b43dec79ee8e682c2ac631c010bdcac54a21ce"
integrity sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==
dependencies:
"@babel/helper-string-parser" "^7.25.9"
"@babel/helper-validator-identifier" "^7.25.9"
@ -8046,6 +8056,18 @@ eslint-plugin-jsx-a11y@^6.7.1:
safe-regex-test "^1.0.3"
string.prototype.includes "^2.0.1"
eslint-plugin-react-compiler@^19.0.0-beta-40c6c23-20250301:
version "19.0.0-beta-40c6c23-20250301"
resolved "https://registry.yarnpkg.com/eslint-plugin-react-compiler/-/eslint-plugin-react-compiler-19.0.0-beta-40c6c23-20250301.tgz#94790bb8774a0a15d168ec8351a5132b0ffebd4c"
integrity sha512-9K59D9imZCdgdbA5OIa4EL1rCoNAmHNDGYW8sI8gYM0ILAb+foIR+3tpv6y0L/KHz1Mbhyx0KqVBq4lSG/5ykQ==
dependencies:
"@babel/core" "^7.24.4"
"@babel/parser" "^7.24.4"
"@babel/plugin-proposal-private-methods" "^7.18.6"
hermes-parser "^0.25.1"
zod "^3.22.4"
zod-validation-error "^3.0.3"
eslint-plugin-react-hooks@^4.6.0:
version "4.6.2"
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz#c829eb06c0e6f484b3fbb85a97e57784f328c596"
@ -9505,6 +9527,18 @@ he@^1.2.0:
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
hermes-estree@0.25.1:
version "0.25.1"
resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.25.1.tgz#6aeec17d1983b4eabf69721f3aa3eb705b17f480"
integrity sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==
hermes-parser@^0.25.1:
version "0.25.1"
resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.25.1.tgz#5be0e487b2090886c62bd8a11724cd766d5f54d1"
integrity sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==
dependencies:
hermes-estree "0.25.1"
highlight.js@^10.7.1:
version "10.7.3"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531"
@ -18715,6 +18749,16 @@ yocto-queue@^1.0.0:
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251"
integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==
zod-validation-error@^3.0.3:
version "3.4.0"
resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-3.4.0.tgz#3a8a1f55c65579822d7faa190b51336c61bee2a6"
integrity sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==
zod@^3.22.4:
version "3.24.2"
resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.2.tgz#8efa74126287c675e92f46871cfc8d15c34372b3"
integrity sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==
zwitch@^2.0.0, zwitch@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7"