aboutsummaryrefslogtreecommitdiffstats
path: root/vanilla/node_modules/vitest
diff options
context:
space:
mode:
authorAdam Mathes <adam@adammathes.com>2026-02-14 14:46:37 -0800
committerAdam Mathes <adam@adammathes.com>2026-02-14 14:46:37 -0800
commitafa87af01c79a9baa539f2992d32154d2a4739bd (patch)
tree92c7416db734270a2fee1d72ee9cc119379ff8e1 /vanilla/node_modules/vitest
parent3b927e84d200402281f68181cd4253bc77e5528d (diff)
downloadneko-afa87af01c79a9baa539f2992d32154d2a4739bd.tar.gz
neko-afa87af01c79a9baa539f2992d32154d2a4739bd.tar.bz2
neko-afa87af01c79a9baa539f2992d32154d2a4739bd.zip
task: delete vanilla js prototype\n\n- Removed vanilla/ directory and web/dist/vanilla directory\n- Updated Makefile, Dockerfile, and CI workflow to remove vanilla references\n- Cleaned up web/web.go to remove vanilla embed and routes\n- Verified build and tests pass\n\nCloses NK-2tcnmq
Diffstat (limited to 'vanilla/node_modules/vitest')
-rw-r--r--vanilla/node_modules/vitest/LICENSE.md691
-rw-r--r--vanilla/node_modules/vitest/README.md7
-rw-r--r--vanilla/node_modules/vitest/browser/context.d.ts7
-rw-r--r--vanilla/node_modules/vitest/browser/context.js20
-rw-r--r--vanilla/node_modules/vitest/config.d.ts3
-rw-r--r--vanilla/node_modules/vitest/coverage.d.ts1
-rw-r--r--vanilla/node_modules/vitest/dist/browser.d.ts46
-rw-r--r--vanilla/node_modules/vitest/dist/browser.js20
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/_commonjsHelpers.D26ty3Ew.js6
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/base.CJ0Y4ePK.js165
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/benchmark.B3N2zMcH.js40
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/benchmark.d.DAaHLpsq.d.ts24
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/browser.d.ChKACdzH.d.ts59
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/cac.DVeoLl0M.js1409
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/cli-api.B7PN_QUv.js13657
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/config.d.Cy95HiCx.d.ts210
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/console.Cf-YriPC.js146
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/constants.D_Q9UYh-.js36
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/coverage.AVPTjMgw.js3292
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/coverage.D_JHT54q.js25
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/coverage.d.BZtK59WP.d.ts37
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/creator.DAmOKTvJ.js673
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/date.Bq6ZW5rf.js73
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/defaults.BOqNVLsY.js74
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/env.D4Lgay0q.js8
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/environment.d.CrsxCzP1.d.ts29
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/evaluatedModules.Dg1zASAC.js17
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/evaluatedModules.d.BxJ5omdx.d.ts7
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/git.Bm2pzPAa.js71
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/global.d.B15mdLcR.d.ts99
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/globals.DOayXfHP.js30
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/index.6Qv1eEA6.js109
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/index.C5r1PdPD.js231
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/index.Chj8NDwU.js206
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/index.CyBMJtT7.js727
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/index.D3XRDfWc.js213
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/index.D4KonVSU.js6343
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/index.M8mOzt4Y.js3839
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/index.Z5E_ObnR.js37
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/init-forks._y3TW739.js41
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/init-threads.DBO2kn-p.js18
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/init.B6MLFIaN.js334
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/inspector.CvyFGlXm.js53
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/modules.BJuCwlRJ.js36
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/node.Ce0vMQM7.js14
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/plugin.d.CtqpEehP.d.ts38
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/reporters.d.CWXNI2jG.d.ts3271
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/rpc.BoxB0q7B.js76
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/rpc.d.RH3apGEf.d.ts64
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/setup-common.Cm-kSBVi.js60
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/startModuleRunner.DEj0jb3e.js861
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/suite.d.BJWk38HB.d.ts10
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/test.B8ej_ZHS.js254
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/traces.CCmnQaNT.js217
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/traces.d.402V_yFI.d.ts18
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/utils.DvEY5TfP.js52
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/vi.2VT5v0um.js3919
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/vm.D3epNOPZ.js744
-rw-r--r--vanilla/node_modules/vitest/dist/chunks/worker.d.Dyxm8DEL.d.ts255
-rw-r--r--vanilla/node_modules/vitest/dist/cli.js28
-rw-r--r--vanilla/node_modules/vitest/dist/config.cjs94
-rw-r--r--vanilla/node_modules/vitest/dist/config.d.ts104
-rw-r--r--vanilla/node_modules/vitest/dist/config.js15
-rw-r--r--vanilla/node_modules/vitest/dist/coverage.d.ts118
-rw-r--r--vanilla/node_modules/vitest/dist/coverage.js23
-rw-r--r--vanilla/node_modules/vitest/dist/environments.d.ts22
-rw-r--r--vanilla/node_modules/vitest/dist/environments.js3
-rw-r--r--vanilla/node_modules/vitest/dist/index.d.ts510
-rw-r--r--vanilla/node_modules/vitest/dist/index.js20
-rw-r--r--vanilla/node_modules/vitest/dist/mocker.d.ts1
-rw-r--r--vanilla/node_modules/vitest/dist/mocker.js1
-rw-r--r--vanilla/node_modules/vitest/dist/module-evaluator.d.ts124
-rw-r--r--vanilla/node_modules/vitest/dist/module-evaluator.js343
-rw-r--r--vanilla/node_modules/vitest/dist/module-runner.js17
-rw-r--r--vanilla/node_modules/vitest/dist/node.d.ts251
-rw-r--r--vanilla/node_modules/vitest/dist/node.js98
-rw-r--r--vanilla/node_modules/vitest/dist/path.js7
-rw-r--r--vanilla/node_modules/vitest/dist/reporters.d.ts27
-rw-r--r--vanilla/node_modules/vitest/dist/reporters.js24
-rw-r--r--vanilla/node_modules/vitest/dist/runners.d.ts50
-rw-r--r--vanilla/node_modules/vitest/dist/runners.js19
-rw-r--r--vanilla/node_modules/vitest/dist/snapshot.d.ts9
-rw-r--r--vanilla/node_modules/vitest/dist/snapshot.js4
-rw-r--r--vanilla/node_modules/vitest/dist/spy.js1
-rw-r--r--vanilla/node_modules/vitest/dist/suite.d.ts5
-rw-r--r--vanilla/node_modules/vitest/dist/suite.js6
-rw-r--r--vanilla/node_modules/vitest/dist/worker.d.ts32
-rw-r--r--vanilla/node_modules/vitest/dist/worker.js48
-rw-r--r--vanilla/node_modules/vitest/dist/workers/forks.js54
-rw-r--r--vanilla/node_modules/vitest/dist/workers/runVmTests.js95
-rw-r--r--vanilla/node_modules/vitest/dist/workers/threads.js55
-rw-r--r--vanilla/node_modules/vitest/dist/workers/vmForks.js36
-rw-r--r--vanilla/node_modules/vitest/dist/workers/vmThreads.js37
-rw-r--r--vanilla/node_modules/vitest/environments.d.ts1
-rw-r--r--vanilla/node_modules/vitest/globals.d.ts20
-rw-r--r--vanilla/node_modules/vitest/import-meta.d.ts5
-rw-r--r--vanilla/node_modules/vitest/importMeta.d.ts4
-rw-r--r--vanilla/node_modules/vitest/index.cjs5
-rw-r--r--vanilla/node_modules/vitest/index.d.cts1
-rw-r--r--vanilla/node_modules/vitest/jsdom.d.ts6
-rw-r--r--vanilla/node_modules/vitest/mocker.d.ts1
-rw-r--r--vanilla/node_modules/vitest/node.d.ts1
-rw-r--r--vanilla/node_modules/vitest/optional-types.d.ts7
-rw-r--r--vanilla/node_modules/vitest/package.json224
-rw-r--r--vanilla/node_modules/vitest/reporters.d.ts1
-rw-r--r--vanilla/node_modules/vitest/runners.d.ts1
-rw-r--r--vanilla/node_modules/vitest/snapshot.d.ts1
-rw-r--r--vanilla/node_modules/vitest/suite.d.ts1
-rw-r--r--vanilla/node_modules/vitest/suppress-warnings.cjs21
-rwxr-xr-xvanilla/node_modules/vitest/vitest.mjs2
-rw-r--r--vanilla/node_modules/vitest/worker.d.ts1
111 files changed, 0 insertions, 45606 deletions
diff --git a/vanilla/node_modules/vitest/LICENSE.md b/vanilla/node_modules/vitest/LICENSE.md
deleted file mode 100644
index ba4ea56..0000000
--- a/vanilla/node_modules/vitest/LICENSE.md
+++ /dev/null
@@ -1,691 +0,0 @@
-# Vitest core license
-Vitest is released under the MIT license:
-
-MIT License
-
-Copyright (c) 2021-Present VoidZero Inc. and Vitest contributors
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
-# Licenses of bundled dependencies
-The published Vitest artifact additionally contains code with the following licenses:
-BSD-3-Clause, ISC, MIT
-
-# Bundled dependencies:
-## @antfu/install-pkg
-License: MIT
-By: Anthony Fu
-Repository: git+https://github.com/antfu/install-pkg.git
-
-> MIT License
->
-> Copyright (c) 2021 Anthony Fu <https://github.com/antfu>
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in all
-> copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-> SOFTWARE.
-
----------------------------------------
-
-## @jridgewell/resolve-uri
-License: MIT
-By: Justin Ridgewell
-Repository: https://github.com/jridgewell/resolve-uri
-
-> Copyright 2019 Justin Ridgewell <jridgewell@google.com>
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in
-> all copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-> SOFTWARE.
-
----------------------------------------
-
-## @jridgewell/sourcemap-codec
-License: MIT
-By: Justin Ridgewell
-Repository: git+https://github.com/jridgewell/sourcemaps.git
-
-> Copyright 2024 Justin Ridgewell <justin@ridgewell.name>
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in
-> all copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-> SOFTWARE.
-
----------------------------------------
-
-## @jridgewell/trace-mapping
-License: MIT
-By: Justin Ridgewell
-Repository: git+https://github.com/jridgewell/sourcemaps.git
-
-> Copyright 2024 Justin Ridgewell <justin@ridgewell.name>
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in
-> all copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-> SOFTWARE.
-
----------------------------------------
-
-## @sinonjs/commons
-License: BSD-3-Clause
-Repository: git+https://github.com/sinonjs/commons.git
-
-> BSD 3-Clause License
->
-> Copyright (c) 2018, Sinon.JS
-> All rights reserved.
->
-> Redistribution and use in source and binary forms, with or without
-> modification, are permitted provided that the following conditions are met:
->
-> * Redistributions of source code must retain the above copyright notice, this
-> list of conditions and the following disclaimer.
->
-> * Redistributions in binary form must reproduce the above copyright notice,
-> this list of conditions and the following disclaimer in the documentation
-> and/or other materials provided with the distribution.
->
-> * Neither the name of the copyright holder nor the names of its
-> contributors may be used to endorse or promote products derived from
-> this software without specific prior written permission.
->
-> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-> AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-> DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-> FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-> DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-> SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-> OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-> OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
----------------------------------------
-
-## @sinonjs/fake-timers
-License: BSD-3-Clause
-By: Christian Johansen
-Repository: git+https://github.com/sinonjs/fake-timers.git
-
-> Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no. All rights reserved.
->
-> Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
->
-> 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
->
-> 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
->
-> 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
->
-> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
----------------------------------------
-
-## acorn-walk
-License: MIT
-By: Marijn Haverbeke, Ingvar Stepanyan, Adrian Heine
-Repository: https://github.com/acornjs/acorn.git
-
-> MIT License
->
-> Copyright (C) 2012-2020 by various contributors (see AUTHORS)
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in
-> all copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-> THE SOFTWARE.
-
----------------------------------------
-
-## birpc
-License: MIT
-By: Anthony Fu
-Repository: git+https://github.com/antfu-collective/birpc.git
-
-> MIT License
->
-> Copyright (c) 2021 Anthony Fu <https://github.com/antfu>
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in all
-> copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-> SOFTWARE.
-
----------------------------------------
-
-## cac
-License: MIT
-By: egoist
-Repository: egoist/cac
-
-> The MIT License (MIT)
->
-> Copyright (c) EGOIST <0x142857@gmail.com> (https://github.com/egoist)
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in
-> all copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-> THE SOFTWARE.
-
----------------------------------------
-
-## empathic
-License: MIT
-By: Luke Edwards
-Repository: lukeed/empathic
-
-> MIT License
->
-> Copyright (c) Luke Edwards <luke.edwards05@gmail.com> (lukeed.com)
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
----------------------------------------
-
-## flatted
-License: ISC
-By: Andrea Giammarchi
-Repository: git+https://github.com/WebReflection/flatted.git
-
-> ISC License
->
-> Copyright (c) 2018-2020, Andrea Giammarchi, @WebReflection
->
-> Permission to use, copy, modify, and/or distribute this software for any
-> purpose with or without fee is hereby granted, provided that the above
-> copyright notice and this permission notice appear in all copies.
->
-> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-> REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-> AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-> INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-> LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-> OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-> PERFORMANCE OF THIS SOFTWARE.
-
----------------------------------------
-
-## js-tokens
-License: MIT
-By: Simon Lydell
-Repository: lydell/js-tokens
-
-> The MIT License (MIT)
->
-> Copyright (c) 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 Simon Lydell
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in
-> all copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-> THE SOFTWARE.
-
----------------------------------------
-
-## kleur
-License: MIT
-By: Luke Edwards
-Repository: lukeed/kleur
-
-> The MIT License (MIT)
->
-> Copyright (c) Luke Edwards <luke.edwards05@gmail.com> (lukeed.com)
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in
-> all copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-> THE SOFTWARE.
-
----------------------------------------
-
-## local-pkg
-License: MIT
-By: Anthony Fu
-Repository: git+https://github.com/antfu-collective/local-pkg.git
-
-> MIT License
->
-> Copyright (c) 2021 Anthony Fu <https://github.com/antfu>
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in all
-> copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-> SOFTWARE.
-
----------------------------------------
-
-## mime
-License: MIT
-By: Robert Kieffer
-Repository: https://github.com/broofa/mime
-
-> MIT License
->
-> Copyright (c) 2023 Robert Kieffer
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in all
-> copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-> SOFTWARE.
-
----------------------------------------
-
-## mlly
-License: MIT
-Repository: unjs/mlly
-
-> MIT License
->
-> Copyright (c) Pooya Parsa <pooya@pi0.io>
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in all
-> copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-> SOFTWARE.
-
----------------------------------------
-
-## package-manager-detector
-License: MIT
-By: Anthony Fu
-Repository: git+https://github.com/antfu-collective/package-manager-detector.git
-
-> MIT License
->
-> Copyright (c) 2020-PRESENT Anthony Fu <https://github.com/antfu>
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in all
-> copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-> SOFTWARE.
-
----------------------------------------
-
-## prompts
-License: MIT
-By: Terkel Gjervig
-Repository: terkelg/prompts
-
-> MIT License
->
-> Copyright (c) 2018 Terkel Gjervig Nielsen
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in all
-> copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-> SOFTWARE.
-
----------------------------------------
-
-## quansync
-License: MIT
-By: Anthony Fu, 三咲智子 Kevin Deng
-Repository: git+https://github.com/quansync-dev/quansync.git
-
-> MIT License
->
-> Copyright (c) 2025-PRESENT Anthony Fu <https://github.com/antfu> and Kevin Deng <https://github.com/sxzz>
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in all
-> copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-> SOFTWARE.
-
----------------------------------------
-
-## sisteransi
-License: MIT
-By: Terkel Gjervig
-Repository: https://github.com/terkelg/sisteransi
-
-> MIT License
->
-> Copyright (c) 2018 Terkel Gjervig Nielsen
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in all
-> copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-> SOFTWARE.
-
----------------------------------------
-
-## strip-literal
-License: MIT
-By: Anthony Fu
-Repository: git+https://github.com/antfu/strip-literal.git
-
-> MIT License
->
-> Copyright (c) 2022 Anthony Fu <https://github.com/antfu>
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in all
-> copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-> SOFTWARE.
-
----------------------------------------
-
-## type-detect
-License: MIT
-By: Jake Luer, Keith Cirkel, David Losert, Aleksey Shvayka, Lucas Fernandes da Costa, Grant Snodgrass, Jeremy Tice, Edward Betts, dvlsg, Amila Welihinda, Jake Champion, Miroslav Bajtoš
-Repository: git+ssh://git@github.com/chaijs/type-detect.git
-
-> Copyright (c) 2013 Jake Luer <jake@alogicalparadox.com> (http://alogicalparadox.com)
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in
-> all copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-> THE SOFTWARE.
-
----------------------------------------
-
-## ufo
-License: MIT
-Repository: unjs/ufo
-
-> MIT License
->
-> Copyright (c) Pooya Parsa <pooya@pi0.io>
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in all
-> copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-> SOFTWARE.
-
----------------------------------------
-
-## ws
-License: MIT
-By: Einar Otto Stangvik
-Repository: git+https://github.com/websockets/ws.git
-
-> Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>
-> Copyright (c) 2013 Arnout Kazemier and contributors
-> Copyright (c) 2016 Luigi Pinca and contributors
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy of
-> this software and associated documentation files (the "Software"), to deal in
-> the Software without restriction, including without limitation the rights to
-> use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-> the Software, and to permit persons to whom the Software is furnished to do so,
-> subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in all
-> copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-> FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-> COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-> IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-> CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vanilla/node_modules/vitest/README.md b/vanilla/node_modules/vitest/README.md
deleted file mode 100644
index 3af9a29..0000000
--- a/vanilla/node_modules/vitest/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# vitest
-
-[![NPM version](https://img.shields.io/npm/v/vitest?color=a1b858&label=)](https://www.npmjs.com/package/vitest)
-
-Next generation testing framework powered by Vite.
-
-[GitHub](https://github.com/vitest-dev/vitest) | [Documentation](https://vitest.dev/)
diff --git a/vanilla/node_modules/vitest/browser/context.d.ts b/vanilla/node_modules/vitest/browser/context.d.ts
deleted file mode 100644
index a0f9bc6..0000000
--- a/vanilla/node_modules/vitest/browser/context.d.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-// @ts-ignore -- @vitest/browser-playwright might not be installed
-export * from '@vitest/browser-playwright/context'
-// @ts-ignore -- @vitest/browser-webdriverio might not be installed
-export * from '@vitest/browser-webdriverio/context'
-// @ts-ignore -- @vitest/browser-preview might not be installed
-export * from '@vitest/browser-preview/context'
-export { BrowserCommands, FsOptions } from 'vitest/internal/browser'
diff --git a/vanilla/node_modules/vitest/browser/context.js b/vanilla/node_modules/vitest/browser/context.js
deleted file mode 100644
index 17119bb..0000000
--- a/vanilla/node_modules/vitest/browser/context.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// Vitest resolves "vitest/browser" as a virtual module instead
-
-// fake exports for static analysis
-export const page = null
-export const server = null
-export const userEvent = null
-export const cdp = null
-export const commands = null
-export const locators = null
-export const utils = null
-
-const pool = globalThis.__vitest_worker__?.ctx?.pool
-
-throw new Error(
- // eslint-disable-next-line prefer-template
- 'vitest/browser can be imported only inside the Browser Mode. '
- + (pool
- ? `Your test is running in ${pool} pool. Make sure your regular tests are excluded from the "test.include" glob pattern.`
- : 'Instead, it was imported outside of Vitest.'),
-)
diff --git a/vanilla/node_modules/vitest/config.d.ts b/vanilla/node_modules/vitest/config.d.ts
deleted file mode 100644
index 36afa87..0000000
--- a/vanilla/node_modules/vitest/config.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-// ensure `@vitest/expect` provides `chai` types
-import type {} from '@vitest/expect'
-export * from './dist/config.js'
diff --git a/vanilla/node_modules/vitest/coverage.d.ts b/vanilla/node_modules/vitest/coverage.d.ts
deleted file mode 100644
index cf1145f..0000000
--- a/vanilla/node_modules/vitest/coverage.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './dist/coverage.js'
diff --git a/vanilla/node_modules/vitest/dist/browser.d.ts b/vanilla/node_modules/vitest/dist/browser.d.ts
deleted file mode 100644
index 909014a..0000000
--- a/vanilla/node_modules/vitest/dist/browser.d.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import { a as SerializedCoverageConfig, S as SerializedConfig } from './chunks/config.d.Cy95HiCx.js';
-import { R as RuntimeCoverageModuleLoader } from './chunks/coverage.d.BZtK59WP.js';
-import { SerializedDiffOptions } from '@vitest/utils/diff';
-export { O as OTELCarrier, T as Traces } from './chunks/traces.d.402V_yFI.js';
-export { collectTests, startTests } from '@vitest/runner';
-import * as _vitest_spy from '@vitest/spy';
-export { _vitest_spy as SpyModule };
-export { LoupeOptions, ParsedStack, StringifyOptions } from '@vitest/utils';
-export { browserFormat, format, inspect, stringify } from '@vitest/utils/display';
-export { processError } from '@vitest/utils/error';
-export { getType } from '@vitest/utils/helpers';
-export { DecodedMap, getOriginalPosition } from '@vitest/utils/source-map';
-export { getSafeTimers, setSafeTimers } from '@vitest/utils/timers';
-import '@vitest/pretty-format';
-import '@vitest/snapshot';
-
-declare function startCoverageInsideWorker(options: SerializedCoverageConfig | undefined, loader: RuntimeCoverageModuleLoader, runtimeOptions: {
- isolate: boolean;
-}): Promise<unknown>;
-declare function takeCoverageInsideWorker(options: SerializedCoverageConfig | undefined, loader: RuntimeCoverageModuleLoader): Promise<unknown>;
-declare function stopCoverageInsideWorker(options: SerializedCoverageConfig | undefined, loader: RuntimeCoverageModuleLoader, runtimeOptions: {
- isolate: boolean;
-}): Promise<unknown>;
-
-interface PublicModuleRunner {
- import: (id: string) => Promise<any>;
-}
-
-declare function setupCommonEnv(config: SerializedConfig): Promise<void>;
-declare function loadDiffConfig(config: SerializedConfig, moduleRunner: PublicModuleRunner): Promise<SerializedDiffOptions | undefined>;
-declare function loadSnapshotSerializers(config: SerializedConfig, moduleRunner: PublicModuleRunner): Promise<void>;
-
-interface FsOptions {
- encoding?: BufferEncoding;
- flag?: string | number;
-}
-interface BrowserCommands {
- readFile: (path: string, options?: BufferEncoding | FsOptions) => Promise<string>;
- writeFile: (path: string, content: string, options?: BufferEncoding | (FsOptions & {
- mode?: number | string;
- })) => Promise<void>;
- removeFile: (path: string) => Promise<void>;
-}
-
-export { loadDiffConfig, loadSnapshotSerializers, setupCommonEnv, startCoverageInsideWorker, stopCoverageInsideWorker, takeCoverageInsideWorker };
-export type { BrowserCommands, FsOptions };
diff --git a/vanilla/node_modules/vitest/dist/browser.js b/vanilla/node_modules/vitest/dist/browser.js
deleted file mode 100644
index 526cd7e..0000000
--- a/vanilla/node_modules/vitest/dist/browser.js
+++ /dev/null
@@ -1,20 +0,0 @@
-export { l as loadDiffConfig, b as loadSnapshotSerializers, c as setupCommonEnv, s as startCoverageInsideWorker, a as stopCoverageInsideWorker, t as takeCoverageInsideWorker } from './chunks/setup-common.Cm-kSBVi.js';
-export { T as Traces } from './chunks/traces.CCmnQaNT.js';
-export { collectTests, startTests } from '@vitest/runner';
-import * as spyModule from '@vitest/spy';
-export { spyModule as SpyModule };
-export { browserFormat, format, inspect, stringify } from '@vitest/utils/display';
-export { processError } from '@vitest/utils/error';
-export { getType } from '@vitest/utils/helpers';
-export { DecodedMap, getOriginalPosition } from '@vitest/utils/source-map';
-export { getSafeTimers, setSafeTimers } from '@vitest/utils/timers';
-import './chunks/coverage.D_JHT54q.js';
-import '@vitest/snapshot';
-import './chunks/utils.DvEY5TfP.js';
-
-/**
-* @internal
-*/
-const __INTERNAL = { _extendedMethods: /* @__PURE__ */ new Set() };
-
-export { __INTERNAL };
diff --git a/vanilla/node_modules/vitest/dist/chunks/_commonjsHelpers.D26ty3Ew.js b/vanilla/node_modules/vitest/dist/chunks/_commonjsHelpers.D26ty3Ew.js
deleted file mode 100644
index 95e8e2e..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/_commonjsHelpers.D26ty3Ew.js
+++ /dev/null
@@ -1,6 +0,0 @@
-var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
-function getDefaultExportFromCjs(x) {
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
-}
-
-export { commonjsGlobal as c, getDefaultExportFromCjs as g };
diff --git a/vanilla/node_modules/vitest/dist/chunks/base.CJ0Y4ePK.js b/vanilla/node_modules/vitest/dist/chunks/base.CJ0Y4ePK.js
deleted file mode 100644
index f00681d..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/base.CJ0Y4ePK.js
+++ /dev/null
@@ -1,165 +0,0 @@
-import { runInThisContext } from 'node:vm';
-import * as spyModule from '@vitest/spy';
-import { r as resolveTestRunner, a as resolveSnapshotEnvironment, s as setupChaiConfig } from './index.6Qv1eEA6.js';
-import { l as loadEnvironment, e as emitModuleRunner } from './init.B6MLFIaN.js';
-import { V as VitestEvaluatedModules } from './evaluatedModules.Dg1zASAC.js';
-import { s as startVitestModuleRunner, c as createNodeImportMeta } from './startModuleRunner.DEj0jb3e.js';
-import { performance as performance$1 } from 'node:perf_hooks';
-import { startTests, collectTests } from '@vitest/runner';
-import { c as setupCommonEnv, s as startCoverageInsideWorker, a as stopCoverageInsideWorker } from './setup-common.Cm-kSBVi.js';
-import { g as globalExpect, v as vi } from './vi.2VT5v0um.js';
-import { c as closeInspector } from './inspector.CvyFGlXm.js';
-import { createRequire } from 'node:module';
-import timers from 'node:timers';
-import timersPromises from 'node:timers/promises';
-import util from 'node:util';
-import { KNOWN_ASSET_TYPES } from '@vitest/utils/constants';
-import { i as index } from './index.Z5E_ObnR.js';
-import { g as getWorkerState, r as resetModules, p as provideWorkerState } from './utils.DvEY5TfP.js';
-
-// this should only be used in Node
-let globalSetup = false;
-async function setupGlobalEnv(config, environment) {
- await setupCommonEnv(config);
- Object.defineProperty(globalThis, "__vitest_index__", {
- value: index,
- enumerable: false
- });
- globalExpect.setState({ environment: environment.name });
- if (globalSetup) return;
- globalSetup = true;
- if ((environment.viteEnvironment || environment.name) === "client") {
- const _require = createRequire(import.meta.url);
- // always mock "required" `css` files, because we cannot process them
- _require.extensions[".css"] = resolveCss;
- _require.extensions[".scss"] = resolveCss;
- _require.extensions[".sass"] = resolveCss;
- _require.extensions[".less"] = resolveCss;
- // since we are using Vite, we can assume how these will be resolved
- KNOWN_ASSET_TYPES.forEach((type) => {
- _require.extensions[`.${type}`] = resolveAsset;
- });
- process.env.SSR = "";
- } else process.env.SSR = "1";
- // @ts-expect-error not typed global for patched timers
- globalThis.__vitest_required__ = {
- util,
- timers,
- timersPromises
- };
- if (!config.disableConsoleIntercept) await setupConsoleLogSpy();
-}
-function resolveCss(mod) {
- mod.exports = "";
-}
-function resolveAsset(mod, url) {
- mod.exports = url;
-}
-async function setupConsoleLogSpy() {
- const { createCustomConsole } = await import('./console.Cf-YriPC.js');
- globalThis.console = createCustomConsole();
-}
-
-// browser shouldn't call this!
-async function run(method, files, config, moduleRunner, environment, traces) {
- const workerState = getWorkerState();
- const [testRunner] = await Promise.all([
- traces.$("vitest.runtime.runner", () => resolveTestRunner(config, moduleRunner, traces)),
- traces.$("vitest.runtime.global_env", () => setupGlobalEnv(config, environment)),
- traces.$("vitest.runtime.coverage.start", () => startCoverageInsideWorker(config.coverage, moduleRunner, { isolate: config.isolate })),
- traces.$("vitest.runtime.snapshot.environment", async () => {
- if (!workerState.config.snapshotOptions.snapshotEnvironment) workerState.config.snapshotOptions.snapshotEnvironment = await resolveSnapshotEnvironment(config, moduleRunner);
- })
- ]);
- workerState.onCancel((reason) => {
- closeInspector(config);
- testRunner.cancel?.(reason);
- });
- workerState.durations.prepare = performance$1.now() - workerState.durations.prepare;
- await traces.$(`vitest.test.runner.${method}`, async () => {
- for (const file of files) {
- if (config.isolate) {
- moduleRunner.mocker.reset();
- resetModules(workerState.evaluatedModules, true);
- }
- workerState.filepath = file.filepath;
- if (method === "run") await traces.$(`vitest.test.runner.${method}.module`, { attributes: { "code.file.path": file.filepath } }, () => startTests([file], testRunner));
- else await traces.$(`vitest.test.runner.${method}.module`, { attributes: { "code.file.path": file.filepath } }, () => collectTests([file], testRunner));
- // reset after tests, because user might call `vi.setConfig` in setupFile
- vi.resetConfig();
- // mocks should not affect different files
- vi.restoreAllMocks();
- }
- });
- await traces.$("vitest.runtime.coverage.stop", () => stopCoverageInsideWorker(config.coverage, moduleRunner, { isolate: config.isolate }));
-}
-
-let _moduleRunner;
-const evaluatedModules = new VitestEvaluatedModules();
-const moduleExecutionInfo = /* @__PURE__ */ new Map();
-function startModuleRunner(options) {
- if (_moduleRunner) return _moduleRunner;
- _moduleRunner = startVitestModuleRunner(options);
- return _moduleRunner;
-}
-let _currentEnvironment;
-let _environmentTime;
-/** @experimental */
-async function setupEnvironment(context) {
- const startTime = performance.now();
- const { environment: { name: environmentName, options: environmentOptions }, rpc, config } = context;
- // we could load @vite/env, but it would take ~8ms, while this takes ~0,02ms
- if (context.config.serializedDefines) try {
- runInThisContext(`(() =>{\n${context.config.serializedDefines}})()`, {
- lineOffset: 1,
- filename: "virtual:load-defines.js"
- });
- } catch (error) {
- throw new Error(`Failed to load custom "defines": ${error.message}`);
- }
- const otel = context.traces;
- const { environment, loader } = await loadEnvironment(environmentName, config.root, rpc, otel);
- _currentEnvironment = environment;
- const env = await otel.$("vitest.runtime.environment.setup", { attributes: {
- "vitest.environment": environment.name,
- "vitest.environment.vite_environment": environment.viteEnvironment || environment.name
- } }, () => environment.setup(globalThis, environmentOptions || config.environmentOptions || {}));
- _environmentTime = performance.now() - startTime;
- if (config.chaiConfig) setupChaiConfig(config.chaiConfig);
- return async () => {
- await otel.$("vitest.runtime.environment.teardown", () => env.teardown(globalThis));
- await loader?.close();
- };
-}
-/** @experimental */
-async function runBaseTests(method, state, traces) {
- const { ctx } = state;
- state.environment = _currentEnvironment;
- state.durations.environment = _environmentTime;
- // state has new context, but we want to reuse existing ones
- state.evaluatedModules = evaluatedModules;
- state.moduleExecutionInfo = moduleExecutionInfo;
- provideWorkerState(globalThis, state);
- if (ctx.invalidates) ctx.invalidates.forEach((filepath) => {
- (state.evaluatedModules.fileToModulesMap.get(filepath) || []).forEach((module) => {
- state.evaluatedModules.invalidateModule(module);
- });
- });
- ctx.files.forEach((i) => {
- const filepath = i.filepath;
- (state.evaluatedModules.fileToModulesMap.get(filepath) || []).forEach((module) => {
- state.evaluatedModules.invalidateModule(module);
- });
- });
- const moduleRunner = startModuleRunner({
- state,
- evaluatedModules: state.evaluatedModules,
- spyModule,
- createImportMeta: createNodeImportMeta,
- traces
- });
- emitModuleRunner(moduleRunner);
- await run(method, ctx.files, ctx.config, moduleRunner, _currentEnvironment, traces);
-}
-
-export { runBaseTests as r, setupEnvironment as s };
diff --git a/vanilla/node_modules/vitest/dist/chunks/benchmark.B3N2zMcH.js b/vanilla/node_modules/vitest/dist/chunks/benchmark.B3N2zMcH.js
deleted file mode 100644
index f51879c..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/benchmark.B3N2zMcH.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import { getCurrentSuite } from '@vitest/runner';
-import { createChainable } from '@vitest/runner/utils';
-import { noop } from '@vitest/utils/helpers';
-import { g as getWorkerState } from './utils.DvEY5TfP.js';
-
-const benchFns = /* @__PURE__ */ new WeakMap();
-const benchOptsMap = /* @__PURE__ */ new WeakMap();
-function getBenchOptions(key) {
- return benchOptsMap.get(key);
-}
-function getBenchFn(key) {
- return benchFns.get(key);
-}
-const bench = createBenchmark(function(name, fn = noop, options = {}) {
- if (getWorkerState().config.mode !== "benchmark") throw new Error("`bench()` is only available in benchmark mode.");
- const task = getCurrentSuite().task(formatName(name), {
- ...this,
- meta: { benchmark: true }
- });
- benchFns.set(task, fn);
- benchOptsMap.set(task, options);
- // vitest runner sets mode to `todo` if handler is not passed down
- // but we store handler separetly
- if (!this.todo && task.mode === "todo") task.mode = "run";
-});
-function createBenchmark(fn) {
- const benchmark = createChainable([
- "skip",
- "only",
- "todo"
- ], fn);
- benchmark.skipIf = (condition) => condition ? benchmark.skip : benchmark;
- benchmark.runIf = (condition) => condition ? benchmark : benchmark.skip;
- return benchmark;
-}
-function formatName(name) {
- return typeof name === "string" ? name : typeof name === "function" ? name.name || "<anonymous>" : String(name);
-}
-
-export { getBenchOptions as a, bench as b, getBenchFn as g };
diff --git a/vanilla/node_modules/vitest/dist/chunks/benchmark.d.DAaHLpsq.d.ts b/vanilla/node_modules/vitest/dist/chunks/benchmark.d.DAaHLpsq.d.ts
deleted file mode 100644
index 388d1c3..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/benchmark.d.DAaHLpsq.d.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { Test } from '@vitest/runner';
-import { ChainableFunction } from '@vitest/runner/utils';
-import { TaskResult, Bench, Options } from 'tinybench';
-
-interface Benchmark extends Test {
- meta: {
- benchmark: true;
- result?: TaskResult;
- };
-}
-interface BenchmarkResult extends TaskResult {
- name: string;
- rank: number;
- sampleCount: number;
- median: number;
-}
-type BenchFunction = (this: Bench) => Promise<void> | void;
-type ChainableBenchmarkAPI = ChainableFunction<"skip" | "only" | "todo", (name: string | Function, fn?: BenchFunction, options?: Options) => void>;
-type BenchmarkAPI = ChainableBenchmarkAPI & {
- skipIf: (condition: any) => ChainableBenchmarkAPI;
- runIf: (condition: any) => ChainableBenchmarkAPI;
-};
-
-export type { BenchmarkResult as B, BenchFunction as a, Benchmark as b, BenchmarkAPI as c };
diff --git a/vanilla/node_modules/vitest/dist/chunks/browser.d.ChKACdzH.d.ts b/vanilla/node_modules/vitest/dist/chunks/browser.d.ChKACdzH.d.ts
deleted file mode 100644
index 98b415a..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/browser.d.ChKACdzH.d.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import { FileSpecification } from '@vitest/runner';
-import { O as OTELCarrier } from './traces.d.402V_yFI.js';
-import { T as TestExecutionMethod } from './worker.d.Dyxm8DEL.js';
-
-type SerializedTestSpecification = [project: {
- name: string | undefined;
- root: string;
-}, file: string, options: {
- pool: string;
- testLines?: number[] | undefined;
-}];
-
-interface ModuleDefinitionLocation {
- line: number;
- column: number;
-}
-interface SourceModuleLocations {
- modules: ModuleDefinitionDiagnostic[];
- untracked: ModuleDefinitionDiagnostic[];
-}
-interface ModuleDefinitionDiagnostic {
- start: ModuleDefinitionLocation;
- end: ModuleDefinitionLocation;
- startIndex: number;
- endIndex: number;
- rawUrl: string;
- resolvedUrl: string;
- resolvedId: string;
-}
-interface ModuleDefinitionDurationsDiagnostic extends ModuleDefinitionDiagnostic {
- selfTime: number;
- totalTime: number;
- transformTime?: number;
- external?: boolean;
- importer?: string;
-}
-interface UntrackedModuleDefinitionDiagnostic {
- url: string;
- resolvedId: string;
- resolvedUrl: string;
- selfTime: number;
- totalTime: number;
- transformTime?: number;
- external?: boolean;
- importer?: string;
-}
-interface SourceModuleDiagnostic {
- modules: ModuleDefinitionDurationsDiagnostic[];
- untrackedModules: UntrackedModuleDefinitionDiagnostic[];
-}
-
-interface BrowserTesterOptions {
- method: TestExecutionMethod;
- files: FileSpecification[];
- providedContext: string;
- otelCarrier?: OTELCarrier;
-}
-
-export type { BrowserTesterOptions as B, ModuleDefinitionDurationsDiagnostic as M, SerializedTestSpecification as S, UntrackedModuleDefinitionDiagnostic as U, ModuleDefinitionDiagnostic as a, ModuleDefinitionLocation as b, SourceModuleDiagnostic as c, SourceModuleLocations as d };
diff --git a/vanilla/node_modules/vitest/dist/chunks/cac.DVeoLl0M.js b/vanilla/node_modules/vitest/dist/chunks/cac.DVeoLl0M.js
deleted file mode 100644
index 31b7ad1..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/cac.DVeoLl0M.js
+++ /dev/null
@@ -1,1409 +0,0 @@
-import { toArray } from '@vitest/utils/helpers';
-import { EventEmitter } from 'events';
-import { normalize } from 'pathe';
-import c from 'tinyrainbow';
-import { a as defaultPort, d as defaultBrowserPort } from './constants.D_Q9UYh-.js';
-import { R as ReportersMap } from './index.M8mOzt4Y.js';
-
-function toArr(any) {
- return any == null ? [] : Array.isArray(any) ? any : [any];
-}
-
-function toVal(out, key, val, opts) {
- var x, old=out[key], nxt=(
- !!~opts.string.indexOf(key) ? (val == null || val === true ? '' : String(val))
- : typeof val === 'boolean' ? val
- : !!~opts.boolean.indexOf(key) ? (val === 'false' ? false : val === 'true' || (out._.push((x = +val,x * 0 === 0) ? x : val),!!val))
- : (x = +val,x * 0 === 0) ? x : val
- );
- out[key] = old == null ? nxt : (Array.isArray(old) ? old.concat(nxt) : [old, nxt]);
-}
-
-function mri2 (args, opts) {
- args = args || [];
- opts = opts || {};
-
- var k, arr, arg, name, val, out={ _:[] };
- var i=0, j=0, idx=0, len=args.length;
-
- const alibi = opts.alias !== void 0;
- const strict = opts.unknown !== void 0;
- const defaults = opts.default !== void 0;
-
- opts.alias = opts.alias || {};
- opts.string = toArr(opts.string);
- opts.boolean = toArr(opts.boolean);
-
- if (alibi) {
- for (k in opts.alias) {
- arr = opts.alias[k] = toArr(opts.alias[k]);
- for (i=0; i < arr.length; i++) {
- (opts.alias[arr[i]] = arr.concat(k)).splice(i, 1);
- }
- }
- }
-
- for (i=opts.boolean.length; i-- > 0;) {
- arr = opts.alias[opts.boolean[i]] || [];
- for (j=arr.length; j-- > 0;) opts.boolean.push(arr[j]);
- }
-
- for (i=opts.string.length; i-- > 0;) {
- arr = opts.alias[opts.string[i]] || [];
- for (j=arr.length; j-- > 0;) opts.string.push(arr[j]);
- }
-
- if (defaults) {
- for (k in opts.default) {
- name = typeof opts.default[k];
- arr = opts.alias[k] = opts.alias[k] || [];
- if (opts[name] !== void 0) {
- opts[name].push(k);
- for (i=0; i < arr.length; i++) {
- opts[name].push(arr[i]);
- }
- }
- }
- }
-
- const keys = strict ? Object.keys(opts.alias) : [];
-
- for (i=0; i < len; i++) {
- arg = args[i];
-
- if (arg === '--') {
- out._ = out._.concat(args.slice(++i));
- break;
- }
-
- for (j=0; j < arg.length; j++) {
- if (arg.charCodeAt(j) !== 45) break; // "-"
- }
-
- if (j === 0) {
- out._.push(arg);
- } else if (arg.substring(j, j + 3) === 'no-') {
- name = arg.substring(j + 3);
- if (strict && !~keys.indexOf(name)) {
- return opts.unknown(arg);
- }
- out[name] = false;
- } else {
- for (idx=j+1; idx < arg.length; idx++) {
- if (arg.charCodeAt(idx) === 61) break; // "="
- }
-
- name = arg.substring(j, idx);
- val = arg.substring(++idx) || (i+1 === len || (''+args[i+1]).charCodeAt(0) === 45 || args[++i]);
- arr = (j === 2 ? [name] : name);
-
- for (idx=0; idx < arr.length; idx++) {
- name = arr[idx];
- if (strict && !~keys.indexOf(name)) return opts.unknown('-'.repeat(j) + name);
- toVal(out, name, (idx + 1 < arr.length) || val, opts);
- }
- }
- }
-
- if (defaults) {
- for (k in opts.default) {
- if (out[k] === void 0) {
- out[k] = opts.default[k];
- }
- }
- }
-
- if (alibi) {
- for (k in out) {
- arr = opts.alias[k] || [];
- while (arr.length > 0) {
- out[arr.shift()] = out[k];
- }
- }
- }
-
- return out;
-}
-
-const removeBrackets = (v) => v.replace(/[<[].+/, "").trim();
-const findAllBrackets = (v) => {
- const ANGLED_BRACKET_RE_GLOBAL = /<([^>]+)>/g;
- const SQUARE_BRACKET_RE_GLOBAL = /\[([^\]]+)\]/g;
- const res = [];
- const parse = (match) => {
- let variadic = false;
- let value = match[1];
- if (value.startsWith("...")) {
- value = value.slice(3);
- variadic = true;
- }
- return {
- required: match[0].startsWith("<"),
- value,
- variadic
- };
- };
- let angledMatch;
- while (angledMatch = ANGLED_BRACKET_RE_GLOBAL.exec(v)) {
- res.push(parse(angledMatch));
- }
- let squareMatch;
- while (squareMatch = SQUARE_BRACKET_RE_GLOBAL.exec(v)) {
- res.push(parse(squareMatch));
- }
- return res;
-};
-const getMriOptions = (options) => {
- const result = {alias: {}, boolean: []};
- for (const [index, option] of options.entries()) {
- if (option.names.length > 1) {
- result.alias[option.names[0]] = option.names.slice(1);
- }
- if (option.isBoolean) {
- if (option.negated) {
- const hasStringTypeOption = options.some((o, i) => {
- return i !== index && o.names.some((name) => option.names.includes(name)) && typeof o.required === "boolean";
- });
- if (!hasStringTypeOption) {
- result.boolean.push(option.names[0]);
- }
- } else {
- result.boolean.push(option.names[0]);
- }
- }
- }
- return result;
-};
-const findLongest = (arr) => {
- return arr.sort((a, b) => {
- return a.length > b.length ? -1 : 1;
- })[0];
-};
-const padRight = (str, length) => {
- return str.length >= length ? str : `${str}${" ".repeat(length - str.length)}`;
-};
-const camelcase = (input) => {
- return input.replace(/([a-z])-([a-z])/g, (_, p1, p2) => {
- return p1 + p2.toUpperCase();
- });
-};
-const setDotProp = (obj, keys, val, transforms) => {
- let i = 0;
- let length = keys.length;
- let t = obj;
- let x;
- let convertKey = (i) => {
- let key = keys[i];
- i--;
- while(i >= 0) {
- key = keys[i] + '.' + key;
- i--;
- }
- return key
- };
- for (; i < length; ++i) {
- x = t[keys[i]];
- const transform = transforms[convertKey(i)] || ((v) => v);
- t = t[keys[i]] = transform(i === length - 1 ? val : x != null ? x : !!~keys[i + 1].indexOf(".") || !(+keys[i + 1] > -1) ? {} : []);
- }
-};
-const getFileName = (input) => {
- const m = /([^\\\/]+)$/.exec(input);
- return m ? m[1] : "";
-};
-const camelcaseOptionName = (name) => {
- return name.split(".").map((v, i) => {
- return i === 0 ? camelcase(v) : v;
- }).join(".");
-};
-class CACError extends Error {
- constructor(message) {
- super(message);
- this.name = this.constructor.name;
- if (typeof Error.captureStackTrace === "function") {
- Error.captureStackTrace(this, this.constructor);
- } else {
- this.stack = new Error(message).stack;
- }
- }
-}
-
-class Option {
- constructor(rawName, description, config) {
- this.rawName = rawName;
- this.description = description;
- this.config = Object.assign({}, config);
- rawName = rawName.replace(/\.\*/g, "");
- this.negated = false;
- this.names = removeBrackets(rawName).split(",").map((v) => {
- let name = v.trim().replace(/^-{1,2}/, "");
- if (name.startsWith("no-")) {
- this.negated = true;
- name = name.replace(/^no-/, "");
- }
- return camelcaseOptionName(name);
- }).sort((a, b) => a.length > b.length ? 1 : -1);
- this.name = this.names[this.names.length - 1];
- if (this.negated && this.config.default == null) {
- this.config.default = true;
- }
- if (rawName.includes("<")) {
- this.required = true;
- } else if (rawName.includes("[")) {
- this.required = false;
- } else {
- this.isBoolean = true;
- }
- }
-}
-
-const processArgs = process.argv;
-const platformInfo = `${process.platform}-${process.arch} node-${process.version}`;
-
-class Command {
- constructor(rawName, description, config = {}, cli) {
- this.rawName = rawName;
- this.description = description;
- this.config = config;
- this.cli = cli;
- this.options = [];
- this.aliasNames = [];
- this.name = removeBrackets(rawName);
- this.args = findAllBrackets(rawName);
- this.examples = [];
- }
- usage(text) {
- this.usageText = text;
- return this;
- }
- allowUnknownOptions() {
- this.config.allowUnknownOptions = true;
- return this;
- }
- ignoreOptionDefaultValue() {
- this.config.ignoreOptionDefaultValue = true;
- return this;
- }
- version(version, customFlags = "-v, --version") {
- this.versionNumber = version;
- this.option(customFlags, "Display version number");
- return this;
- }
- example(example) {
- this.examples.push(example);
- return this;
- }
- option(rawName, description, config) {
- const option = new Option(rawName, description, config);
- this.options.push(option);
- return this;
- }
- alias(name) {
- this.aliasNames.push(name);
- return this;
- }
- action(callback) {
- this.commandAction = callback;
- return this;
- }
- isMatched(name) {
- return this.name === name || this.aliasNames.includes(name);
- }
- get isDefaultCommand() {
- return this.name === "" || this.aliasNames.includes("!");
- }
- get isGlobalCommand() {
- return this instanceof GlobalCommand;
- }
- hasOption(name) {
- name = name.split(".")[0];
- return this.options.find((option) => {
- return option.names.includes(name);
- });
- }
- outputHelp() {
- const {name, commands} = this.cli;
- const {
- versionNumber,
- options: globalOptions,
- helpCallback
- } = this.cli.globalCommand;
- let sections = [
- {
- body: `${name}${versionNumber ? `/${versionNumber}` : ""}`
- }
- ];
- sections.push({
- title: "Usage",
- body: ` $ ${name} ${this.usageText || this.rawName}`
- });
- const showCommands = (this.isGlobalCommand || this.isDefaultCommand) && commands.length > 0;
- if (showCommands) {
- const longestCommandName = findLongest(commands.map((command) => command.rawName));
- sections.push({
- title: "Commands",
- body: commands.map((command) => {
- return ` ${padRight(command.rawName, longestCommandName.length)} ${command.description}`;
- }).join("\n")
- });
- sections.push({
- title: `For more info, run any command with the \`--help\` flag`,
- body: commands.map((command) => ` $ ${name}${command.name === "" ? "" : ` ${command.name}`} --help`).join("\n")
- });
- }
- let options = this.isGlobalCommand ? globalOptions : [...this.options, ...globalOptions || []];
- if (!this.isGlobalCommand && !this.isDefaultCommand) {
- options = options.filter((option) => option.name !== "version");
- }
- if (options.length > 0) {
- const longestOptionName = findLongest(options.map((option) => option.rawName));
- sections.push({
- title: "Options",
- body: options.map((option) => {
- return ` ${padRight(option.rawName, longestOptionName.length)} ${option.description} ${option.config.default === void 0 ? "" : `(default: ${option.config.default})`}`;
- }).join("\n")
- });
- }
- if (this.examples.length > 0) {
- sections.push({
- title: "Examples",
- body: this.examples.map((example) => {
- if (typeof example === "function") {
- return example(name);
- }
- return example;
- }).join("\n")
- });
- }
- if (helpCallback) {
- sections = helpCallback(sections) || sections;
- }
- console.log(sections.map((section) => {
- return section.title ? `${section.title}:
-${section.body}` : section.body;
- }).join("\n\n"));
- }
- outputVersion() {
- const {name} = this.cli;
- const {versionNumber} = this.cli.globalCommand;
- if (versionNumber) {
- console.log(`${name}/${versionNumber} ${platformInfo}`);
- }
- }
- checkRequiredArgs() {
- const minimalArgsCount = this.args.filter((arg) => arg.required).length;
- if (this.cli.args.length < minimalArgsCount) {
- throw new CACError(`missing required args for command \`${this.rawName}\``);
- }
- }
- checkUnknownOptions() {
- const {options, globalCommand} = this.cli;
- if (!this.config.allowUnknownOptions) {
- for (const name of Object.keys(options)) {
- if (name !== "--" && !this.hasOption(name) && !globalCommand.hasOption(name)) {
- throw new CACError(`Unknown option \`${name.length > 1 ? `--${name}` : `-${name}`}\``);
- }
- }
- }
- }
- checkOptionValue() {
- const {options: parsedOptions, globalCommand} = this.cli;
- const options = [...globalCommand.options, ...this.options];
- for (const option of options) {
- // skip dot names because only top level options are required
- if (option.name.includes('.')) {
- continue;
- }
- const value = parsedOptions[option.name];
- if (option.required) {
- const hasNegated = options.some((o) => o.negated && o.names.includes(option.name));
- if (value === true || value === false && !hasNegated) {
- throw new CACError(`option \`${option.rawName}\` value is missing`);
- }
- }
- }
- }
-}
-class GlobalCommand extends Command {
- constructor(cli) {
- super("@@global@@", "", {}, cli);
- }
-}
-
-var __assign = Object.assign;
-class CAC extends EventEmitter {
- constructor(name = "") {
- super();
- this.name = name;
- this.commands = [];
- this.rawArgs = [];
- this.args = [];
- this.options = {};
- this.globalCommand = new GlobalCommand(this);
- this.globalCommand.usage("<command> [options]");
- }
- usage(text) {
- this.globalCommand.usage(text);
- return this;
- }
- command(rawName, description, config) {
- const command = new Command(rawName, description || "", config, this);
- command.globalCommand = this.globalCommand;
- this.commands.push(command);
- return command;
- }
- option(rawName, description, config) {
- this.globalCommand.option(rawName, description, config);
- return this;
- }
- help(callback) {
- this.globalCommand.option("-h, --help", "Display this message");
- this.globalCommand.helpCallback = callback;
- this.showHelpOnExit = true;
- return this;
- }
- version(version, customFlags = "-v, --version") {
- this.globalCommand.version(version, customFlags);
- this.showVersionOnExit = true;
- return this;
- }
- example(example) {
- this.globalCommand.example(example);
- return this;
- }
- outputHelp() {
- if (this.matchedCommand) {
- this.matchedCommand.outputHelp();
- } else {
- this.globalCommand.outputHelp();
- }
- }
- outputVersion() {
- this.globalCommand.outputVersion();
- }
- setParsedInfo({args, options}, matchedCommand, matchedCommandName) {
- this.args = args;
- this.options = options;
- if (matchedCommand) {
- this.matchedCommand = matchedCommand;
- }
- if (matchedCommandName) {
- this.matchedCommandName = matchedCommandName;
- }
- return this;
- }
- unsetMatchedCommand() {
- this.matchedCommand = void 0;
- this.matchedCommandName = void 0;
- }
- parse(argv = processArgs, {
- run = true
- } = {}) {
- this.rawArgs = argv;
- if (!this.name) {
- this.name = argv[1] ? getFileName(argv[1]) : "cli";
- }
- let shouldParse = true;
- for (const command of this.commands) {
- const parsed = this.mri(argv.slice(2), command);
- const commandName = parsed.args[0];
- if (command.isMatched(commandName)) {
- shouldParse = false;
- const parsedInfo = __assign(__assign({}, parsed), {
- args: parsed.args.slice(1)
- });
- this.setParsedInfo(parsedInfo, command, commandName);
- this.emit(`command:${commandName}`, command);
- }
- }
- if (shouldParse) {
- for (const command of this.commands) {
- if (command.name === "") {
- shouldParse = false;
- const parsed = this.mri(argv.slice(2), command);
- this.setParsedInfo(parsed, command);
- this.emit(`command:!`, command);
- }
- }
- }
- if (shouldParse) {
- const parsed = this.mri(argv.slice(2));
- this.setParsedInfo(parsed);
- }
- if (this.options.help && this.showHelpOnExit) {
- this.outputHelp();
- run = false;
- this.unsetMatchedCommand();
- }
- if (this.options.version && this.showVersionOnExit && this.matchedCommandName == null) {
- this.outputVersion();
- run = false;
- this.unsetMatchedCommand();
- }
- const parsedArgv = {args: this.args, options: this.options};
- if (run) {
- this.runMatchedCommand();
- }
- if (!this.matchedCommand && this.args[0]) {
- this.emit("command:*");
- }
- return parsedArgv;
- }
- mri(argv, command) {
- const cliOptions = [
- ...this.globalCommand.options,
- ...command ? command.options : []
- ];
- const mriOptions = getMriOptions(cliOptions);
- let argsAfterDoubleDashes = [];
- const doubleDashesIndex = argv.indexOf("--");
- if (doubleDashesIndex > -1) {
- argsAfterDoubleDashes = argv.slice(doubleDashesIndex + 1);
- argv = argv.slice(0, doubleDashesIndex);
- }
- let parsed = mri2(argv, mriOptions);
- parsed = Object.keys(parsed).reduce((res, name) => {
- return __assign(__assign({}, res), {
- [camelcaseOptionName(name)]: parsed[name]
- });
- }, {_: []});
- const args = parsed._;
- const options = {
- "--": argsAfterDoubleDashes
- };
- const ignoreDefault = command && command.config.ignoreOptionDefaultValue ? command.config.ignoreOptionDefaultValue : this.globalCommand.config.ignoreOptionDefaultValue;
- let transforms = Object.create(null);
- for (const cliOption of cliOptions) {
- if (!ignoreDefault && cliOption.config.default !== void 0) {
- for (const name of cliOption.names) {
- options[name] = cliOption.config.default;
- }
- }
- if (cliOption.config.type != null) {
- if (transforms[cliOption.name] === void 0) {
- transforms[cliOption.name] = cliOption.config.type;
- }
- }
- }
- for (const key of Object.keys(parsed)) {
- if (key !== "_") {
- const keys = key.split(".");
- setDotProp(options, keys, parsed[key], transforms);
- // setByType(options, transforms);
- }
- }
- return {
- args,
- options
- };
- }
- runMatchedCommand() {
- const {args, options, matchedCommand: command} = this;
- if (!command || !command.commandAction)
- return;
- command.checkUnknownOptions();
- command.checkOptionValue();
- command.checkRequiredArgs();
- const actionArgs = [];
- command.args.forEach((arg, index) => {
- if (arg.variadic) {
- actionArgs.push(args.slice(index));
- } else {
- actionArgs.push(args[index]);
- }
- });
- actionArgs.push(options);
- return command.commandAction.apply(this, actionArgs);
- }
-}
-
-const cac = (name = "") => new CAC(name);
-
-var version = "4.0.18";
-
-const apiConfig = (port) => ({
- port: {
- description: `Specify server port. Note if the port is already being used, Vite will automatically try the next available port so this may not be the actual port the server ends up listening on. If true will be set to \`${port}\``,
- argument: "[port]"
- },
- host: {
- description: "Specify which IP addresses the server should listen on. Set this to `0.0.0.0` or `true` to listen on all addresses, including LAN and public addresses",
- argument: "[host]"
- },
- strictPort: { description: "Set to true to exit if port is already in use, instead of automatically trying the next available port" },
- middlewareMode: null
-});
-function watermarkTransform(value) {
- if (typeof value === "string") return value.split(",").map(Number);
- return value;
-}
-function transformNestedBoolean(value) {
- if (typeof value === "boolean") return { enabled: value };
- return value;
-}
-const cliOptionsConfig = {
- root: {
- description: "Root path",
- shorthand: "r",
- argument: "<path>",
- normalize: true
- },
- config: {
- shorthand: "c",
- description: "Path to config file",
- argument: "<path>",
- normalize: true
- },
- update: {
- shorthand: "u",
- description: "Update snapshot"
- },
- watch: {
- shorthand: "w",
- description: "Enable watch mode"
- },
- testNamePattern: {
- description: "Run tests with full names matching the specified regexp pattern",
- argument: "<pattern>",
- shorthand: "t"
- },
- dir: {
- description: "Base directory to scan for the test files",
- argument: "<path>",
- normalize: true
- },
- ui: { description: "Enable UI" },
- open: { description: "Open UI automatically (default: `!process.env.CI`)" },
- api: {
- argument: "[port]",
- description: `Specify server port. Note if the port is already being used, Vite will automatically try the next available port so this may not be the actual port the server ends up listening on. If true will be set to ${defaultPort}`,
- subcommands: apiConfig(defaultPort)
- },
- silent: {
- description: "Silent console output from tests. Use `'passed-only'` to see logs from failing tests only.",
- argument: "[value]",
- transform(value) {
- if (value === "true" || value === "yes" || value === true) return true;
- if (value === "false" || value === "no" || value === false) return false;
- if (value === "passed-only") return value;
- throw new TypeError(`Unexpected value "--silent=${value}". Use "--silent=true ${value}" instead.`);
- }
- },
- hideSkippedTests: { description: "Hide logs for skipped tests" },
- reporters: {
- alias: "reporter",
- description: `Specify reporters (${Object.keys(ReportersMap).join(", ")})`,
- argument: "<name>",
- subcommands: null,
- array: true
- },
- outputFile: {
- argument: "<filename/-s>",
- description: "Write test results to a file when supporter reporter is also specified, use cac's dot notation for individual outputs of multiple reporters (example: `--outputFile.tap=./tap.txt`)",
- subcommands: null
- },
- coverage: {
- description: "Enable coverage report",
- argument: "",
- transform: transformNestedBoolean,
- subcommands: {
- provider: {
- description: "Select the tool for coverage collection, available values are: \"v8\", \"istanbul\" and \"custom\"",
- argument: "<name>"
- },
- enabled: { description: "Enables coverage collection. Can be overridden using the `--coverage` CLI option (default: `false`)" },
- include: {
- description: "Files included in coverage as glob patterns. May be specified more than once when using multiple patterns. By default only files covered by tests are included.",
- argument: "<pattern>",
- array: true
- },
- exclude: {
- description: "Files to be excluded in coverage. May be specified more than once when using multiple extensions.",
- argument: "<pattern>",
- array: true
- },
- clean: { description: "Clean coverage results before running tests (default: true)" },
- cleanOnRerun: { description: "Clean coverage report on watch rerun (default: true)" },
- reportsDirectory: {
- description: "Directory to write coverage report to (default: ./coverage)",
- argument: "<path>",
- normalize: true
- },
- reporter: {
- description: "Coverage reporters to use. Visit [`coverage.reporter`](https://vitest.dev/config/#coverage-reporter) for more information (default: `[\"text\", \"html\", \"clover\", \"json\"]`)",
- argument: "<name>",
- subcommands: null,
- array: true
- },
- reportOnFailure: { description: "Generate coverage report even when tests fail (default: `false`)" },
- allowExternal: { description: "Collect coverage of files outside the project root (default: `false`)" },
- skipFull: { description: "Do not show files with 100% statement, branch, and function coverage (default: `false`)" },
- thresholds: {
- description: null,
- argument: "",
- subcommands: {
- perFile: { description: "Check thresholds per file. See `--coverage.thresholds.lines`, `--coverage.thresholds.functions`, `--coverage.thresholds.branches` and `--coverage.thresholds.statements` for the actual thresholds (default: `false`)" },
- autoUpdate: {
- description: "Update threshold values: \"lines\", \"functions\", \"branches\" and \"statements\" to configuration file when current coverage is above the configured thresholds (default: `false`)",
- argument: "<boolean|function>",
- subcommands: null,
- transform(value) {
- if (value === "true" || value === "yes" || value === true) return true;
- if (value === "false" || value === "no" || value === false) return false;
- return value;
- }
- },
- lines: {
- description: "Threshold for lines. Visit [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) for more information. This option is not available for custom providers",
- argument: "<number>"
- },
- functions: {
- description: "Threshold for functions. Visit [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) for more information. This option is not available for custom providers",
- argument: "<number>"
- },
- branches: {
- description: "Threshold for branches. Visit [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) for more information. This option is not available for custom providers",
- argument: "<number>"
- },
- statements: {
- description: "Threshold for statements. Visit [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) for more information. This option is not available for custom providers",
- argument: "<number>"
- },
- 100: { description: "Shortcut to set all coverage thresholds to 100 (default: `false`)" }
- }
- },
- ignoreClassMethods: {
- description: "Array of class method names to ignore for coverage. Visit [istanbuljs](https://github.com/istanbuljs/nyc#ignoring-methods) for more information. This option is only available for the istanbul providers (default: `[]`)",
- argument: "<name>",
- array: true
- },
- processingConcurrency: {
- description: "Concurrency limit used when processing the coverage results. (default min between 20 and the number of CPUs)",
- argument: "<number>"
- },
- customProviderModule: {
- description: "Specifies the module name or path for the custom coverage provider module. Visit [Custom Coverage Provider](https://vitest.dev/guide/coverage#custom-coverage-provider) for more information. This option is only available for custom providers",
- argument: "<path>",
- normalize: true
- },
- watermarks: {
- description: null,
- argument: "",
- subcommands: {
- statements: {
- description: "High and low watermarks for statements in the format of `<high>,<low>`",
- argument: "<watermarks>",
- transform: watermarkTransform
- },
- lines: {
- description: "High and low watermarks for lines in the format of `<high>,<low>`",
- argument: "<watermarks>",
- transform: watermarkTransform
- },
- branches: {
- description: "High and low watermarks for branches in the format of `<high>,<low>`",
- argument: "<watermarks>",
- transform: watermarkTransform
- },
- functions: {
- description: "High and low watermarks for functions in the format of `<high>,<low>`",
- argument: "<watermarks>",
- transform: watermarkTransform
- }
- }
- }
- }
- },
- mode: {
- description: "Override Vite mode (default: `test` or `benchmark`)",
- argument: "<name>"
- },
- isolate: { description: "Run every test file in isolation. To disable isolation, use `--no-isolate` (default: `true`)" },
- globals: { description: "Inject apis globally" },
- dom: { description: "Mock browser API with happy-dom" },
- browser: {
- description: "Run tests in the browser. Equivalent to `--browser.enabled` (default: `false`)",
- argument: "<name>",
- transform(browser) {
- if (typeof browser === "boolean") return { enabled: browser };
- if (browser === "true" || browser === "false") return { enabled: browser === "true" };
- if (browser === "yes" || browser === "no") return { enabled: browser === "yes" };
- if (typeof browser === "string") return { name: browser };
- return browser;
- },
- subcommands: {
- enabled: { description: "Run tests in the browser. Equivalent to `--browser.enabled` (default: `false`)" },
- name: {
- description: "Run all tests in a specific browser. Some browsers are only available for specific providers (see `--browser.provider`).",
- argument: "<name>"
- },
- headless: { description: "Run the browser in headless mode (i.e. without opening the GUI (Graphical User Interface)). If you are running Vitest in CI, it will be enabled by default (default: `process.env.CI`)" },
- api: {
- description: "Specify options for the browser API server. Does not affect the --api option",
- argument: "[port]",
- subcommands: apiConfig(defaultBrowserPort)
- },
- isolate: { description: "Run every browser test file in isolation. To disable isolation, use `--browser.isolate=false` (default: `true`)" },
- ui: { description: "Show Vitest UI when running tests (default: `!process.env.CI`)" },
- fileParallelism: { description: "Should browser test files run in parallel. Use `--browser.fileParallelism=false` to disable (default: `true`)" },
- connectTimeout: {
- description: "If connection to the browser takes longer, the test suite will fail (default: `60_000`)",
- argument: "<timeout>"
- },
- trackUnhandledErrors: { description: "Control if Vitest catches uncaught exceptions so they can be reported (default: `true`)" },
- trace: {
- description: "Enable trace view mode. Supported: \"on\", \"off\", \"on-first-retry\", \"on-all-retries\", \"retain-on-failure\".",
- argument: "<mode>",
- subcommands: null,
- transform(value) {
- return { mode: value };
- }
- },
- orchestratorScripts: null,
- commands: null,
- viewport: null,
- screenshotDirectory: null,
- screenshotFailures: null,
- locators: null,
- testerHtmlPath: null,
- instances: null,
- expect: null,
- provider: null
- }
- },
- pool: {
- description: "Specify pool, if not running in the browser (default: `forks`)",
- argument: "<pool>",
- subcommands: null
- },
- execArgv: {
- description: "Pass additional arguments to `node` process when spawning `worker_threads` or `child_process`.",
- argument: "<option>",
- array: true
- },
- vmMemoryLimit: {
- description: "Memory limit for VM pools. If you see memory leaks, try to tinker this value.",
- argument: "<limit>"
- },
- fileParallelism: { description: "Should all test files run in parallel. Use `--no-file-parallelism` to disable (default: `true`)" },
- maxWorkers: {
- description: "Maximum number or percentage of workers to run tests in",
- argument: "<workers>"
- },
- environment: {
- description: "Specify runner environment, if not running in the browser (default: `node`)",
- argument: "<name>",
- subcommands: null
- },
- passWithNoTests: { description: "Pass when no tests are found" },
- logHeapUsage: { description: "Show the size of heap for each test when running in node" },
- allowOnly: { description: "Allow tests and suites that are marked as only (default: `!process.env.CI`)" },
- dangerouslyIgnoreUnhandledErrors: { description: "Ignore any unhandled errors that occur" },
- shard: {
- description: "Test suite shard to execute in a format of `<index>/<count>`",
- argument: "<shards>"
- },
- changed: {
- description: "Run tests that are affected by the changed files (default: `false`)",
- argument: "[since]"
- },
- sequence: {
- description: "Options for how tests should be sorted",
- argument: "<options>",
- subcommands: {
- shuffle: {
- description: "Run files and tests in a random order. Enabling this option will impact Vitest's cache and have a performance impact. May be useful to find tests that accidentally depend on another run previously (default: `false`)",
- argument: "",
- subcommands: {
- files: { description: "Run files in a random order. Long running tests will not start earlier if you enable this option. (default: `false`)" },
- tests: { description: "Run tests in a random order (default: `false`)" }
- }
- },
- concurrent: { description: "Make tests run in parallel (default: `false`)" },
- seed: {
- description: "Set the randomization seed. This option will have no effect if `--sequence.shuffle` is falsy. Visit [\"Random Seed\" page](https://en.wikipedia.org/wiki/Random_seed) for more information",
- argument: "<seed>"
- },
- hooks: {
- description: "Changes the order in which hooks are executed. Accepted values are: \"stack\", \"list\" and \"parallel\". Visit [`sequence.hooks`](https://vitest.dev/config/#sequence-hooks) for more information (default: `\"parallel\"`)",
- argument: "<order>"
- },
- setupFiles: {
- description: "Changes the order in which setup files are executed. Accepted values are: \"list\" and \"parallel\". If set to \"list\", will run setup files in the order they are defined. If set to \"parallel\", will run setup files in parallel (default: `\"parallel\"`)",
- argument: "<order>"
- },
- groupOrder: null
- }
- },
- inspect: {
- description: "Enable Node.js inspector (default: `127.0.0.1:9229`)",
- argument: "[[host:]port]",
- transform(portOrEnabled) {
- if (portOrEnabled === 0 || portOrEnabled === "true" || portOrEnabled === "yes") return true;
- if (portOrEnabled === "false" || portOrEnabled === "no") return false;
- return portOrEnabled;
- }
- },
- inspectBrk: {
- description: "Enable Node.js inspector and break before the test starts",
- argument: "[[host:]port]",
- transform(portOrEnabled) {
- if (portOrEnabled === 0 || portOrEnabled === "true" || portOrEnabled === "yes") return true;
- if (portOrEnabled === "false" || portOrEnabled === "no") return false;
- return portOrEnabled;
- }
- },
- inspector: null,
- testTimeout: {
- description: "Default timeout of a test in milliseconds (default: `5000`). Use `0` to disable timeout completely.",
- argument: "<timeout>"
- },
- hookTimeout: {
- description: "Default hook timeout in milliseconds (default: `10000`). Use `0` to disable timeout completely.",
- argument: "<timeout>"
- },
- bail: {
- description: "Stop test execution when given number of tests have failed (default: `0`)",
- argument: "<number>"
- },
- retry: {
- description: "Retry the test specific number of times if it fails (default: `0`)",
- argument: "<times>"
- },
- diff: {
- description: "DiffOptions object or a path to a module which exports DiffOptions object",
- argument: "<path>",
- subcommands: {
- aAnnotation: {
- description: "Annotation for expected lines (default: `Expected`)",
- argument: "<annotation>"
- },
- aIndicator: {
- description: "Indicator for expected lines (default: `-`)",
- argument: "<indicator>"
- },
- bAnnotation: {
- description: "Annotation for received lines (default: `Received`)",
- argument: "<annotation>"
- },
- bIndicator: {
- description: "Indicator for received lines (default: `+`)",
- argument: "<indicator>"
- },
- commonIndicator: {
- description: "Indicator for common lines (default: ` `)",
- argument: "<indicator>"
- },
- contextLines: {
- description: "Number of lines of context to show around each change (default: `5`)",
- argument: "<lines>"
- },
- emptyFirstOrLastLinePlaceholder: {
- description: "Placeholder for an empty first or last line (default: `\"\"`)",
- argument: "<placeholder>"
- },
- expand: { description: "Expand all common lines (default: `true`)" },
- includeChangeCounts: { description: "Include comparison counts in diff output (default: `false`)" },
- omitAnnotationLines: { description: "Omit annotation lines from the output (default: `false`)" },
- printBasicPrototype: { description: "Print basic prototype Object and Array (default: `true`)" },
- maxDepth: {
- description: "Limit the depth to recurse when printing nested objects (default: `20`)",
- argument: "<maxDepth>"
- },
- truncateThreshold: {
- description: "Number of lines to show before and after each change (default: `0`)",
- argument: "<threshold>"
- },
- truncateAnnotation: {
- description: "Annotation for truncated lines (default: `... Diff result is truncated`)",
- argument: "<annotation>"
- }
- }
- },
- exclude: {
- description: "Additional file globs to be excluded from test",
- argument: "<glob>",
- array: true
- },
- expandSnapshotDiff: { description: "Show full diff when snapshot fails" },
- disableConsoleIntercept: { description: "Disable automatic interception of console logging (default: `false`)" },
- typecheck: {
- description: "Enable typechecking alongside tests (default: `false`)",
- argument: "",
- transform: transformNestedBoolean,
- subcommands: {
- enabled: { description: "Enable typechecking alongside tests (default: `false`)" },
- only: { description: "Run only typecheck tests. This automatically enables typecheck (default: `false`)" },
- checker: {
- description: "Specify the typechecker to use. Available values are: \"tsc\" and \"vue-tsc\" and a path to an executable (default: `\"tsc\"`)",
- argument: "<name>",
- subcommands: null
- },
- allowJs: { description: "Allow JavaScript files to be typechecked. By default takes the value from tsconfig.json" },
- ignoreSourceErrors: { description: "Ignore type errors from source files" },
- tsconfig: {
- description: "Path to a custom tsconfig file",
- argument: "<path>",
- normalize: true
- },
- spawnTimeout: {
- description: "Minimum time in milliseconds it takes to spawn the typechecker",
- argument: "<time>"
- },
- include: null,
- exclude: null
- }
- },
- project: {
- description: "The name of the project to run if you are using Vitest workspace feature. This can be repeated for multiple projects: `--project=1 --project=2`. You can also filter projects using wildcards like `--project=packages*`, and exclude projects with `--project=!pattern`.",
- argument: "<name>",
- array: true
- },
- slowTestThreshold: {
- description: "Threshold in milliseconds for a test or suite to be considered slow (default: `300`)",
- argument: "<threshold>"
- },
- teardownTimeout: {
- description: "Default timeout of a teardown function in milliseconds (default: `10000`)",
- argument: "<timeout>"
- },
- cache: {
- description: "Enable cache",
- argument: "",
- subcommands: { dir: null },
- default: true,
- transform(cache) {
- if (typeof cache !== "boolean" && cache) throw new Error("--cache.dir is deprecated");
- if (cache) return {};
- return cache;
- }
- },
- maxConcurrency: {
- description: "Maximum number of concurrent tests in a suite (default: `5`)",
- argument: "<number>"
- },
- expect: {
- description: "Configuration options for `expect()` matches",
- argument: "",
- subcommands: {
- requireAssertions: { description: "Require that all tests have at least one assertion" },
- poll: {
- description: "Default options for `expect.poll()`",
- argument: "",
- subcommands: {
- interval: {
- description: "Poll interval in milliseconds for `expect.poll()` assertions (default: `50`)",
- argument: "<interval>"
- },
- timeout: {
- description: "Poll timeout in milliseconds for `expect.poll()` assertions (default: `1000`)",
- argument: "<timeout>"
- }
- },
- transform(value) {
- if (typeof value !== "object") throw new TypeError(`Unexpected value for --expect.poll: ${value}. If you need to configure timeout, use --expect.poll.timeout=<timeout>`);
- return value;
- }
- }
- },
- transform(value) {
- if (typeof value !== "object") throw new TypeError(`Unexpected value for --expect: ${value}. If you need to configure expect options, use --expect.{name}=<value> syntax`);
- return value;
- }
- },
- printConsoleTrace: { description: "Always print console stack traces" },
- includeTaskLocation: { description: "Collect test and suite locations in the `location` property" },
- attachmentsDir: {
- description: "The directory where attachments from `context.annotate` are stored in (default: `.vitest-attachments`)",
- argument: "<dir>"
- },
- run: { description: "Disable watch mode" },
- color: {
- description: "Removes colors from the console output",
- alias: "no-color"
- },
- clearScreen: { description: "Clear terminal screen when re-running tests during watch mode (default: `true`)" },
- configLoader: {
- description: "Use `bundle` to bundle the config with esbuild or `runner` (experimental) to process it on the fly. This is only available in vite version 6.1.0 and above. (default: `bundle`)",
- argument: "<loader>"
- },
- standalone: { description: "Start Vitest without running tests. Tests will be running only on change. This option is ignored when CLI file filters are passed. (default: `false`)" },
- mergeReports: {
- description: "Path to a blob reports directory. If this options is used, Vitest won't run any tests, it will only report previously recorded tests",
- argument: "[path]",
- transform(value) {
- if (!value || typeof value === "boolean") return ".vitest-reports";
- return value;
- }
- },
- clearCache: { description: "Delete all Vitest caches, including `experimental.fsModuleCache`, without running any tests. This will reduce the performance in the subsequent test run." },
- experimental: {
- description: "Experimental features.",
- argument: "<features>",
- subcommands: {
- fsModuleCache: { description: "Enable caching of modules on the file system between reruns." },
- fsModuleCachePath: null,
- openTelemetry: null,
- printImportBreakdown: { description: "Print import breakdown after the summary. If the reporter doesn't support summary, this will have no effect. Note that UI's \"Module Graph\" tab always has an import breakdown." }
- }
- },
- cliExclude: null,
- server: null,
- setupFiles: null,
- globalSetup: null,
- snapshotFormat: null,
- snapshotSerializers: null,
- includeSource: null,
- alias: null,
- env: null,
- environmentOptions: null,
- unstubEnvs: null,
- related: null,
- restoreMocks: null,
- runner: null,
- mockReset: null,
- forceRerunTriggers: null,
- unstubGlobals: null,
- uiBase: null,
- benchmark: null,
- include: null,
- fakeTimers: null,
- chaiConfig: null,
- clearMocks: null,
- css: null,
- deps: null,
- name: null,
- snapshotEnvironment: null,
- compare: null,
- outputJson: null,
- json: null,
- provide: null,
- filesOnly: null,
- projects: null,
- watchTriggerPatterns: null
-};
-const benchCliOptionsConfig = {
- compare: {
- description: "Benchmark output file to compare against",
- argument: "<filename>"
- },
- outputJson: {
- description: "Benchmark output file",
- argument: "<filename>"
- }
-};
-const collectCliOptionsConfig = {
- ...cliOptionsConfig,
- json: {
- description: "Print collected tests as JSON or write to a file (Default: false)",
- argument: "[true/path]"
- },
- filesOnly: { description: "Print only test files with out the test cases" },
- changed: {
- description: "Print only tests that are affected by the changed files (default: `false`)",
- argument: "[since]"
- }
-};
-
-function addCommand(cli, name, option) {
- const commandName = option.alias || name;
- let command = option.shorthand ? `-${option.shorthand}, --${commandName}` : `--${commandName}`;
- if ("argument" in option) command += ` ${option.argument}`;
- function transform(value) {
- if (!option.array && Array.isArray(value)) {
- const received = value.map((s) => typeof s === "string" ? `"${s}"` : s).join(", ");
- throw new Error(`Expected a single value for option "${command}", received [${received}]`);
- }
- value = removeQuotes(value);
- if (option.transform) return option.transform(value);
- if (option.array) return toArray(value);
- if (option.normalize) return normalize(String(value));
- return value;
- }
- const hasSubcommands = "subcommands" in option && option.subcommands;
- if (option.description) {
- let description = option.description.replace(/\[.*\]\((.*)\)/, "$1").replace(/`/g, "");
- if (hasSubcommands) description += `. Use '--help --${commandName}' for more info.`;
- cli.option(command, description, { type: transform });
- }
- if (hasSubcommands) for (const commandName in option.subcommands) {
- const subcommand = option.subcommands[commandName];
- if (subcommand) addCommand(cli, `${name}.${commandName}`, subcommand);
- }
-}
-function addCliOptions(cli, options) {
- for (const [optionName, option] of Object.entries(options)) if (option) addCommand(cli, optionName, option);
-}
-function createCLI(options = {}) {
- const cli = cac("vitest");
- cli.version(version);
- addCliOptions(cli, cliOptionsConfig);
- cli.help((info) => {
- const helpSection = info.find((current) => current.title?.startsWith("For more info, run any command"));
- if (helpSection) helpSection.body += "\n $ vitest --help --expand-help";
- const options = info.find((current) => current.title === "Options");
- if (typeof options !== "object") return info;
- const helpIndex = process.argv.findIndex((arg) => arg === "--help");
- const subcommands = process.argv.slice(helpIndex + 1);
- const defaultOutput = options.body.split("\n").filter((line) => /^\s+--\S+\./.test(line) === false).join("\n");
- // Filter out options with dot-notation if --help is not called with a subcommand (default behavior)
- if (subcommands.length === 0) {
- options.body = defaultOutput;
- return info;
- }
- if (subcommands.length === 1 && (subcommands[0] === "--expand-help" || subcommands[0] === "--expandHelp")) return info;
- const subcommandMarker = "$SUB_COMMAND_MARKER$";
- const banner = info.find((current) => /^vitest\/\d+\.\d+\.\d+$/.test(current.body));
- function addBannerWarning(warning) {
- if (typeof banner?.body === "string") {
- if (banner?.body.includes(warning)) return;
- banner.body = `${banner.body}\n WARN: ${warning}`;
- }
- }
- // If other subcommand combinations are used, only show options for the subcommand
- for (let i = 0; i < subcommands.length; i++) {
- const subcommand = subcommands[i];
- // --help --expand-help can't be called with multiple subcommands and is handled above
- if (subcommand === "--expand-help" || subcommand === "--expandHelp") {
- addBannerWarning("--expand-help subcommand ignored because, when used with --help, it must be the only subcommand");
- continue;
- }
- // Mark the help section for the subcommands
- if (subcommand.startsWith("--")) options.body = options.body.split("\n").map((line) => line.trim().startsWith(subcommand) ? `${subcommandMarker}${line}` : line).join("\n");
- }
- // Filter based on the marked options to preserve the original sort order
- options.body = options.body.split("\n").map((line) => line.startsWith(subcommandMarker) ? line.split(subcommandMarker)[1] : "").filter((line) => line.length !== 0).join("\n");
- if (!options.body) {
- addBannerWarning("no options were found for your subcommands so we printed the whole output");
- options.body = defaultOutput;
- }
- return info;
- });
- cli.command("run [...filters]", void 0, options).action(run);
- cli.command("related [...filters]", void 0, options).action(runRelated);
- cli.command("watch [...filters]", void 0, options).action(watch);
- cli.command("dev [...filters]", void 0, options).action(watch);
- addCliOptions(cli.command("bench [...filters]", void 0, options).action(benchmark), benchCliOptionsConfig);
- cli.command("init <project>", void 0, options).action(init);
- addCliOptions(cli.command("list [...filters]", void 0, options).action((filters, options) => collect("test", filters, options)), collectCliOptionsConfig);
- cli.command("[...filters]", void 0, options).action((filters, options) => start("test", filters, options));
- return cli;
-}
-function removeQuotes(str) {
- if (typeof str !== "string") {
- if (Array.isArray(str)) return str.map(removeQuotes);
- return str;
- }
- if (str[0] === "\"" && str.endsWith("\"")) return str.slice(1, -1);
- if (str.startsWith(`'`) && str.endsWith(`'`)) return str.slice(1, -1);
- return str;
-}
-function splitArgv(argv) {
- argv = argv.replace(/(['"])(?:(?!\1).)+\1/g, (match) => match.replace(/\s/g, "\0"));
- return argv.split(" ").map((arg) => {
- arg = arg.replace(/\0/g, " ");
- return removeQuotes(arg);
- });
-}
-function parseCLI(argv, config = {}) {
- const arrayArgs = typeof argv === "string" ? splitArgv(argv) : argv;
- if (arrayArgs[0] !== "vitest") throw new Error(`Expected "vitest" as the first argument, received "${arrayArgs[0]}"`);
- arrayArgs[0] = "/index.js";
- arrayArgs.unshift("node");
- let { args, options } = createCLI(config).parse(arrayArgs, { run: false });
- if (arrayArgs[2] === "watch" || arrayArgs[2] === "dev") options.watch = true;
- if (arrayArgs[2] === "run" && !options.watch) options.run = true;
- if (arrayArgs[2] === "related") {
- options.related = args;
- options.passWithNoTests ??= true;
- args = [];
- }
- return {
- filter: args,
- options
- };
-}
-async function runRelated(relatedFiles, argv) {
- argv.related = relatedFiles;
- argv.passWithNoTests ??= true;
- await start("test", [], argv);
-}
-async function watch(cliFilters, options) {
- options.watch = true;
- await start("test", cliFilters, options);
-}
-async function run(cliFilters, options) {
- // "vitest run --watch" should still be watch mode
- options.run = !options.watch;
- await start("test", cliFilters, options);
-}
-async function benchmark(cliFilters, options) {
- console.warn(c.yellow("Benchmarking is an experimental feature.\nBreaking changes might not follow SemVer, please pin Vitest's version when using it."));
- await start("benchmark", cliFilters, options);
-}
-function normalizeCliOptions(cliFilters, argv) {
- if (argv.exclude) {
- argv.cliExclude = toArray(argv.exclude);
- delete argv.exclude;
- }
- if (cliFilters.some((filter) => filter.includes(":"))) argv.includeTaskLocation ??= true;
- if (typeof argv.typecheck?.only === "boolean") argv.typecheck.enabled ??= true;
- if (argv.clearCache) {
- argv.watch = false;
- argv.run = true;
- }
- return argv;
-}
-async function start(mode, cliFilters, options) {
- try {
- const { startVitest } = await import('./cli-api.B7PN_QUv.js').then(function (n) { return n.q; });
- const ctx = await startVitest(mode, cliFilters.map(normalize), normalizeCliOptions(cliFilters, options));
- if (!ctx.shouldKeepServer()) await ctx.exit();
- } catch (e) {
- const { errorBanner } = await import('./index.M8mOzt4Y.js').then(function (n) { return n.A; });
- console.error(`\n${errorBanner("Startup Error")}`);
- console.error(e);
- console.error("\n\n");
- if (process.exitCode == null) process.exitCode = 1;
- process.exit();
- }
-}
-async function init(project) {
- if (project !== "browser") {
- console.error(/* @__PURE__ */ new Error("Only the \"browser\" project is supported. Use \"vitest init browser\" to create a new project."));
- process.exit(1);
- }
- const { create } = await import('./creator.DAmOKTvJ.js');
- await create();
-}
-async function collect(mode, cliFilters, options) {
- try {
- const { prepareVitest, processCollected, outputFileList } = await import('./cli-api.B7PN_QUv.js').then(function (n) { return n.q; });
- const ctx = await prepareVitest(mode, {
- ...normalizeCliOptions(cliFilters, options),
- watch: false,
- run: true
- }, void 0, void 0, cliFilters);
- if (!options.filesOnly) {
- const { testModules: tests, unhandledErrors: errors } = await ctx.collect(cliFilters.map(normalize));
- if (errors.length) {
- console.error("\nThere were unhandled errors during test collection");
- errors.forEach((e) => console.error(e));
- console.error("\n\n");
- await ctx.close();
- return;
- }
- processCollected(ctx, tests, options);
- } else outputFileList(await ctx.getRelevantTestSpecifications(cliFilters.map(normalize)), options);
- await ctx.close();
- } catch (e) {
- const { errorBanner } = await import('./index.M8mOzt4Y.js').then(function (n) { return n.A; });
- console.error(`\n${errorBanner("Collect Error")}`);
- console.error(e);
- console.error("\n\n");
- if (process.exitCode == null) process.exitCode = 1;
- process.exit();
- }
-}
-
-export { createCLI as c, parseCLI as p, version as v };
diff --git a/vanilla/node_modules/vitest/dist/chunks/cli-api.B7PN_QUv.js b/vanilla/node_modules/vitest/dist/chunks/cli-api.B7PN_QUv.js
deleted file mode 100644
index 5987574..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/cli-api.B7PN_QUv.js
+++ /dev/null
@@ -1,13657 +0,0 @@
-import fs, { promises, existsSync, mkdirSync, readFileSync, statSync, readdirSync, writeFileSync } from 'node:fs';
-import { relative, resolve, dirname, join, extname, normalize, basename, isAbsolute } from 'pathe';
-import { C as CoverageProviderMap } from './coverage.D_JHT54q.js';
-import path, { resolve as resolve$1 } from 'node:path';
-import { noop, createDefer, slash, withTrailingSlash, cleanUrl, wrapId, isExternalUrl, unwrapId, toArray, deepMerge, nanoid, deepClone, isPrimitive, notNullish } from '@vitest/utils/helpers';
-import { a as any, p as prompt } from './index.D4KonVSU.js';
-import { h as hash, R as RandomSequencer, i as isPackageExists, c as isBrowserEnabled, r as resolveConfig, g as getCoverageProvider, a as resolveApiServerConfig, d as resolveModule } from './coverage.AVPTjMgw.js';
-import * as vite from 'vite';
-import { isFileServingAllowed as isFileServingAllowed$1, parseAst, searchForWorkspaceRoot, fetchModule, version, mergeConfig, createServer, isFileLoadingAllowed, normalizePath } from 'vite';
-import { A as API_PATH, c as configFiles, d as defaultBrowserPort, a as defaultPort } from './constants.D_Q9UYh-.js';
-import * as nodeos from 'node:os';
-import nodeos__default, { tmpdir } from 'node:os';
-import { generateHash as generateHash$1, createTaskName, calculateSuiteHash, someTasksAreOnly, interpretTaskModes, hasFailed, generateFileHash, limitConcurrency, createFileTask as createFileTask$1, getTasks, isTestCase } from '@vitest/runner/utils';
-import { SnapshotManager } from '@vitest/snapshot/manager';
-import { v as version$1 } from './cac.DVeoLl0M.js';
-import { performance as performance$1 } from 'node:perf_hooks';
-import { c as createBirpc } from './index.Chj8NDwU.js';
-import { p as parse, d as stringify, e as createIndexLocationsMap, h as TraceMap, o as originalPositionFor, i as ancestor, j as printError, f as formatProjectName, w as withLabel, k as errorBanner, l as divider, m as Typechecker, n as generateCodeFrame, q as escapeRegExp, r as createDefinesScript, R as ReportersMap, u as groupBy, B as BlobReporter, v as readBlobs, x as convertTasksToEvents, H as HangingProcessReporter, y as wildcardPatternToRegExp, z as stdout } from './index.M8mOzt4Y.js';
-import require$$0$3 from 'events';
-import require$$1$1 from 'https';
-import require$$2 from 'http';
-import require$$3 from 'net';
-import require$$4 from 'tls';
-import require$$1 from 'crypto';
-import require$$0$2 from 'stream';
-import require$$7 from 'url';
-import require$$0 from 'zlib';
-import require$$0$1 from 'buffer';
-import { g as getDefaultExportFromCjs } from './_commonjsHelpers.D26ty3Ew.js';
-import crypto, { createHash } from 'node:crypto';
-import { rootDir, distDir } from '../path.js';
-import { T as Traces } from './traces.CCmnQaNT.js';
-import { createDebug } from 'obug';
-import { rm, readFile, writeFile, rename, stat, unlink, mkdir, copyFile } from 'node:fs/promises';
-import c from 'tinyrainbow';
-import { VitestModuleEvaluator } from '#module-evaluator';
-import { ModuleRunner } from 'vite/module-runner';
-import { Console } from 'node:console';
-import { highlight } from '@vitest/utils/highlight';
-import { createRequire, builtinModules, isBuiltin as isBuiltin$1 } from 'node:module';
-import url, { fileURLToPath, pathToFileURL } from 'node:url';
-import { i as isTTY, a as isWindows } from './env.D4Lgay0q.js';
-import { isatty } from 'node:tty';
-import EventEmitter$1, { EventEmitter } from 'node:events';
-import { t as toBuiltin, i as isBuiltin } from './modules.BJuCwlRJ.js';
-import { fork } from 'node:child_process';
-import { Worker } from 'node:worker_threads';
-import pm from 'picomatch';
-import { glob, isDynamicPattern } from 'tinyglobby';
-import MagicString from 'magic-string';
-import { hoistMocksPlugin, automockPlugin } from '@vitest/mocker/node';
-import { c as configDefaults } from './defaults.BOqNVLsY.js';
-import { KNOWN_ASSET_RE } from '@vitest/utils/constants';
-import { findNearestPackageData } from '@vitest/utils/resolver';
-import * as esModuleLexer from 'es-module-lexer';
-import { a as BenchmarkReportsMap } from './index.C5r1PdPD.js';
-import assert$1 from 'node:assert';
-import { serializeValue } from '@vitest/utils/serialize';
-import { parseErrorStacktrace } from '@vitest/utils/source-map';
-import readline from 'node:readline';
-import { stripVTControlCharacters } from 'node:util';
-
-var bufferUtil = {exports: {}};
-
-var constants;
-var hasRequiredConstants;
-
-function requireConstants () {
- if (hasRequiredConstants) return constants;
- hasRequiredConstants = 1;
-
- const BINARY_TYPES = ['nodebuffer', 'arraybuffer', 'fragments'];
- const hasBlob = typeof Blob !== 'undefined';
-
- if (hasBlob) BINARY_TYPES.push('blob');
-
- constants = {
- BINARY_TYPES,
- EMPTY_BUFFER: Buffer.alloc(0),
- GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
- hasBlob,
- kForOnEventAttribute: Symbol('kIsForOnEventAttribute'),
- kListener: Symbol('kListener'),
- kStatusCode: Symbol('status-code'),
- kWebSocket: Symbol('websocket'),
- NOOP: () => {}
- };
- return constants;
-}
-
-var hasRequiredBufferUtil;
-
-function requireBufferUtil () {
- if (hasRequiredBufferUtil) return bufferUtil.exports;
- hasRequiredBufferUtil = 1;
-
- const { EMPTY_BUFFER } = requireConstants();
-
- const FastBuffer = Buffer[Symbol.species];
-
- /**
- * Merges an array of buffers into a new buffer.
- *
- * @param {Buffer[]} list The array of buffers to concat
- * @param {Number} totalLength The total length of buffers in the list
- * @return {Buffer} The resulting buffer
- * @public
- */
- function concat(list, totalLength) {
- if (list.length === 0) return EMPTY_BUFFER;
- if (list.length === 1) return list[0];
-
- const target = Buffer.allocUnsafe(totalLength);
- let offset = 0;
-
- for (let i = 0; i < list.length; i++) {
- const buf = list[i];
- target.set(buf, offset);
- offset += buf.length;
- }
-
- if (offset < totalLength) {
- return new FastBuffer(target.buffer, target.byteOffset, offset);
- }
-
- return target;
- }
-
- /**
- * Masks a buffer using the given mask.
- *
- * @param {Buffer} source The buffer to mask
- * @param {Buffer} mask The mask to use
- * @param {Buffer} output The buffer where to store the result
- * @param {Number} offset The offset at which to start writing
- * @param {Number} length The number of bytes to mask.
- * @public
- */
- function _mask(source, mask, output, offset, length) {
- for (let i = 0; i < length; i++) {
- output[offset + i] = source[i] ^ mask[i & 3];
- }
- }
-
- /**
- * Unmasks a buffer using the given mask.
- *
- * @param {Buffer} buffer The buffer to unmask
- * @param {Buffer} mask The mask to use
- * @public
- */
- function _unmask(buffer, mask) {
- for (let i = 0; i < buffer.length; i++) {
- buffer[i] ^= mask[i & 3];
- }
- }
-
- /**
- * Converts a buffer to an `ArrayBuffer`.
- *
- * @param {Buffer} buf The buffer to convert
- * @return {ArrayBuffer} Converted buffer
- * @public
- */
- function toArrayBuffer(buf) {
- if (buf.length === buf.buffer.byteLength) {
- return buf.buffer;
- }
-
- return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length);
- }
-
- /**
- * Converts `data` to a `Buffer`.
- *
- * @param {*} data The data to convert
- * @return {Buffer} The buffer
- * @throws {TypeError}
- * @public
- */
- function toBuffer(data) {
- toBuffer.readOnly = true;
-
- if (Buffer.isBuffer(data)) return data;
-
- let buf;
-
- if (data instanceof ArrayBuffer) {
- buf = new FastBuffer(data);
- } else if (ArrayBuffer.isView(data)) {
- buf = new FastBuffer(data.buffer, data.byteOffset, data.byteLength);
- } else {
- buf = Buffer.from(data);
- toBuffer.readOnly = false;
- }
-
- return buf;
- }
-
- bufferUtil.exports = {
- concat,
- mask: _mask,
- toArrayBuffer,
- toBuffer,
- unmask: _unmask
- };
-
- /* istanbul ignore else */
- if (!process.env.WS_NO_BUFFER_UTIL) {
- try {
- const bufferUtil$1 = require('bufferutil');
-
- bufferUtil.exports.mask = function (source, mask, output, offset, length) {
- if (length < 48) _mask(source, mask, output, offset, length);
- else bufferUtil$1.mask(source, mask, output, offset, length);
- };
-
- bufferUtil.exports.unmask = function (buffer, mask) {
- if (buffer.length < 32) _unmask(buffer, mask);
- else bufferUtil$1.unmask(buffer, mask);
- };
- } catch (e) {
- // Continue regardless of the error.
- }
- }
- return bufferUtil.exports;
-}
-
-var limiter;
-var hasRequiredLimiter;
-
-function requireLimiter () {
- if (hasRequiredLimiter) return limiter;
- hasRequiredLimiter = 1;
-
- const kDone = Symbol('kDone');
- const kRun = Symbol('kRun');
-
- /**
- * A very simple job queue with adjustable concurrency. Adapted from
- * https://github.com/STRML/async-limiter
- */
- class Limiter {
- /**
- * Creates a new `Limiter`.
- *
- * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed
- * to run concurrently
- */
- constructor(concurrency) {
- this[kDone] = () => {
- this.pending--;
- this[kRun]();
- };
- this.concurrency = concurrency || Infinity;
- this.jobs = [];
- this.pending = 0;
- }
-
- /**
- * Adds a job to the queue.
- *
- * @param {Function} job The job to run
- * @public
- */
- add(job) {
- this.jobs.push(job);
- this[kRun]();
- }
-
- /**
- * Removes a job from the queue and runs it if possible.
- *
- * @private
- */
- [kRun]() {
- if (this.pending === this.concurrency) return;
-
- if (this.jobs.length) {
- const job = this.jobs.shift();
-
- this.pending++;
- job(this[kDone]);
- }
- }
- }
-
- limiter = Limiter;
- return limiter;
-}
-
-var permessageDeflate;
-var hasRequiredPermessageDeflate;
-
-function requirePermessageDeflate () {
- if (hasRequiredPermessageDeflate) return permessageDeflate;
- hasRequiredPermessageDeflate = 1;
-
- const zlib = require$$0;
-
- const bufferUtil = requireBufferUtil();
- const Limiter = requireLimiter();
- const { kStatusCode } = requireConstants();
-
- const FastBuffer = Buffer[Symbol.species];
- const TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]);
- const kPerMessageDeflate = Symbol('permessage-deflate');
- const kTotalLength = Symbol('total-length');
- const kCallback = Symbol('callback');
- const kBuffers = Symbol('buffers');
- const kError = Symbol('error');
-
- //
- // We limit zlib concurrency, which prevents severe memory fragmentation
- // as documented in https://github.com/nodejs/node/issues/8871#issuecomment-250915913
- // and https://github.com/websockets/ws/issues/1202
- //
- // Intentionally global; it's the global thread pool that's an issue.
- //
- let zlibLimiter;
-
- /**
- * permessage-deflate implementation.
- */
- class PerMessageDeflate {
- /**
- * Creates a PerMessageDeflate instance.
- *
- * @param {Object} [options] Configuration options
- * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support
- * for, or request, a custom client window size
- * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/
- * acknowledge disabling of client context takeover
- * @param {Number} [options.concurrencyLimit=10] The number of concurrent
- * calls to zlib
- * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the
- * use of a custom server window size
- * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept
- * disabling of server context takeover
- * @param {Number} [options.threshold=1024] Size (in bytes) below which
- * messages should not be compressed if context takeover is disabled
- * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on
- * deflate
- * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on
- * inflate
- * @param {Boolean} [isServer=false] Create the instance in either server or
- * client mode
- * @param {Number} [maxPayload=0] The maximum allowed message length
- */
- constructor(options, isServer, maxPayload) {
- this._maxPayload = maxPayload | 0;
- this._options = options || {};
- this._threshold =
- this._options.threshold !== undefined ? this._options.threshold : 1024;
- this._isServer = !!isServer;
- this._deflate = null;
- this._inflate = null;
-
- this.params = null;
-
- if (!zlibLimiter) {
- const concurrency =
- this._options.concurrencyLimit !== undefined
- ? this._options.concurrencyLimit
- : 10;
- zlibLimiter = new Limiter(concurrency);
- }
- }
-
- /**
- * @type {String}
- */
- static get extensionName() {
- return 'permessage-deflate';
- }
-
- /**
- * Create an extension negotiation offer.
- *
- * @return {Object} Extension parameters
- * @public
- */
- offer() {
- const params = {};
-
- if (this._options.serverNoContextTakeover) {
- params.server_no_context_takeover = true;
- }
- if (this._options.clientNoContextTakeover) {
- params.client_no_context_takeover = true;
- }
- if (this._options.serverMaxWindowBits) {
- params.server_max_window_bits = this._options.serverMaxWindowBits;
- }
- if (this._options.clientMaxWindowBits) {
- params.client_max_window_bits = this._options.clientMaxWindowBits;
- } else if (this._options.clientMaxWindowBits == null) {
- params.client_max_window_bits = true;
- }
-
- return params;
- }
-
- /**
- * Accept an extension negotiation offer/response.
- *
- * @param {Array} configurations The extension negotiation offers/reponse
- * @return {Object} Accepted configuration
- * @public
- */
- accept(configurations) {
- configurations = this.normalizeParams(configurations);
-
- this.params = this._isServer
- ? this.acceptAsServer(configurations)
- : this.acceptAsClient(configurations);
-
- return this.params;
- }
-
- /**
- * Releases all resources used by the extension.
- *
- * @public
- */
- cleanup() {
- if (this._inflate) {
- this._inflate.close();
- this._inflate = null;
- }
-
- if (this._deflate) {
- const callback = this._deflate[kCallback];
-
- this._deflate.close();
- this._deflate = null;
-
- if (callback) {
- callback(
- new Error(
- 'The deflate stream was closed while data was being processed'
- )
- );
- }
- }
- }
-
- /**
- * Accept an extension negotiation offer.
- *
- * @param {Array} offers The extension negotiation offers
- * @return {Object} Accepted configuration
- * @private
- */
- acceptAsServer(offers) {
- const opts = this._options;
- const accepted = offers.find((params) => {
- if (
- (opts.serverNoContextTakeover === false &&
- params.server_no_context_takeover) ||
- (params.server_max_window_bits &&
- (opts.serverMaxWindowBits === false ||
- (typeof opts.serverMaxWindowBits === 'number' &&
- opts.serverMaxWindowBits > params.server_max_window_bits))) ||
- (typeof opts.clientMaxWindowBits === 'number' &&
- !params.client_max_window_bits)
- ) {
- return false;
- }
-
- return true;
- });
-
- if (!accepted) {
- throw new Error('None of the extension offers can be accepted');
- }
-
- if (opts.serverNoContextTakeover) {
- accepted.server_no_context_takeover = true;
- }
- if (opts.clientNoContextTakeover) {
- accepted.client_no_context_takeover = true;
- }
- if (typeof opts.serverMaxWindowBits === 'number') {
- accepted.server_max_window_bits = opts.serverMaxWindowBits;
- }
- if (typeof opts.clientMaxWindowBits === 'number') {
- accepted.client_max_window_bits = opts.clientMaxWindowBits;
- } else if (
- accepted.client_max_window_bits === true ||
- opts.clientMaxWindowBits === false
- ) {
- delete accepted.client_max_window_bits;
- }
-
- return accepted;
- }
-
- /**
- * Accept the extension negotiation response.
- *
- * @param {Array} response The extension negotiation response
- * @return {Object} Accepted configuration
- * @private
- */
- acceptAsClient(response) {
- const params = response[0];
-
- if (
- this._options.clientNoContextTakeover === false &&
- params.client_no_context_takeover
- ) {
- throw new Error('Unexpected parameter "client_no_context_takeover"');
- }
-
- if (!params.client_max_window_bits) {
- if (typeof this._options.clientMaxWindowBits === 'number') {
- params.client_max_window_bits = this._options.clientMaxWindowBits;
- }
- } else if (
- this._options.clientMaxWindowBits === false ||
- (typeof this._options.clientMaxWindowBits === 'number' &&
- params.client_max_window_bits > this._options.clientMaxWindowBits)
- ) {
- throw new Error(
- 'Unexpected or invalid parameter "client_max_window_bits"'
- );
- }
-
- return params;
- }
-
- /**
- * Normalize parameters.
- *
- * @param {Array} configurations The extension negotiation offers/reponse
- * @return {Array} The offers/response with normalized parameters
- * @private
- */
- normalizeParams(configurations) {
- configurations.forEach((params) => {
- Object.keys(params).forEach((key) => {
- let value = params[key];
-
- if (value.length > 1) {
- throw new Error(`Parameter "${key}" must have only a single value`);
- }
-
- value = value[0];
-
- if (key === 'client_max_window_bits') {
- if (value !== true) {
- const num = +value;
- if (!Number.isInteger(num) || num < 8 || num > 15) {
- throw new TypeError(
- `Invalid value for parameter "${key}": ${value}`
- );
- }
- value = num;
- } else if (!this._isServer) {
- throw new TypeError(
- `Invalid value for parameter "${key}": ${value}`
- );
- }
- } else if (key === 'server_max_window_bits') {
- const num = +value;
- if (!Number.isInteger(num) || num < 8 || num > 15) {
- throw new TypeError(
- `Invalid value for parameter "${key}": ${value}`
- );
- }
- value = num;
- } else if (
- key === 'client_no_context_takeover' ||
- key === 'server_no_context_takeover'
- ) {
- if (value !== true) {
- throw new TypeError(
- `Invalid value for parameter "${key}": ${value}`
- );
- }
- } else {
- throw new Error(`Unknown parameter "${key}"`);
- }
-
- params[key] = value;
- });
- });
-
- return configurations;
- }
-
- /**
- * Decompress data. Concurrency limited.
- *
- * @param {Buffer} data Compressed data
- * @param {Boolean} fin Specifies whether or not this is the last fragment
- * @param {Function} callback Callback
- * @public
- */
- decompress(data, fin, callback) {
- zlibLimiter.add((done) => {
- this._decompress(data, fin, (err, result) => {
- done();
- callback(err, result);
- });
- });
- }
-
- /**
- * Compress data. Concurrency limited.
- *
- * @param {(Buffer|String)} data Data to compress
- * @param {Boolean} fin Specifies whether or not this is the last fragment
- * @param {Function} callback Callback
- * @public
- */
- compress(data, fin, callback) {
- zlibLimiter.add((done) => {
- this._compress(data, fin, (err, result) => {
- done();
- callback(err, result);
- });
- });
- }
-
- /**
- * Decompress data.
- *
- * @param {Buffer} data Compressed data
- * @param {Boolean} fin Specifies whether or not this is the last fragment
- * @param {Function} callback Callback
- * @private
- */
- _decompress(data, fin, callback) {
- const endpoint = this._isServer ? 'client' : 'server';
-
- if (!this._inflate) {
- const key = `${endpoint}_max_window_bits`;
- const windowBits =
- typeof this.params[key] !== 'number'
- ? zlib.Z_DEFAULT_WINDOWBITS
- : this.params[key];
-
- this._inflate = zlib.createInflateRaw({
- ...this._options.zlibInflateOptions,
- windowBits
- });
- this._inflate[kPerMessageDeflate] = this;
- this._inflate[kTotalLength] = 0;
- this._inflate[kBuffers] = [];
- this._inflate.on('error', inflateOnError);
- this._inflate.on('data', inflateOnData);
- }
-
- this._inflate[kCallback] = callback;
-
- this._inflate.write(data);
- if (fin) this._inflate.write(TRAILER);
-
- this._inflate.flush(() => {
- const err = this._inflate[kError];
-
- if (err) {
- this._inflate.close();
- this._inflate = null;
- callback(err);
- return;
- }
-
- const data = bufferUtil.concat(
- this._inflate[kBuffers],
- this._inflate[kTotalLength]
- );
-
- if (this._inflate._readableState.endEmitted) {
- this._inflate.close();
- this._inflate = null;
- } else {
- this._inflate[kTotalLength] = 0;
- this._inflate[kBuffers] = [];
-
- if (fin && this.params[`${endpoint}_no_context_takeover`]) {
- this._inflate.reset();
- }
- }
-
- callback(null, data);
- });
- }
-
- /**
- * Compress data.
- *
- * @param {(Buffer|String)} data Data to compress
- * @param {Boolean} fin Specifies whether or not this is the last fragment
- * @param {Function} callback Callback
- * @private
- */
- _compress(data, fin, callback) {
- const endpoint = this._isServer ? 'server' : 'client';
-
- if (!this._deflate) {
- const key = `${endpoint}_max_window_bits`;
- const windowBits =
- typeof this.params[key] !== 'number'
- ? zlib.Z_DEFAULT_WINDOWBITS
- : this.params[key];
-
- this._deflate = zlib.createDeflateRaw({
- ...this._options.zlibDeflateOptions,
- windowBits
- });
-
- this._deflate[kTotalLength] = 0;
- this._deflate[kBuffers] = [];
-
- this._deflate.on('data', deflateOnData);
- }
-
- this._deflate[kCallback] = callback;
-
- this._deflate.write(data);
- this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {
- if (!this._deflate) {
- //
- // The deflate stream was closed while data was being processed.
- //
- return;
- }
-
- let data = bufferUtil.concat(
- this._deflate[kBuffers],
- this._deflate[kTotalLength]
- );
-
- if (fin) {
- data = new FastBuffer(data.buffer, data.byteOffset, data.length - 4);
- }
-
- //
- // Ensure that the callback will not be called again in
- // `PerMessageDeflate#cleanup()`.
- //
- this._deflate[kCallback] = null;
-
- this._deflate[kTotalLength] = 0;
- this._deflate[kBuffers] = [];
-
- if (fin && this.params[`${endpoint}_no_context_takeover`]) {
- this._deflate.reset();
- }
-
- callback(null, data);
- });
- }
- }
-
- permessageDeflate = PerMessageDeflate;
-
- /**
- * The listener of the `zlib.DeflateRaw` stream `'data'` event.
- *
- * @param {Buffer} chunk A chunk of data
- * @private
- */
- function deflateOnData(chunk) {
- this[kBuffers].push(chunk);
- this[kTotalLength] += chunk.length;
- }
-
- /**
- * The listener of the `zlib.InflateRaw` stream `'data'` event.
- *
- * @param {Buffer} chunk A chunk of data
- * @private
- */
- function inflateOnData(chunk) {
- this[kTotalLength] += chunk.length;
-
- if (
- this[kPerMessageDeflate]._maxPayload < 1 ||
- this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload
- ) {
- this[kBuffers].push(chunk);
- return;
- }
-
- this[kError] = new RangeError('Max payload size exceeded');
- this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH';
- this[kError][kStatusCode] = 1009;
- this.removeListener('data', inflateOnData);
-
- //
- // The choice to employ `zlib.reset()` over `zlib.close()` is dictated by the
- // fact that in Node.js versions prior to 13.10.0, the callback for
- // `zlib.flush()` is not called if `zlib.close()` is used. Utilizing
- // `zlib.reset()` ensures that either the callback is invoked or an error is
- // emitted.
- //
- this.reset();
- }
-
- /**
- * The listener of the `zlib.InflateRaw` stream `'error'` event.
- *
- * @param {Error} err The emitted error
- * @private
- */
- function inflateOnError(err) {
- //
- // There is no need to call `Zlib#close()` as the handle is automatically
- // closed when an error is emitted.
- //
- this[kPerMessageDeflate]._inflate = null;
-
- if (this[kError]) {
- this[kCallback](this[kError]);
- return;
- }
-
- err[kStatusCode] = 1007;
- this[kCallback](err);
- }
- return permessageDeflate;
-}
-
-var validation = {exports: {}};
-
-var hasRequiredValidation;
-
-function requireValidation () {
- if (hasRequiredValidation) return validation.exports;
- hasRequiredValidation = 1;
-
- const { isUtf8 } = require$$0$1;
-
- const { hasBlob } = requireConstants();
-
- //
- // Allowed token characters:
- //
- // '!', '#', '$', '%', '&', ''', '*', '+', '-',
- // '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~'
- //
- // tokenChars[32] === 0 // ' '
- // tokenChars[33] === 1 // '!'
- // tokenChars[34] === 0 // '"'
- // ...
- //
- // prettier-ignore
- const tokenChars = [
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31
- 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127
- ];
-
- /**
- * Checks if a status code is allowed in a close frame.
- *
- * @param {Number} code The status code
- * @return {Boolean} `true` if the status code is valid, else `false`
- * @public
- */
- function isValidStatusCode(code) {
- return (
- (code >= 1000 &&
- code <= 1014 &&
- code !== 1004 &&
- code !== 1005 &&
- code !== 1006) ||
- (code >= 3000 && code <= 4999)
- );
- }
-
- /**
- * Checks if a given buffer contains only correct UTF-8.
- * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by
- * Markus Kuhn.
- *
- * @param {Buffer} buf The buffer to check
- * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false`
- * @public
- */
- function _isValidUTF8(buf) {
- const len = buf.length;
- let i = 0;
-
- while (i < len) {
- if ((buf[i] & 0x80) === 0) {
- // 0xxxxxxx
- i++;
- } else if ((buf[i] & 0xe0) === 0xc0) {
- // 110xxxxx 10xxxxxx
- if (
- i + 1 === len ||
- (buf[i + 1] & 0xc0) !== 0x80 ||
- (buf[i] & 0xfe) === 0xc0 // Overlong
- ) {
- return false;
- }
-
- i += 2;
- } else if ((buf[i] & 0xf0) === 0xe0) {
- // 1110xxxx 10xxxxxx 10xxxxxx
- if (
- i + 2 >= len ||
- (buf[i + 1] & 0xc0) !== 0x80 ||
- (buf[i + 2] & 0xc0) !== 0x80 ||
- (buf[i] === 0xe0 && (buf[i + 1] & 0xe0) === 0x80) || // Overlong
- (buf[i] === 0xed && (buf[i + 1] & 0xe0) === 0xa0) // Surrogate (U+D800 - U+DFFF)
- ) {
- return false;
- }
-
- i += 3;
- } else if ((buf[i] & 0xf8) === 0xf0) {
- // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- if (
- i + 3 >= len ||
- (buf[i + 1] & 0xc0) !== 0x80 ||
- (buf[i + 2] & 0xc0) !== 0x80 ||
- (buf[i + 3] & 0xc0) !== 0x80 ||
- (buf[i] === 0xf0 && (buf[i + 1] & 0xf0) === 0x80) || // Overlong
- (buf[i] === 0xf4 && buf[i + 1] > 0x8f) ||
- buf[i] > 0xf4 // > U+10FFFF
- ) {
- return false;
- }
-
- i += 4;
- } else {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Determines whether a value is a `Blob`.
- *
- * @param {*} value The value to be tested
- * @return {Boolean} `true` if `value` is a `Blob`, else `false`
- * @private
- */
- function isBlob(value) {
- return (
- hasBlob &&
- typeof value === 'object' &&
- typeof value.arrayBuffer === 'function' &&
- typeof value.type === 'string' &&
- typeof value.stream === 'function' &&
- (value[Symbol.toStringTag] === 'Blob' ||
- value[Symbol.toStringTag] === 'File')
- );
- }
-
- validation.exports = {
- isBlob,
- isValidStatusCode,
- isValidUTF8: _isValidUTF8,
- tokenChars
- };
-
- if (isUtf8) {
- validation.exports.isValidUTF8 = function (buf) {
- return buf.length < 24 ? _isValidUTF8(buf) : isUtf8(buf);
- };
- } /* istanbul ignore else */ else if (!process.env.WS_NO_UTF_8_VALIDATE) {
- try {
- const isValidUTF8 = require('utf-8-validate');
-
- validation.exports.isValidUTF8 = function (buf) {
- return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf);
- };
- } catch (e) {
- // Continue regardless of the error.
- }
- }
- return validation.exports;
-}
-
-var receiver;
-var hasRequiredReceiver;
-
-function requireReceiver () {
- if (hasRequiredReceiver) return receiver;
- hasRequiredReceiver = 1;
-
- const { Writable } = require$$0$2;
-
- const PerMessageDeflate = requirePermessageDeflate();
- const {
- BINARY_TYPES,
- EMPTY_BUFFER,
- kStatusCode,
- kWebSocket
- } = requireConstants();
- const { concat, toArrayBuffer, unmask } = requireBufferUtil();
- const { isValidStatusCode, isValidUTF8 } = requireValidation();
-
- const FastBuffer = Buffer[Symbol.species];
-
- const GET_INFO = 0;
- const GET_PAYLOAD_LENGTH_16 = 1;
- const GET_PAYLOAD_LENGTH_64 = 2;
- const GET_MASK = 3;
- const GET_DATA = 4;
- const INFLATING = 5;
- const DEFER_EVENT = 6;
-
- /**
- * HyBi Receiver implementation.
- *
- * @extends Writable
- */
- class Receiver extends Writable {
- /**
- * Creates a Receiver instance.
- *
- * @param {Object} [options] Options object
- * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether
- * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
- * multiple times in the same tick
- * @param {String} [options.binaryType=nodebuffer] The type for binary data
- * @param {Object} [options.extensions] An object containing the negotiated
- * extensions
- * @param {Boolean} [options.isServer=false] Specifies whether to operate in
- * client or server mode
- * @param {Number} [options.maxPayload=0] The maximum allowed message length
- * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
- * not to skip UTF-8 validation for text and close messages
- */
- constructor(options = {}) {
- super();
-
- this._allowSynchronousEvents =
- options.allowSynchronousEvents !== undefined
- ? options.allowSynchronousEvents
- : true;
- this._binaryType = options.binaryType || BINARY_TYPES[0];
- this._extensions = options.extensions || {};
- this._isServer = !!options.isServer;
- this._maxPayload = options.maxPayload | 0;
- this._skipUTF8Validation = !!options.skipUTF8Validation;
- this[kWebSocket] = undefined;
-
- this._bufferedBytes = 0;
- this._buffers = [];
-
- this._compressed = false;
- this._payloadLength = 0;
- this._mask = undefined;
- this._fragmented = 0;
- this._masked = false;
- this._fin = false;
- this._opcode = 0;
-
- this._totalPayloadLength = 0;
- this._messageLength = 0;
- this._fragments = [];
-
- this._errored = false;
- this._loop = false;
- this._state = GET_INFO;
- }
-
- /**
- * Implements `Writable.prototype._write()`.
- *
- * @param {Buffer} chunk The chunk of data to write
- * @param {String} encoding The character encoding of `chunk`
- * @param {Function} cb Callback
- * @private
- */
- _write(chunk, encoding, cb) {
- if (this._opcode === 0x08 && this._state == GET_INFO) return cb();
-
- this._bufferedBytes += chunk.length;
- this._buffers.push(chunk);
- this.startLoop(cb);
- }
-
- /**
- * Consumes `n` bytes from the buffered data.
- *
- * @param {Number} n The number of bytes to consume
- * @return {Buffer} The consumed bytes
- * @private
- */
- consume(n) {
- this._bufferedBytes -= n;
-
- if (n === this._buffers[0].length) return this._buffers.shift();
-
- if (n < this._buffers[0].length) {
- const buf = this._buffers[0];
- this._buffers[0] = new FastBuffer(
- buf.buffer,
- buf.byteOffset + n,
- buf.length - n
- );
-
- return new FastBuffer(buf.buffer, buf.byteOffset, n);
- }
-
- const dst = Buffer.allocUnsafe(n);
-
- do {
- const buf = this._buffers[0];
- const offset = dst.length - n;
-
- if (n >= buf.length) {
- dst.set(this._buffers.shift(), offset);
- } else {
- dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset);
- this._buffers[0] = new FastBuffer(
- buf.buffer,
- buf.byteOffset + n,
- buf.length - n
- );
- }
-
- n -= buf.length;
- } while (n > 0);
-
- return dst;
- }
-
- /**
- * Starts the parsing loop.
- *
- * @param {Function} cb Callback
- * @private
- */
- startLoop(cb) {
- this._loop = true;
-
- do {
- switch (this._state) {
- case GET_INFO:
- this.getInfo(cb);
- break;
- case GET_PAYLOAD_LENGTH_16:
- this.getPayloadLength16(cb);
- break;
- case GET_PAYLOAD_LENGTH_64:
- this.getPayloadLength64(cb);
- break;
- case GET_MASK:
- this.getMask();
- break;
- case GET_DATA:
- this.getData(cb);
- break;
- case INFLATING:
- case DEFER_EVENT:
- this._loop = false;
- return;
- }
- } while (this._loop);
-
- if (!this._errored) cb();
- }
-
- /**
- * Reads the first two bytes of a frame.
- *
- * @param {Function} cb Callback
- * @private
- */
- getInfo(cb) {
- if (this._bufferedBytes < 2) {
- this._loop = false;
- return;
- }
-
- const buf = this.consume(2);
-
- if ((buf[0] & 0x30) !== 0x00) {
- const error = this.createError(
- RangeError,
- 'RSV2 and RSV3 must be clear',
- true,
- 1002,
- 'WS_ERR_UNEXPECTED_RSV_2_3'
- );
-
- cb(error);
- return;
- }
-
- const compressed = (buf[0] & 0x40) === 0x40;
-
- if (compressed && !this._extensions[PerMessageDeflate.extensionName]) {
- const error = this.createError(
- RangeError,
- 'RSV1 must be clear',
- true,
- 1002,
- 'WS_ERR_UNEXPECTED_RSV_1'
- );
-
- cb(error);
- return;
- }
-
- this._fin = (buf[0] & 0x80) === 0x80;
- this._opcode = buf[0] & 0x0f;
- this._payloadLength = buf[1] & 0x7f;
-
- if (this._opcode === 0x00) {
- if (compressed) {
- const error = this.createError(
- RangeError,
- 'RSV1 must be clear',
- true,
- 1002,
- 'WS_ERR_UNEXPECTED_RSV_1'
- );
-
- cb(error);
- return;
- }
-
- if (!this._fragmented) {
- const error = this.createError(
- RangeError,
- 'invalid opcode 0',
- true,
- 1002,
- 'WS_ERR_INVALID_OPCODE'
- );
-
- cb(error);
- return;
- }
-
- this._opcode = this._fragmented;
- } else if (this._opcode === 0x01 || this._opcode === 0x02) {
- if (this._fragmented) {
- const error = this.createError(
- RangeError,
- `invalid opcode ${this._opcode}`,
- true,
- 1002,
- 'WS_ERR_INVALID_OPCODE'
- );
-
- cb(error);
- return;
- }
-
- this._compressed = compressed;
- } else if (this._opcode > 0x07 && this._opcode < 0x0b) {
- if (!this._fin) {
- const error = this.createError(
- RangeError,
- 'FIN must be set',
- true,
- 1002,
- 'WS_ERR_EXPECTED_FIN'
- );
-
- cb(error);
- return;
- }
-
- if (compressed) {
- const error = this.createError(
- RangeError,
- 'RSV1 must be clear',
- true,
- 1002,
- 'WS_ERR_UNEXPECTED_RSV_1'
- );
-
- cb(error);
- return;
- }
-
- if (
- this._payloadLength > 0x7d ||
- (this._opcode === 0x08 && this._payloadLength === 1)
- ) {
- const error = this.createError(
- RangeError,
- `invalid payload length ${this._payloadLength}`,
- true,
- 1002,
- 'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH'
- );
-
- cb(error);
- return;
- }
- } else {
- const error = this.createError(
- RangeError,
- `invalid opcode ${this._opcode}`,
- true,
- 1002,
- 'WS_ERR_INVALID_OPCODE'
- );
-
- cb(error);
- return;
- }
-
- if (!this._fin && !this._fragmented) this._fragmented = this._opcode;
- this._masked = (buf[1] & 0x80) === 0x80;
-
- if (this._isServer) {
- if (!this._masked) {
- const error = this.createError(
- RangeError,
- 'MASK must be set',
- true,
- 1002,
- 'WS_ERR_EXPECTED_MASK'
- );
-
- cb(error);
- return;
- }
- } else if (this._masked) {
- const error = this.createError(
- RangeError,
- 'MASK must be clear',
- true,
- 1002,
- 'WS_ERR_UNEXPECTED_MASK'
- );
-
- cb(error);
- return;
- }
-
- if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16;
- else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64;
- else this.haveLength(cb);
- }
-
- /**
- * Gets extended payload length (7+16).
- *
- * @param {Function} cb Callback
- * @private
- */
- getPayloadLength16(cb) {
- if (this._bufferedBytes < 2) {
- this._loop = false;
- return;
- }
-
- this._payloadLength = this.consume(2).readUInt16BE(0);
- this.haveLength(cb);
- }
-
- /**
- * Gets extended payload length (7+64).
- *
- * @param {Function} cb Callback
- * @private
- */
- getPayloadLength64(cb) {
- if (this._bufferedBytes < 8) {
- this._loop = false;
- return;
- }
-
- const buf = this.consume(8);
- const num = buf.readUInt32BE(0);
-
- //
- // The maximum safe integer in JavaScript is 2^53 - 1. An error is returned
- // if payload length is greater than this number.
- //
- if (num > Math.pow(2, 53 - 32) - 1) {
- const error = this.createError(
- RangeError,
- 'Unsupported WebSocket frame: payload length > 2^53 - 1',
- false,
- 1009,
- 'WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH'
- );
-
- cb(error);
- return;
- }
-
- this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4);
- this.haveLength(cb);
- }
-
- /**
- * Payload length has been read.
- *
- * @param {Function} cb Callback
- * @private
- */
- haveLength(cb) {
- if (this._payloadLength && this._opcode < 0x08) {
- this._totalPayloadLength += this._payloadLength;
- if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) {
- const error = this.createError(
- RangeError,
- 'Max payload size exceeded',
- false,
- 1009,
- 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'
- );
-
- cb(error);
- return;
- }
- }
-
- if (this._masked) this._state = GET_MASK;
- else this._state = GET_DATA;
- }
-
- /**
- * Reads mask bytes.
- *
- * @private
- */
- getMask() {
- if (this._bufferedBytes < 4) {
- this._loop = false;
- return;
- }
-
- this._mask = this.consume(4);
- this._state = GET_DATA;
- }
-
- /**
- * Reads data bytes.
- *
- * @param {Function} cb Callback
- * @private
- */
- getData(cb) {
- let data = EMPTY_BUFFER;
-
- if (this._payloadLength) {
- if (this._bufferedBytes < this._payloadLength) {
- this._loop = false;
- return;
- }
-
- data = this.consume(this._payloadLength);
-
- if (
- this._masked &&
- (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0
- ) {
- unmask(data, this._mask);
- }
- }
-
- if (this._opcode > 0x07) {
- this.controlMessage(data, cb);
- return;
- }
-
- if (this._compressed) {
- this._state = INFLATING;
- this.decompress(data, cb);
- return;
- }
-
- if (data.length) {
- //
- // This message is not compressed so its length is the sum of the payload
- // length of all fragments.
- //
- this._messageLength = this._totalPayloadLength;
- this._fragments.push(data);
- }
-
- this.dataMessage(cb);
- }
-
- /**
- * Decompresses data.
- *
- * @param {Buffer} data Compressed data
- * @param {Function} cb Callback
- * @private
- */
- decompress(data, cb) {
- const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
-
- perMessageDeflate.decompress(data, this._fin, (err, buf) => {
- if (err) return cb(err);
-
- if (buf.length) {
- this._messageLength += buf.length;
- if (this._messageLength > this._maxPayload && this._maxPayload > 0) {
- const error = this.createError(
- RangeError,
- 'Max payload size exceeded',
- false,
- 1009,
- 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'
- );
-
- cb(error);
- return;
- }
-
- this._fragments.push(buf);
- }
-
- this.dataMessage(cb);
- if (this._state === GET_INFO) this.startLoop(cb);
- });
- }
-
- /**
- * Handles a data message.
- *
- * @param {Function} cb Callback
- * @private
- */
- dataMessage(cb) {
- if (!this._fin) {
- this._state = GET_INFO;
- return;
- }
-
- const messageLength = this._messageLength;
- const fragments = this._fragments;
-
- this._totalPayloadLength = 0;
- this._messageLength = 0;
- this._fragmented = 0;
- this._fragments = [];
-
- if (this._opcode === 2) {
- let data;
-
- if (this._binaryType === 'nodebuffer') {
- data = concat(fragments, messageLength);
- } else if (this._binaryType === 'arraybuffer') {
- data = toArrayBuffer(concat(fragments, messageLength));
- } else if (this._binaryType === 'blob') {
- data = new Blob(fragments);
- } else {
- data = fragments;
- }
-
- if (this._allowSynchronousEvents) {
- this.emit('message', data, true);
- this._state = GET_INFO;
- } else {
- this._state = DEFER_EVENT;
- setImmediate(() => {
- this.emit('message', data, true);
- this._state = GET_INFO;
- this.startLoop(cb);
- });
- }
- } else {
- const buf = concat(fragments, messageLength);
-
- if (!this._skipUTF8Validation && !isValidUTF8(buf)) {
- const error = this.createError(
- Error,
- 'invalid UTF-8 sequence',
- true,
- 1007,
- 'WS_ERR_INVALID_UTF8'
- );
-
- cb(error);
- return;
- }
-
- if (this._state === INFLATING || this._allowSynchronousEvents) {
- this.emit('message', buf, false);
- this._state = GET_INFO;
- } else {
- this._state = DEFER_EVENT;
- setImmediate(() => {
- this.emit('message', buf, false);
- this._state = GET_INFO;
- this.startLoop(cb);
- });
- }
- }
- }
-
- /**
- * Handles a control message.
- *
- * @param {Buffer} data Data to handle
- * @return {(Error|RangeError|undefined)} A possible error
- * @private
- */
- controlMessage(data, cb) {
- if (this._opcode === 0x08) {
- if (data.length === 0) {
- this._loop = false;
- this.emit('conclude', 1005, EMPTY_BUFFER);
- this.end();
- } else {
- const code = data.readUInt16BE(0);
-
- if (!isValidStatusCode(code)) {
- const error = this.createError(
- RangeError,
- `invalid status code ${code}`,
- true,
- 1002,
- 'WS_ERR_INVALID_CLOSE_CODE'
- );
-
- cb(error);
- return;
- }
-
- const buf = new FastBuffer(
- data.buffer,
- data.byteOffset + 2,
- data.length - 2
- );
-
- if (!this._skipUTF8Validation && !isValidUTF8(buf)) {
- const error = this.createError(
- Error,
- 'invalid UTF-8 sequence',
- true,
- 1007,
- 'WS_ERR_INVALID_UTF8'
- );
-
- cb(error);
- return;
- }
-
- this._loop = false;
- this.emit('conclude', code, buf);
- this.end();
- }
-
- this._state = GET_INFO;
- return;
- }
-
- if (this._allowSynchronousEvents) {
- this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);
- this._state = GET_INFO;
- } else {
- this._state = DEFER_EVENT;
- setImmediate(() => {
- this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);
- this._state = GET_INFO;
- this.startLoop(cb);
- });
- }
- }
-
- /**
- * Builds an error object.
- *
- * @param {function(new:Error|RangeError)} ErrorCtor The error constructor
- * @param {String} message The error message
- * @param {Boolean} prefix Specifies whether or not to add a default prefix to
- * `message`
- * @param {Number} statusCode The status code
- * @param {String} errorCode The exposed error code
- * @return {(Error|RangeError)} The error
- * @private
- */
- createError(ErrorCtor, message, prefix, statusCode, errorCode) {
- this._loop = false;
- this._errored = true;
-
- const err = new ErrorCtor(
- prefix ? `Invalid WebSocket frame: ${message}` : message
- );
-
- Error.captureStackTrace(err, this.createError);
- err.code = errorCode;
- err[kStatusCode] = statusCode;
- return err;
- }
- }
-
- receiver = Receiver;
- return receiver;
-}
-
-/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex" }] */
-
-var sender;
-var hasRequiredSender;
-
-function requireSender () {
- if (hasRequiredSender) return sender;
- hasRequiredSender = 1;
-
- const { Duplex } = require$$0$2;
- const { randomFillSync } = require$$1;
-
- const PerMessageDeflate = requirePermessageDeflate();
- const { EMPTY_BUFFER, kWebSocket, NOOP } = requireConstants();
- const { isBlob, isValidStatusCode } = requireValidation();
- const { mask: applyMask, toBuffer } = requireBufferUtil();
-
- const kByteLength = Symbol('kByteLength');
- const maskBuffer = Buffer.alloc(4);
- const RANDOM_POOL_SIZE = 8 * 1024;
- let randomPool;
- let randomPoolPointer = RANDOM_POOL_SIZE;
-
- const DEFAULT = 0;
- const DEFLATING = 1;
- const GET_BLOB_DATA = 2;
-
- /**
- * HyBi Sender implementation.
- */
- class Sender {
- /**
- * Creates a Sender instance.
- *
- * @param {Duplex} socket The connection socket
- * @param {Object} [extensions] An object containing the negotiated extensions
- * @param {Function} [generateMask] The function used to generate the masking
- * key
- */
- constructor(socket, extensions, generateMask) {
- this._extensions = extensions || {};
-
- if (generateMask) {
- this._generateMask = generateMask;
- this._maskBuffer = Buffer.alloc(4);
- }
-
- this._socket = socket;
-
- this._firstFragment = true;
- this._compress = false;
-
- this._bufferedBytes = 0;
- this._queue = [];
- this._state = DEFAULT;
- this.onerror = NOOP;
- this[kWebSocket] = undefined;
- }
-
- /**
- * Frames a piece of data according to the HyBi WebSocket protocol.
- *
- * @param {(Buffer|String)} data The data to frame
- * @param {Object} options Options object
- * @param {Boolean} [options.fin=false] Specifies whether or not to set the
- * FIN bit
- * @param {Function} [options.generateMask] The function used to generate the
- * masking key
- * @param {Boolean} [options.mask=false] Specifies whether or not to mask
- * `data`
- * @param {Buffer} [options.maskBuffer] The buffer used to store the masking
- * key
- * @param {Number} options.opcode The opcode
- * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
- * modified
- * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
- * RSV1 bit
- * @return {(Buffer|String)[]} The framed data
- * @public
- */
- static frame(data, options) {
- let mask;
- let merge = false;
- let offset = 2;
- let skipMasking = false;
-
- if (options.mask) {
- mask = options.maskBuffer || maskBuffer;
-
- if (options.generateMask) {
- options.generateMask(mask);
- } else {
- if (randomPoolPointer === RANDOM_POOL_SIZE) {
- /* istanbul ignore else */
- if (randomPool === undefined) {
- //
- // This is lazily initialized because server-sent frames must not
- // be masked so it may never be used.
- //
- randomPool = Buffer.alloc(RANDOM_POOL_SIZE);
- }
-
- randomFillSync(randomPool, 0, RANDOM_POOL_SIZE);
- randomPoolPointer = 0;
- }
-
- mask[0] = randomPool[randomPoolPointer++];
- mask[1] = randomPool[randomPoolPointer++];
- mask[2] = randomPool[randomPoolPointer++];
- mask[3] = randomPool[randomPoolPointer++];
- }
-
- skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0;
- offset = 6;
- }
-
- let dataLength;
-
- if (typeof data === 'string') {
- if (
- (!options.mask || skipMasking) &&
- options[kByteLength] !== undefined
- ) {
- dataLength = options[kByteLength];
- } else {
- data = Buffer.from(data);
- dataLength = data.length;
- }
- } else {
- dataLength = data.length;
- merge = options.mask && options.readOnly && !skipMasking;
- }
-
- let payloadLength = dataLength;
-
- if (dataLength >= 65536) {
- offset += 8;
- payloadLength = 127;
- } else if (dataLength > 125) {
- offset += 2;
- payloadLength = 126;
- }
-
- const target = Buffer.allocUnsafe(merge ? dataLength + offset : offset);
-
- target[0] = options.fin ? options.opcode | 0x80 : options.opcode;
- if (options.rsv1) target[0] |= 0x40;
-
- target[1] = payloadLength;
-
- if (payloadLength === 126) {
- target.writeUInt16BE(dataLength, 2);
- } else if (payloadLength === 127) {
- target[2] = target[3] = 0;
- target.writeUIntBE(dataLength, 4, 6);
- }
-
- if (!options.mask) return [target, data];
-
- target[1] |= 0x80;
- target[offset - 4] = mask[0];
- target[offset - 3] = mask[1];
- target[offset - 2] = mask[2];
- target[offset - 1] = mask[3];
-
- if (skipMasking) return [target, data];
-
- if (merge) {
- applyMask(data, mask, target, offset, dataLength);
- return [target];
- }
-
- applyMask(data, mask, data, 0, dataLength);
- return [target, data];
- }
-
- /**
- * Sends a close message to the other peer.
- *
- * @param {Number} [code] The status code component of the body
- * @param {(String|Buffer)} [data] The message component of the body
- * @param {Boolean} [mask=false] Specifies whether or not to mask the message
- * @param {Function} [cb] Callback
- * @public
- */
- close(code, data, mask, cb) {
- let buf;
-
- if (code === undefined) {
- buf = EMPTY_BUFFER;
- } else if (typeof code !== 'number' || !isValidStatusCode(code)) {
- throw new TypeError('First argument must be a valid error code number');
- } else if (data === undefined || !data.length) {
- buf = Buffer.allocUnsafe(2);
- buf.writeUInt16BE(code, 0);
- } else {
- const length = Buffer.byteLength(data);
-
- if (length > 123) {
- throw new RangeError('The message must not be greater than 123 bytes');
- }
-
- buf = Buffer.allocUnsafe(2 + length);
- buf.writeUInt16BE(code, 0);
-
- if (typeof data === 'string') {
- buf.write(data, 2);
- } else {
- buf.set(data, 2);
- }
- }
-
- const options = {
- [kByteLength]: buf.length,
- fin: true,
- generateMask: this._generateMask,
- mask,
- maskBuffer: this._maskBuffer,
- opcode: 0x08,
- readOnly: false,
- rsv1: false
- };
-
- if (this._state !== DEFAULT) {
- this.enqueue([this.dispatch, buf, false, options, cb]);
- } else {
- this.sendFrame(Sender.frame(buf, options), cb);
- }
- }
-
- /**
- * Sends a ping message to the other peer.
- *
- * @param {*} data The message to send
- * @param {Boolean} [mask=false] Specifies whether or not to mask `data`
- * @param {Function} [cb] Callback
- * @public
- */
- ping(data, mask, cb) {
- let byteLength;
- let readOnly;
-
- if (typeof data === 'string') {
- byteLength = Buffer.byteLength(data);
- readOnly = false;
- } else if (isBlob(data)) {
- byteLength = data.size;
- readOnly = false;
- } else {
- data = toBuffer(data);
- byteLength = data.length;
- readOnly = toBuffer.readOnly;
- }
-
- if (byteLength > 125) {
- throw new RangeError('The data size must not be greater than 125 bytes');
- }
-
- const options = {
- [kByteLength]: byteLength,
- fin: true,
- generateMask: this._generateMask,
- mask,
- maskBuffer: this._maskBuffer,
- opcode: 0x09,
- readOnly,
- rsv1: false
- };
-
- if (isBlob(data)) {
- if (this._state !== DEFAULT) {
- this.enqueue([this.getBlobData, data, false, options, cb]);
- } else {
- this.getBlobData(data, false, options, cb);
- }
- } else if (this._state !== DEFAULT) {
- this.enqueue([this.dispatch, data, false, options, cb]);
- } else {
- this.sendFrame(Sender.frame(data, options), cb);
- }
- }
-
- /**
- * Sends a pong message to the other peer.
- *
- * @param {*} data The message to send
- * @param {Boolean} [mask=false] Specifies whether or not to mask `data`
- * @param {Function} [cb] Callback
- * @public
- */
- pong(data, mask, cb) {
- let byteLength;
- let readOnly;
-
- if (typeof data === 'string') {
- byteLength = Buffer.byteLength(data);
- readOnly = false;
- } else if (isBlob(data)) {
- byteLength = data.size;
- readOnly = false;
- } else {
- data = toBuffer(data);
- byteLength = data.length;
- readOnly = toBuffer.readOnly;
- }
-
- if (byteLength > 125) {
- throw new RangeError('The data size must not be greater than 125 bytes');
- }
-
- const options = {
- [kByteLength]: byteLength,
- fin: true,
- generateMask: this._generateMask,
- mask,
- maskBuffer: this._maskBuffer,
- opcode: 0x0a,
- readOnly,
- rsv1: false
- };
-
- if (isBlob(data)) {
- if (this._state !== DEFAULT) {
- this.enqueue([this.getBlobData, data, false, options, cb]);
- } else {
- this.getBlobData(data, false, options, cb);
- }
- } else if (this._state !== DEFAULT) {
- this.enqueue([this.dispatch, data, false, options, cb]);
- } else {
- this.sendFrame(Sender.frame(data, options), cb);
- }
- }
-
- /**
- * Sends a data message to the other peer.
- *
- * @param {*} data The message to send
- * @param {Object} options Options object
- * @param {Boolean} [options.binary=false] Specifies whether `data` is binary
- * or text
- * @param {Boolean} [options.compress=false] Specifies whether or not to
- * compress `data`
- * @param {Boolean} [options.fin=false] Specifies whether the fragment is the
- * last one
- * @param {Boolean} [options.mask=false] Specifies whether or not to mask
- * `data`
- * @param {Function} [cb] Callback
- * @public
- */
- send(data, options, cb) {
- const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
- let opcode = options.binary ? 2 : 1;
- let rsv1 = options.compress;
-
- let byteLength;
- let readOnly;
-
- if (typeof data === 'string') {
- byteLength = Buffer.byteLength(data);
- readOnly = false;
- } else if (isBlob(data)) {
- byteLength = data.size;
- readOnly = false;
- } else {
- data = toBuffer(data);
- byteLength = data.length;
- readOnly = toBuffer.readOnly;
- }
-
- if (this._firstFragment) {
- this._firstFragment = false;
- if (
- rsv1 &&
- perMessageDeflate &&
- perMessageDeflate.params[
- perMessageDeflate._isServer
- ? 'server_no_context_takeover'
- : 'client_no_context_takeover'
- ]
- ) {
- rsv1 = byteLength >= perMessageDeflate._threshold;
- }
- this._compress = rsv1;
- } else {
- rsv1 = false;
- opcode = 0;
- }
-
- if (options.fin) this._firstFragment = true;
-
- const opts = {
- [kByteLength]: byteLength,
- fin: options.fin,
- generateMask: this._generateMask,
- mask: options.mask,
- maskBuffer: this._maskBuffer,
- opcode,
- readOnly,
- rsv1
- };
-
- if (isBlob(data)) {
- if (this._state !== DEFAULT) {
- this.enqueue([this.getBlobData, data, this._compress, opts, cb]);
- } else {
- this.getBlobData(data, this._compress, opts, cb);
- }
- } else if (this._state !== DEFAULT) {
- this.enqueue([this.dispatch, data, this._compress, opts, cb]);
- } else {
- this.dispatch(data, this._compress, opts, cb);
- }
- }
-
- /**
- * Gets the contents of a blob as binary data.
- *
- * @param {Blob} blob The blob
- * @param {Boolean} [compress=false] Specifies whether or not to compress
- * the data
- * @param {Object} options Options object
- * @param {Boolean} [options.fin=false] Specifies whether or not to set the
- * FIN bit
- * @param {Function} [options.generateMask] The function used to generate the
- * masking key
- * @param {Boolean} [options.mask=false] Specifies whether or not to mask
- * `data`
- * @param {Buffer} [options.maskBuffer] The buffer used to store the masking
- * key
- * @param {Number} options.opcode The opcode
- * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
- * modified
- * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
- * RSV1 bit
- * @param {Function} [cb] Callback
- * @private
- */
- getBlobData(blob, compress, options, cb) {
- this._bufferedBytes += options[kByteLength];
- this._state = GET_BLOB_DATA;
-
- blob
- .arrayBuffer()
- .then((arrayBuffer) => {
- if (this._socket.destroyed) {
- const err = new Error(
- 'The socket was closed while the blob was being read'
- );
-
- //
- // `callCallbacks` is called in the next tick to ensure that errors
- // that might be thrown in the callbacks behave like errors thrown
- // outside the promise chain.
- //
- process.nextTick(callCallbacks, this, err, cb);
- return;
- }
-
- this._bufferedBytes -= options[kByteLength];
- const data = toBuffer(arrayBuffer);
-
- if (!compress) {
- this._state = DEFAULT;
- this.sendFrame(Sender.frame(data, options), cb);
- this.dequeue();
- } else {
- this.dispatch(data, compress, options, cb);
- }
- })
- .catch((err) => {
- //
- // `onError` is called in the next tick for the same reason that
- // `callCallbacks` above is.
- //
- process.nextTick(onError, this, err, cb);
- });
- }
-
- /**
- * Dispatches a message.
- *
- * @param {(Buffer|String)} data The message to send
- * @param {Boolean} [compress=false] Specifies whether or not to compress
- * `data`
- * @param {Object} options Options object
- * @param {Boolean} [options.fin=false] Specifies whether or not to set the
- * FIN bit
- * @param {Function} [options.generateMask] The function used to generate the
- * masking key
- * @param {Boolean} [options.mask=false] Specifies whether or not to mask
- * `data`
- * @param {Buffer} [options.maskBuffer] The buffer used to store the masking
- * key
- * @param {Number} options.opcode The opcode
- * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
- * modified
- * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
- * RSV1 bit
- * @param {Function} [cb] Callback
- * @private
- */
- dispatch(data, compress, options, cb) {
- if (!compress) {
- this.sendFrame(Sender.frame(data, options), cb);
- return;
- }
-
- const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
-
- this._bufferedBytes += options[kByteLength];
- this._state = DEFLATING;
- perMessageDeflate.compress(data, options.fin, (_, buf) => {
- if (this._socket.destroyed) {
- const err = new Error(
- 'The socket was closed while data was being compressed'
- );
-
- callCallbacks(this, err, cb);
- return;
- }
-
- this._bufferedBytes -= options[kByteLength];
- this._state = DEFAULT;
- options.readOnly = false;
- this.sendFrame(Sender.frame(buf, options), cb);
- this.dequeue();
- });
- }
-
- /**
- * Executes queued send operations.
- *
- * @private
- */
- dequeue() {
- while (this._state === DEFAULT && this._queue.length) {
- const params = this._queue.shift();
-
- this._bufferedBytes -= params[3][kByteLength];
- Reflect.apply(params[0], this, params.slice(1));
- }
- }
-
- /**
- * Enqueues a send operation.
- *
- * @param {Array} params Send operation parameters.
- * @private
- */
- enqueue(params) {
- this._bufferedBytes += params[3][kByteLength];
- this._queue.push(params);
- }
-
- /**
- * Sends a frame.
- *
- * @param {(Buffer | String)[]} list The frame to send
- * @param {Function} [cb] Callback
- * @private
- */
- sendFrame(list, cb) {
- if (list.length === 2) {
- this._socket.cork();
- this._socket.write(list[0]);
- this._socket.write(list[1], cb);
- this._socket.uncork();
- } else {
- this._socket.write(list[0], cb);
- }
- }
- }
-
- sender = Sender;
-
- /**
- * Calls queued callbacks with an error.
- *
- * @param {Sender} sender The `Sender` instance
- * @param {Error} err The error to call the callbacks with
- * @param {Function} [cb] The first callback
- * @private
- */
- function callCallbacks(sender, err, cb) {
- if (typeof cb === 'function') cb(err);
-
- for (let i = 0; i < sender._queue.length; i++) {
- const params = sender._queue[i];
- const callback = params[params.length - 1];
-
- if (typeof callback === 'function') callback(err);
- }
- }
-
- /**
- * Handles a `Sender` error.
- *
- * @param {Sender} sender The `Sender` instance
- * @param {Error} err The error
- * @param {Function} [cb] The first pending callback
- * @private
- */
- function onError(sender, err, cb) {
- callCallbacks(sender, err, cb);
- sender.onerror(err);
- }
- return sender;
-}
-
-var eventTarget;
-var hasRequiredEventTarget;
-
-function requireEventTarget () {
- if (hasRequiredEventTarget) return eventTarget;
- hasRequiredEventTarget = 1;
-
- const { kForOnEventAttribute, kListener } = requireConstants();
-
- const kCode = Symbol('kCode');
- const kData = Symbol('kData');
- const kError = Symbol('kError');
- const kMessage = Symbol('kMessage');
- const kReason = Symbol('kReason');
- const kTarget = Symbol('kTarget');
- const kType = Symbol('kType');
- const kWasClean = Symbol('kWasClean');
-
- /**
- * Class representing an event.
- */
- class Event {
- /**
- * Create a new `Event`.
- *
- * @param {String} type The name of the event
- * @throws {TypeError} If the `type` argument is not specified
- */
- constructor(type) {
- this[kTarget] = null;
- this[kType] = type;
- }
-
- /**
- * @type {*}
- */
- get target() {
- return this[kTarget];
- }
-
- /**
- * @type {String}
- */
- get type() {
- return this[kType];
- }
- }
-
- Object.defineProperty(Event.prototype, 'target', { enumerable: true });
- Object.defineProperty(Event.prototype, 'type', { enumerable: true });
-
- /**
- * Class representing a close event.
- *
- * @extends Event
- */
- class CloseEvent extends Event {
- /**
- * Create a new `CloseEvent`.
- *
- * @param {String} type The name of the event
- * @param {Object} [options] A dictionary object that allows for setting
- * attributes via object members of the same name
- * @param {Number} [options.code=0] The status code explaining why the
- * connection was closed
- * @param {String} [options.reason=''] A human-readable string explaining why
- * the connection was closed
- * @param {Boolean} [options.wasClean=false] Indicates whether or not the
- * connection was cleanly closed
- */
- constructor(type, options = {}) {
- super(type);
-
- this[kCode] = options.code === undefined ? 0 : options.code;
- this[kReason] = options.reason === undefined ? '' : options.reason;
- this[kWasClean] = options.wasClean === undefined ? false : options.wasClean;
- }
-
- /**
- * @type {Number}
- */
- get code() {
- return this[kCode];
- }
-
- /**
- * @type {String}
- */
- get reason() {
- return this[kReason];
- }
-
- /**
- * @type {Boolean}
- */
- get wasClean() {
- return this[kWasClean];
- }
- }
-
- Object.defineProperty(CloseEvent.prototype, 'code', { enumerable: true });
- Object.defineProperty(CloseEvent.prototype, 'reason', { enumerable: true });
- Object.defineProperty(CloseEvent.prototype, 'wasClean', { enumerable: true });
-
- /**
- * Class representing an error event.
- *
- * @extends Event
- */
- class ErrorEvent extends Event {
- /**
- * Create a new `ErrorEvent`.
- *
- * @param {String} type The name of the event
- * @param {Object} [options] A dictionary object that allows for setting
- * attributes via object members of the same name
- * @param {*} [options.error=null] The error that generated this event
- * @param {String} [options.message=''] The error message
- */
- constructor(type, options = {}) {
- super(type);
-
- this[kError] = options.error === undefined ? null : options.error;
- this[kMessage] = options.message === undefined ? '' : options.message;
- }
-
- /**
- * @type {*}
- */
- get error() {
- return this[kError];
- }
-
- /**
- * @type {String}
- */
- get message() {
- return this[kMessage];
- }
- }
-
- Object.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true });
- Object.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true });
-
- /**
- * Class representing a message event.
- *
- * @extends Event
- */
- class MessageEvent extends Event {
- /**
- * Create a new `MessageEvent`.
- *
- * @param {String} type The name of the event
- * @param {Object} [options] A dictionary object that allows for setting
- * attributes via object members of the same name
- * @param {*} [options.data=null] The message content
- */
- constructor(type, options = {}) {
- super(type);
-
- this[kData] = options.data === undefined ? null : options.data;
- }
-
- /**
- * @type {*}
- */
- get data() {
- return this[kData];
- }
- }
-
- Object.defineProperty(MessageEvent.prototype, 'data', { enumerable: true });
-
- /**
- * This provides methods for emulating the `EventTarget` interface. It's not
- * meant to be used directly.
- *
- * @mixin
- */
- const EventTarget = {
- /**
- * Register an event listener.
- *
- * @param {String} type A string representing the event type to listen for
- * @param {(Function|Object)} handler The listener to add
- * @param {Object} [options] An options object specifies characteristics about
- * the event listener
- * @param {Boolean} [options.once=false] A `Boolean` indicating that the
- * listener should be invoked at most once after being added. If `true`,
- * the listener would be automatically removed when invoked.
- * @public
- */
- addEventListener(type, handler, options = {}) {
- for (const listener of this.listeners(type)) {
- if (
- !options[kForOnEventAttribute] &&
- listener[kListener] === handler &&
- !listener[kForOnEventAttribute]
- ) {
- return;
- }
- }
-
- let wrapper;
-
- if (type === 'message') {
- wrapper = function onMessage(data, isBinary) {
- const event = new MessageEvent('message', {
- data: isBinary ? data : data.toString()
- });
-
- event[kTarget] = this;
- callListener(handler, this, event);
- };
- } else if (type === 'close') {
- wrapper = function onClose(code, message) {
- const event = new CloseEvent('close', {
- code,
- reason: message.toString(),
- wasClean: this._closeFrameReceived && this._closeFrameSent
- });
-
- event[kTarget] = this;
- callListener(handler, this, event);
- };
- } else if (type === 'error') {
- wrapper = function onError(error) {
- const event = new ErrorEvent('error', {
- error,
- message: error.message
- });
-
- event[kTarget] = this;
- callListener(handler, this, event);
- };
- } else if (type === 'open') {
- wrapper = function onOpen() {
- const event = new Event('open');
-
- event[kTarget] = this;
- callListener(handler, this, event);
- };
- } else {
- return;
- }
-
- wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute];
- wrapper[kListener] = handler;
-
- if (options.once) {
- this.once(type, wrapper);
- } else {
- this.on(type, wrapper);
- }
- },
-
- /**
- * Remove an event listener.
- *
- * @param {String} type A string representing the event type to remove
- * @param {(Function|Object)} handler The listener to remove
- * @public
- */
- removeEventListener(type, handler) {
- for (const listener of this.listeners(type)) {
- if (listener[kListener] === handler && !listener[kForOnEventAttribute]) {
- this.removeListener(type, listener);
- break;
- }
- }
- }
- };
-
- eventTarget = {
- CloseEvent,
- ErrorEvent,
- Event,
- EventTarget,
- MessageEvent
- };
-
- /**
- * Call an event listener
- *
- * @param {(Function|Object)} listener The listener to call
- * @param {*} thisArg The value to use as `this`` when calling the listener
- * @param {Event} event The event to pass to the listener
- * @private
- */
- function callListener(listener, thisArg, event) {
- if (typeof listener === 'object' && listener.handleEvent) {
- listener.handleEvent.call(listener, event);
- } else {
- listener.call(thisArg, event);
- }
- }
- return eventTarget;
-}
-
-var extension;
-var hasRequiredExtension;
-
-function requireExtension () {
- if (hasRequiredExtension) return extension;
- hasRequiredExtension = 1;
-
- const { tokenChars } = requireValidation();
-
- /**
- * Adds an offer to the map of extension offers or a parameter to the map of
- * parameters.
- *
- * @param {Object} dest The map of extension offers or parameters
- * @param {String} name The extension or parameter name
- * @param {(Object|Boolean|String)} elem The extension parameters or the
- * parameter value
- * @private
- */
- function push(dest, name, elem) {
- if (dest[name] === undefined) dest[name] = [elem];
- else dest[name].push(elem);
- }
-
- /**
- * Parses the `Sec-WebSocket-Extensions` header into an object.
- *
- * @param {String} header The field value of the header
- * @return {Object} The parsed object
- * @public
- */
- function parse(header) {
- const offers = Object.create(null);
- let params = Object.create(null);
- let mustUnescape = false;
- let isEscaping = false;
- let inQuotes = false;
- let extensionName;
- let paramName;
- let start = -1;
- let code = -1;
- let end = -1;
- let i = 0;
-
- for (; i < header.length; i++) {
- code = header.charCodeAt(i);
-
- if (extensionName === undefined) {
- if (end === -1 && tokenChars[code] === 1) {
- if (start === -1) start = i;
- } else if (
- i !== 0 &&
- (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */
- ) {
- if (end === -1 && start !== -1) end = i;
- } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) {
- if (start === -1) {
- throw new SyntaxError(`Unexpected character at index ${i}`);
- }
-
- if (end === -1) end = i;
- const name = header.slice(start, end);
- if (code === 0x2c) {
- push(offers, name, params);
- params = Object.create(null);
- } else {
- extensionName = name;
- }
-
- start = end = -1;
- } else {
- throw new SyntaxError(`Unexpected character at index ${i}`);
- }
- } else if (paramName === undefined) {
- if (end === -1 && tokenChars[code] === 1) {
- if (start === -1) start = i;
- } else if (code === 0x20 || code === 0x09) {
- if (end === -1 && start !== -1) end = i;
- } else if (code === 0x3b || code === 0x2c) {
- if (start === -1) {
- throw new SyntaxError(`Unexpected character at index ${i}`);
- }
-
- if (end === -1) end = i;
- push(params, header.slice(start, end), true);
- if (code === 0x2c) {
- push(offers, extensionName, params);
- params = Object.create(null);
- extensionName = undefined;
- }
-
- start = end = -1;
- } else if (code === 0x3d /* '=' */ && start !== -1 && end === -1) {
- paramName = header.slice(start, i);
- start = end = -1;
- } else {
- throw new SyntaxError(`Unexpected character at index ${i}`);
- }
- } else {
- //
- // The value of a quoted-string after unescaping must conform to the
- // token ABNF, so only token characters are valid.
- // Ref: https://tools.ietf.org/html/rfc6455#section-9.1
- //
- if (isEscaping) {
- if (tokenChars[code] !== 1) {
- throw new SyntaxError(`Unexpected character at index ${i}`);
- }
- if (start === -1) start = i;
- else if (!mustUnescape) mustUnescape = true;
- isEscaping = false;
- } else if (inQuotes) {
- if (tokenChars[code] === 1) {
- if (start === -1) start = i;
- } else if (code === 0x22 /* '"' */ && start !== -1) {
- inQuotes = false;
- end = i;
- } else if (code === 0x5c /* '\' */) {
- isEscaping = true;
- } else {
- throw new SyntaxError(`Unexpected character at index ${i}`);
- }
- } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) {
- inQuotes = true;
- } else if (end === -1 && tokenChars[code] === 1) {
- if (start === -1) start = i;
- } else if (start !== -1 && (code === 0x20 || code === 0x09)) {
- if (end === -1) end = i;
- } else if (code === 0x3b || code === 0x2c) {
- if (start === -1) {
- throw new SyntaxError(`Unexpected character at index ${i}`);
- }
-
- if (end === -1) end = i;
- let value = header.slice(start, end);
- if (mustUnescape) {
- value = value.replace(/\\/g, '');
- mustUnescape = false;
- }
- push(params, paramName, value);
- if (code === 0x2c) {
- push(offers, extensionName, params);
- params = Object.create(null);
- extensionName = undefined;
- }
-
- paramName = undefined;
- start = end = -1;
- } else {
- throw new SyntaxError(`Unexpected character at index ${i}`);
- }
- }
- }
-
- if (start === -1 || inQuotes || code === 0x20 || code === 0x09) {
- throw new SyntaxError('Unexpected end of input');
- }
-
- if (end === -1) end = i;
- const token = header.slice(start, end);
- if (extensionName === undefined) {
- push(offers, token, params);
- } else {
- if (paramName === undefined) {
- push(params, token, true);
- } else if (mustUnescape) {
- push(params, paramName, token.replace(/\\/g, ''));
- } else {
- push(params, paramName, token);
- }
- push(offers, extensionName, params);
- }
-
- return offers;
- }
-
- /**
- * Builds the `Sec-WebSocket-Extensions` header field value.
- *
- * @param {Object} extensions The map of extensions and parameters to format
- * @return {String} A string representing the given object
- * @public
- */
- function format(extensions) {
- return Object.keys(extensions)
- .map((extension) => {
- let configurations = extensions[extension];
- if (!Array.isArray(configurations)) configurations = [configurations];
- return configurations
- .map((params) => {
- return [extension]
- .concat(
- Object.keys(params).map((k) => {
- let values = params[k];
- if (!Array.isArray(values)) values = [values];
- return values
- .map((v) => (v === true ? k : `${k}=${v}`))
- .join('; ');
- })
- )
- .join('; ');
- })
- .join(', ');
- })
- .join(', ');
- }
-
- extension = { format, parse };
- return extension;
-}
-
-/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex|Readable$", "caughtErrors": "none" }] */
-
-var websocket;
-var hasRequiredWebsocket;
-
-function requireWebsocket () {
- if (hasRequiredWebsocket) return websocket;
- hasRequiredWebsocket = 1;
-
- const EventEmitter = require$$0$3;
- const https = require$$1$1;
- const http = require$$2;
- const net = require$$3;
- const tls = require$$4;
- const { randomBytes, createHash } = require$$1;
- const { Duplex, Readable } = require$$0$2;
- const { URL } = require$$7;
-
- const PerMessageDeflate = requirePermessageDeflate();
- const Receiver = requireReceiver();
- const Sender = requireSender();
- const { isBlob } = requireValidation();
-
- const {
- BINARY_TYPES,
- EMPTY_BUFFER,
- GUID,
- kForOnEventAttribute,
- kListener,
- kStatusCode,
- kWebSocket,
- NOOP
- } = requireConstants();
- const {
- EventTarget: { addEventListener, removeEventListener }
- } = requireEventTarget();
- const { format, parse } = requireExtension();
- const { toBuffer } = requireBufferUtil();
-
- const closeTimeout = 30 * 1000;
- const kAborted = Symbol('kAborted');
- const protocolVersions = [8, 13];
- const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
- const subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/;
-
- /**
- * Class representing a WebSocket.
- *
- * @extends EventEmitter
- */
- class WebSocket extends EventEmitter {
- /**
- * Create a new `WebSocket`.
- *
- * @param {(String|URL)} address The URL to which to connect
- * @param {(String|String[])} [protocols] The subprotocols
- * @param {Object} [options] Connection options
- */
- constructor(address, protocols, options) {
- super();
-
- this._binaryType = BINARY_TYPES[0];
- this._closeCode = 1006;
- this._closeFrameReceived = false;
- this._closeFrameSent = false;
- this._closeMessage = EMPTY_BUFFER;
- this._closeTimer = null;
- this._errorEmitted = false;
- this._extensions = {};
- this._paused = false;
- this._protocol = '';
- this._readyState = WebSocket.CONNECTING;
- this._receiver = null;
- this._sender = null;
- this._socket = null;
-
- if (address !== null) {
- this._bufferedAmount = 0;
- this._isServer = false;
- this._redirects = 0;
-
- if (protocols === undefined) {
- protocols = [];
- } else if (!Array.isArray(protocols)) {
- if (typeof protocols === 'object' && protocols !== null) {
- options = protocols;
- protocols = [];
- } else {
- protocols = [protocols];
- }
- }
-
- initAsClient(this, address, protocols, options);
- } else {
- this._autoPong = options.autoPong;
- this._isServer = true;
- }
- }
-
- /**
- * For historical reasons, the custom "nodebuffer" type is used by the default
- * instead of "blob".
- *
- * @type {String}
- */
- get binaryType() {
- return this._binaryType;
- }
-
- set binaryType(type) {
- if (!BINARY_TYPES.includes(type)) return;
-
- this._binaryType = type;
-
- //
- // Allow to change `binaryType` on the fly.
- //
- if (this._receiver) this._receiver._binaryType = type;
- }
-
- /**
- * @type {Number}
- */
- get bufferedAmount() {
- if (!this._socket) return this._bufferedAmount;
-
- return this._socket._writableState.length + this._sender._bufferedBytes;
- }
-
- /**
- * @type {String}
- */
- get extensions() {
- return Object.keys(this._extensions).join();
- }
-
- /**
- * @type {Boolean}
- */
- get isPaused() {
- return this._paused;
- }
-
- /**
- * @type {Function}
- */
- /* istanbul ignore next */
- get onclose() {
- return null;
- }
-
- /**
- * @type {Function}
- */
- /* istanbul ignore next */
- get onerror() {
- return null;
- }
-
- /**
- * @type {Function}
- */
- /* istanbul ignore next */
- get onopen() {
- return null;
- }
-
- /**
- * @type {Function}
- */
- /* istanbul ignore next */
- get onmessage() {
- return null;
- }
-
- /**
- * @type {String}
- */
- get protocol() {
- return this._protocol;
- }
-
- /**
- * @type {Number}
- */
- get readyState() {
- return this._readyState;
- }
-
- /**
- * @type {String}
- */
- get url() {
- return this._url;
- }
-
- /**
- * Set up the socket and the internal resources.
- *
- * @param {Duplex} socket The network socket between the server and client
- * @param {Buffer} head The first packet of the upgraded stream
- * @param {Object} options Options object
- * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether
- * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
- * multiple times in the same tick
- * @param {Function} [options.generateMask] The function used to generate the
- * masking key
- * @param {Number} [options.maxPayload=0] The maximum allowed message size
- * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
- * not to skip UTF-8 validation for text and close messages
- * @private
- */
- setSocket(socket, head, options) {
- const receiver = new Receiver({
- allowSynchronousEvents: options.allowSynchronousEvents,
- binaryType: this.binaryType,
- extensions: this._extensions,
- isServer: this._isServer,
- maxPayload: options.maxPayload,
- skipUTF8Validation: options.skipUTF8Validation
- });
-
- const sender = new Sender(socket, this._extensions, options.generateMask);
-
- this._receiver = receiver;
- this._sender = sender;
- this._socket = socket;
-
- receiver[kWebSocket] = this;
- sender[kWebSocket] = this;
- socket[kWebSocket] = this;
-
- receiver.on('conclude', receiverOnConclude);
- receiver.on('drain', receiverOnDrain);
- receiver.on('error', receiverOnError);
- receiver.on('message', receiverOnMessage);
- receiver.on('ping', receiverOnPing);
- receiver.on('pong', receiverOnPong);
-
- sender.onerror = senderOnError;
-
- //
- // These methods may not be available if `socket` is just a `Duplex`.
- //
- if (socket.setTimeout) socket.setTimeout(0);
- if (socket.setNoDelay) socket.setNoDelay();
-
- if (head.length > 0) socket.unshift(head);
-
- socket.on('close', socketOnClose);
- socket.on('data', socketOnData);
- socket.on('end', socketOnEnd);
- socket.on('error', socketOnError);
-
- this._readyState = WebSocket.OPEN;
- this.emit('open');
- }
-
- /**
- * Emit the `'close'` event.
- *
- * @private
- */
- emitClose() {
- if (!this._socket) {
- this._readyState = WebSocket.CLOSED;
- this.emit('close', this._closeCode, this._closeMessage);
- return;
- }
-
- if (this._extensions[PerMessageDeflate.extensionName]) {
- this._extensions[PerMessageDeflate.extensionName].cleanup();
- }
-
- this._receiver.removeAllListeners();
- this._readyState = WebSocket.CLOSED;
- this.emit('close', this._closeCode, this._closeMessage);
- }
-
- /**
- * Start a closing handshake.
- *
- * +----------+ +-----------+ +----------+
- * - - -|ws.close()|-->|close frame|-->|ws.close()|- - -
- * | +----------+ +-----------+ +----------+ |
- * +----------+ +-----------+ |
- * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING
- * +----------+ +-----------+ |
- * | | | +---+ |
- * +------------------------+-->|fin| - - - -
- * | +---+ | +---+
- * - - - - -|fin|<---------------------+
- * +---+
- *
- * @param {Number} [code] Status code explaining why the connection is closing
- * @param {(String|Buffer)} [data] The reason why the connection is
- * closing
- * @public
- */
- close(code, data) {
- if (this.readyState === WebSocket.CLOSED) return;
- if (this.readyState === WebSocket.CONNECTING) {
- const msg = 'WebSocket was closed before the connection was established';
- abortHandshake(this, this._req, msg);
- return;
- }
-
- if (this.readyState === WebSocket.CLOSING) {
- if (
- this._closeFrameSent &&
- (this._closeFrameReceived || this._receiver._writableState.errorEmitted)
- ) {
- this._socket.end();
- }
-
- return;
- }
-
- this._readyState = WebSocket.CLOSING;
- this._sender.close(code, data, !this._isServer, (err) => {
- //
- // This error is handled by the `'error'` listener on the socket. We only
- // want to know if the close frame has been sent here.
- //
- if (err) return;
-
- this._closeFrameSent = true;
-
- if (
- this._closeFrameReceived ||
- this._receiver._writableState.errorEmitted
- ) {
- this._socket.end();
- }
- });
-
- setCloseTimer(this);
- }
-
- /**
- * Pause the socket.
- *
- * @public
- */
- pause() {
- if (
- this.readyState === WebSocket.CONNECTING ||
- this.readyState === WebSocket.CLOSED
- ) {
- return;
- }
-
- this._paused = true;
- this._socket.pause();
- }
-
- /**
- * Send a ping.
- *
- * @param {*} [data] The data to send
- * @param {Boolean} [mask] Indicates whether or not to mask `data`
- * @param {Function} [cb] Callback which is executed when the ping is sent
- * @public
- */
- ping(data, mask, cb) {
- if (this.readyState === WebSocket.CONNECTING) {
- throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
- }
-
- if (typeof data === 'function') {
- cb = data;
- data = mask = undefined;
- } else if (typeof mask === 'function') {
- cb = mask;
- mask = undefined;
- }
-
- if (typeof data === 'number') data = data.toString();
-
- if (this.readyState !== WebSocket.OPEN) {
- sendAfterClose(this, data, cb);
- return;
- }
-
- if (mask === undefined) mask = !this._isServer;
- this._sender.ping(data || EMPTY_BUFFER, mask, cb);
- }
-
- /**
- * Send a pong.
- *
- * @param {*} [data] The data to send
- * @param {Boolean} [mask] Indicates whether or not to mask `data`
- * @param {Function} [cb] Callback which is executed when the pong is sent
- * @public
- */
- pong(data, mask, cb) {
- if (this.readyState === WebSocket.CONNECTING) {
- throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
- }
-
- if (typeof data === 'function') {
- cb = data;
- data = mask = undefined;
- } else if (typeof mask === 'function') {
- cb = mask;
- mask = undefined;
- }
-
- if (typeof data === 'number') data = data.toString();
-
- if (this.readyState !== WebSocket.OPEN) {
- sendAfterClose(this, data, cb);
- return;
- }
-
- if (mask === undefined) mask = !this._isServer;
- this._sender.pong(data || EMPTY_BUFFER, mask, cb);
- }
-
- /**
- * Resume the socket.
- *
- * @public
- */
- resume() {
- if (
- this.readyState === WebSocket.CONNECTING ||
- this.readyState === WebSocket.CLOSED
- ) {
- return;
- }
-
- this._paused = false;
- if (!this._receiver._writableState.needDrain) this._socket.resume();
- }
-
- /**
- * Send a data message.
- *
- * @param {*} data The message to send
- * @param {Object} [options] Options object
- * @param {Boolean} [options.binary] Specifies whether `data` is binary or
- * text
- * @param {Boolean} [options.compress] Specifies whether or not to compress
- * `data`
- * @param {Boolean} [options.fin=true] Specifies whether the fragment is the
- * last one
- * @param {Boolean} [options.mask] Specifies whether or not to mask `data`
- * @param {Function} [cb] Callback which is executed when data is written out
- * @public
- */
- send(data, options, cb) {
- if (this.readyState === WebSocket.CONNECTING) {
- throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
- }
-
- if (typeof options === 'function') {
- cb = options;
- options = {};
- }
-
- if (typeof data === 'number') data = data.toString();
-
- if (this.readyState !== WebSocket.OPEN) {
- sendAfterClose(this, data, cb);
- return;
- }
-
- const opts = {
- binary: typeof data !== 'string',
- mask: !this._isServer,
- compress: true,
- fin: true,
- ...options
- };
-
- if (!this._extensions[PerMessageDeflate.extensionName]) {
- opts.compress = false;
- }
-
- this._sender.send(data || EMPTY_BUFFER, opts, cb);
- }
-
- /**
- * Forcibly close the connection.
- *
- * @public
- */
- terminate() {
- if (this.readyState === WebSocket.CLOSED) return;
- if (this.readyState === WebSocket.CONNECTING) {
- const msg = 'WebSocket was closed before the connection was established';
- abortHandshake(this, this._req, msg);
- return;
- }
-
- if (this._socket) {
- this._readyState = WebSocket.CLOSING;
- this._socket.destroy();
- }
- }
- }
-
- /**
- * @constant {Number} CONNECTING
- * @memberof WebSocket
- */
- Object.defineProperty(WebSocket, 'CONNECTING', {
- enumerable: true,
- value: readyStates.indexOf('CONNECTING')
- });
-
- /**
- * @constant {Number} CONNECTING
- * @memberof WebSocket.prototype
- */
- Object.defineProperty(WebSocket.prototype, 'CONNECTING', {
- enumerable: true,
- value: readyStates.indexOf('CONNECTING')
- });
-
- /**
- * @constant {Number} OPEN
- * @memberof WebSocket
- */
- Object.defineProperty(WebSocket, 'OPEN', {
- enumerable: true,
- value: readyStates.indexOf('OPEN')
- });
-
- /**
- * @constant {Number} OPEN
- * @memberof WebSocket.prototype
- */
- Object.defineProperty(WebSocket.prototype, 'OPEN', {
- enumerable: true,
- value: readyStates.indexOf('OPEN')
- });
-
- /**
- * @constant {Number} CLOSING
- * @memberof WebSocket
- */
- Object.defineProperty(WebSocket, 'CLOSING', {
- enumerable: true,
- value: readyStates.indexOf('CLOSING')
- });
-
- /**
- * @constant {Number} CLOSING
- * @memberof WebSocket.prototype
- */
- Object.defineProperty(WebSocket.prototype, 'CLOSING', {
- enumerable: true,
- value: readyStates.indexOf('CLOSING')
- });
-
- /**
- * @constant {Number} CLOSED
- * @memberof WebSocket
- */
- Object.defineProperty(WebSocket, 'CLOSED', {
- enumerable: true,
- value: readyStates.indexOf('CLOSED')
- });
-
- /**
- * @constant {Number} CLOSED
- * @memberof WebSocket.prototype
- */
- Object.defineProperty(WebSocket.prototype, 'CLOSED', {
- enumerable: true,
- value: readyStates.indexOf('CLOSED')
- });
-
- [
- 'binaryType',
- 'bufferedAmount',
- 'extensions',
- 'isPaused',
- 'protocol',
- 'readyState',
- 'url'
- ].forEach((property) => {
- Object.defineProperty(WebSocket.prototype, property, { enumerable: true });
- });
-
- //
- // Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes.
- // See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface
- //
- ['open', 'error', 'close', 'message'].forEach((method) => {
- Object.defineProperty(WebSocket.prototype, `on${method}`, {
- enumerable: true,
- get() {
- for (const listener of this.listeners(method)) {
- if (listener[kForOnEventAttribute]) return listener[kListener];
- }
-
- return null;
- },
- set(handler) {
- for (const listener of this.listeners(method)) {
- if (listener[kForOnEventAttribute]) {
- this.removeListener(method, listener);
- break;
- }
- }
-
- if (typeof handler !== 'function') return;
-
- this.addEventListener(method, handler, {
- [kForOnEventAttribute]: true
- });
- }
- });
- });
-
- WebSocket.prototype.addEventListener = addEventListener;
- WebSocket.prototype.removeEventListener = removeEventListener;
-
- websocket = WebSocket;
-
- /**
- * Initialize a WebSocket client.
- *
- * @param {WebSocket} websocket The client to initialize
- * @param {(String|URL)} address The URL to which to connect
- * @param {Array} protocols The subprotocols
- * @param {Object} [options] Connection options
- * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether any
- * of the `'message'`, `'ping'`, and `'pong'` events can be emitted multiple
- * times in the same tick
- * @param {Boolean} [options.autoPong=true] Specifies whether or not to
- * automatically send a pong in response to a ping
- * @param {Function} [options.finishRequest] A function which can be used to
- * customize the headers of each http request before it is sent
- * @param {Boolean} [options.followRedirects=false] Whether or not to follow
- * redirects
- * @param {Function} [options.generateMask] The function used to generate the
- * masking key
- * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the
- * handshake request
- * @param {Number} [options.maxPayload=104857600] The maximum allowed message
- * size
- * @param {Number} [options.maxRedirects=10] The maximum number of redirects
- * allowed
- * @param {String} [options.origin] Value of the `Origin` or
- * `Sec-WebSocket-Origin` header
- * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable
- * permessage-deflate
- * @param {Number} [options.protocolVersion=13] Value of the
- * `Sec-WebSocket-Version` header
- * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
- * not to skip UTF-8 validation for text and close messages
- * @private
- */
- function initAsClient(websocket, address, protocols, options) {
- const opts = {
- allowSynchronousEvents: true,
- autoPong: true,
- protocolVersion: protocolVersions[1],
- maxPayload: 100 * 1024 * 1024,
- skipUTF8Validation: false,
- perMessageDeflate: true,
- followRedirects: false,
- maxRedirects: 10,
- ...options,
- socketPath: undefined,
- hostname: undefined,
- protocol: undefined,
- timeout: undefined,
- method: 'GET',
- host: undefined,
- path: undefined,
- port: undefined
- };
-
- websocket._autoPong = opts.autoPong;
-
- if (!protocolVersions.includes(opts.protocolVersion)) {
- throw new RangeError(
- `Unsupported protocol version: ${opts.protocolVersion} ` +
- `(supported versions: ${protocolVersions.join(', ')})`
- );
- }
-
- let parsedUrl;
-
- if (address instanceof URL) {
- parsedUrl = address;
- } else {
- try {
- parsedUrl = new URL(address);
- } catch (e) {
- throw new SyntaxError(`Invalid URL: ${address}`);
- }
- }
-
- if (parsedUrl.protocol === 'http:') {
- parsedUrl.protocol = 'ws:';
- } else if (parsedUrl.protocol === 'https:') {
- parsedUrl.protocol = 'wss:';
- }
-
- websocket._url = parsedUrl.href;
-
- const isSecure = parsedUrl.protocol === 'wss:';
- const isIpcUrl = parsedUrl.protocol === 'ws+unix:';
- let invalidUrlMessage;
-
- if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) {
- invalidUrlMessage =
- 'The URL\'s protocol must be one of "ws:", "wss:", ' +
- '"http:", "https:", or "ws+unix:"';
- } else if (isIpcUrl && !parsedUrl.pathname) {
- invalidUrlMessage = "The URL's pathname is empty";
- } else if (parsedUrl.hash) {
- invalidUrlMessage = 'The URL contains a fragment identifier';
- }
-
- if (invalidUrlMessage) {
- const err = new SyntaxError(invalidUrlMessage);
-
- if (websocket._redirects === 0) {
- throw err;
- } else {
- emitErrorAndClose(websocket, err);
- return;
- }
- }
-
- const defaultPort = isSecure ? 443 : 80;
- const key = randomBytes(16).toString('base64');
- const request = isSecure ? https.request : http.request;
- const protocolSet = new Set();
- let perMessageDeflate;
-
- opts.createConnection =
- opts.createConnection || (isSecure ? tlsConnect : netConnect);
- opts.defaultPort = opts.defaultPort || defaultPort;
- opts.port = parsedUrl.port || defaultPort;
- opts.host = parsedUrl.hostname.startsWith('[')
- ? parsedUrl.hostname.slice(1, -1)
- : parsedUrl.hostname;
- opts.headers = {
- ...opts.headers,
- 'Sec-WebSocket-Version': opts.protocolVersion,
- 'Sec-WebSocket-Key': key,
- Connection: 'Upgrade',
- Upgrade: 'websocket'
- };
- opts.path = parsedUrl.pathname + parsedUrl.search;
- opts.timeout = opts.handshakeTimeout;
-
- if (opts.perMessageDeflate) {
- perMessageDeflate = new PerMessageDeflate(
- opts.perMessageDeflate !== true ? opts.perMessageDeflate : {},
- false,
- opts.maxPayload
- );
- opts.headers['Sec-WebSocket-Extensions'] = format({
- [PerMessageDeflate.extensionName]: perMessageDeflate.offer()
- });
- }
- if (protocols.length) {
- for (const protocol of protocols) {
- if (
- typeof protocol !== 'string' ||
- !subprotocolRegex.test(protocol) ||
- protocolSet.has(protocol)
- ) {
- throw new SyntaxError(
- 'An invalid or duplicated subprotocol was specified'
- );
- }
-
- protocolSet.add(protocol);
- }
-
- opts.headers['Sec-WebSocket-Protocol'] = protocols.join(',');
- }
- if (opts.origin) {
- if (opts.protocolVersion < 13) {
- opts.headers['Sec-WebSocket-Origin'] = opts.origin;
- } else {
- opts.headers.Origin = opts.origin;
- }
- }
- if (parsedUrl.username || parsedUrl.password) {
- opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;
- }
-
- if (isIpcUrl) {
- const parts = opts.path.split(':');
-
- opts.socketPath = parts[0];
- opts.path = parts[1];
- }
-
- let req;
-
- if (opts.followRedirects) {
- if (websocket._redirects === 0) {
- websocket._originalIpc = isIpcUrl;
- websocket._originalSecure = isSecure;
- websocket._originalHostOrSocketPath = isIpcUrl
- ? opts.socketPath
- : parsedUrl.host;
-
- const headers = options && options.headers;
-
- //
- // Shallow copy the user provided options so that headers can be changed
- // without mutating the original object.
- //
- options = { ...options, headers: {} };
-
- if (headers) {
- for (const [key, value] of Object.entries(headers)) {
- options.headers[key.toLowerCase()] = value;
- }
- }
- } else if (websocket.listenerCount('redirect') === 0) {
- const isSameHost = isIpcUrl
- ? websocket._originalIpc
- ? opts.socketPath === websocket._originalHostOrSocketPath
- : false
- : websocket._originalIpc
- ? false
- : parsedUrl.host === websocket._originalHostOrSocketPath;
-
- if (!isSameHost || (websocket._originalSecure && !isSecure)) {
- //
- // Match curl 7.77.0 behavior and drop the following headers. These
- // headers are also dropped when following a redirect to a subdomain.
- //
- delete opts.headers.authorization;
- delete opts.headers.cookie;
-
- if (!isSameHost) delete opts.headers.host;
-
- opts.auth = undefined;
- }
- }
-
- //
- // Match curl 7.77.0 behavior and make the first `Authorization` header win.
- // If the `Authorization` header is set, then there is nothing to do as it
- // will take precedence.
- //
- if (opts.auth && !options.headers.authorization) {
- options.headers.authorization =
- 'Basic ' + Buffer.from(opts.auth).toString('base64');
- }
-
- req = websocket._req = request(opts);
-
- if (websocket._redirects) {
- //
- // Unlike what is done for the `'upgrade'` event, no early exit is
- // triggered here if the user calls `websocket.close()` or
- // `websocket.terminate()` from a listener of the `'redirect'` event. This
- // is because the user can also call `request.destroy()` with an error
- // before calling `websocket.close()` or `websocket.terminate()` and this
- // would result in an error being emitted on the `request` object with no
- // `'error'` event listeners attached.
- //
- websocket.emit('redirect', websocket.url, req);
- }
- } else {
- req = websocket._req = request(opts);
- }
-
- if (opts.timeout) {
- req.on('timeout', () => {
- abortHandshake(websocket, req, 'Opening handshake has timed out');
- });
- }
-
- req.on('error', (err) => {
- if (req === null || req[kAborted]) return;
-
- req = websocket._req = null;
- emitErrorAndClose(websocket, err);
- });
-
- req.on('response', (res) => {
- const location = res.headers.location;
- const statusCode = res.statusCode;
-
- if (
- location &&
- opts.followRedirects &&
- statusCode >= 300 &&
- statusCode < 400
- ) {
- if (++websocket._redirects > opts.maxRedirects) {
- abortHandshake(websocket, req, 'Maximum redirects exceeded');
- return;
- }
-
- req.abort();
-
- let addr;
-
- try {
- addr = new URL(location, address);
- } catch (e) {
- const err = new SyntaxError(`Invalid URL: ${location}`);
- emitErrorAndClose(websocket, err);
- return;
- }
-
- initAsClient(websocket, addr, protocols, options);
- } else if (!websocket.emit('unexpected-response', req, res)) {
- abortHandshake(
- websocket,
- req,
- `Unexpected server response: ${res.statusCode}`
- );
- }
- });
-
- req.on('upgrade', (res, socket, head) => {
- websocket.emit('upgrade', res);
-
- //
- // The user may have closed the connection from a listener of the
- // `'upgrade'` event.
- //
- if (websocket.readyState !== WebSocket.CONNECTING) return;
-
- req = websocket._req = null;
-
- const upgrade = res.headers.upgrade;
-
- if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {
- abortHandshake(websocket, socket, 'Invalid Upgrade header');
- return;
- }
-
- const digest = createHash('sha1')
- .update(key + GUID)
- .digest('base64');
-
- if (res.headers['sec-websocket-accept'] !== digest) {
- abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header');
- return;
- }
-
- const serverProt = res.headers['sec-websocket-protocol'];
- let protError;
-
- if (serverProt !== undefined) {
- if (!protocolSet.size) {
- protError = 'Server sent a subprotocol but none was requested';
- } else if (!protocolSet.has(serverProt)) {
- protError = 'Server sent an invalid subprotocol';
- }
- } else if (protocolSet.size) {
- protError = 'Server sent no subprotocol';
- }
-
- if (protError) {
- abortHandshake(websocket, socket, protError);
- return;
- }
-
- if (serverProt) websocket._protocol = serverProt;
-
- const secWebSocketExtensions = res.headers['sec-websocket-extensions'];
-
- if (secWebSocketExtensions !== undefined) {
- if (!perMessageDeflate) {
- const message =
- 'Server sent a Sec-WebSocket-Extensions header but no extension ' +
- 'was requested';
- abortHandshake(websocket, socket, message);
- return;
- }
-
- let extensions;
-
- try {
- extensions = parse(secWebSocketExtensions);
- } catch (err) {
- const message = 'Invalid Sec-WebSocket-Extensions header';
- abortHandshake(websocket, socket, message);
- return;
- }
-
- const extensionNames = Object.keys(extensions);
-
- if (
- extensionNames.length !== 1 ||
- extensionNames[0] !== PerMessageDeflate.extensionName
- ) {
- const message = 'Server indicated an extension that was not requested';
- abortHandshake(websocket, socket, message);
- return;
- }
-
- try {
- perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]);
- } catch (err) {
- const message = 'Invalid Sec-WebSocket-Extensions header';
- abortHandshake(websocket, socket, message);
- return;
- }
-
- websocket._extensions[PerMessageDeflate.extensionName] =
- perMessageDeflate;
- }
-
- websocket.setSocket(socket, head, {
- allowSynchronousEvents: opts.allowSynchronousEvents,
- generateMask: opts.generateMask,
- maxPayload: opts.maxPayload,
- skipUTF8Validation: opts.skipUTF8Validation
- });
- });
-
- if (opts.finishRequest) {
- opts.finishRequest(req, websocket);
- } else {
- req.end();
- }
- }
-
- /**
- * Emit the `'error'` and `'close'` events.
- *
- * @param {WebSocket} websocket The WebSocket instance
- * @param {Error} The error to emit
- * @private
- */
- function emitErrorAndClose(websocket, err) {
- websocket._readyState = WebSocket.CLOSING;
- //
- // The following assignment is practically useless and is done only for
- // consistency.
- //
- websocket._errorEmitted = true;
- websocket.emit('error', err);
- websocket.emitClose();
- }
-
- /**
- * Create a `net.Socket` and initiate a connection.
- *
- * @param {Object} options Connection options
- * @return {net.Socket} The newly created socket used to start the connection
- * @private
- */
- function netConnect(options) {
- options.path = options.socketPath;
- return net.connect(options);
- }
-
- /**
- * Create a `tls.TLSSocket` and initiate a connection.
- *
- * @param {Object} options Connection options
- * @return {tls.TLSSocket} The newly created socket used to start the connection
- * @private
- */
- function tlsConnect(options) {
- options.path = undefined;
-
- if (!options.servername && options.servername !== '') {
- options.servername = net.isIP(options.host) ? '' : options.host;
- }
-
- return tls.connect(options);
- }
-
- /**
- * Abort the handshake and emit an error.
- *
- * @param {WebSocket} websocket The WebSocket instance
- * @param {(http.ClientRequest|net.Socket|tls.Socket)} stream The request to
- * abort or the socket to destroy
- * @param {String} message The error message
- * @private
- */
- function abortHandshake(websocket, stream, message) {
- websocket._readyState = WebSocket.CLOSING;
-
- const err = new Error(message);
- Error.captureStackTrace(err, abortHandshake);
-
- if (stream.setHeader) {
- stream[kAborted] = true;
- stream.abort();
-
- if (stream.socket && !stream.socket.destroyed) {
- //
- // On Node.js >= 14.3.0 `request.abort()` does not destroy the socket if
- // called after the request completed. See
- // https://github.com/websockets/ws/issues/1869.
- //
- stream.socket.destroy();
- }
-
- process.nextTick(emitErrorAndClose, websocket, err);
- } else {
- stream.destroy(err);
- stream.once('error', websocket.emit.bind(websocket, 'error'));
- stream.once('close', websocket.emitClose.bind(websocket));
- }
- }
-
- /**
- * Handle cases where the `ping()`, `pong()`, or `send()` methods are called
- * when the `readyState` attribute is `CLOSING` or `CLOSED`.
- *
- * @param {WebSocket} websocket The WebSocket instance
- * @param {*} [data] The data to send
- * @param {Function} [cb] Callback
- * @private
- */
- function sendAfterClose(websocket, data, cb) {
- if (data) {
- const length = isBlob(data) ? data.size : toBuffer(data).length;
-
- //
- // The `_bufferedAmount` property is used only when the peer is a client and
- // the opening handshake fails. Under these circumstances, in fact, the
- // `setSocket()` method is not called, so the `_socket` and `_sender`
- // properties are set to `null`.
- //
- if (websocket._socket) websocket._sender._bufferedBytes += length;
- else websocket._bufferedAmount += length;
- }
-
- if (cb) {
- const err = new Error(
- `WebSocket is not open: readyState ${websocket.readyState} ` +
- `(${readyStates[websocket.readyState]})`
- );
- process.nextTick(cb, err);
- }
- }
-
- /**
- * The listener of the `Receiver` `'conclude'` event.
- *
- * @param {Number} code The status code
- * @param {Buffer} reason The reason for closing
- * @private
- */
- function receiverOnConclude(code, reason) {
- const websocket = this[kWebSocket];
-
- websocket._closeFrameReceived = true;
- websocket._closeMessage = reason;
- websocket._closeCode = code;
-
- if (websocket._socket[kWebSocket] === undefined) return;
-
- websocket._socket.removeListener('data', socketOnData);
- process.nextTick(resume, websocket._socket);
-
- if (code === 1005) websocket.close();
- else websocket.close(code, reason);
- }
-
- /**
- * The listener of the `Receiver` `'drain'` event.
- *
- * @private
- */
- function receiverOnDrain() {
- const websocket = this[kWebSocket];
-
- if (!websocket.isPaused) websocket._socket.resume();
- }
-
- /**
- * The listener of the `Receiver` `'error'` event.
- *
- * @param {(RangeError|Error)} err The emitted error
- * @private
- */
- function receiverOnError(err) {
- const websocket = this[kWebSocket];
-
- if (websocket._socket[kWebSocket] !== undefined) {
- websocket._socket.removeListener('data', socketOnData);
-
- //
- // On Node.js < 14.0.0 the `'error'` event is emitted synchronously. See
- // https://github.com/websockets/ws/issues/1940.
- //
- process.nextTick(resume, websocket._socket);
-
- websocket.close(err[kStatusCode]);
- }
-
- if (!websocket._errorEmitted) {
- websocket._errorEmitted = true;
- websocket.emit('error', err);
- }
- }
-
- /**
- * The listener of the `Receiver` `'finish'` event.
- *
- * @private
- */
- function receiverOnFinish() {
- this[kWebSocket].emitClose();
- }
-
- /**
- * The listener of the `Receiver` `'message'` event.
- *
- * @param {Buffer|ArrayBuffer|Buffer[])} data The message
- * @param {Boolean} isBinary Specifies whether the message is binary or not
- * @private
- */
- function receiverOnMessage(data, isBinary) {
- this[kWebSocket].emit('message', data, isBinary);
- }
-
- /**
- * The listener of the `Receiver` `'ping'` event.
- *
- * @param {Buffer} data The data included in the ping frame
- * @private
- */
- function receiverOnPing(data) {
- const websocket = this[kWebSocket];
-
- if (websocket._autoPong) websocket.pong(data, !this._isServer, NOOP);
- websocket.emit('ping', data);
- }
-
- /**
- * The listener of the `Receiver` `'pong'` event.
- *
- * @param {Buffer} data The data included in the pong frame
- * @private
- */
- function receiverOnPong(data) {
- this[kWebSocket].emit('pong', data);
- }
-
- /**
- * Resume a readable stream
- *
- * @param {Readable} stream The readable stream
- * @private
- */
- function resume(stream) {
- stream.resume();
- }
-
- /**
- * The `Sender` error event handler.
- *
- * @param {Error} The error
- * @private
- */
- function senderOnError(err) {
- const websocket = this[kWebSocket];
-
- if (websocket.readyState === WebSocket.CLOSED) return;
- if (websocket.readyState === WebSocket.OPEN) {
- websocket._readyState = WebSocket.CLOSING;
- setCloseTimer(websocket);
- }
-
- //
- // `socket.end()` is used instead of `socket.destroy()` to allow the other
- // peer to finish sending queued data. There is no need to set a timer here
- // because `CLOSING` means that it is already set or not needed.
- //
- this._socket.end();
-
- if (!websocket._errorEmitted) {
- websocket._errorEmitted = true;
- websocket.emit('error', err);
- }
- }
-
- /**
- * Set a timer to destroy the underlying raw socket of a WebSocket.
- *
- * @param {WebSocket} websocket The WebSocket instance
- * @private
- */
- function setCloseTimer(websocket) {
- websocket._closeTimer = setTimeout(
- websocket._socket.destroy.bind(websocket._socket),
- closeTimeout
- );
- }
-
- /**
- * The listener of the socket `'close'` event.
- *
- * @private
- */
- function socketOnClose() {
- const websocket = this[kWebSocket];
-
- this.removeListener('close', socketOnClose);
- this.removeListener('data', socketOnData);
- this.removeListener('end', socketOnEnd);
-
- websocket._readyState = WebSocket.CLOSING;
-
- let chunk;
-
- //
- // The close frame might not have been received or the `'end'` event emitted,
- // for example, if the socket was destroyed due to an error. Ensure that the
- // `receiver` stream is closed after writing any remaining buffered data to
- // it. If the readable side of the socket is in flowing mode then there is no
- // buffered data as everything has been already written and `readable.read()`
- // will return `null`. If instead, the socket is paused, any possible buffered
- // data will be read as a single chunk.
- //
- if (
- !this._readableState.endEmitted &&
- !websocket._closeFrameReceived &&
- !websocket._receiver._writableState.errorEmitted &&
- (chunk = websocket._socket.read()) !== null
- ) {
- websocket._receiver.write(chunk);
- }
-
- websocket._receiver.end();
-
- this[kWebSocket] = undefined;
-
- clearTimeout(websocket._closeTimer);
-
- if (
- websocket._receiver._writableState.finished ||
- websocket._receiver._writableState.errorEmitted
- ) {
- websocket.emitClose();
- } else {
- websocket._receiver.on('error', receiverOnFinish);
- websocket._receiver.on('finish', receiverOnFinish);
- }
- }
-
- /**
- * The listener of the socket `'data'` event.
- *
- * @param {Buffer} chunk A chunk of data
- * @private
- */
- function socketOnData(chunk) {
- if (!this[kWebSocket]._receiver.write(chunk)) {
- this.pause();
- }
- }
-
- /**
- * The listener of the socket `'end'` event.
- *
- * @private
- */
- function socketOnEnd() {
- const websocket = this[kWebSocket];
-
- websocket._readyState = WebSocket.CLOSING;
- websocket._receiver.end();
- this.end();
- }
-
- /**
- * The listener of the socket `'error'` event.
- *
- * @private
- */
- function socketOnError() {
- const websocket = this[kWebSocket];
-
- this.removeListener('error', socketOnError);
- this.on('error', NOOP);
-
- if (websocket) {
- websocket._readyState = WebSocket.CLOSING;
- this.destroy();
- }
- }
- return websocket;
-}
-
-/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^WebSocket$" }] */
-
-var stream;
-var hasRequiredStream;
-
-function requireStream () {
- if (hasRequiredStream) return stream;
- hasRequiredStream = 1;
-
- requireWebsocket();
- const { Duplex } = require$$0$2;
-
- /**
- * Emits the `'close'` event on a stream.
- *
- * @param {Duplex} stream The stream.
- * @private
- */
- function emitClose(stream) {
- stream.emit('close');
- }
-
- /**
- * The listener of the `'end'` event.
- *
- * @private
- */
- function duplexOnEnd() {
- if (!this.destroyed && this._writableState.finished) {
- this.destroy();
- }
- }
-
- /**
- * The listener of the `'error'` event.
- *
- * @param {Error} err The error
- * @private
- */
- function duplexOnError(err) {
- this.removeListener('error', duplexOnError);
- this.destroy();
- if (this.listenerCount('error') === 0) {
- // Do not suppress the throwing behavior.
- this.emit('error', err);
- }
- }
-
- /**
- * Wraps a `WebSocket` in a duplex stream.
- *
- * @param {WebSocket} ws The `WebSocket` to wrap
- * @param {Object} [options] The options for the `Duplex` constructor
- * @return {Duplex} The duplex stream
- * @public
- */
- function createWebSocketStream(ws, options) {
- let terminateOnDestroy = true;
-
- const duplex = new Duplex({
- ...options,
- autoDestroy: false,
- emitClose: false,
- objectMode: false,
- writableObjectMode: false
- });
-
- ws.on('message', function message(msg, isBinary) {
- const data =
- !isBinary && duplex._readableState.objectMode ? msg.toString() : msg;
-
- if (!duplex.push(data)) ws.pause();
- });
-
- ws.once('error', function error(err) {
- if (duplex.destroyed) return;
-
- // Prevent `ws.terminate()` from being called by `duplex._destroy()`.
- //
- // - If the `'error'` event is emitted before the `'open'` event, then
- // `ws.terminate()` is a noop as no socket is assigned.
- // - Otherwise, the error is re-emitted by the listener of the `'error'`
- // event of the `Receiver` object. The listener already closes the
- // connection by calling `ws.close()`. This allows a close frame to be
- // sent to the other peer. If `ws.terminate()` is called right after this,
- // then the close frame might not be sent.
- terminateOnDestroy = false;
- duplex.destroy(err);
- });
-
- ws.once('close', function close() {
- if (duplex.destroyed) return;
-
- duplex.push(null);
- });
-
- duplex._destroy = function (err, callback) {
- if (ws.readyState === ws.CLOSED) {
- callback(err);
- process.nextTick(emitClose, duplex);
- return;
- }
-
- let called = false;
-
- ws.once('error', function error(err) {
- called = true;
- callback(err);
- });
-
- ws.once('close', function close() {
- if (!called) callback(err);
- process.nextTick(emitClose, duplex);
- });
-
- if (terminateOnDestroy) ws.terminate();
- };
-
- duplex._final = function (callback) {
- if (ws.readyState === ws.CONNECTING) {
- ws.once('open', function open() {
- duplex._final(callback);
- });
- return;
- }
-
- // If the value of the `_socket` property is `null` it means that `ws` is a
- // client websocket and the handshake failed. In fact, when this happens, a
- // socket is never assigned to the websocket. Wait for the `'error'` event
- // that will be emitted by the websocket.
- if (ws._socket === null) return;
-
- if (ws._socket._writableState.finished) {
- callback();
- if (duplex._readableState.endEmitted) duplex.destroy();
- } else {
- ws._socket.once('finish', function finish() {
- // `duplex` is not destroyed here because the `'end'` event will be
- // emitted on `duplex` after this `'finish'` event. The EOF signaling
- // `null` chunk is, in fact, pushed when the websocket emits `'close'`.
- callback();
- });
- ws.close();
- }
- };
-
- duplex._read = function () {
- if (ws.isPaused) ws.resume();
- };
-
- duplex._write = function (chunk, encoding, callback) {
- if (ws.readyState === ws.CONNECTING) {
- ws.once('open', function open() {
- duplex._write(chunk, encoding, callback);
- });
- return;
- }
-
- ws.send(chunk, callback);
- };
-
- duplex.on('end', duplexOnEnd);
- duplex.on('error', duplexOnError);
- return duplex;
- }
-
- stream = createWebSocketStream;
- return stream;
-}
-
-requireStream();
-
-requireReceiver();
-
-requireSender();
-
-requireWebsocket();
-
-var subprotocol;
-var hasRequiredSubprotocol;
-
-function requireSubprotocol () {
- if (hasRequiredSubprotocol) return subprotocol;
- hasRequiredSubprotocol = 1;
-
- const { tokenChars } = requireValidation();
-
- /**
- * Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names.
- *
- * @param {String} header The field value of the header
- * @return {Set} The subprotocol names
- * @public
- */
- function parse(header) {
- const protocols = new Set();
- let start = -1;
- let end = -1;
- let i = 0;
-
- for (i; i < header.length; i++) {
- const code = header.charCodeAt(i);
-
- if (end === -1 && tokenChars[code] === 1) {
- if (start === -1) start = i;
- } else if (
- i !== 0 &&
- (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */
- ) {
- if (end === -1 && start !== -1) end = i;
- } else if (code === 0x2c /* ',' */) {
- if (start === -1) {
- throw new SyntaxError(`Unexpected character at index ${i}`);
- }
-
- if (end === -1) end = i;
-
- const protocol = header.slice(start, end);
-
- if (protocols.has(protocol)) {
- throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
- }
-
- protocols.add(protocol);
- start = end = -1;
- } else {
- throw new SyntaxError(`Unexpected character at index ${i}`);
- }
- }
-
- if (start === -1 || end !== -1) {
- throw new SyntaxError('Unexpected end of input');
- }
-
- const protocol = header.slice(start, i);
-
- if (protocols.has(protocol)) {
- throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
- }
-
- protocols.add(protocol);
- return protocols;
- }
-
- subprotocol = { parse };
- return subprotocol;
-}
-
-/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex$", "caughtErrors": "none" }] */
-
-var websocketServer;
-var hasRequiredWebsocketServer;
-
-function requireWebsocketServer () {
- if (hasRequiredWebsocketServer) return websocketServer;
- hasRequiredWebsocketServer = 1;
-
- const EventEmitter = require$$0$3;
- const http = require$$2;
- const { Duplex } = require$$0$2;
- const { createHash } = require$$1;
-
- const extension = requireExtension();
- const PerMessageDeflate = requirePermessageDeflate();
- const subprotocol = requireSubprotocol();
- const WebSocket = requireWebsocket();
- const { GUID, kWebSocket } = requireConstants();
-
- const keyRegex = /^[+/0-9A-Za-z]{22}==$/;
-
- const RUNNING = 0;
- const CLOSING = 1;
- const CLOSED = 2;
-
- /**
- * Class representing a WebSocket server.
- *
- * @extends EventEmitter
- */
- class WebSocketServer extends EventEmitter {
- /**
- * Create a `WebSocketServer` instance.
- *
- * @param {Object} options Configuration options
- * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether
- * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
- * multiple times in the same tick
- * @param {Boolean} [options.autoPong=true] Specifies whether or not to
- * automatically send a pong in response to a ping
- * @param {Number} [options.backlog=511] The maximum length of the queue of
- * pending connections
- * @param {Boolean} [options.clientTracking=true] Specifies whether or not to
- * track clients
- * @param {Function} [options.handleProtocols] A hook to handle protocols
- * @param {String} [options.host] The hostname where to bind the server
- * @param {Number} [options.maxPayload=104857600] The maximum allowed message
- * size
- * @param {Boolean} [options.noServer=false] Enable no server mode
- * @param {String} [options.path] Accept only connections matching this path
- * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable
- * permessage-deflate
- * @param {Number} [options.port] The port where to bind the server
- * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S
- * server to use
- * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
- * not to skip UTF-8 validation for text and close messages
- * @param {Function} [options.verifyClient] A hook to reject connections
- * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket`
- * class to use. It must be the `WebSocket` class or class that extends it
- * @param {Function} [callback] A listener for the `listening` event
- */
- constructor(options, callback) {
- super();
-
- options = {
- allowSynchronousEvents: true,
- autoPong: true,
- maxPayload: 100 * 1024 * 1024,
- skipUTF8Validation: false,
- perMessageDeflate: false,
- handleProtocols: null,
- clientTracking: true,
- verifyClient: null,
- noServer: false,
- backlog: null, // use default (511 as implemented in net.js)
- server: null,
- host: null,
- path: null,
- port: null,
- WebSocket,
- ...options
- };
-
- if (
- (options.port == null && !options.server && !options.noServer) ||
- (options.port != null && (options.server || options.noServer)) ||
- (options.server && options.noServer)
- ) {
- throw new TypeError(
- 'One and only one of the "port", "server", or "noServer" options ' +
- 'must be specified'
- );
- }
-
- if (options.port != null) {
- this._server = http.createServer((req, res) => {
- const body = http.STATUS_CODES[426];
-
- res.writeHead(426, {
- 'Content-Length': body.length,
- 'Content-Type': 'text/plain'
- });
- res.end(body);
- });
- this._server.listen(
- options.port,
- options.host,
- options.backlog,
- callback
- );
- } else if (options.server) {
- this._server = options.server;
- }
-
- if (this._server) {
- const emitConnection = this.emit.bind(this, 'connection');
-
- this._removeListeners = addListeners(this._server, {
- listening: this.emit.bind(this, 'listening'),
- error: this.emit.bind(this, 'error'),
- upgrade: (req, socket, head) => {
- this.handleUpgrade(req, socket, head, emitConnection);
- }
- });
- }
-
- if (options.perMessageDeflate === true) options.perMessageDeflate = {};
- if (options.clientTracking) {
- this.clients = new Set();
- this._shouldEmitClose = false;
- }
-
- this.options = options;
- this._state = RUNNING;
- }
-
- /**
- * Returns the bound address, the address family name, and port of the server
- * as reported by the operating system if listening on an IP socket.
- * If the server is listening on a pipe or UNIX domain socket, the name is
- * returned as a string.
- *
- * @return {(Object|String|null)} The address of the server
- * @public
- */
- address() {
- if (this.options.noServer) {
- throw new Error('The server is operating in "noServer" mode');
- }
-
- if (!this._server) return null;
- return this._server.address();
- }
-
- /**
- * Stop the server from accepting new connections and emit the `'close'` event
- * when all existing connections are closed.
- *
- * @param {Function} [cb] A one-time listener for the `'close'` event
- * @public
- */
- close(cb) {
- if (this._state === CLOSED) {
- if (cb) {
- this.once('close', () => {
- cb(new Error('The server is not running'));
- });
- }
-
- process.nextTick(emitClose, this);
- return;
- }
-
- if (cb) this.once('close', cb);
-
- if (this._state === CLOSING) return;
- this._state = CLOSING;
-
- if (this.options.noServer || this.options.server) {
- if (this._server) {
- this._removeListeners();
- this._removeListeners = this._server = null;
- }
-
- if (this.clients) {
- if (!this.clients.size) {
- process.nextTick(emitClose, this);
- } else {
- this._shouldEmitClose = true;
- }
- } else {
- process.nextTick(emitClose, this);
- }
- } else {
- const server = this._server;
-
- this._removeListeners();
- this._removeListeners = this._server = null;
-
- //
- // The HTTP/S server was created internally. Close it, and rely on its
- // `'close'` event.
- //
- server.close(() => {
- emitClose(this);
- });
- }
- }
-
- /**
- * See if a given request should be handled by this server instance.
- *
- * @param {http.IncomingMessage} req Request object to inspect
- * @return {Boolean} `true` if the request is valid, else `false`
- * @public
- */
- shouldHandle(req) {
- if (this.options.path) {
- const index = req.url.indexOf('?');
- const pathname = index !== -1 ? req.url.slice(0, index) : req.url;
-
- if (pathname !== this.options.path) return false;
- }
-
- return true;
- }
-
- /**
- * Handle a HTTP Upgrade request.
- *
- * @param {http.IncomingMessage} req The request object
- * @param {Duplex} socket The network socket between the server and client
- * @param {Buffer} head The first packet of the upgraded stream
- * @param {Function} cb Callback
- * @public
- */
- handleUpgrade(req, socket, head, cb) {
- socket.on('error', socketOnError);
-
- const key = req.headers['sec-websocket-key'];
- const upgrade = req.headers.upgrade;
- const version = +req.headers['sec-websocket-version'];
-
- if (req.method !== 'GET') {
- const message = 'Invalid HTTP method';
- abortHandshakeOrEmitwsClientError(this, req, socket, 405, message);
- return;
- }
-
- if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {
- const message = 'Invalid Upgrade header';
- abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
- return;
- }
-
- if (key === undefined || !keyRegex.test(key)) {
- const message = 'Missing or invalid Sec-WebSocket-Key header';
- abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
- return;
- }
-
- if (version !== 13 && version !== 8) {
- const message = 'Missing or invalid Sec-WebSocket-Version header';
- abortHandshakeOrEmitwsClientError(this, req, socket, 400, message, {
- 'Sec-WebSocket-Version': '13, 8'
- });
- return;
- }
-
- if (!this.shouldHandle(req)) {
- abortHandshake(socket, 400);
- return;
- }
-
- const secWebSocketProtocol = req.headers['sec-websocket-protocol'];
- let protocols = new Set();
-
- if (secWebSocketProtocol !== undefined) {
- try {
- protocols = subprotocol.parse(secWebSocketProtocol);
- } catch (err) {
- const message = 'Invalid Sec-WebSocket-Protocol header';
- abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
- return;
- }
- }
-
- const secWebSocketExtensions = req.headers['sec-websocket-extensions'];
- const extensions = {};
-
- if (
- this.options.perMessageDeflate &&
- secWebSocketExtensions !== undefined
- ) {
- const perMessageDeflate = new PerMessageDeflate(
- this.options.perMessageDeflate,
- true,
- this.options.maxPayload
- );
-
- try {
- const offers = extension.parse(secWebSocketExtensions);
-
- if (offers[PerMessageDeflate.extensionName]) {
- perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);
- extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
- }
- } catch (err) {
- const message =
- 'Invalid or unacceptable Sec-WebSocket-Extensions header';
- abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
- return;
- }
- }
-
- //
- // Optionally call external client verification handler.
- //
- if (this.options.verifyClient) {
- const info = {
- origin:
- req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`],
- secure: !!(req.socket.authorized || req.socket.encrypted),
- req
- };
-
- if (this.options.verifyClient.length === 2) {
- this.options.verifyClient(info, (verified, code, message, headers) => {
- if (!verified) {
- return abortHandshake(socket, code || 401, message, headers);
- }
-
- this.completeUpgrade(
- extensions,
- key,
- protocols,
- req,
- socket,
- head,
- cb
- );
- });
- return;
- }
-
- if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);
- }
-
- this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);
- }
-
- /**
- * Upgrade the connection to WebSocket.
- *
- * @param {Object} extensions The accepted extensions
- * @param {String} key The value of the `Sec-WebSocket-Key` header
- * @param {Set} protocols The subprotocols
- * @param {http.IncomingMessage} req The request object
- * @param {Duplex} socket The network socket between the server and client
- * @param {Buffer} head The first packet of the upgraded stream
- * @param {Function} cb Callback
- * @throws {Error} If called more than once with the same socket
- * @private
- */
- completeUpgrade(extensions, key, protocols, req, socket, head, cb) {
- //
- // Destroy the socket if the client has already sent a FIN packet.
- //
- if (!socket.readable || !socket.writable) return socket.destroy();
-
- if (socket[kWebSocket]) {
- throw new Error(
- 'server.handleUpgrade() was called more than once with the same ' +
- 'socket, possibly due to a misconfiguration'
- );
- }
-
- if (this._state > RUNNING) return abortHandshake(socket, 503);
-
- const digest = createHash('sha1')
- .update(key + GUID)
- .digest('base64');
-
- const headers = [
- 'HTTP/1.1 101 Switching Protocols',
- 'Upgrade: websocket',
- 'Connection: Upgrade',
- `Sec-WebSocket-Accept: ${digest}`
- ];
-
- const ws = new this.options.WebSocket(null, undefined, this.options);
-
- if (protocols.size) {
- //
- // Optionally call external protocol selection handler.
- //
- const protocol = this.options.handleProtocols
- ? this.options.handleProtocols(protocols, req)
- : protocols.values().next().value;
-
- if (protocol) {
- headers.push(`Sec-WebSocket-Protocol: ${protocol}`);
- ws._protocol = protocol;
- }
- }
-
- if (extensions[PerMessageDeflate.extensionName]) {
- const params = extensions[PerMessageDeflate.extensionName].params;
- const value = extension.format({
- [PerMessageDeflate.extensionName]: [params]
- });
- headers.push(`Sec-WebSocket-Extensions: ${value}`);
- ws._extensions = extensions;
- }
-
- //
- // Allow external modification/inspection of handshake headers.
- //
- this.emit('headers', headers, req);
-
- socket.write(headers.concat('\r\n').join('\r\n'));
- socket.removeListener('error', socketOnError);
-
- ws.setSocket(socket, head, {
- allowSynchronousEvents: this.options.allowSynchronousEvents,
- maxPayload: this.options.maxPayload,
- skipUTF8Validation: this.options.skipUTF8Validation
- });
-
- if (this.clients) {
- this.clients.add(ws);
- ws.on('close', () => {
- this.clients.delete(ws);
-
- if (this._shouldEmitClose && !this.clients.size) {
- process.nextTick(emitClose, this);
- }
- });
- }
-
- cb(ws, req);
- }
- }
-
- websocketServer = WebSocketServer;
-
- /**
- * Add event listeners on an `EventEmitter` using a map of <event, listener>
- * pairs.
- *
- * @param {EventEmitter} server The event emitter
- * @param {Object.<String, Function>} map The listeners to add
- * @return {Function} A function that will remove the added listeners when
- * called
- * @private
- */
- function addListeners(server, map) {
- for (const event of Object.keys(map)) server.on(event, map[event]);
-
- return function removeListeners() {
- for (const event of Object.keys(map)) {
- server.removeListener(event, map[event]);
- }
- };
- }
-
- /**
- * Emit a `'close'` event on an `EventEmitter`.
- *
- * @param {EventEmitter} server The event emitter
- * @private
- */
- function emitClose(server) {
- server._state = CLOSED;
- server.emit('close');
- }
-
- /**
- * Handle socket errors.
- *
- * @private
- */
- function socketOnError() {
- this.destroy();
- }
-
- /**
- * Close the connection when preconditions are not fulfilled.
- *
- * @param {Duplex} socket The socket of the upgrade request
- * @param {Number} code The HTTP response status code
- * @param {String} [message] The HTTP response body
- * @param {Object} [headers] Additional HTTP response headers
- * @private
- */
- function abortHandshake(socket, code, message, headers) {
- //
- // The socket is writable unless the user destroyed or ended it before calling
- // `server.handleUpgrade()` or in the `verifyClient` function, which is a user
- // error. Handling this does not make much sense as the worst that can happen
- // is that some of the data written by the user might be discarded due to the
- // call to `socket.end()` below, which triggers an `'error'` event that in
- // turn causes the socket to be destroyed.
- //
- message = message || http.STATUS_CODES[code];
- headers = {
- Connection: 'close',
- 'Content-Type': 'text/html',
- 'Content-Length': Buffer.byteLength(message),
- ...headers
- };
-
- socket.once('finish', socket.destroy);
-
- socket.end(
- `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` +
- Object.keys(headers)
- .map((h) => `${h}: ${headers[h]}`)
- .join('\r\n') +
- '\r\n\r\n' +
- message
- );
- }
-
- /**
- * Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least
- * one listener for it, otherwise call `abortHandshake()`.
- *
- * @param {WebSocketServer} server The WebSocket server
- * @param {http.IncomingMessage} req The request object
- * @param {Duplex} socket The socket of the upgrade request
- * @param {Number} code The HTTP response status code
- * @param {String} message The HTTP response body
- * @param {Object} [headers] The HTTP response headers
- * @private
- */
- function abortHandshakeOrEmitwsClientError(
- server,
- req,
- socket,
- code,
- message,
- headers
- ) {
- if (server.listenerCount('wsClientError')) {
- const err = new Error(message);
- Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);
-
- server.emit('wsClientError', err, socket, req);
- } else {
- abortHandshake(socket, code, message, headers);
- }
- }
- return websocketServer;
-}
-
-var websocketServerExports = requireWebsocketServer();
-var WebSocketServer = /*@__PURE__*/getDefaultExportFromCjs(websocketServerExports);
-
-function getTestFileEnvironment(project, testFile, browser = false) {
- let environment;
- if (browser) environment = project.browser?.vite.environments.client;
- else for (const name in project.vite.environments) {
- const env = project.vite.environments[name];
- if (env.moduleGraph.getModuleById(testFile)) {
- environment = env;
- break;
- }
- }
- return environment;
-}
-
-async function getModuleGraph(ctx, projectName, testFilePath, browser = false) {
- const graph = {};
- const externalized = /* @__PURE__ */ new Set();
- const inlined = /* @__PURE__ */ new Set();
- const project = ctx.getProjectByName(projectName);
- const environment = getTestFileEnvironment(project, testFilePath, browser);
- if (!environment) throw new Error(`Cannot find environment for ${testFilePath}`);
- const seen = /* @__PURE__ */ new Map();
- function get(mod) {
- if (!mod || !mod.id) return;
- if (mod.id === "\0vitest/browser" || mod.id.includes("plugin-vue:export-helper")) return;
- if (seen.has(mod)) return seen.get(mod);
- const id = clearId(mod.id);
- seen.set(mod, id);
- if (id.startsWith("__vite-browser-external:")) {
- const external = id.slice(24);
- externalized.add(external);
- return external;
- }
- const external = project._resolver.wasExternalized(id);
- if (typeof external === "string") {
- externalized.add(external);
- return external;
- }
- if (browser && mod.file?.includes(project.browser.vite.config.cacheDir)) {
- externalized.add(mod.id);
- return id;
- }
- inlined.add(id);
- graph[id] = Array.from(mod.importedModules).filter((i) => i.id && !i.id.includes("/vitest/dist/")).map((m) => get(m)).filter(Boolean);
- return id;
- }
- get(environment.moduleGraph.getModuleById(testFilePath));
- project.config.setupFiles.forEach((setupFile) => {
- get(environment.moduleGraph.getModuleById(setupFile));
- });
- return {
- graph,
- externalized: Array.from(externalized),
- inlined: Array.from(inlined)
- };
-}
-function clearId(id) {
- return id?.replace(/\?v=\w+$/, "") || "";
-}
-
-// Serialization support utils.
-function cloneByOwnProperties(value) {
- // Clones the value's properties into a new Object. The simpler approach of
- // Object.assign() won't work in the case that properties are not enumerable.
- return Object.getOwnPropertyNames(value).reduce((clone, prop) => {
- clone[prop] = value[prop];
- return clone;
- }, {});
-}
-/**
-* Replacer function for serialization methods such as JS.stringify() or
-* flatted.stringify().
-*/
-function stringifyReplace(key, value) {
- if (value instanceof Error) {
- const cloned = cloneByOwnProperties(value);
- return {
- name: value.name,
- message: value.message,
- stack: value.stack,
- ...cloned
- };
- } else return value;
-}
-
-function isValidApiRequest(config, req) {
- const url = new URL(req.url ?? "", "http://localhost");
- // validate token. token is injected in ui/tester/orchestrator html, which is cross origin protected.
- try {
- const token = url.searchParams.get("token");
- if (token && crypto.timingSafeEqual(Buffer.from(token), Buffer.from(config.api.token))) return true;
- }
- // an error is thrown when the length is incorrect
-catch {}
- return false;
-}
-
-function setup(ctx, _server) {
- const wss = new WebSocketServer({ noServer: true });
- const clients = /* @__PURE__ */ new Map();
- (_server || ctx.vite).httpServer?.on("upgrade", (request, socket, head) => {
- if (!request.url) return;
- const { pathname } = new URL(request.url, "http://localhost");
- if (pathname !== API_PATH) return;
- if (!isValidApiRequest(ctx.config, request)) {
- socket.destroy();
- return;
- }
- wss.handleUpgrade(request, socket, head, (ws) => {
- wss.emit("connection", ws, request);
- setupClient(ws);
- });
- });
- function setupClient(ws) {
- const rpc = createBirpc({
- async onTaskUpdate(packs, events) {
- await ctx._testRun.updated(packs, events);
- },
- getFiles() {
- return ctx.state.getFiles();
- },
- getPaths() {
- return ctx.state.getPaths();
- },
- async readTestFile(id) {
- if (!ctx.state.filesMap.has(id) || !existsSync(id)) return null;
- return promises.readFile(id, "utf-8");
- },
- async saveTestFile(id, content) {
- if (!ctx.state.filesMap.has(id) || !existsSync(id)) throw new Error(`Test file "${id}" was not registered, so it cannot be updated using the API.`);
- return promises.writeFile(id, content, "utf-8");
- },
- async rerun(files, resetTestNamePattern) {
- await ctx.rerunFiles(files, void 0, true, resetTestNamePattern);
- },
- async rerunTask(id) {
- await ctx.rerunTask(id);
- },
- getConfig() {
- return ctx.getRootProject().serializedConfig;
- },
- getResolvedProjectLabels() {
- return ctx.projects.map((p) => ({
- name: p.name,
- color: p.color
- }));
- },
- async getExternalResult(moduleId, testFileTaskId) {
- const testModule = ctx.state.getReportedEntityById(testFileTaskId);
- if (!testModule) return;
- if (!isFileServingAllowed$1(testModule.project.vite.config, moduleId)) return;
- const result = {};
- try {
- result.source = await promises.readFile(moduleId, "utf-8");
- } catch {}
- return result;
- },
- async getTransformResult(projectName, moduleId, testFileTaskId, browser = false) {
- const project = ctx.getProjectByName(projectName);
- const testModule = ctx.state.getReportedEntityById(testFileTaskId);
- if (!testModule || !isFileServingAllowed$1(project.vite.config, moduleId)) return;
- const environment = getTestFileEnvironment(project, testModule.moduleId, browser);
- const moduleNode = environment?.moduleGraph.getModuleById(moduleId);
- if (!environment || !moduleNode?.transformResult) return;
- const result = moduleNode.transformResult;
- try {
- result.source = result.source || (moduleNode.file ? await promises.readFile(moduleNode.file, "utf-8") : void 0);
- } catch {}
- // TODO: store this in HTML reporter separetly
- const transformDuration = ctx.state.metadata[projectName]?.duration[moduleNode.url]?.[0];
- if (transformDuration != null) result.transformTime = transformDuration;
- try {
- const diagnostic = await ctx.experimental_getSourceModuleDiagnostic(moduleId, testModule);
- result.modules = diagnostic.modules;
- result.untrackedModules = diagnostic.untrackedModules;
- } catch {}
- return result;
- },
- async getModuleGraph(project, id, browser) {
- return getModuleGraph(ctx, project, id, browser);
- },
- async updateSnapshot(file) {
- if (!file) await ctx.updateSnapshot();
- else await ctx.updateSnapshot([file.filepath]);
- },
- getUnhandledErrors() {
- return ctx.state.getUnhandledErrors();
- },
- async getTestFiles() {
- return (await ctx.globTestSpecifications()).map((spec) => [
- {
- name: spec.project.config.name,
- root: spec.project.config.root
- },
- spec.moduleId,
- { pool: spec.pool }
- ]);
- }
- }, {
- post: (msg) => ws.send(msg),
- on: (fn) => ws.on("message", fn),
- eventNames: [
- "onUserConsoleLog",
- "onFinished",
- "onFinishedReportCoverage",
- "onCollected",
- "onTaskUpdate"
- ],
- serialize: (data) => stringify(data, stringifyReplace),
- deserialize: parse,
- timeout: -1
- });
- clients.set(ws, rpc);
- ws.on("close", () => {
- clients.delete(ws);
- rpc.$close(/* @__PURE__ */ new Error("[vitest-api]: Pending methods while closing rpc"));
- });
- }
- ctx.reporters.push(new WebSocketReporter(ctx, wss, clients));
-}
-class WebSocketReporter {
- start = 0;
- end = 0;
- constructor(ctx, wss, clients) {
- this.ctx = ctx;
- this.wss = wss;
- this.clients = clients;
- }
- onTestModuleCollected(testModule) {
- if (this.clients.size === 0) return;
- this.clients.forEach((client) => {
- client.onCollected?.([testModule.task])?.catch?.(noop);
- });
- }
- onTestRunStart(specifications) {
- if (this.clients.size === 0) return;
- this.start = performance$1.now();
- const serializedSpecs = specifications.map((spec) => spec.toJSON());
- this.clients.forEach((client) => {
- client.onSpecsCollected?.(serializedSpecs)?.catch?.(noop);
- });
- }
- async onTestCaseAnnotate(testCase, annotation) {
- if (this.clients.size === 0) return;
- this.clients.forEach((client) => {
- client.onTestAnnotate?.(testCase.id, annotation)?.catch?.(noop);
- });
- }
- async onTestCaseArtifactRecord(testCase, artifact) {
- if (this.clients.size === 0) return;
- this.clients.forEach((client) => {
- client.onTestArtifactRecord?.(testCase.id, artifact)?.catch?.(noop);
- });
- }
- async onTaskUpdate(packs, events) {
- if (this.clients.size === 0) return;
- this.clients.forEach((client) => {
- client.onTaskUpdate?.(packs, events)?.catch?.(noop);
- });
- }
- sum(items, cb) {
- return items.reduce((total, next) => {
- return total + Math.max(cb(next) || 0, 0);
- }, 0);
- }
- onTestRunEnd(testModules, unhandledErrors) {
- if (!this.clients.size) return;
- const files = testModules.map((testModule) => testModule.task);
- const errors = [...unhandledErrors];
- this.end = performance$1.now();
- const blobs = this.ctx.state.blobs;
- // Execution time is either sum of all runs of `--merge-reports` or the current run's time
- const executionTime = blobs?.executionTimes ? this.sum(blobs.executionTimes, (time) => time) : this.end - this.start;
- this.clients.forEach((client) => {
- client.onFinished?.(files, errors, void 0, executionTime)?.catch?.(noop);
- });
- }
- onFinishedReportCoverage() {
- this.clients.forEach((client) => {
- client.onFinishedReportCoverage?.()?.catch?.(noop);
- });
- }
- onUserConsoleLog(log) {
- this.clients.forEach((client) => {
- client.onUserConsoleLog?.(log)?.catch?.(noop);
- });
- }
-}
-
-var setup$1 = /*#__PURE__*/Object.freeze({
- __proto__: null,
- WebSocketReporter: WebSocketReporter,
- setup: setup
-});
-
-function createDebugger(namespace) {
- const debug = createDebug(namespace);
- if (debug.enabled) return debug;
-}
-
-const debug$1 = createDebugger("vitest:ast-collect-info");
-const verbose = createDebugger("vitest:ast-collect-verbose");
-function astParseFile(filepath, code) {
- const ast = parseAst(code);
- if (verbose) verbose("Collecting", filepath, code);
- else debug$1?.("Collecting", filepath);
- const definitions = [];
- const getName = (callee) => {
- if (!callee) return null;
- if (callee.type === "Identifier") return callee.name;
- if (callee.type === "CallExpression") return getName(callee.callee);
- if (callee.type === "TaggedTemplateExpression") return getName(callee.tag);
- if (callee.type === "MemberExpression") {
- if (callee.object?.type === "Identifier" && [
- "it",
- "test",
- "describe",
- "suite"
- ].includes(callee.object.name)) return callee.object?.name;
- if (callee.object?.name?.startsWith("__vite_ssr_") || callee.object?.object?.name?.startsWith("__vite_ssr_") && callee.object?.property?.name === "Vitest") return getName(callee.property);
- // call as `__vite_ssr__.test.skip()`
- return getName(callee.object?.property);
- }
- // unwrap (0, ...)
- if (callee.type === "SequenceExpression" && callee.expressions.length === 2) {
- const [e0, e1] = callee.expressions;
- if (e0.type === "Literal" && e0.value === 0) return getName(e1);
- }
- return null;
- };
- ancestor(ast, { CallExpression(node) {
- const { callee } = node;
- const name = getName(callee);
- if (!name) return;
- if (![
- "it",
- "test",
- "describe",
- "suite"
- ].includes(name)) {
- verbose?.(`Skipping ${name} (unknown call)`);
- return;
- }
- const property = callee?.property?.name;
- let mode = !property || property === name ? "run" : property;
- // they will be picked up in the next iteration
- if ([
- "each",
- "for",
- "skipIf",
- "runIf"
- ].includes(mode)) return;
- let start;
- const end = node.end;
- // .each or (0, __vite_ssr_exports_0__.test)()
- if (callee.type === "CallExpression" || callee.type === "SequenceExpression" || callee.type === "TaggedTemplateExpression") start = callee.end;
- else start = node.start;
- const messageNode = node.arguments?.[0];
- if (messageNode == null) {
- verbose?.(`Skipping node at ${node.start} because it doesn't have a name`);
- return;
- }
- let message;
- if (messageNode?.type === "Literal" || messageNode?.type === "TemplateLiteral") message = code.slice(messageNode.start + 1, messageNode.end - 1);
- else message = code.slice(messageNode.start, messageNode.end);
- if (message.startsWith("0,")) message = message.slice(2);
- message = message.replace(/__vite_ssr_import_\d+__\./g, "").replace(/__vi_import_\d+__\./g, "");
- // cannot statically analyze, so we always skip it
- if (mode === "skipIf" || mode === "runIf") mode = "skip";
- const parentCalleeName = typeof callee?.callee === "object" && callee?.callee.type === "MemberExpression" && callee?.callee.property?.name;
- let isDynamicEach = parentCalleeName === "each" || parentCalleeName === "for";
- if (!isDynamicEach && callee.type === "TaggedTemplateExpression") {
- const property = callee.tag?.property?.name;
- isDynamicEach = property === "each" || property === "for";
- }
- debug$1?.("Found", name, message, `(${mode})`);
- definitions.push({
- start,
- end,
- name: message,
- type: name === "it" || name === "test" ? "test" : "suite",
- mode,
- task: null,
- dynamic: isDynamicEach
- });
- } });
- return {
- ast,
- definitions
- };
-}
-function createFailedFileTask(project, filepath, error) {
- const testFilepath = relative(project.config.root, filepath);
- const file = {
- filepath,
- type: "suite",
- id: /* @__PURE__ */ generateHash$1(`${testFilepath}${project.config.name || ""}`),
- name: testFilepath,
- fullName: testFilepath,
- mode: "run",
- tasks: [],
- start: 0,
- end: 0,
- projectName: project.name,
- meta: {},
- pool: project.browser ? "browser" : project.config.pool,
- file: null,
- result: {
- state: "fail",
- errors: serializeError(project, error)
- }
- };
- file.file = file;
- return file;
-}
-function serializeError(ctx, error) {
- if ("errors" in error && "pluginCode" in error) return error.errors.map((e) => {
- return {
- name: error.name,
- message: e.text,
- stack: e.location ? `${error.name}: ${e.text}\n at ${relative(ctx.config.root, e.location.file)}:${e.location.line}:${e.location.column}` : ""
- };
- });
- return [{
- name: error.name,
- stack: error.stack,
- message: error.message
- }];
-}
-function createFileTask(testFilepath, code, requestMap, options) {
- const { definitions, ast } = astParseFile(testFilepath, code);
- const file = {
- filepath: options.filepath,
- type: "suite",
- id: /* @__PURE__ */ generateHash$1(`${testFilepath}${options.name || ""}`),
- name: testFilepath,
- fullName: testFilepath,
- mode: "run",
- tasks: [],
- start: ast.start,
- end: ast.end,
- projectName: options.name,
- meta: {},
- pool: "browser",
- file: null
- };
- file.file = file;
- const indexMap = createIndexLocationsMap(code);
- const map = requestMap && new TraceMap(requestMap);
- let lastSuite = file;
- const updateLatestSuite = (index) => {
- while (lastSuite.suite && lastSuite.end < index) lastSuite = lastSuite.suite;
- return lastSuite;
- };
- definitions.sort((a, b) => a.start - b.start).forEach((definition) => {
- const latestSuite = updateLatestSuite(definition.start);
- let mode = definition.mode;
- if (latestSuite.mode !== "run")
- // inherit suite mode, if it's set
- mode = latestSuite.mode;
- const processedLocation = indexMap.get(definition.start);
- let location;
- if (map && processedLocation) {
- const originalLocation = originalPositionFor(map, {
- line: processedLocation.line,
- column: processedLocation.column
- });
- if (originalLocation.column != null) {
- verbose?.(`Found location for`, definition.type, definition.name, `${processedLocation.line}:${processedLocation.column}`, "->", `${originalLocation.line}:${originalLocation.column}`);
- location = originalLocation;
- } else debug$1?.("Cannot find original location for", definition.type, definition.name, `${processedLocation.column}:${processedLocation.line}`);
- } else debug$1?.("Cannot find original location for", definition.type, definition.name, `${definition.start}`);
- if (definition.type === "suite") {
- const task = {
- type: definition.type,
- id: "",
- suite: latestSuite,
- file,
- tasks: [],
- mode,
- name: definition.name,
- fullName: createTaskName([latestSuite.fullName, definition.name]),
- fullTestName: createTaskName([latestSuite.fullTestName, definition.name]),
- end: definition.end,
- start: definition.start,
- location,
- dynamic: definition.dynamic,
- meta: {}
- };
- definition.task = task;
- latestSuite.tasks.push(task);
- lastSuite = task;
- return;
- }
- const task = {
- type: definition.type,
- id: "",
- suite: latestSuite,
- file,
- mode,
- context: {},
- name: definition.name,
- fullName: createTaskName([latestSuite.fullName, definition.name]),
- fullTestName: createTaskName([latestSuite.fullTestName, definition.name]),
- end: definition.end,
- start: definition.start,
- location,
- dynamic: definition.dynamic,
- meta: {},
- timeout: 0,
- annotations: [],
- artifacts: []
- };
- definition.task = task;
- latestSuite.tasks.push(task);
- });
- calculateSuiteHash(file);
- const hasOnly = someTasksAreOnly(file);
- interpretTaskModes(file, options.testNamePattern, void 0, hasOnly, false, options.allowOnly);
- markDynamicTests(file.tasks);
- if (!file.tasks.length) file.result = {
- state: "fail",
- errors: [{
- name: "Error",
- message: `No test suite found in file ${options.filepath}`
- }]
- };
- return file;
-}
-async function astCollectTests(project, filepath) {
- const request = await transformSSR(project, filepath);
- const testFilepath = relative(project.config.root, filepath);
- if (!request) {
- debug$1?.("Cannot parse", testFilepath, "(vite didn't return anything)");
- return createFailedFileTask(project, filepath, /* @__PURE__ */ new Error(`Failed to parse ${testFilepath}. Vite didn't return anything.`));
- }
- return createFileTask(testFilepath, request.code, request.map, {
- name: project.config.name,
- filepath,
- allowOnly: project.config.allowOnly,
- testNamePattern: project.config.testNamePattern,
- pool: project.browser ? "browser" : project.config.pool
- });
-}
-async function transformSSR(project, filepath) {
- const request = await project.vite.transformRequest(filepath, { ssr: false });
- if (!request) return null;
- return await project.vite.ssrTransform(request.code, request.map, filepath);
-}
-function markDynamicTests(tasks) {
- for (const task of tasks) {
- if (task.dynamic) task.id += "-dynamic";
- if ("tasks" in task) markDynamicTests(task.tasks);
- }
-}
-function escapeRegex(str) {
- return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
-}
-const kReplacers = new Map([
- ["%i", "\\d+?"],
- ["%#", "\\d+?"],
- ["%d", "[\\d.eE+-]+?"],
- ["%f", "[\\d.eE+-]+?"],
- ["%s", ".+?"],
- ["%j", ".+?"],
- ["%o", ".+?"],
- ["%%", "%"]
-]);
-function escapeTestName(label, dynamic) {
- if (!dynamic) return escapeRegex(label);
- // Replace object access patterns ($value, $obj.a) with %s first
- let pattern = label.replace(/\$[a-z_.]+/gi, "%s");
- pattern = escapeRegex(pattern);
- // Replace percent placeholders with their respective regex
- pattern = pattern.replace(/%[i#dfsjo%]/g, (m) => kReplacers.get(m) || m);
- return pattern;
-}
-
-class BrowserSessions {
- sessions = /* @__PURE__ */ new Map();
- sessionIds = /* @__PURE__ */ new Set();
- getSession(sessionId) {
- return this.sessions.get(sessionId);
- }
- destroySession(sessionId) {
- this.sessions.delete(sessionId);
- }
- createSession(sessionId, project, pool) {
- // this promise only waits for the WS connection with the orhcestrator to be established
- const defer = createDefer();
- const timeout = setTimeout(() => {
- defer.reject(/* @__PURE__ */ new Error(`Failed to connect to the browser session "${sessionId}" [${project.name}] within the timeout.`));
- }, project.vitest.config.browser.connectTimeout ?? 6e4).unref();
- this.sessions.set(sessionId, {
- project,
- connected: () => {
- defer.resolve();
- clearTimeout(timeout);
- },
- fail: (error) => {
- defer.resolve();
- clearTimeout(timeout);
- pool.reject(error);
- }
- });
- return defer;
- }
-}
-
-class FilesStatsCache {
- cache = /* @__PURE__ */ new Map();
- getStats(key) {
- return this.cache.get(key);
- }
- async populateStats(root, specs) {
- const promises = specs.map((spec) => {
- const key = `${spec.project.name}:${relative(root, spec.moduleId)}`;
- return this.updateStats(spec.moduleId, key);
- });
- await Promise.all(promises);
- }
- async updateStats(fsPath, key) {
- if (!fs.existsSync(fsPath)) return;
- const stats = await fs.promises.stat(fsPath);
- this.cache.set(key, { size: stats.size });
- }
- removeStats(fsPath) {
- this.cache.forEach((_, key) => {
- if (key.endsWith(fsPath)) this.cache.delete(key);
- });
- }
-}
-
-class ResultsCache {
- cache = /* @__PURE__ */ new Map();
- workspacesKeyMap = /* @__PURE__ */ new Map();
- cachePath = null;
- version;
- root = "/";
- constructor(logger) {
- this.logger = logger;
- this.version = Vitest.version;
- }
- getCachePath() {
- return this.cachePath;
- }
- setConfig(root, config) {
- this.root = root;
- if (config) this.cachePath = resolve(config.dir, "results.json");
- }
- getResults(key) {
- return this.cache.get(key);
- }
- async clearCache() {
- if (this.cachePath && existsSync(this.cachePath)) {
- await rm(this.cachePath, {
- force: true,
- recursive: true
- });
- this.logger.log("[cache] cleared results cache at", this.cachePath);
- }
- }
- async readFromCache() {
- if (!this.cachePath) return;
- if (!fs.existsSync(this.cachePath)) return;
- const resultsCache = await fs.promises.readFile(this.cachePath, "utf8");
- const { results, version } = JSON.parse(resultsCache || "[]");
- const [major, minor] = version.split(".");
- // handling changed in 0.30.0
- if (major > 0 || Number(minor) >= 30) {
- this.cache = new Map(results);
- this.version = version;
- results.forEach(([spec]) => {
- const [projectName, relativePath] = spec.split(":");
- const keyMap = this.workspacesKeyMap.get(relativePath) || [];
- keyMap.push(projectName);
- this.workspacesKeyMap.set(relativePath, keyMap);
- });
- }
- }
- updateResults(files) {
- files.forEach((file) => {
- const result = file.result;
- if (!result) return;
- const duration = result.duration || 0;
- // store as relative, so cache would be the same in CI and locally
- const relativePath = relative(this.root, file.filepath);
- this.cache.set(`${file.projectName || ""}:${relativePath}`, {
- duration: duration >= 0 ? duration : 0,
- failed: result.state === "fail"
- });
- });
- }
- removeFromCache(filepath) {
- this.cache.forEach((_, key) => {
- if (key.endsWith(filepath)) this.cache.delete(key);
- });
- }
- async writeToCache() {
- if (!this.cachePath) return;
- const results = Array.from(this.cache.entries());
- const cacheDirname = dirname(this.cachePath);
- if (!fs.existsSync(cacheDirname)) await fs.promises.mkdir(cacheDirname, { recursive: true });
- const cache = JSON.stringify({
- version: this.version,
- results
- });
- await fs.promises.writeFile(this.cachePath, cache);
- }
-}
-
-class VitestCache {
- results;
- stats = new FilesStatsCache();
- constructor(logger) {
- this.results = new ResultsCache(logger);
- }
- getFileTestResults(key) {
- return this.results.getResults(key);
- }
- getFileStats(key) {
- return this.stats.getStats(key);
- }
- static resolveCacheDir(root, dir, projectName) {
- return resolve(root, slash(dir || "node_modules/.vite"), "vitest", hash("sha1", projectName || "", "hex"));
- }
-}
-
-const debugFs = createDebugger("vitest:cache:fs");
-const debugMemory = createDebugger("vitest:cache:memory");
-const cacheComment = "\n//# vitestCache=";
-const cacheCommentLength = 17;
-const METADATA_FILE = "_metadata.json";
-const parallelFsCacheRead = /* @__PURE__ */ new Map();
-/**
-* @experimental
-*/
-class FileSystemModuleCache {
- /**
- * Even though it's possible to override the folder of project's caches
- * We still keep a single metadata file for all projects because
- * - they can reference files between each other
- * - lockfile changes are reflected for the whole workspace, not just for a single project
- */
- rootCache;
- metadataFilePath;
- version = "1.0.0-beta.4";
- fsCacheRoots = /* @__PURE__ */ new WeakMap();
- fsEnvironmentHashMap = /* @__PURE__ */ new WeakMap();
- fsCacheKeyGenerators = /* @__PURE__ */ new Set();
- // this exists only to avoid the perf. cost of reading a file and generating a hash again
- // surprisingly, on some machines this has negligible effect
- fsCacheKeys = /* @__PURE__ */ new WeakMap();
- constructor(vitest) {
- this.vitest = vitest;
- const workspaceRoot = searchForWorkspaceRoot(vitest.vite.config.root);
- this.rootCache = vitest.config.experimental.fsModuleCachePath || join(workspaceRoot, "node_modules", ".experimental-vitest-cache");
- this.metadataFilePath = join(this.rootCache, METADATA_FILE);
- }
- defineCacheKeyGenerator(callback) {
- this.fsCacheKeyGenerators.add(callback);
- }
- async clearCache(log = true) {
- const fsCachePaths = this.vitest.projects.map((r) => {
- return r.config.experimental.fsModuleCachePath || this.rootCache;
- });
- const uniquePaths = Array.from(new Set(fsCachePaths));
- await Promise.all(uniquePaths.map((directory) => rm(directory, {
- force: true,
- recursive: true
- })));
- if (log) this.vitest.logger.log(`[cache] cleared fs module cache at ${uniquePaths.join(", ")}`);
- }
- readCachedFileConcurrently(cachedFilePath) {
- if (!parallelFsCacheRead.has(cachedFilePath)) parallelFsCacheRead.set(cachedFilePath, readFile(cachedFilePath, "utf-8").then((code) => {
- const matchIndex = code.lastIndexOf(cacheComment);
- if (matchIndex === -1) {
- debugFs?.(`${c.red("[empty]")} ${cachedFilePath} exists, but doesn't have a ${cacheComment} comment, transforming by vite instead`);
- return;
- }
- return {
- code,
- meta: this.fromBase64(code.slice(matchIndex + cacheCommentLength))
- };
- }).finally(() => {
- parallelFsCacheRead.delete(cachedFilePath);
- }));
- return parallelFsCacheRead.get(cachedFilePath);
- }
- async getCachedModule(cachedFilePath) {
- if (!existsSync(cachedFilePath)) {
- debugFs?.(`${c.red("[empty]")} ${cachedFilePath} doesn't exist, transforming by vite first`);
- return;
- }
- const fileResult = await this.readCachedFileConcurrently(cachedFilePath);
- if (!fileResult) return;
- const { code, meta } = fileResult;
- debugFs?.(`${c.green("[read]")} ${meta.id} is cached in ${cachedFilePath}`);
- return {
- id: meta.id,
- url: meta.url,
- file: meta.file,
- code,
- importedUrls: meta.importedUrls,
- mappings: meta.mappings
- };
- }
- async saveCachedModule(cachedFilePath, fetchResult, importedUrls = [], mappings = false) {
- if ("code" in fetchResult) {
- const result = {
- file: fetchResult.file,
- id: fetchResult.id,
- url: fetchResult.url,
- importedUrls,
- mappings
- };
- debugFs?.(`${c.yellow("[write]")} ${fetchResult.id} is cached in ${cachedFilePath}`);
- await atomicWriteFile(cachedFilePath, `${fetchResult.code}${cacheComment}${this.toBase64(result)}`);
- }
- }
- toBase64(obj) {
- const json = stringify(obj);
- return Buffer.from(json).toString("base64");
- }
- fromBase64(obj) {
- return parse(Buffer.from(obj, "base64").toString("utf-8"));
- }
- invalidateCachePath(environment, id) {
- debugFs?.(`cache for ${id} in ${environment.name} environment is invalidated`);
- this.fsCacheKeys.get(environment)?.delete(id);
- }
- invalidateAllCachePaths(environment) {
- debugFs?.(`the ${environment.name} environment cache is invalidated`);
- this.fsCacheKeys.get(environment)?.clear();
- }
- getMemoryCachePath(environment, id) {
- const result = this.fsCacheKeys.get(environment)?.get(id);
- if (result != null) debugMemory?.(`${c.green("[read]")} ${id} was cached in ${result}`);
- else if (result === null) debugMemory?.(`${c.green("[read]")} ${id} was bailed out`);
- return result;
- }
- generateCachePath(vitestConfig, environment, id, fileContent) {
- // bail out if file has import.meta.glob because it depends on other files
- // TODO: figure out a way to still support it
- if (fileContent.includes("import.meta.glob(")) {
- this.saveMemoryCache(environment, id, null);
- debugMemory?.(`${c.yellow("[write]")} ${id} was bailed out because it has "import.meta.glob"`);
- return null;
- }
- let hashString = "";
- for (const generator of this.fsCacheKeyGenerators) {
- const result = generator({
- environment,
- id,
- sourceCode: fileContent
- });
- if (typeof result === "string") hashString += result;
- if (result === false) {
- this.saveMemoryCache(environment, id, null);
- debugMemory?.(`${c.yellow("[write]")} ${id} was bailed out by a custom generator`);
- return null;
- }
- }
- const config = environment.config;
- // coverage provider is dynamic, so we also clear the whole cache if
- // vitest.enableCoverage/vitest.disableCoverage is called
- const coverageAffectsCache = String(this.vitest.config.coverage.enabled && this.vitest.coverageProvider?.requiresTransform?.(id));
- let cacheConfig = this.fsEnvironmentHashMap.get(environment);
- if (!cacheConfig) {
- cacheConfig = JSON.stringify({
- root: config.root,
- base: config.base,
- mode: config.mode,
- consumer: config.consumer,
- resolve: config.resolve,
- plugins: config.plugins.filter((p) => p.api?.vitest?.experimental?.ignoreFsModuleCache !== true).map((p) => p.name),
- configFileDependencies: config.configFileDependencies.map((file) => tryReadFileSync(file)),
- environment: environment.name,
- css: vitestConfig.css
- }, (_, value) => {
- if (typeof value === "function" || value instanceof RegExp) return value.toString();
- return value;
- });
- this.fsEnvironmentHashMap.set(environment, cacheConfig);
- }
- hashString += id + fileContent + (process.env.NODE_ENV ?? "") + this.version + cacheConfig + coverageAffectsCache;
- const cacheKey = hash("sha1", hashString, "hex");
- let cacheRoot = this.fsCacheRoots.get(vitestConfig);
- if (cacheRoot == null) {
- cacheRoot = vitestConfig.experimental.fsModuleCachePath || this.rootCache;
- this.fsCacheRoots.set(vitestConfig, cacheRoot);
- if (!existsSync(cacheRoot)) mkdirSync(cacheRoot, { recursive: true });
- }
- const fsResultPath = join(cacheRoot, cacheKey);
- debugMemory?.(`${c.yellow("[write]")} ${id} generated a cache in ${fsResultPath}`);
- this.saveMemoryCache(environment, id, fsResultPath);
- return fsResultPath;
- }
- saveMemoryCache(environment, id, cache) {
- let environmentKeys = this.fsCacheKeys.get(environment);
- if (!environmentKeys) {
- environmentKeys = /* @__PURE__ */ new Map();
- this.fsCacheKeys.set(environment, environmentKeys);
- }
- environmentKeys.set(id, cache);
- }
- async readMetadata() {
- // metadata is shared between every projects in the workspace, so we ignore project's fsModuleCachePath
- if (!existsSync(this.metadataFilePath)) return;
- try {
- const content = await readFile(this.metadataFilePath, "utf-8");
- return JSON.parse(content);
- } catch {}
- }
- // before vitest starts running tests, we check that the lockfile wasn't updated
- // if it was, we nuke the previous cache in case a custom plugin was updated
- // or a new version of vite/vitest is installed
- // for the same reason we also cache config file content, but that won't catch changes made in external plugins
- async ensureCacheIntegrity() {
- if (![this.vitest.getRootProject(), ...this.vitest.projects].some((p) => p.config.experimental.fsModuleCache)) return;
- const metadata = await this.readMetadata();
- const currentLockfileHash = getLockfileHash(this.vitest.vite.config.root);
- // no metadata found, just store a new one, don't reset the cache
- if (!metadata) {
- if (!existsSync(this.rootCache)) mkdirSync(this.rootCache, { recursive: true });
- debugFs?.(`fs metadata file was created with hash ${currentLockfileHash}`);
- await writeFile(this.metadataFilePath, JSON.stringify({ lockfileHash: currentLockfileHash }, null, 2), "utf-8");
- return;
- }
- // if lockfile didn't change, don't do anything
- if (metadata.lockfileHash === currentLockfileHash) return;
- // lockfile changed, let's clear all caches
- await this.clearCache(false);
- this.vitest.vite.config.logger.info(`fs cache was cleared because lockfile has changed`, {
- timestamp: true,
- environment: c.yellow("[vitest]")
- });
- debugFs?.(`fs cache was cleared because lockfile has changed`);
- }
-}
-/**
-* Performs an atomic write operation using the write-then-rename pattern.
-*
-* Why we need this:
-* - Ensures file integrity by never leaving partially written files on disk
-* - Prevents other processes from reading incomplete data during writes
-* - Particularly important for test files where incomplete writes could cause test failures
-*
-* The implementation writes to a temporary file first, then renames it to the target path.
-* This rename operation is atomic on most filesystems (including POSIX-compliant ones),
-* guaranteeing that other processes will only ever see the complete file.
-*
-* Added in https://github.com/vitest-dev/vitest/pull/7531
-*/
-async function atomicWriteFile(realFilePath, data) {
- const tmpFilePath = join(dirname(realFilePath), `.tmp-${Date.now()}-${Math.random().toString(36).slice(2)}`);
- try {
- await writeFile(tmpFilePath, data, "utf-8");
- await rename(tmpFilePath, realFilePath);
- } finally {
- try {
- if (await stat(tmpFilePath)) await unlink(tmpFilePath);
- } catch {}
- }
-}
-// lockfile hash resolution taken from vite
-// since this is experimental, we don't ask to expose it
-const lockfileFormats = [
- {
- path: "node_modules/.package-lock.json",
- checkPatchesDir: "patches",
- manager: "npm"
- },
- {
- path: "node_modules/.yarn-state.yml",
- checkPatchesDir: false,
- manager: "yarn"
- },
- {
- path: ".pnp.cjs",
- checkPatchesDir: ".yarn/patches",
- manager: "yarn"
- },
- {
- path: ".pnp.js",
- checkPatchesDir: ".yarn/patches",
- manager: "yarn"
- },
- {
- path: "node_modules/.yarn-integrity",
- checkPatchesDir: "patches",
- manager: "yarn"
- },
- {
- path: "node_modules/.pnpm/lock.yaml",
- checkPatchesDir: false,
- manager: "pnpm"
- },
- {
- path: ".rush/temp/shrinkwrap-deps.json",
- checkPatchesDir: false,
- manager: "pnpm"
- },
- {
- path: "bun.lock",
- checkPatchesDir: "patches",
- manager: "bun"
- },
- {
- path: "bun.lockb",
- checkPatchesDir: "patches",
- manager: "bun"
- }
-].sort((_, { manager }) => {
- return process.env.npm_config_user_agent?.startsWith(manager) ? 1 : -1;
-});
-const lockfilePaths = lockfileFormats.map((l) => l.path);
-function getLockfileHash(root) {
- const lockfilePath = lookupFile(root, lockfilePaths);
- let content = lockfilePath ? fs.readFileSync(lockfilePath, "utf-8") : "";
- if (lockfilePath) {
- const normalizedLockfilePath = lockfilePath.replaceAll("\\", "/");
- const lockfileFormat = lockfileFormats.find((f) => normalizedLockfilePath.endsWith(f.path));
- if (lockfileFormat.checkPatchesDir) {
- const stat = tryStatSync(join(lockfilePath.slice(0, -lockfileFormat.path.length), lockfileFormat.checkPatchesDir));
- if (stat?.isDirectory()) content += stat.mtimeMs.toString();
- }
- }
- return hash("sha256", content, "hex").substring(0, 8).padEnd(8, "_");
-}
-function lookupFile(dir, fileNames) {
- while (dir) {
- for (const fileName of fileNames) {
- const fullPath = join(dir, fileName);
- if (tryStatSync(fullPath)?.isFile()) return fullPath;
- }
- const parentDir = dirname(dir);
- if (parentDir === dir) return;
- dir = parentDir;
- }
-}
-function tryReadFileSync(file) {
- try {
- return readFileSync(file, "utf-8");
- } catch {
- return "";
- }
-}
-function tryStatSync(file) {
- try {
- // The "throwIfNoEntry" is a performance optimization for cases where the file does not exist
- return fs.statSync(file, { throwIfNoEntry: false });
- } catch {}
-}
-
-// this is copy pasted from vite
-function normalizeResolvedIdToUrl(environment, resolvedId) {
- const root = environment.config.root;
- const depsOptimizer = environment.depsOptimizer;
- let url;
- // normalize all imports into resolved URLs
- // e.g. `import 'foo'` -> `import '/@fs/.../node_modules/foo/index.js'`
- if (resolvedId.startsWith(withTrailingSlash(root)))
- // in root: infer short absolute path from root
- url = resolvedId.slice(root.length);
- else if (depsOptimizer?.isOptimizedDepFile(resolvedId) || resolvedId !== "/@react-refresh" && path.isAbsolute(resolvedId) && existsSync(cleanUrl(resolvedId)))
- // an optimized deps may not yet exists in the filesystem, or
- // a regular file exists but is out of root: rewrite to absolute /@fs/ paths
- url = path.posix.join("/@fs/", resolvedId);
- else url = resolvedId;
- // if the resolved id is not a valid browser import specifier,
- // prefix it to make it valid. We will strip this before feeding it
- // back into the transform pipeline
- if (url[0] !== "." && url[0] !== "/") url = wrapId(resolvedId);
- return url;
-}
-
-const saveCachePromises = /* @__PURE__ */ new Map();
-const readFilePromises = /* @__PURE__ */ new Map();
-class ModuleFetcher {
- tmpDirectories = /* @__PURE__ */ new Set();
- fsCacheEnabled;
- constructor(resolver, config, fsCache, tmpProjectDir) {
- this.resolver = resolver;
- this.config = config;
- this.fsCache = fsCache;
- this.tmpProjectDir = tmpProjectDir;
- this.fsCacheEnabled = config.experimental?.fsModuleCache === true;
- }
- async fetch(trace, url, importer, environment, makeTmpCopies, options) {
- if (url.startsWith("data:")) {
- trace.setAttribute("vitest.module.external", url);
- return {
- externalize: url,
- type: "builtin"
- };
- }
- if (url === "/@vite/client" || url === "@vite/client") {
- trace.setAttribute("vitest.module.external", url);
- return {
- externalize: "/@vite/client",
- type: "module"
- };
- }
- const isFileUrl = url.startsWith("file://");
- if (isExternalUrl(url) && !isFileUrl) {
- trace.setAttribute("vitest.module.external", url);
- return {
- externalize: url,
- type: "network"
- };
- }
- // handle unresolved id of dynamic import skipped by Vite import analysis
- if (url[0] !== "/") {
- const resolved = await environment.pluginContainer.resolveId(url, importer);
- if (resolved) url = normalizeResolvedIdToUrl(environment, resolved.id);
- }
- const moduleGraphModule = await environment.moduleGraph.ensureEntryFromUrl(unwrapId(url));
- const cached = !!moduleGraphModule.transformResult;
- if (moduleGraphModule.file) trace.setAttribute("code.file.path", moduleGraphModule.file);
- if (options?.cached && cached) return { cache: true };
- const externalize = await this.resolver.shouldExternalize(moduleGraphModule.id);
- if (externalize) return {
- externalize,
- type: "module"
- };
- const cachePath = await this.getCachePath(environment, moduleGraphModule);
- // full fs caching is disabled, but we still want to keep tmp files if makeTmpCopies is enabled
- // this is primarily used by the forks pool to avoid using process.send(bigBuffer)
- if (cachePath == null) {
- const result = await this.fetchAndProcess(environment, url, importer, moduleGraphModule, options);
- this.recordResult(trace, result);
- if (!makeTmpCopies || !("code" in result)) return result;
- const transformResult = moduleGraphModule.transformResult;
- const tmpPath = transformResult && Reflect.get(transformResult, "_vitest_tmp");
- if (typeof tmpPath === "string") return getCachedResult(result, tmpPath);
- const tmpDir = join(this.tmpProjectDir, environment.name);
- if (!this.tmpDirectories.has(tmpDir)) {
- if (!existsSync(tmpDir)) mkdirSync(tmpDir, { recursive: true });
- this.tmpDirectories.add(tmpDir);
- }
- const tmpFile = join(tmpDir, hash("sha1", result.id, "hex"));
- return this.cacheResult(result, tmpFile).then((result) => {
- if (transformResult) Reflect.set(transformResult, "_vitest_tmp", tmpFile);
- return result;
- });
- }
- if (saveCachePromises.has(cachePath)) return saveCachePromises.get(cachePath).then((result) => {
- this.recordResult(trace, result);
- return result;
- });
- const cachedModule = await this.getCachedModule(cachePath, environment, moduleGraphModule, importer);
- if (cachedModule) {
- this.recordResult(trace, cachedModule);
- return cachedModule;
- }
- const result = await this.fetchAndProcess(environment, url, importer, moduleGraphModule, options);
- const importedUrls = this.getSerializedImports(moduleGraphModule);
- const map = moduleGraphModule.transformResult?.map;
- const mappings = map && !("version" in map) && map.mappings === "";
- return this.cacheResult(result, cachePath, importedUrls, !!mappings);
- }
- // we need this for UI to be able to show a module graph
- getSerializedImports(node) {
- const imports = [];
- node.importedModules.forEach((importer) => {
- imports.push(importer.url);
- });
- return imports;
- }
- recordResult(trace, result) {
- if ("externalize" in result) trace.setAttributes({
- "vitest.fetched_module.external": result.externalize,
- "vitest.fetched_module.type": result.type
- });
- if ("id" in result) {
- trace.setAttributes({
- "vitest.fetched_module.invalidate": result.invalidate,
- "vitest.fetched_module.id": result.id,
- "vitest.fetched_module.url": result.url,
- "vitest.fetched_module.cache": false
- });
- if (result.file) trace.setAttribute("code.file.path", result.file);
- }
- if ("code" in result) trace.setAttribute("vitest.fetched_module.code_length", result.code.length);
- }
- async getCachePath(environment, moduleGraphModule) {
- if (!this.fsCacheEnabled) return null;
- const moduleId = moduleGraphModule.id;
- const memoryCacheKey = this.fsCache.getMemoryCachePath(environment, moduleId);
- // undefined means there is no key in memory
- // null means the file should not be cached
- if (memoryCacheKey !== void 0) return memoryCacheKey;
- const fileContent = await this.readFileContentToCache(environment, moduleGraphModule);
- return this.fsCache.generateCachePath(this.config, environment, moduleGraphModule.id, fileContent);
- }
- async readFileContentToCache(environment, moduleGraphModule) {
- if (moduleGraphModule.file && !moduleGraphModule.file.startsWith("\0") && !moduleGraphModule.file.startsWith("virtual:")) {
- const result = await this.readFileConcurrently(moduleGraphModule.file);
- if (result != null) return result;
- }
- const loadResult = await environment.pluginContainer.load(moduleGraphModule.id);
- if (typeof loadResult === "string") return loadResult;
- if (loadResult != null) return loadResult.code;
- return "";
- }
- async getCachedModule(cachePath, environment, moduleGraphModule, importer) {
- if (moduleGraphModule.transformResult?.__vitestTmp) return {
- cached: true,
- file: moduleGraphModule.file,
- id: moduleGraphModule.id,
- tmp: moduleGraphModule.transformResult.__vitestTmp,
- url: moduleGraphModule.url,
- invalidate: false
- };
- const cachedModule = await this.fsCache.getCachedModule(cachePath);
- if (!cachedModule) return;
- // keep the module graph in sync
- let map = extractSourceMap(cachedModule.code);
- if (map && cachedModule.file) map.file = cachedModule.file;
- // mappings is a special source map identifier in rollup
- if (!map && cachedModule.mappings) map = { mappings: "" };
- moduleGraphModule.transformResult = {
- code: cachedModule.code,
- map,
- ssr: true,
- __vitestTmp: cachePath
- };
- // we populate the module graph to make the watch mode work because it relies on importers
- if (importer) {
- const environmentNode = environment.moduleGraph.getModuleById(importer);
- if (environmentNode) moduleGraphModule.importers.add(environmentNode);
- }
- await Promise.all(cachedModule.importedUrls.map(async (url) => {
- const moduleNode = await environment.moduleGraph.ensureEntryFromUrl(url).catch(() => null);
- if (moduleNode) {
- moduleNode.importers.add(moduleGraphModule);
- moduleGraphModule.importedModules.add(moduleNode);
- }
- }));
- return {
- cached: true,
- file: cachedModule.file,
- id: cachedModule.id,
- tmp: cachePath,
- url: cachedModule.url,
- invalidate: false
- };
- }
- async fetchAndProcess(environment, url, importer, moduleGraphModule, options) {
- return processResultSource(environment, await fetchModule(environment, url, importer, {
- ...options,
- inlineSourceMap: false
- }).catch(handleRollupError));
- }
- async cacheResult(result, cachePath, importedUrls = [], mappings = false) {
- const returnResult = "code" in result ? getCachedResult(result, cachePath) : result;
- if (saveCachePromises.has(cachePath)) {
- await saveCachePromises.get(cachePath);
- return returnResult;
- }
- const savePromise = this.fsCache.saveCachedModule(cachePath, result, importedUrls, mappings).then(() => result).finally(() => {
- saveCachePromises.delete(cachePath);
- });
- saveCachePromises.set(cachePath, savePromise);
- await savePromise;
- return returnResult;
- }
- readFileConcurrently(file) {
- if (!readFilePromises.has(file)) readFilePromises.set(
- file,
- // virtual file can have a "file" property
- readFile(file, "utf-8").catch(() => null).finally(() => {
- readFilePromises.delete(file);
- })
- );
- return readFilePromises.get(file);
- }
-}
-function createFetchModuleFunction(resolver, config, fsCache, traces, tmpProjectDir) {
- const fetcher = new ModuleFetcher(resolver, config, fsCache, tmpProjectDir);
- return async (url, importer, environment, cacheFs, options, otelCarrier) => {
- await traces.waitInit();
- const context = otelCarrier ? traces.getContextFromCarrier(otelCarrier) : void 0;
- return traces.$("vitest.module.transform", context ? { context } : {}, (span) => fetcher.fetch(span, url, importer, environment, cacheFs, options));
- };
-}
-let SOURCEMAPPING_URL = "sourceMa";
-SOURCEMAPPING_URL += "ppingURL";
-const MODULE_RUNNER_SOURCEMAPPING_SOURCE = "//# sourceMappingSource=vite-generated";
-function processResultSource(environment, result) {
- if (!("code" in result)) return result;
- const node = environment.moduleGraph.getModuleById(result.id);
- if (node?.transformResult)
- // this also overrides node.transformResult.code which is also what the module
- // runner does under the hood by default (we disable source maps inlining)
- inlineSourceMap(node.transformResult);
- return {
- ...result,
- code: node?.transformResult?.code || result.code
- };
-}
-const OTHER_SOURCE_MAP_REGEXP = new RegExp(`//# ${SOURCEMAPPING_URL}=data:application/json[^,]+base64,([A-Za-z0-9+/=]+)$`, "gm");
-// we have to inline the source map ourselves, because
-// - we don't need //# sourceURL since we are running code in VM
-// - important in stack traces and the V8 coverage
-// - we need to inject an empty line for --inspect-brk
-function inlineSourceMap(result) {
- const map = result.map;
- let code = result.code;
- if (!map || !("version" in map) || code.includes(MODULE_RUNNER_SOURCEMAPPING_SOURCE)) return result;
- // to reduce the payload size, we only inline vite node source map, because it's also the only one we use
- OTHER_SOURCE_MAP_REGEXP.lastIndex = 0;
- if (OTHER_SOURCE_MAP_REGEXP.test(code)) code = code.replace(OTHER_SOURCE_MAP_REGEXP, "");
- const sourceMap = { ...map };
- // If the first line is not present on source maps, add simple 1:1 mapping ([0,0,0,0], [1,0,0,0])
- // so that debuggers can be set to break on first line
- if (sourceMap.mappings[0] === ";") sourceMap.mappings = `AAAA,CAAA${sourceMap.mappings}`;
- result.code = `${code.trimEnd()}\n${MODULE_RUNNER_SOURCEMAPPING_SOURCE}\n//# ${SOURCEMAPPING_URL}=${genSourceMapUrl(sourceMap)}\n`;
- return result;
-}
-function genSourceMapUrl(map) {
- if (typeof map !== "string") map = JSON.stringify(map);
- return `data:application/json;base64,${Buffer.from(map).toString("base64")}`;
-}
-function getCachedResult(result, tmp) {
- return {
- cached: true,
- file: result.file,
- id: result.id,
- tmp,
- url: result.url,
- invalidate: result.invalidate
- };
-}
-const MODULE_RUNNER_SOURCEMAPPING_REGEXP = /* @__PURE__ */ new RegExp(`//# ${SOURCEMAPPING_URL}=data:application/json;base64,(.+)`);
-function extractSourceMap(code) {
- const pattern = `//# ${SOURCEMAPPING_URL}=data:application/json;base64,`;
- const lastIndex = code.lastIndexOf(pattern);
- if (lastIndex === -1) return null;
- const mapString = MODULE_RUNNER_SOURCEMAPPING_REGEXP.exec(code.slice(lastIndex))?.[1];
- if (!mapString) return null;
- const sourceMap = JSON.parse(Buffer.from(mapString, "base64").toString("utf-8"));
- // remove source map mapping added by "inlineSourceMap" to keep the original behaviour of transformRequest
- if (sourceMap.mappings.startsWith("AAAA,CAAA;"))
- // 9 because we want to only remove "AAAA,CAAA", but keep ; at the start
- sourceMap.mappings = sourceMap.mappings.slice(9);
- return sourceMap;
-}
-// serialize rollup error on server to preserve details as a test error
-function handleRollupError(e) {
- if (e instanceof Error && ("plugin" in e || "frame" in e || "id" in e))
- // eslint-disable-next-line no-throw-literal
- throw {
- name: e.name,
- message: e.message,
- stack: e.stack,
- cause: e.cause,
- __vitest_rollup_error__: {
- plugin: e.plugin,
- id: e.id,
- loc: e.loc,
- frame: e.frame
- }
- };
- throw e;
-}
-
-class ServerModuleRunner extends ModuleRunner {
- constructor(environment, fetcher, config) {
- super({
- hmr: false,
- transport: { async invoke(event) {
- if (event.type !== "custom") throw new Error(`Vitest Module Runner doesn't support Vite HMR events.`);
- const { name, data } = event.data;
- if (name === "getBuiltins") return await environment.hot.handleInvoke(event);
- if (name !== "fetchModule") return { error: /* @__PURE__ */ new Error(`Unknown method: ${name}. Expected "fetchModule".`) };
- try {
- const result = await fetcher(data[0], data[1], environment, false, data[2]);
- if ("tmp" in result) {
- const code = await readFile(result.tmp);
- return { result: {
- ...result,
- code
- } };
- }
- return { result };
- } catch (error) {
- return { error };
- }
- } }
- }, new VitestModuleEvaluator());
- this.environment = environment;
- this.config = config;
- }
- async import(rawId) {
- const resolved = await this.environment.pluginContainer.resolveId(rawId, this.config.root);
- if (!resolved) return super.import(rawId);
- // Vite will make "@vitest/coverage-v8" into "@vitest/coverage-v8.js" url
- // instead of using an actual file path-like URL, so we resolve it here first
- const url = normalizeResolvedIdToUrl(this.environment, resolved.id);
- return super.import(url);
- }
-}
-
-class FilesNotFoundError extends Error {
- code = "VITEST_FILES_NOT_FOUND";
- constructor(mode) {
- super(`No ${mode} files found`);
- }
-}
-class GitNotFoundError extends Error {
- code = "VITEST_GIT_NOT_FOUND";
- constructor() {
- super("Could not find Git root. Have you initialized git with `git init`?");
- }
-}
-class LocationFilterFileNotFoundError extends Error {
- code = "VITEST_LOCATION_FILTER_FILE_NOT_FOUND";
- constructor(filename) {
- super(`Couldn\'t find file ${filename}. Note when specifying the test location you have to specify the full test filename.`);
- }
-}
-class IncludeTaskLocationDisabledError extends Error {
- code = "VITEST_INCLUDE_TASK_LOCATION_DISABLED";
- constructor() {
- super("Received line number filters while `includeTaskLocation` option is disabled");
- }
-}
-class RangeLocationFilterProvidedError extends Error {
- code = "VITEST_RANGE_LOCATION_FILTER_PROVIDED";
- constructor(filter) {
- super(`Found "-" in location filter ${filter}. Note that range location filters are not supported. Consider specifying the exact line numbers of your tests.`);
- }
-}
-class VitestFilteredOutProjectError extends Error {
- code = "VITEST_FILTERED_OUT_PROJECT";
- constructor() {
- super("VITEST_FILTERED_OUT_PROJECT");
- }
-}
-
-const HIGHLIGHT_SUPPORTED_EXTS = new Set(["js", "ts"].flatMap((lang) => [
- `.${lang}`,
- `.m${lang}`,
- `.c${lang}`,
- `.${lang}x`,
- `.m${lang}x`,
- `.c${lang}x`
-]));
-function highlightCode(id, source, colors) {
- const ext = extname(id);
- if (!HIGHLIGHT_SUPPORTED_EXTS.has(ext)) return source;
- return highlight(source, {
- jsx: ext.endsWith("x"),
- colors: c
- });
-}
-
-const PAD = " ";
-const ESC$1 = "\x1B[";
-const ERASE_DOWN = `${ESC$1}J`;
-const ERASE_SCROLLBACK = `${ESC$1}3J`;
-const CURSOR_TO_START = `${ESC$1}1;1H`;
-const HIDE_CURSOR = `${ESC$1}?25l`;
-const SHOW_CURSOR = `${ESC$1}?25h`;
-const CLEAR_SCREEN = "\x1Bc";
-class Logger {
- _clearScreenPending;
- _highlights = /* @__PURE__ */ new Map();
- cleanupListeners = [];
- console;
- constructor(ctx, outputStream = process.stdout, errorStream = process.stderr) {
- this.ctx = ctx;
- this.outputStream = outputStream;
- this.errorStream = errorStream;
- this.console = new Console({
- stdout: outputStream,
- stderr: errorStream
- });
- this._highlights.clear();
- this.addCleanupListeners();
- this.registerUnhandledRejection();
- if (this.outputStream.isTTY) this.outputStream.write(HIDE_CURSOR);
- }
- log(...args) {
- this._clearScreen();
- this.console.log(...args);
- }
- error(...args) {
- this._clearScreen();
- this.console.error(...args);
- }
- warn(...args) {
- this._clearScreen();
- this.console.warn(...args);
- }
- clearFullScreen(message = "") {
- if (!this.ctx.config.clearScreen) {
- this.console.log(message);
- return;
- }
- if (message) this.console.log(`${CLEAR_SCREEN}${ERASE_SCROLLBACK}${message}`);
- else this.outputStream.write(`${CLEAR_SCREEN}${ERASE_SCROLLBACK}`);
- }
- clearScreen(message, force = false) {
- if (!this.ctx.config.clearScreen) {
- this.console.log(message);
- return;
- }
- this._clearScreenPending = message;
- if (force) this._clearScreen();
- }
- _clearScreen() {
- if (this._clearScreenPending == null) return;
- const log = this._clearScreenPending;
- this._clearScreenPending = void 0;
- this.console.log(`${CURSOR_TO_START}${ERASE_DOWN}${log}`);
- }
- printError(err, options = {}) {
- printError(err, this.ctx, this, options);
- }
- deprecate(message) {
- this.error(c.bold(c.bgYellow(" DEPRECATED ")), c.yellow(message));
- }
- clearHighlightCache(filename) {
- if (filename) this._highlights.delete(filename);
- else this._highlights.clear();
- }
- highlight(filename, source) {
- if (this._highlights.has(filename)) return this._highlights.get(filename);
- const code = highlightCode(filename, source);
- this._highlights.set(filename, code);
- return code;
- }
- printNoTestFound(filters) {
- const config = this.ctx.config;
- if (config.watch && (config.changed || config.related?.length)) this.log(`No affected ${config.mode} files found\n`);
- else if (config.watch) this.log(c.red(`No ${config.mode} files found. You can change the file name pattern by pressing "p"\n`));
- else if (config.passWithNoTests) this.log(`No ${config.mode} files found, exiting with code 0\n`);
- else this.error(c.red(`No ${config.mode} files found, exiting with code 1\n`));
- const comma = c.dim(", ");
- if (filters?.length) this.console.error(c.dim("filter: ") + c.yellow(filters.join(comma)));
- const projectsFilter = toArray(config.project);
- if (projectsFilter.length) this.console.error(c.dim("projects: ") + c.yellow(projectsFilter.join(comma)));
- this.ctx.projects.forEach((project) => {
- const config = project.config;
- if (!project.isRootProject() && project.name) this.console.error(`\n${formatProjectName(project)}\n`);
- if (config.include) this.console.error(c.dim("include: ") + c.yellow(config.include.join(comma)));
- if (config.exclude) this.console.error(c.dim("exclude: ") + c.yellow(config.exclude.join(comma)));
- if (config.typecheck.enabled) {
- this.console.error(c.dim("typecheck include: ") + c.yellow(config.typecheck.include.join(comma)));
- this.console.error(c.dim("typecheck exclude: ") + c.yellow(config.typecheck.exclude.join(comma)));
- }
- });
- this.console.error();
- }
- printBanner() {
- this.log();
- const color = this.ctx.config.watch ? "blue" : "cyan";
- const mode = this.ctx.config.watch ? "DEV" : "RUN";
- this.log(withLabel(color, mode, `v${this.ctx.version} `) + c.gray(this.ctx.config.root));
- if (this.ctx.config.sequence.sequencer === RandomSequencer) this.log(PAD + c.gray(`Running tests with seed "${this.ctx.config.sequence.seed}"`));
- if (this.ctx.config.ui) {
- const host = this.ctx.config.api?.host || "localhost";
- const port = this.ctx.vite.config.server.port;
- const base = this.ctx.config.uiBase;
- this.log(PAD + c.dim(c.green(`UI started at http://${host}:${c.bold(port)}${base}`)));
- } else if (this.ctx.config.api?.port) {
- const resolvedUrls = this.ctx.vite.resolvedUrls;
- // workaround for https://github.com/vitejs/vite/issues/15438, it was fixed in vite 5.1
- const fallbackUrl = `http://${this.ctx.config.api.host || "localhost"}:${this.ctx.config.api.port}`;
- const origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0] ?? fallbackUrl;
- this.log(PAD + c.dim(c.green(`API started at ${new URL("/", origin)}`)));
- }
- if (this.ctx.coverageProvider) this.log(PAD + c.dim("Coverage enabled with ") + c.yellow(this.ctx.coverageProvider.name));
- if (this.ctx.config.standalone) this.log(c.yellow(`\nVitest is running in standalone mode. Edit a test file to rerun tests.`));
- else this.log();
- }
- printBrowserBanner(project) {
- if (!project.browser) return;
- const resolvedUrls = project.browser.vite.resolvedUrls;
- const origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0];
- if (!origin) return;
- const output = project.isRootProject() ? "" : formatProjectName(project);
- const provider = project.browser.provider?.name;
- const providerString = provider === "preview" ? "" : ` by ${c.reset(c.bold(provider))}`;
- this.log(c.dim(`${output}Browser runner started${providerString} ${c.dim("at")} ${c.blue(new URL("/__vitest_test__/", origin))}\n`));
- }
- printUnhandledErrors(errors) {
- const errorMessage = c.red(c.bold(`\nVitest caught ${errors.length} unhandled error${errors.length > 1 ? "s" : ""} during the test run.
-This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected.`));
- this.error(errorBanner("Unhandled Errors"));
- this.error(errorMessage);
- errors.forEach((err) => {
- this.printError(err, {
- fullStack: true,
- type: err.type || "Unhandled Error"
- });
- });
- this.error(c.red(divider()));
- }
- printSourceTypeErrors(errors) {
- const errorMessage = c.red(c.bold(`\nVitest found ${errors.length} error${errors.length > 1 ? "s" : ""} not related to your test files.`));
- this.log(errorBanner("Source Errors"));
- this.log(errorMessage);
- errors.forEach((err) => {
- this.printError(err, { fullStack: true });
- });
- this.log(c.red(divider()));
- }
- getColumns() {
- return "columns" in this.outputStream ? this.outputStream.columns : 80;
- }
- onTerminalCleanup(listener) {
- this.cleanupListeners.push(listener);
- }
- addCleanupListeners() {
- const cleanup = () => {
- this.cleanupListeners.forEach((fn) => fn());
- if (this.outputStream.isTTY) this.outputStream.write(SHOW_CURSOR);
- };
- const onExit = (signal, exitCode) => {
- cleanup();
- // Interrupted signals don't set exit code automatically.
- // Use same exit code as node: https://nodejs.org/api/process.html#signal-events
- if (process.exitCode === void 0) process.exitCode = exitCode !== void 0 ? 128 + exitCode : Number(signal);
- // Timeout to flush stderr
- setTimeout(() => process.exit(), 1);
- };
- process.once("SIGINT", onExit);
- process.once("SIGTERM", onExit);
- process.once("exit", onExit);
- this.ctx.onClose(() => {
- process.off("SIGINT", onExit);
- process.off("SIGTERM", onExit);
- process.off("exit", onExit);
- cleanup();
- });
- }
- registerUnhandledRejection() {
- const onUnhandledRejection = (err) => {
- process.exitCode = 1;
- this.printError(err, {
- fullStack: true,
- type: "Unhandled Rejection"
- });
- this.error("\n\n");
- process.exit();
- };
- process.on("unhandledRejection", onUnhandledRejection);
- this.ctx.onClose(() => {
- process.off("unhandledRejection", onUnhandledRejection);
- });
- }
-}
-
-// this function recieves the module diagnostic with the location of imports
-// and populates it with collected import durations; the duration is injected
-// only if the current module is the one that imported the module
-// if testModule is not defined, then Vitest aggregates durations of ALL collected test modules
-function collectModuleDurationsDiagnostic(moduleId, state, moduleDiagnostic, testModule) {
- if (!moduleDiagnostic) return {
- modules: [],
- untrackedModules: []
- };
- const modules = [];
- const modulesById = {};
- const allModules = [...moduleDiagnostic.modules, ...moduleDiagnostic.untracked];
- const visitedByFiles = {};
- // this aggregates the times for _ALL_ tests if testModule is not passed
- // so if the module was imported in separate tests, the time will be accumulated
- for (const files of testModule ? [[testModule.task]] : state.filesMap.values()) for (const file of files) {
- const importDurations = file.importDurations;
- if (!importDurations) continue;
- const currentModule = state.getReportedEntity(file);
- if (!currentModule) continue;
- const visitedKey = currentModule.project.config.isolate === false ? "non-isolate" : file.id;
- if (!visitedByFiles[visitedKey]) visitedByFiles[visitedKey] = /* @__PURE__ */ new Set();
- const visited = visitedByFiles[visitedKey];
- allModules.forEach(({ resolvedId, resolvedUrl }) => {
- const durations = importDurations[resolvedId];
- // do not accumulate if module was already visited by suite (or suites in non-isolate mode)
- if (!durations || visited.has(resolvedId)) return;
- const importer = getModuleImporter(moduleId, durations, currentModule);
- modulesById[resolvedId] ??= {
- selfTime: 0,
- totalTime: 0,
- transformTime: 0,
- external: durations.external,
- importer
- };
- // only track if the current module imported this module,
- // otherwise it was imported instantly because it's cached
- if (importer === moduleId) {
- visited.add(resolvedId);
- modulesById[resolvedId].selfTime += durations.selfTime;
- modulesById[resolvedId].totalTime += durations.totalTime;
- // don't aggregate
- modulesById[resolvedId].transformTime = state.metadata[currentModule.project.name]?.duration[resolvedUrl]?.[0];
- }
- });
- }
- // if module was imported twice in the same file,
- // show only one time - the second should be shown as 0
- const visitedInFile = /* @__PURE__ */ new Set();
- moduleDiagnostic.modules.forEach((diagnostic) => {
- const durations = modulesById[diagnostic.resolvedId];
- if (!durations) return;
- if (visitedInFile.has(diagnostic.resolvedId)) modules.push({
- ...diagnostic,
- selfTime: 0,
- totalTime: 0,
- transformTime: 0,
- external: durations.external,
- importer: durations.importer
- });
- else {
- visitedInFile.add(diagnostic.resolvedId);
- modules.push({
- ...diagnostic,
- ...durations
- });
- }
- });
- const untracked = [];
- moduleDiagnostic.untracked.forEach((diagnostic) => {
- const durations = modulesById[diagnostic.resolvedId];
- if (!durations) return;
- if (visitedInFile.has(diagnostic.resolvedId)) untracked.push({
- selfTime: 0,
- totalTime: 0,
- transformTime: 0,
- external: durations.external,
- importer: durations.importer,
- resolvedId: diagnostic.resolvedId,
- resolvedUrl: diagnostic.resolvedUrl,
- url: diagnostic.rawUrl
- });
- else {
- visitedInFile.add(diagnostic.resolvedId);
- untracked.push({
- ...durations,
- resolvedId: diagnostic.resolvedId,
- resolvedUrl: diagnostic.resolvedUrl,
- url: diagnostic.rawUrl
- });
- }
- });
- return {
- modules,
- untrackedModules: untracked
- };
-}
-function getModuleImporter(moduleId, durations, testModule) {
- if (durations.importer === moduleId) return moduleId;
- if (!durations.importer) {
- if (moduleId === testModule.moduleId) return testModule.moduleId;
- return testModule.project.config.setupFiles.includes(moduleId) ? moduleId : durations.importer;
- }
- return durations.importer;
-}
-// the idea of this is very simple
-// it parses the source code to extract import/export statements
-// it parses SSR transformed file to extract __vite_ssr_import__ and __vite_ssr_dynamic_import__
-// it combines the two by looking at the original positions of SSR primitives
-// in the end, we are able to return a list of modules that were imported by this module
-// mapped to their IDs in Vite's module graph
-async function collectSourceModulesLocations(moduleId, moduleGraph) {
- const transformResult = moduleGraph.getModuleById(moduleId)?.transformResult;
- if (!transformResult || !transformResult.ssr) return;
- const map = transformResult.map;
- if (!map || !("version" in map) || !map.sources.length) return;
- const sourceImports = map.sources.reduce((acc, sourceId, index) => {
- const source = map.sourcesContent?.[index];
- if (source != null) acc[sourceId] = parseSourceImportsAndExports(source);
- return acc;
- }, {});
- const transformImports = await parseTransformResult(moduleGraph, transformResult);
- const traceMap = map && "version" in map && new TraceMap(map);
- const modules = {};
- const untracked = [];
- transformImports.forEach((row) => {
- const original = traceMap && originalPositionFor(traceMap, row.start);
- if (original && original.source != null) {
- // if there are several at the same position, this is a bug
- // probably caused by import.meta.glob imports returning incorrect positions
- // all the new import.meta.glob imports come first, so only the last module on this line is correct
- const sourceImport = sourceImports[original.source].get(`${original.line}:${original.column}`);
- if (sourceImport) {
- if (modules[sourceImport.rawUrl]) {
- // remove imports with a different resolvedId
- const differentImports = modules[sourceImport.rawUrl].filter((d) => d.resolvedId !== row.resolvedId);
- untracked.push(...differentImports);
- modules[sourceImport.rawUrl] = modules[sourceImport.rawUrl].filter((d) => d.resolvedId === row.resolvedId);
- }
- modules[sourceImport.rawUrl] ??= [];
- modules[sourceImport.rawUrl].push({
- start: sourceImport.start,
- end: sourceImport.end,
- startIndex: sourceImport.startIndex,
- endIndex: sourceImport.endIndex,
- rawUrl: sourceImport.rawUrl,
- resolvedId: row.resolvedId,
- resolvedUrl: row.resolvedUrl
- });
- }
- }
- });
- return {
- modules: Object.values(modules).flat(),
- untracked
- };
-}
-function fillSourcesMap(syntax, sourcesMap, source, indexMap) {
- const splitSeparator = `${syntax} `;
- const splitSources = source.split(splitSeparator);
- const chunks = [];
- let index = 0;
- for (const chunk of splitSources) {
- chunks.push({
- chunk,
- startIndex: index
- });
- index += chunk.length + splitSeparator.length;
- }
- chunks.forEach(({ chunk, startIndex }) => {
- const normalized = chunk.replace(/'/g, "\"");
- const startQuoteIdx = normalized.indexOf("\"");
- if (startQuoteIdx === -1) return;
- const endQuoteIdx = normalized.indexOf("\"", startQuoteIdx + 1);
- if (endQuoteIdx === -1) return;
- const staticSyntax = {
- startIndex: startIndex + startQuoteIdx,
- endIndex: startIndex + endQuoteIdx + 1,
- start: indexMap.get(startIndex + startQuoteIdx),
- end: indexMap.get(startIndex + endQuoteIdx + 1),
- rawUrl: normalized.slice(startQuoteIdx + 1, endQuoteIdx)
- };
- // -7 to include "import "
- for (let i = startIndex - 7; i < staticSyntax.endIndex; i++) {
- const location = indexMap.get(i);
- if (location) sourcesMap.set(`${location.line}:${location.column}`, staticSyntax);
- }
- });
-}
-// this function tries to parse ESM static import and export statements from
-// the source. if the source is not JS/TS, but supports static ESM syntax,
-// then this will also find them because it' only checks the strings, it doesn't parse the AST
-function parseSourceImportsAndExports(source) {
- if (!source.includes("import ") && !source.includes("export ")) return /* @__PURE__ */ new Map();
- const sourcesMap = /* @__PURE__ */ new Map();
- const indexMap = createIndexLocationsMap(source);
- fillSourcesMap("import", sourcesMap, source, indexMap);
- fillSourcesMap("export", sourcesMap, source, indexMap);
- return sourcesMap;
-}
-async function parseTransformResult(moduleGraph, transformResult) {
- const code = transformResult.code;
- const regexp = /(?:__vite_ssr_import__|__vite_ssr_dynamic_import__)\("([^"]+)"/g;
- const lineColumnMap = createIndexLocationsMap(code);
- const importPositions = [];
- let match;
- // eslint-disable-next-line no-cond-assign
- while (match = regexp.exec(code)) {
- const startIndex = match.index;
- const endIndex = match.index + match[0].length - 1;
- importPositions.push({
- raw: match[1],
- startIndex,
- endIndex
- });
- }
- return (await Promise.all(importPositions.map(async ({ startIndex, endIndex, raw }) => {
- const position = lineColumnMap.get(startIndex);
- const endPosition = lineColumnMap.get(endIndex);
- const moduleNode = await moduleGraph.getModuleByUrl(raw);
- if (!position || !endPosition || !moduleNode || !moduleNode.id) return;
- return {
- resolvedId: moduleNode.id,
- resolvedUrl: moduleNode.url,
- start: position,
- end: endPosition,
- startIndex,
- endIndex
- };
- }))).filter((n) => n != null);
-}
-
-const __dirname$1 = url.fileURLToPath(new URL(".", import.meta.url));
-class VitestPackageInstaller {
- isPackageExists(name, options) {
- return isPackageExists(name, options);
- }
- async ensureInstalled(dependency, root, version) {
- if (process.env.VITEST_SKIP_INSTALL_CHECKS) return true;
- if (process.versions.pnp) {
- const targetRequire = createRequire(__dirname$1);
- try {
- targetRequire.resolve(dependency, { paths: [root, __dirname$1] });
- return true;
- } catch {}
- }
- if (/* @__PURE__ */ isPackageExists(dependency, { paths: [root, __dirname$1] })) return true;
- process.stderr.write(c.red(`${c.inverse(c.red(" MISSING DEPENDENCY "))} Cannot find dependency '${dependency}'\n\n`));
- if (!isTTY) return false;
- const { install } = await (await import('./index.D4KonVSU.js').then(function (n) { return n.i; })).default({
- type: "confirm",
- name: "install",
- message: c.reset(`Do you want to install ${c.green(dependency)}?`)
- });
- if (install) {
- const packageName = version ? `${dependency}@${version}` : dependency;
- await (await import('./index.D3XRDfWc.js')).installPackage(packageName, { dev: true });
- // TODO: somehow it fails to load the package after installation, remove this when it's fixed
- process.stderr.write(c.yellow(`\nPackage ${packageName} installed, re-run the command to start.\n`));
- process.exit();
- return true;
- }
- return false;
- }
-}
-
-function getDefaultThreadsCount(config) {
- const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length;
- return config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1);
-}
-function getWorkerMemoryLimit(config) {
- if (config.vmMemoryLimit) return config.vmMemoryLimit;
- return 1 / (config.maxWorkers ?? getDefaultThreadsCount(config));
-}
-/**
-* Converts a string representing an amount of memory to bytes.
-*
-* @param input The value to convert to bytes.
-* @param percentageReference The reference value to use when a '%' value is supplied.
-*/
-function stringToBytes(input, percentageReference) {
- if (input === null || input === void 0) return input;
- if (typeof input === "string") if (Number.isNaN(Number.parseFloat(input.slice(-1)))) {
- let [, numericString, trailingChars] = input.match(/(.*?)([^0-9.-]+)$/) || [];
- if (trailingChars && numericString) {
- const numericValue = Number.parseFloat(numericString);
- trailingChars = trailingChars.toLowerCase();
- switch (trailingChars) {
- case "%":
- input = numericValue / 100;
- break;
- case "kb":
- case "k": return numericValue * 1e3;
- case "kib": return numericValue * 1024;
- case "mb":
- case "m": return numericValue * 1e3 * 1e3;
- case "mib": return numericValue * 1024 * 1024;
- case "gb":
- case "g": return numericValue * 1e3 * 1e3 * 1e3;
- case "gib": return numericValue * 1024 * 1024 * 1024;
- }
- }
- } else input = Number.parseFloat(input);
- if (typeof input === "number") if (input <= 1 && input > 0) if (percentageReference) return Math.floor(input * percentageReference);
- else throw new Error("For a percentage based memory limit a percentageReference must be supplied");
- else if (input > 1) return Math.floor(input);
- else throw new Error("Unexpected numerical input for \"memoryLimit\"");
- return null;
-}
-
-async function getSpecificationsEnvironments(specifications) {
- const environments = /* @__PURE__ */ new WeakMap();
- const cache = /* @__PURE__ */ new Map();
- await Promise.all(specifications.map(async (spec) => {
- const { moduleId: filepath, project } = spec;
- // reuse if projects have the same test files
- let code = cache.get(filepath);
- if (!code) {
- code = await promises.readFile(filepath, "utf-8");
- cache.set(filepath, code);
- }
- // 1. Check for control comments in the file
- let env = code.match(/@(?:vitest|jest)-environment\s+([\w-]+)\b/)?.[1];
- // 2. Fallback to global env
- env ||= project.config.environment || "node";
- let envOptionsJson = code.match(/@(?:vitest|jest)-environment-options\s+(.+)/)?.[1];
- if (envOptionsJson?.endsWith("*/"))
- // Trim closing Docblock characters the above regex might have captured
- envOptionsJson = envOptionsJson.slice(0, -2);
- const envOptions = JSON.parse(envOptionsJson || "null");
- const environment = {
- name: env,
- options: envOptions ? { [env === "happy-dom" ? "happyDOM" : env]: envOptions } : null
- };
- environments.set(spec, environment);
- }));
- return environments;
-}
-
-const debug = createDebugger("vitest:browser:pool");
-function createBrowserPool(vitest) {
- const providers = /* @__PURE__ */ new Set();
- const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length;
- // if there are more than ~12 threads (optimistically), the main thread chokes
- // https://github.com/vitest-dev/vitest/issues/7871
- const maxThreadsCount = Math.min(12, numCpus - 1);
- const threadsCount = vitest.config.watch ? Math.max(Math.floor(maxThreadsCount / 2), 1) : Math.max(maxThreadsCount, 1);
- const projectPools = /* @__PURE__ */ new WeakMap();
- const ensurePool = (project) => {
- if (projectPools.has(project)) return projectPools.get(project);
- debug?.("creating pool for project %s", project.name);
- const resolvedUrls = project.browser.vite.resolvedUrls;
- const origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0];
- if (!origin) throw new Error(`Can't find browser origin URL for project "${project.name}"`);
- const pool = new BrowserPool(project, {
- maxWorkers: getThreadsCount(project),
- origin
- });
- projectPools.set(project, pool);
- vitest.onCancel(() => {
- pool.cancel();
- });
- return pool;
- };
- const runWorkspaceTests = async (method, specs) => {
- const groupedFiles = /* @__PURE__ */ new Map();
- for (const { project, moduleId, testLines } of specs) {
- const files = groupedFiles.get(project) || [];
- files.push({
- filepath: moduleId,
- testLocations: testLines
- });
- groupedFiles.set(project, files);
- }
- let isCancelled = false;
- vitest.onCancel(() => {
- isCancelled = true;
- });
- const initialisedPools = await Promise.all([...groupedFiles.entries()].map(async ([project, files]) => {
- await project._initBrowserProvider();
- if (!project.browser) throw new TypeError(`The browser server was not initialized${project.name ? ` for the "${project.name}" project` : ""}. This is a bug in Vitest. Please, open a new issue with reproduction.`);
- if (isCancelled) return;
- debug?.("provider is ready for %s project", project.name);
- const pool = ensurePool(project);
- vitest.state.clearFiles(project, files.map((f) => f.filepath));
- providers.add(project.browser.provider);
- return {
- pool,
- provider: project.browser.provider,
- runTests: () => pool.runTests(method, files)
- };
- }));
- if (isCancelled) return;
- const parallelPools = [];
- const nonParallelPools = [];
- for (const pool of initialisedPools) {
- if (!pool)
- // this means it was cancelled
- return;
- if (pool.provider.mocker && pool.provider.supportsParallelism) parallelPools.push(pool.runTests);
- else nonParallelPools.push(pool.runTests);
- }
- await Promise.all(parallelPools.map((runTests) => runTests()));
- for (const runTests of nonParallelPools) {
- if (isCancelled) return;
- await runTests();
- }
- };
- function getThreadsCount(project) {
- const config = project.config.browser;
- if (!config.headless || !config.fileParallelism || !project.browser.provider.supportsParallelism) return 1;
- if (project.config.maxWorkers) return project.config.maxWorkers;
- return threadsCount;
- }
- return {
- name: "browser",
- async close() {
- await Promise.all([...providers].map((provider) => provider.close()));
- vitest._browserSessions.sessionIds.clear();
- providers.clear();
- vitest.projects.forEach((project) => {
- project.browser?.state.orchestrators.forEach((orchestrator) => {
- orchestrator.$close();
- });
- });
- debug?.("browser pool closed all providers");
- },
- runTests: (files) => runWorkspaceTests("run", files),
- collectTests: (files) => runWorkspaceTests("collect", files)
- };
-}
-function escapePathToRegexp(path) {
- return path.replace(/[/\\.?*()^${}|[\]+]/g, "\\$&");
-}
-class BrowserPool {
- _queue = [];
- _promise;
- _providedContext;
- readySessions = /* @__PURE__ */ new Set();
- _traces;
- _otel;
- constructor(project, options) {
- this.project = project;
- this.options = options;
- this._traces = project.vitest._traces;
- this._otel = this._traces.startContextSpan("vitest.browser");
- this._otel.span.setAttributes({
- "vitest.project": project.name,
- "vitest.browser.provider": this.project.browser.provider.name
- });
- }
- cancel() {
- this._queue = [];
- this._otel.span.end();
- }
- reject(error) {
- this._promise?.reject(error);
- this._promise = void 0;
- this.cancel();
- }
- get orchestrators() {
- return this.project.browser.state.orchestrators;
- }
- async runTests(method, files) {
- this._promise ??= createDefer();
- if (!files.length) {
- debug?.("no tests found, finishing test run immediately");
- this._promise.resolve();
- return this._promise;
- }
- this._providedContext = stringify(this.project.getProvidedContext());
- this._queue.push(...files);
- this.readySessions.forEach((sessionId) => {
- if (this._queue.length) {
- this.readySessions.delete(sessionId);
- this.runNextTest(method, sessionId);
- }
- });
- if (this.orchestrators.size >= this.options.maxWorkers) {
- debug?.("all orchestrators are ready, not creating more");
- return this._promise;
- }
- // open the minimum amount of tabs
- // if there is only 1 file running, we don't need 8 tabs running
- const workerCount = Math.min(this.options.maxWorkers - this.orchestrators.size, files.length);
- const promises = [];
- for (let i = 0; i < workerCount; i++) {
- const sessionId = crypto.randomUUID();
- this.project.vitest._browserSessions.sessionIds.add(sessionId);
- const project = this.project.name;
- debug?.("[%s] creating session for %s", sessionId, project);
- let page = this._traces.$(`vitest.browser.open`, {
- context: this._otel.context,
- attributes: { "vitest.browser.session_id": sessionId }
- }, () => this.openPage(sessionId));
- page = page.then(() => {
- // start running tests on the page when it's ready
- this.runNextTest(method, sessionId);
- });
- promises.push(page);
- }
- await Promise.all(promises);
- debug?.("all sessions are created");
- return this._promise;
- }
- async openPage(sessionId) {
- const sessionPromise = this.project.vitest._browserSessions.createSession(sessionId, this.project, this);
- const browser = this.project.browser;
- const url = new URL("/__vitest_test__/", this.options.origin);
- url.searchParams.set("sessionId", sessionId);
- const otelCarrier = this._traces.getContextCarrier();
- if (otelCarrier) url.searchParams.set("otelCarrier", JSON.stringify(otelCarrier));
- const pagePromise = browser.provider.openPage(sessionId, url.toString());
- await Promise.all([sessionPromise, pagePromise]);
- }
- getOrchestrator(sessionId) {
- const orchestrator = this.orchestrators.get(sessionId);
- if (!orchestrator) throw new Error(`Orchestrator not found for session ${sessionId}. This is a bug in Vitest. Please, open a new issue with reproduction.`);
- return orchestrator;
- }
- finishSession(sessionId) {
- this.readySessions.add(sessionId);
- // the last worker finished running tests
- if (this.readySessions.size === this.orchestrators.size) {
- this._otel.span.end();
- this._promise?.resolve();
- this._promise = void 0;
- debug?.("[%s] all tests finished running", sessionId);
- } else debug?.(`did not finish sessions for ${sessionId}: |ready - %s| |overall - %s|`, [...this.readySessions].join(", "), [...this.orchestrators.keys()].join(", "));
- }
- runNextTest(method, sessionId) {
- const file = this._queue.shift();
- if (!file) {
- debug?.("[%s] no more tests to run", sessionId);
- // we don't need to cleanup testers if isolation is enabled,
- // because cleanup is done at the end of every test
- if (this.project.config.browser.isolate) {
- this.finishSession(sessionId);
- return;
- }
- this.getOrchestrator(sessionId).cleanupTesters().catch((error) => this.reject(error)).finally(() => this.finishSession(sessionId));
- return;
- }
- if (!this._promise) throw new Error(`Unexpected empty queue`);
- const orchestrator = this.getOrchestrator(sessionId);
- debug?.("[%s] run test %s", sessionId, file);
- this.setBreakpoint(sessionId, file.filepath).then(() => {
- this._traces.$(`vitest.browser.run`, {
- context: this._otel.context,
- attributes: { "code.file.path": file.filepath }
- }, async () => {
- return orchestrator.createTesters({
- method,
- files: [file],
- providedContext: this._providedContext || "[{}]",
- otelCarrier: this._traces.getContextCarrier()
- });
- }).then(() => {
- debug?.("[%s] test %s finished running", sessionId, file);
- this.runNextTest(method, sessionId);
- }).catch((error) => {
- // if user cancels the test run manually, ignore the error and exit gracefully
- if (this.project.vitest.isCancelling && error instanceof Error && error.message.startsWith("Browser connection was closed while running tests")) {
- this.cancel();
- this._promise?.resolve();
- this._promise = void 0;
- debug?.("[%s] browser connection was closed", sessionId);
- return;
- }
- debug?.("[%s] error during %s test run: %s", sessionId, file, error);
- this.reject(new Error(`Failed to run the test ${file.filepath}.`, { cause: error }));
- });
- }).catch((err) => this.reject(err));
- }
- async setBreakpoint(sessionId, file) {
- if (!this.project.config.inspector.waitForDebugger) return;
- const provider = this.project.browser.provider;
- const browser = this.project.config.browser.name;
- if (shouldIgnoreDebugger(provider.name, browser)) {
- debug?.("[$s] ignoring debugger in %s browser because it is not supported", sessionId, browser);
- return;
- }
- if (!provider.getCDPSession) throw new Error("Unable to set breakpoint, CDP not supported");
- debug?.("[%s] set breakpoint for %s", sessionId, file);
- const session = await provider.getCDPSession(sessionId);
- await session.send("Debugger.enable", {});
- await session.send("Debugger.setBreakpointByUrl", {
- lineNumber: 0,
- urlRegex: escapePathToRegexp(file)
- });
- }
-}
-function shouldIgnoreDebugger(provider, browser) {
- if (provider === "webdriverio") return browser !== "chrome" && browser !== "edge";
- return browser !== "chromium";
-}
-
-function createMethodsRPC(project, methodsOptions = {}) {
- const vitest = project.vitest;
- const cacheFs = methodsOptions.cacheFs ?? false;
- project.vitest.state.metadata[project.name] ??= {
- externalized: {},
- duration: {},
- tmps: {}
- };
- if (project.config.dumpDir && !existsSync(project.config.dumpDir)) mkdirSync(project.config.dumpDir, { recursive: true });
- project.vitest.state.metadata[project.name].dumpDir = project.config.dumpDir;
- return {
- async fetch(url, importer, environmentName, options, otelCarrier) {
- const environment = project.vite.environments[environmentName];
- if (!environment) throw new Error(`The environment ${environmentName} was not defined in the Vite config.`);
- const start = performance.now();
- return await project._fetcher(url, importer, environment, cacheFs, options, otelCarrier).then((result) => {
- const duration = performance.now() - start;
- project.vitest.state.transformTime += duration;
- const metadata = project.vitest.state.metadata[project.name];
- if ("externalize" in result) metadata.externalized[url] = result.externalize;
- if ("tmp" in result) metadata.tmps[url] = result.tmp;
- metadata.duration[url] ??= [];
- metadata.duration[url].push(duration);
- return result;
- });
- },
- async resolve(id, importer, environmentName) {
- const environment = project.vite.environments[environmentName];
- if (!environment) throw new Error(`The environment ${environmentName} was not defined in the Vite config.`);
- const resolved = await environment.pluginContainer.resolveId(id, importer);
- if (!resolved) return null;
- const file = cleanUrl(resolved.id);
- if (resolved.external) return {
- file,
- url: isBuiltin(resolved.id) ? toBuiltin(resolved.id) : resolved.id,
- id: resolved.id
- };
- return {
- file: cleanUrl(resolved.id),
- url: normalizeResolvedIdToUrl(environment, resolved.id),
- id: resolved.id
- };
- },
- snapshotSaved(snapshot) {
- vitest.snapshot.add(snapshot);
- },
- resolveSnapshotPath(testPath) {
- return vitest.snapshot.resolvePath(testPath, { config: project.serializedConfig });
- },
- async transform(id) {
- const environment = project.vite.environments.__vitest_vm__;
- if (!environment) throw new Error(`The VM environment was not defined in the Vite config. This is a bug in Vitest. Please, open a new issue with reproduction.`);
- const url = normalizeResolvedIdToUrl(environment, fileURLToPath(id));
- return { code: (await environment.transformRequest(url).catch(handleRollupError))?.code };
- },
- async onQueued(file) {
- if (methodsOptions.collect) vitest.state.collectFiles(project, [file]);
- else await vitest._testRun.enqueued(project, file);
- },
- async onCollected(files) {
- if (methodsOptions.collect) vitest.state.collectFiles(project, files);
- else await vitest._testRun.collected(project, files);
- },
- onAfterSuiteRun(meta) {
- vitest.coverageProvider?.onAfterSuiteRun(meta);
- },
- async onTaskArtifactRecord(testId, artifact) {
- return vitest._testRun.recordArtifact(testId, artifact);
- },
- async onTaskUpdate(packs, events) {
- if (methodsOptions.collect) vitest.state.updateTasks(packs);
- else await vitest._testRun.updated(packs, events);
- },
- async onUserConsoleLog(log) {
- if (methodsOptions.collect) vitest.state.updateUserLog(log);
- else await vitest._testRun.log(log);
- },
- onUnhandledError(err, type) {
- vitest.state.catchError(err, type);
- },
- onCancel(reason) {
- vitest.cancelCurrentRun(reason);
- },
- getCountOfFailedTests() {
- return vitest.state.getCountOfFailedTests();
- }
- };
-}
-
-var RunnerState = /* @__PURE__ */ function(RunnerState) {
- RunnerState["IDLE"] = "idle";
- RunnerState["STARTING"] = "starting";
- RunnerState["STARTED"] = "started";
- RunnerState["START_FAILURE"] = "start_failure";
- RunnerState["STOPPING"] = "stopping";
- RunnerState["STOPPED"] = "stopped";
- return RunnerState;
-}(RunnerState || {});
-const START_TIMEOUT = 6e4;
-const STOP_TIMEOUT = 6e4;
-/** @experimental */
-class PoolRunner {
- /** Exposed to test runner as `VITEST_POOL_ID`. Value is between 1-`maxWorkers`. */
- poolId = void 0;
- project;
- environment;
- _state = RunnerState.IDLE;
- _operationLock = null;
- _terminatePromise = createDefer();
- _eventEmitter = new EventEmitter();
- _offCancel;
- _rpc;
- _otel = null;
- _traces;
- get isTerminated() {
- return this._state === RunnerState.STOPPED;
- }
- waitForTerminated() {
- return this._terminatePromise;
- }
- get isStarted() {
- return this._state === RunnerState.STARTED;
- }
- constructor(options, worker) {
- this.worker = worker;
- this.project = options.project;
- this.environment = options.environment;
- const vitest = this.project.vitest;
- this._traces = vitest._traces;
- if (this._traces.isEnabled()) {
- const { span: workerSpan, context } = this._traces.startContextSpan("vitest.worker");
- this._otel = {
- span: workerSpan,
- workerContext: context,
- files: []
- };
- this._otel.span.setAttributes({
- "vitest.worker.name": this.worker.name,
- "vitest.project": this.project.name,
- "vitest.environment": this.environment.name
- });
- }
- this._rpc = createBirpc(createMethodsRPC(this.project, {
- collect: options.method === "collect",
- cacheFs: worker.cacheFs
- }), {
- eventNames: ["onCancel"],
- post: (request) => {
- if (this._state !== RunnerState.STOPPING && this._state !== RunnerState.STOPPED) this.postMessage(request);
- },
- on: (callback) => this._eventEmitter.on("rpc", callback),
- timeout: -1
- });
- this._offCancel = vitest.onCancel((reason) => this._rpc.onCancel(reason));
- }
- /**
- * "reconfigure" can only be called if `environment` is different, since different project always
- * requires a new PoolRunner instance.
- */
- reconfigure(task) {
- this.environment = task.context.environment;
- this._otel?.span.setAttribute("vitest.environment", this.environment.name);
- }
- postMessage(message) {
- // Only send messages when runner is active (not fully stopped)
- // Allow sending during STOPPING state for the 'stop' message itself
- if (this._state !== RunnerState.STOPPED) return this.worker.send(message);
- }
- startTracesSpan(name) {
- const traces = this._traces;
- if (!this._otel) return traces.startSpan(name);
- const { span, context } = traces.startContextSpan(name, this._otel.workerContext);
- this._otel.currentContext = context;
- const end = span.end.bind(span);
- span.end = (endTime) => {
- this._otel.currentContext = void 0;
- return end(endTime);
- };
- return span;
- }
- request(method, context) {
- this._otel?.files.push(...context.files.map((f) => f.filepath));
- return this.postMessage({
- __vitest_worker_request__: true,
- type: method,
- context,
- otelCarrier: this.getOTELCarrier()
- });
- }
- getOTELCarrier() {
- const activeContext = this._otel?.currentContext || this._otel?.workerContext;
- return activeContext ? this._traces.getContextCarrier(activeContext) : void 0;
- }
- async start(options) {
- // Wait for any ongoing operation to complete
- if (this._operationLock) await this._operationLock;
- if (this._state === RunnerState.STARTED || this._state === RunnerState.STARTING) return;
- if (this._state === RunnerState.STOPPED) throw new Error("[vitest-pool-runner]: Cannot start a stopped runner");
- // Create operation lock to prevent concurrent start/stop
- this._operationLock = createDefer();
- let startSpan;
- try {
- this._state = RunnerState.STARTING;
- await this._traces.$(`vitest.${this.worker.name}.start`, { context: this._otel?.workerContext }, () => this.worker.start());
- // Attach event listeners AFTER starting worker to avoid issues
- // if worker.start() fails
- this.worker.on("error", this.emitWorkerError);
- this.worker.on("exit", this.emitUnexpectedExit);
- this.worker.on("message", this.emitWorkerMessage);
- startSpan = this.startTracesSpan("vitest.worker.start");
- const startPromise = this.withTimeout(this.waitForStart(), START_TIMEOUT);
- const globalConfig = this.project.vitest.config.experimental.openTelemetry;
- const projectConfig = this.project.config.experimental.openTelemetry;
- const tracesEnabled = projectConfig?.enabled ?? globalConfig?.enabled === true;
- const tracesSdk = projectConfig?.sdkPath ?? globalConfig?.sdkPath;
- this.postMessage({
- type: "start",
- poolId: this.poolId,
- workerId: options.workerId,
- __vitest_worker_request__: true,
- options: { reportMemory: this.worker.reportMemory ?? false },
- context: {
- environment: {
- name: this.environment.name,
- options: this.environment.options
- },
- config: this.project.serializedConfig,
- pool: this.worker.name
- },
- traces: {
- enabled: tracesEnabled,
- sdkPath: tracesSdk,
- otelCarrier: this.getOTELCarrier()
- }
- });
- await startPromise;
- this._state = RunnerState.STARTED;
- } catch (error) {
- this._state = RunnerState.START_FAILURE;
- startSpan?.recordException(error);
- throw error;
- } finally {
- startSpan?.end();
- this._operationLock.resolve();
- this._operationLock = null;
- }
- }
- async stop(options) {
- // Wait for any ongoing operation to complete
- if (this._operationLock) await this._operationLock;
- if (this._state === RunnerState.STOPPED || this._state === RunnerState.STOPPING) return;
- this._otel?.span.setAttribute("vitest.worker.files", this._otel.files);
- if (this._state === RunnerState.IDLE) {
- this._otel?.span.end();
- this._state = RunnerState.STOPPED;
- return;
- }
- // Create operation lock to prevent concurrent start/stop
- this._operationLock = createDefer();
- try {
- this._state = RunnerState.STOPPING;
- // Remove exit listener early to avoid "unexpected exit" errors during shutdown
- this.worker.off("exit", this.emitUnexpectedExit);
- const stopSpan = this.startTracesSpan("vitest.worker.stop");
- await this.withTimeout(new Promise((resolve) => {
- const onStop = (response) => {
- if (response.type === "stopped") {
- if (response.error) {
- stopSpan.recordException(response.error);
- this.project.vitest.state.catchError(response.error, "Teardown Error");
- }
- resolve();
- this.off("message", onStop);
- }
- };
- // Don't wait for graceful exit's response when force exiting
- if (options?.force) return onStop({
- type: "stopped",
- __vitest_worker_response__: true
- });
- this.on("message", onStop);
- this.postMessage({
- type: "stop",
- __vitest_worker_request__: true,
- otelCarrier: this.getOTELCarrier()
- });
- }), STOP_TIMEOUT).finally(() => {
- stopSpan.end();
- });
- this._eventEmitter.removeAllListeners();
- this._offCancel();
- this._rpc.$close(/* @__PURE__ */ new Error("[vitest-pool-runner]: Pending methods while closing rpc"));
- // Stop the worker process (this sets _fork/_thread to undefined)
- // Worker's event listeners (error, message) are implicitly removed when worker terminates
- await this._traces.$(`vitest.${this.worker.name}.stop`, { context: this._otel?.workerContext }, () => this.worker.stop());
- this._state = RunnerState.STOPPED;
- } catch (error) {
- // Ensure we transition to stopped state even on error
- this._state = RunnerState.STOPPED;
- throw error;
- } finally {
- this._operationLock.resolve();
- this._operationLock = null;
- this._otel?.span.end();
- this._terminatePromise.resolve();
- }
- }
- on(event, callback) {
- this._eventEmitter.on(event, callback);
- }
- off(event, callback) {
- this._eventEmitter.off(event, callback);
- }
- emitWorkerError = (maybeError) => {
- const error = maybeError instanceof Error ? maybeError : new Error(String(maybeError));
- this._eventEmitter.emit("error", error);
- };
- emitWorkerMessage = (response) => {
- try {
- const message = this.worker.deserialize(response);
- if (typeof message === "object" && message != null && message.__vitest_worker_response__) this._eventEmitter.emit("message", message);
- else this._eventEmitter.emit("rpc", message);
- } catch (error) {
- this._eventEmitter.emit("error", error);
- }
- };
- emitUnexpectedExit = () => {
- const error = /* @__PURE__ */ new Error("Worker exited unexpectedly");
- this._eventEmitter.emit("error", error);
- };
- waitForStart() {
- return new Promise((resolve, reject) => {
- const onStart = (message) => {
- if (message.type === "started") {
- this.off("message", onStart);
- if (message.error) reject(message.error);
- else resolve();
- }
- };
- this.on("message", onStart);
- });
- }
- withTimeout(promise, timeout) {
- return new Promise((resolve_, reject_) => {
- const timer = setTimeout(() => reject(/* @__PURE__ */ new Error("[vitest-pool-runner]: Timeout waiting for worker to respond")), timeout);
- function resolve(value) {
- clearTimeout(timer);
- resolve_(value);
- }
- function reject(error) {
- clearTimeout(timer);
- reject_(error);
- }
- promise.then(resolve, reject);
- });
- }
-}
-
-const SIGKILL_TIMEOUT = 500;
-/** @experimental */
-class ForksPoolWorker {
- name = "forks";
- cacheFs = true;
- entrypoint;
- execArgv;
- env;
- _fork;
- stdout;
- stderr;
- constructor(options) {
- this.execArgv = options.execArgv;
- this.env = options.env;
- this.stdout = options.project.vitest.logger.outputStream;
- this.stderr = options.project.vitest.logger.errorStream;
- /** Loads {@link file://./../../../runtime/workers/forks.ts} */
- this.entrypoint = resolve$1(options.distPath, "workers/forks.js");
- }
- on(event, callback) {
- this.fork.on(event, callback);
- }
- off(event, callback) {
- this.fork.off(event, callback);
- }
- send(message) {
- this.fork.send(message);
- }
- async start() {
- this._fork ||= fork(this.entrypoint, [], {
- env: this.env,
- execArgv: this.execArgv,
- stdio: "pipe",
- serialization: "advanced"
- });
- if (this._fork.stdout) {
- this.stdout.setMaxListeners(1 + this.stdout.getMaxListeners());
- this._fork.stdout.pipe(this.stdout);
- }
- if (this._fork.stderr) {
- this.stderr.setMaxListeners(1 + this.stderr.getMaxListeners());
- this._fork.stderr.pipe(this.stderr);
- }
- }
- async stop() {
- const fork = this.fork;
- const waitForExit = new Promise((resolve) => {
- if (fork.exitCode != null) resolve();
- else fork.once("exit", resolve);
- });
- /*
- * If process running user's code does not stop on SIGTERM, send SIGKILL.
- * This is similar to
- * - https://github.com/jestjs/jest/blob/25a8785584c9d54a05887001ee7f498d489a5441/packages/jest-worker/src/workers/ChildProcessWorker.ts#L463-L477
- * - https://github.com/tinylibs/tinypool/blob/40b4b3eb926dabfbfd3d0a7e3d1222d4dd1c0d2d/src/runtime/process-worker.ts#L56
- */
- const sigkillTimeout = setTimeout(() => fork.kill("SIGKILL"), SIGKILL_TIMEOUT);
- fork.kill();
- await waitForExit;
- clearTimeout(sigkillTimeout);
- if (fork.stdout) {
- fork.stdout?.unpipe(this.stdout);
- this.stdout.setMaxListeners(this.stdout.getMaxListeners() - 1);
- }
- if (fork.stderr) {
- fork.stderr?.unpipe(this.stderr);
- this.stderr.setMaxListeners(this.stderr.getMaxListeners() - 1);
- }
- this._fork = void 0;
- }
- deserialize(data) {
- return data;
- }
- get fork() {
- if (!this._fork) throw new Error(`The child process was torn down or never initialized. This is a bug in Vitest.`);
- return this._fork;
- }
-}
-
-/** @experimental */
-class ThreadsPoolWorker {
- name = "threads";
- entrypoint;
- execArgv;
- env;
- _thread;
- stdout;
- stderr;
- constructor(options) {
- this.execArgv = options.execArgv;
- this.env = options.env;
- this.stdout = options.project.vitest.logger.outputStream;
- this.stderr = options.project.vitest.logger.errorStream;
- /** Loads {@link file://./../../../runtime/workers/threads.ts} */
- this.entrypoint = resolve$1(options.distPath, "workers/threads.js");
- }
- on(event, callback) {
- this.thread.on(event, callback);
- }
- off(event, callback) {
- this.thread.off(event, callback);
- }
- send(message) {
- this.thread.postMessage(message);
- }
- async start() {
- // This can be called multiple times if the runtime is shared.
- this._thread ||= new Worker(this.entrypoint, {
- env: this.env,
- execArgv: this.execArgv,
- stdout: true,
- stderr: true
- });
- this.stdout.setMaxListeners(1 + this.stdout.getMaxListeners());
- this._thread.stdout.pipe(this.stdout);
- this.stderr.setMaxListeners(1 + this.stderr.getMaxListeners());
- this._thread.stderr.pipe(this.stderr);
- }
- async stop() {
- await this.thread.terminate();
- this._thread?.stdout?.unpipe(this.stdout);
- this.stdout.setMaxListeners(this.stdout.getMaxListeners() - 1);
- this._thread?.stderr?.unpipe(this.stderr);
- this.stderr.setMaxListeners(this.stderr.getMaxListeners() - 1);
- this._thread = void 0;
- }
- deserialize(data) {
- return data;
- }
- get thread() {
- if (!this._thread) throw new Error(`The worker thread was torn down or never initialized. This is a bug in Vitest.`);
- return this._thread;
- }
-}
-
-/** @experimental */
-class TypecheckPoolWorker {
- name = "typecheck";
- project;
- _eventEmitter = new EventEmitter$1();
- constructor(options) {
- this.project = options.project;
- }
- async start() {
- // noop, onMessage handles it
- }
- async stop() {
- // noop, onMessage handles it
- }
- canReuse() {
- return true;
- }
- send(message) {
- onMessage(message, this.project).then((response) => {
- if (response) this._eventEmitter.emit("message", response);
- });
- }
- on(event, callback) {
- this._eventEmitter.on(event, callback);
- }
- off(event, callback) {
- this._eventEmitter.on(event, callback);
- }
- deserialize(data) {
- return data;
- }
-}
-const __vitest_worker_response__ = true;
-const runners = /* @__PURE__ */ new WeakMap();
-async function onMessage(message, project) {
- if (message?.__vitest_worker_request__ !== true) return;
- let runner = runners.get(project.vitest);
- if (!runner) {
- runner = createRunner(project.vitest);
- runners.set(project.vitest, runner);
- }
- let runPromise;
- switch (message.type) {
- case "start": return {
- type: "started",
- __vitest_worker_response__
- };
- case "run":
- runPromise = runner.runTests(message.context.files, project).catch((error) => error);
- return {
- type: "testfileFinished",
- error: await runPromise,
- __vitest_worker_response__
- };
- case "collect":
- runPromise = runner.collectTests(message.context.files, project).catch((error) => error);
- return {
- type: "testfileFinished",
- error: await runPromise,
- __vitest_worker_response__
- };
- case "stop":
- await runPromise;
- return {
- type: "stopped",
- __vitest_worker_response__
- };
- }
- throw new Error(`Unexpected message ${JSON.stringify(message, null, 2)}`);
-}
-function createRunner(vitest) {
- const promisesMap = /* @__PURE__ */ new WeakMap();
- const rerunTriggered = /* @__PURE__ */ new WeakSet();
- async function onParseEnd(project, { files, sourceErrors }) {
- const checker = project.typechecker;
- const { packs, events } = checker.getTestPacksAndEvents();
- await vitest._testRun.updated(packs, events);
- if (!project.config.typecheck.ignoreSourceErrors) sourceErrors.forEach((error) => vitest.state.catchError(error, "Unhandled Source Error"));
- if (!hasFailed(files) && !sourceErrors.length && checker.getExitCode()) {
- const error = new Error(checker.getOutput());
- error.stack = "";
- vitest.state.catchError(error, "Typecheck Error");
- }
- promisesMap.get(project)?.resolve();
- rerunTriggered.delete(project);
- // triggered by TSC watcher, not Vitest watcher, so we need to emulate what Vitest does in this case
- if (vitest.config.watch && !vitest.runningPromise) {
- const modules = files.map((file) => vitest.state.getReportedEntity(file)).filter((e) => e?.type === "module");
- const state = vitest.isCancelling ? "interrupted" : modules.some((m) => !m.ok()) ? "failed" : "passed";
- await vitest.report("onTestRunEnd", modules, [], state);
- await vitest.report("onWatcherStart", files, [...project.config.typecheck.ignoreSourceErrors ? [] : sourceErrors, ...vitest.state.getUnhandledErrors()]);
- }
- }
- async function createWorkspaceTypechecker(project, files) {
- const checker = project.typechecker ?? new Typechecker(project);
- if (project.typechecker) return checker;
- project.typechecker = checker;
- checker.setFiles(files);
- checker.onParseStart(async () => {
- const files = checker.getTestFiles();
- for (const file of files) await vitest._testRun.enqueued(project, file);
- await vitest._testRun.collected(project, files);
- });
- checker.onParseEnd((result) => onParseEnd(project, result));
- checker.onWatcherRerun(async () => {
- rerunTriggered.add(project);
- if (!vitest.runningPromise) {
- vitest.state.clearErrors();
- await vitest.report("onWatcherRerun", files, "File change detected. Triggering rerun.");
- }
- await checker.collectTests();
- const testFiles = checker.getTestFiles();
- for (const file of testFiles) await vitest._testRun.enqueued(project, file);
- await vitest._testRun.collected(project, testFiles);
- const { packs, events } = checker.getTestPacksAndEvents();
- await vitest._testRun.updated(packs, events);
- });
- return checker;
- }
- async function startTypechecker(project, files) {
- if (project.typechecker) return;
- const checker = await createWorkspaceTypechecker(project, files);
- await checker.collectTests();
- await checker.start();
- }
- async function collectTests(specs, project) {
- const files = specs.map((spec) => spec.filepath);
- const checker = await createWorkspaceTypechecker(project, files);
- checker.setFiles(files);
- await checker.collectTests();
- const testFiles = checker.getTestFiles();
- vitest.state.collectFiles(project, testFiles);
- }
- async function runTests(specs, project) {
- const promises = [];
- const files = specs.map((spec) => spec.filepath);
- const promise = createDefer();
- // check that watcher actually triggered rerun
- const triggered = await new Promise((resolve) => {
- const _i = setInterval(() => {
- if (!project.typechecker || rerunTriggered.has(project)) {
- resolve(true);
- clearInterval(_i);
- }
- });
- setTimeout(() => {
- resolve(false);
- clearInterval(_i);
- }, 500).unref();
- });
- // Re-run but wasn't triggered by tsc
- if (promisesMap.has(project) && !triggered) return promisesMap.get(project);
- if (project.typechecker && !triggered) {
- const testFiles = project.typechecker.getTestFiles();
- for (const file of testFiles) await vitest._testRun.enqueued(project, file);
- await vitest._testRun.collected(project, testFiles);
- await onParseEnd(project, project.typechecker.getResult());
- }
- promises.push(promise);
- promisesMap.set(project, promise);
- promises.push(startTypechecker(project, files));
- await Promise.all(promises);
- }
- return {
- runTests,
- collectTests
- };
-}
-
-/** @experimental */
-class VmForksPoolWorker extends ForksPoolWorker {
- name = "vmForks";
- reportMemory = true;
- entrypoint;
- constructor(options) {
- super({
- ...options,
- execArgv: [...options.execArgv, "--experimental-vm-modules"]
- });
- /** Loads {@link file://./../../../runtime/workers/vmForks.ts} */
- this.entrypoint = resolve$1(options.distPath, "workers/vmForks.js");
- }
- canReuse() {
- return true;
- }
-}
-
-/** @experimental */
-class VmThreadsPoolWorker extends ThreadsPoolWorker {
- name = "vmThreads";
- reportMemory = true;
- entrypoint;
- constructor(options) {
- super({
- ...options,
- execArgv: [...options.execArgv, "--experimental-vm-modules"]
- });
- /** Loads {@link file://./../../../runtime/workers/vmThreads.ts} */
- this.entrypoint = resolve$1(options.distPath, "workers/vmThreads.js");
- }
- canReuse() {
- return true;
- }
-}
-
-const WORKER_START_TIMEOUT = 9e4;
-class Pool {
- maxWorkers = 0;
- workerIds = /* @__PURE__ */ new Map();
- queue = [];
- activeTasks = [];
- sharedRunners = [];
- exitPromises = [];
- _isCancelling = false;
- constructor(options, logger) {
- this.options = options;
- this.logger = logger;
- }
- setMaxWorkers(maxWorkers) {
- this.maxWorkers = maxWorkers;
- this.workerIds = new Map(Array.from({ length: maxWorkers }).fill(0).map((_, i) => [i + 1, true]));
- }
- async run(task, method) {
- // Prevent new tasks from being queued during cancellation
- if (this._isCancelling) throw new Error("[vitest-pool]: Cannot run tasks while pool is cancelling");
- // Every runner related failure should make this promise reject so that it's picked by pool.
- // This resolver is used to make the error handling in recursive queue easier.
- const testFinish = withResolvers();
- this.queue.push({
- task,
- resolver: testFinish,
- method
- });
- this.schedule();
- await testFinish.promise;
- }
- async schedule() {
- if (this.queue.length === 0 || this.activeTasks.length >= this.maxWorkers) return;
- const { task, resolver, method } = this.queue.shift();
- try {
- let isMemoryLimitReached = false;
- const runner = this.getPoolRunner(task, method);
- const poolId = runner.poolId ?? this.getWorkerId();
- runner.poolId = poolId;
- const activeTask = {
- task,
- resolver,
- method,
- cancelTask
- };
- this.activeTasks.push(activeTask);
- // active tasks receive cancel signal and shut down gracefully
- async function cancelTask(options) {
- if (options?.force) await runner.stop({ force: true });
- await runner.waitForTerminated();
- resolver.reject(/* @__PURE__ */ new Error("Cancelled"));
- }
- const onFinished = (message) => {
- if (message?.__vitest_worker_response__ && message.type === "testfileFinished") {
- if (task.memoryLimit && message.usedMemory) isMemoryLimitReached = message.usedMemory >= task.memoryLimit;
- if (message.error) this.options.state.catchError(message.error, "Test Run Error");
- runner.off("message", onFinished);
- resolver.resolve();
- }
- };
- runner.on("message", onFinished);
- if (!runner.isStarted) {
- runner.on("error", (error) => {
- resolver.reject(new Error(`[vitest-pool]: Worker ${task.worker} emitted error.`, { cause: error }));
- });
- const id = setTimeout(() => resolver.reject(/* @__PURE__ */ new Error(`[vitest-pool]: Timeout starting ${task.worker} runner.`)), WORKER_START_TIMEOUT);
- await runner.start({ workerId: task.context.workerId }).catch((error) => resolver.reject(new Error(`[vitest-pool]: Failed to start ${task.worker} worker for test files ${formatFiles(task)}.`, { cause: error }))).finally(() => clearTimeout(id));
- }
- let span;
- if (!resolver.isRejected) {
- span = runner.startTracesSpan(`vitest.worker.${method}`);
- // Start running the test in the worker
- runner.request(method, task.context);
- }
- await resolver.promise.catch((error) => span?.recordException(error)).finally(() => span?.end());
- const index = this.activeTasks.indexOf(activeTask);
- if (index !== -1) this.activeTasks.splice(index, 1);
- if (!task.isolate && !isMemoryLimitReached && this.queue[0]?.task.isolate === false && isEqualRunner(runner, this.queue[0].task)) {
- this.sharedRunners.push(runner);
- return this.schedule();
- }
- // Runner terminations are started but not awaited until the end of full run.
- // Runner termination can also already start from task cancellation.
- if (!runner.isTerminated) {
- const id = setTimeout(() => this.logger.error(`[vitest-pool]: Timeout terminating ${task.worker} worker for test files ${formatFiles(task)}.`), this.options.teardownTimeout);
- this.exitPromises.push(runner.stop({ force: resolver.isRejected }).then(() => clearTimeout(id)).catch((error) => this.logger.error(`[vitest-pool]: Failed to terminate ${task.worker} worker for test files ${formatFiles(task)}.`, error)));
- }
- this.freeWorkerId(poolId);
- }
- // This is mostly to avoid zombie workers when/if Vitest internals run into errors
-catch (error) {
- return resolver.reject(error);
- }
- return this.schedule();
- }
- async cancel() {
- // Force exit if previous cancel is still on-going
- // for example when user does 'CTRL+c' twice in row
- const force = this._isCancelling;
- // Set flag to prevent new tasks from being queued
- this._isCancelling = true;
- const pendingTasks = this.queue.splice(0);
- if (pendingTasks.length) {
- const error = /* @__PURE__ */ new Error("Cancelled");
- pendingTasks.forEach((task) => task.resolver.reject(error));
- }
- await Promise.all(this.activeTasks.map((task) => task.cancelTask({ force })));
- this.activeTasks = [];
- await Promise.all(this.sharedRunners.map((runner) => runner.stop()));
- this.sharedRunners = [];
- await Promise.all(this.exitPromises);
- this.exitPromises = [];
- this.workerIds.forEach((_, id) => this.freeWorkerId(id));
- // Reset flag after cancellation completes
- this._isCancelling = false;
- }
- async close() {
- await this.cancel();
- }
- getPoolRunner(task, method) {
- if (task.isolate === false) {
- const index = this.sharedRunners.findIndex((runner) => isEqualRunner(runner, task));
- if (index !== -1) {
- const runner = this.sharedRunners.splice(index, 1)[0];
- runner.reconfigure(task);
- return runner;
- }
- }
- const options = {
- distPath: this.options.distPath,
- project: task.project,
- method,
- environment: task.context.environment,
- env: task.env,
- execArgv: task.execArgv
- };
- switch (task.worker) {
- case "forks": return new PoolRunner(options, new ForksPoolWorker(options));
- case "vmForks": return new PoolRunner(options, new VmForksPoolWorker(options));
- case "threads": return new PoolRunner(options, new ThreadsPoolWorker(options));
- case "vmThreads": return new PoolRunner(options, new VmThreadsPoolWorker(options));
- case "typescript": return new PoolRunner(options, new TypecheckPoolWorker(options));
- }
- const customPool = task.project.config.poolRunner;
- if (customPool != null && customPool.name === task.worker) return new PoolRunner(options, customPool.createPoolWorker(options));
- throw new Error(`Runner ${task.worker} is not supported. Test files: ${formatFiles(task)}.`);
- }
- getWorkerId() {
- let workerId = 0;
- this.workerIds.forEach((state, id) => {
- if (state && !workerId) {
- workerId = id;
- this.workerIds.set(id, false);
- }
- });
- return workerId;
- }
- freeWorkerId(id) {
- this.workerIds.set(id, true);
- }
-}
-function withResolvers() {
- let resolve = () => {};
- let reject = (_error) => {};
- const resolver = {
- promise: new Promise((res, rej) => {
- resolve = res;
- reject = rej;
- }),
- resolve,
- reject: (reason) => {
- resolver.isRejected = true;
- reject(reason);
- },
- isRejected: false
- };
- return resolver;
-}
-function formatFiles(task) {
- return task.context.files.map((file) => file.filepath).join(", ");
-}
-function isEqualRunner(runner, task) {
- if (task.isolate) throw new Error("Isolated tasks should not share runners");
- if (runner.worker.name !== task.worker || runner.project !== task.project) return false;
- // by default, check that the environments are the same
- // some workers (like vmThreads/vmForks) do not need this check
- if (!runner.worker.canReuse) return isEnvironmentEqual(task.context.environment, runner.environment);
- return runner.worker.canReuse(task);
-}
-function isEnvironmentEqual(env1, env2) {
- if (env1.name !== env2.name) return false;
- return deepEqual(env1.options, env2.options);
-}
-function deepEqual(obj1, obj2) {
- if (obj1 === obj2) return true;
- if (obj1 == null || obj2 == null) return obj1 === obj2;
- if (typeof obj1 !== "object" || typeof obj2 !== "object") return false;
- const keys1 = Object.keys(obj1);
- const keys2 = Object.keys(obj2);
- if (keys1.length !== keys2.length) return false;
- for (const key of keys1) if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) return false;
- return true;
-}
-
-const suppressWarningsPath = resolve(rootDir, "./suppress-warnings.cjs");
-function getFilePoolName(project) {
- if (project.config.browser.enabled) return "browser";
- return project.config.pool;
-}
-function createPool(ctx) {
- const pool = new Pool({
- distPath: ctx.distPath,
- teardownTimeout: ctx.config.teardownTimeout,
- state: ctx.state
- }, ctx.logger);
- const options = resolveOptions(ctx);
- const Sequencer = ctx.config.sequence.sequencer;
- const sequencer = new Sequencer(ctx);
- let browserPool;
- async function executeTests(method, specs, invalidates) {
- ctx.onCancel(() => pool.cancel());
- if (ctx.config.shard) {
- if (!ctx.config.passWithNoTests && ctx.config.shard.count > specs.length) throw new Error(`--shard <count> must be a smaller than count of test files. Resolved ${specs.length} test files for --shard=${ctx.config.shard.index}/${ctx.config.shard.count}.`);
- specs = await sequencer.shard(Array.from(specs));
- }
- const taskGroups = [];
- let workerId = 0;
- const sorted = await sequencer.sort(specs);
- const environments = await getSpecificationsEnvironments(specs);
- const groups = groupSpecs(sorted, environments);
- const projectEnvs = /* @__PURE__ */ new WeakMap();
- const projectExecArgvs = /* @__PURE__ */ new WeakMap();
- for (const group of groups) {
- if (!group) continue;
- const taskGroup = [];
- const browserSpecs = [];
- taskGroups.push({
- tasks: taskGroup,
- maxWorkers: group.maxWorkers,
- browserSpecs
- });
- for (const specs of group.specs) {
- const { project, pool } = specs[0];
- if (pool === "browser") {
- browserSpecs.push(...specs);
- continue;
- }
- const environment = environments.get(specs[0]);
- if (!environment) throw new Error(`Cannot find the environment. This is a bug in Vitest.`);
- let env = projectEnvs.get(project);
- if (!env) {
- env = {
- ...process.env,
- ...options.env,
- ...ctx.config.env,
- ...project.config.env
- };
- // env are case-insensitive on Windows, but spawned processes don't support it
- if (isWindows) for (const name in env) env[name.toUpperCase()] = env[name];
- projectEnvs.set(project, env);
- }
- let execArgv = projectExecArgvs.get(project);
- if (!execArgv) {
- execArgv = [...options.execArgv, ...project.config.execArgv];
- projectExecArgvs.set(project, execArgv);
- }
- taskGroup.push({
- context: {
- files: specs.map((spec) => ({
- filepath: spec.moduleId,
- testLocations: spec.testLines
- })),
- invalidates,
- providedContext: project.getProvidedContext(),
- workerId: workerId++,
- environment
- },
- project,
- env,
- execArgv,
- worker: pool,
- isolate: project.config.isolate,
- memoryLimit: getMemoryLimit(ctx.config, pool) ?? null
- });
- }
- }
- const results = [];
- for (const { tasks, browserSpecs, maxWorkers } of taskGroups) {
- pool.setMaxWorkers(maxWorkers);
- const promises = tasks.map(async (task) => {
- if (ctx.isCancelling) return ctx.state.cancelFiles(task.context.files, task.project);
- try {
- await pool.run(task, method);
- } catch (error) {
- // Intentionally cancelled
- if (ctx.isCancelling && error instanceof Error && error.message === "Cancelled") ctx.state.cancelFiles(task.context.files, task.project);
- else throw error;
- }
- });
- if (browserSpecs.length) {
- browserPool ??= createBrowserPool(ctx);
- if (method === "collect") promises.push(browserPool.collectTests(browserSpecs));
- else promises.push(browserPool.runTests(browserSpecs));
- }
- const groupResults = await Promise.allSettled(promises);
- results.push(...groupResults);
- }
- const errors = results.filter((result) => result.status === "rejected").map((result) => result.reason);
- if (errors.length > 0) throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error.");
- }
- return {
- name: "default",
- runTests: (files, invalidates) => executeTests("run", files, invalidates),
- collectTests: (files, invalidates) => executeTests("collect", files, invalidates),
- async close() {
- await Promise.all([
- pool.close(),
- browserPool?.close?.(),
- ...ctx.projects.map((project) => project.typechecker?.stop())
- ]);
- }
- };
-}
-function resolveOptions(ctx) {
- // in addition to resolve.conditions Vite also adds production/development,
- // see: https://github.com/vitejs/vite/blob/af2aa09575229462635b7cbb6d248ca853057ba2/packages/vite/src/node/plugins/resolve.ts#L1056-L1080
- const viteMajor = Number(version.split(".")[0]);
- const conditions = [...new Set(viteMajor >= 6 ? ctx.vite.config.ssr.resolve?.conditions ?? [] : [
- "production",
- "development",
- ...ctx.vite.config.resolve.conditions
- ])].filter((condition) => {
- if (condition === "production") return ctx.vite.config.isProduction;
- if (condition === "development") return !ctx.vite.config.isProduction;
- return true;
- }).map((condition) => {
- if (viteMajor >= 6 && condition === "development|production") return ctx.vite.config.isProduction ? "production" : "development";
- return condition;
- }).flatMap((c) => ["--conditions", c]);
- return {
- execArgv: [
- ...process.execArgv.filter((execArg) => execArg.startsWith("--cpu-prof") || execArg.startsWith("--heap-prof") || execArg.startsWith("--diagnostic-dir")),
- ...conditions,
- "--experimental-import-meta-resolve",
- ...globalThis.Deno ? [] : ["--require", suppressWarningsPath]
- ],
- env: {
- TEST: "true",
- VITEST: "true",
- NODE_ENV: process.env.NODE_ENV || "test",
- VITEST_MODE: ctx.config.watch ? "WATCH" : "RUN",
- FORCE_TTY: isatty(1) ? "true" : ""
- }
- };
-}
-function resolveMaxWorkers(project) {
- if (project.config.maxWorkers) return project.config.maxWorkers;
- if (project.vitest.config.maxWorkers) return project.vitest.config.maxWorkers;
- const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length;
- if (project.vitest.config.watch) return Math.max(Math.floor(numCpus / 2), 1);
- return Math.max(numCpus - 1, 1);
-}
-function getMemoryLimit(config, pool) {
- if (pool !== "vmForks" && pool !== "vmThreads") return null;
- const memory = nodeos.totalmem();
- const limit = getWorkerMemoryLimit(config);
- if (typeof memory === "number") return stringToBytes(limit, config.watch ? memory / 2 : memory);
- // If totalmem is not supported we cannot resolve percentage based values like 0.5, "50%"
- if (typeof limit === "number" && limit > 1 || typeof limit === "string" && limit.at(-1) !== "%") return stringToBytes(limit);
- // just ignore "memoryLimit" value because we cannot detect memory limit
- return null;
-}
-function groupSpecs(specs, environments) {
- const groups = [];
- // Files without file parallelism but without explicit sequence.groupOrder
- const sequential = {
- specs: [],
- maxWorkers: 1
- };
- // Type tests are run in a single group, per project
- const typechecks = {};
- const serializedEnvironmentOptions = /* @__PURE__ */ new Map();
- function getSerializedOptions(env) {
- const options = serializedEnvironmentOptions.get(env);
- if (options) return options;
- const serialized = JSON.stringify(env.options);
- serializedEnvironmentOptions.set(env, serialized);
- return serialized;
- }
- function isEqualEnvironments(a, b) {
- const aEnv = environments.get(a);
- const bEnv = environments.get(b);
- if (!aEnv && !bEnv) return true;
- if (!aEnv || !bEnv || aEnv.name !== bEnv.name) return false;
- if (!aEnv.options && !bEnv.options) return true;
- if (!aEnv.options || !bEnv.options) return false;
- return getSerializedOptions(aEnv) === getSerializedOptions(bEnv);
- }
- specs.forEach((spec) => {
- if (spec.pool === "typescript") {
- typechecks[spec.project.name] ||= [];
- typechecks[spec.project.name].push(spec);
- return;
- }
- const order = spec.project.config.sequence.groupOrder;
- const isolate = spec.project.config.isolate;
- // Files that have disabled parallelism and default groupOrder are set into their own group
- if (isolate === true && order === 0 && spec.project.config.maxWorkers === 1) return sequential.specs.push([spec]);
- const maxWorkers = resolveMaxWorkers(spec.project);
- groups[order] ||= {
- specs: [],
- maxWorkers
- };
- // Multiple projects with different maxWorkers but same groupOrder
- if (groups[order].maxWorkers !== maxWorkers) {
- const last = groups[order].specs.at(-1)?.at(-1)?.project.name;
- throw new Error(`Projects "${last}" and "${spec.project.name}" have different 'maxWorkers' but same 'sequence.groupOrder'.\nProvide unique 'sequence.groupOrder' for them.`);
- }
- // Non-isolated single worker can receive all files at once
- if (isolate === false && maxWorkers === 1) {
- const previous = groups[order].specs[0]?.[0];
- if (previous && previous.project.name === spec.project.name && isEqualEnvironments(spec, previous)) return groups[order].specs[0].push(spec);
- }
- groups[order].specs.push([spec]);
- });
- let order = Math.max(0, ...groups.keys()) + 1;
- for (const projectName in typechecks) {
- const maxWorkers = resolveMaxWorkers(typechecks[projectName][0].project);
- const previous = groups[order - 1];
- if (previous && previous.typecheck && maxWorkers !== previous.maxWorkers) order += 1;
- groups[order] ||= {
- specs: [],
- maxWorkers,
- typecheck: true
- };
- groups[order].specs.push(typechecks[projectName]);
- }
- if (sequential.specs.length) groups.push(sequential);
- return groups;
-}
-
-function serializeConfig(project) {
- const { config, globalConfig } = project;
- const viteConfig = project._vite?.config;
- const optimizer = config.deps?.optimizer || {};
- return {
- environmentOptions: config.environmentOptions,
- mode: config.mode,
- isolate: config.isolate,
- maxWorkers: config.maxWorkers,
- base: config.base,
- logHeapUsage: config.logHeapUsage,
- runner: config.runner,
- bail: config.bail,
- defines: config.defines,
- chaiConfig: config.chaiConfig,
- setupFiles: config.setupFiles,
- allowOnly: config.allowOnly,
- testTimeout: config.testTimeout,
- testNamePattern: config.testNamePattern,
- hookTimeout: config.hookTimeout,
- clearMocks: config.clearMocks,
- mockReset: config.mockReset,
- restoreMocks: config.restoreMocks,
- unstubEnvs: config.unstubEnvs,
- unstubGlobals: config.unstubGlobals,
- maxConcurrency: config.maxConcurrency,
- pool: config.pool,
- expect: config.expect,
- snapshotSerializers: config.snapshotSerializers,
- diff: config.diff,
- retry: config.retry,
- disableConsoleIntercept: config.disableConsoleIntercept,
- root: config.root,
- name: config.name,
- globals: config.globals,
- snapshotEnvironment: config.snapshotEnvironment,
- passWithNoTests: config.passWithNoTests,
- coverage: ((coverage) => {
- const htmlReporter = coverage.reporter.find(([reporterName]) => reporterName === "html");
- const subdir = htmlReporter && htmlReporter[1]?.subdir;
- return {
- reportsDirectory: coverage.reportsDirectory,
- provider: coverage.provider,
- enabled: coverage.enabled,
- htmlReporter: htmlReporter ? { subdir } : void 0,
- customProviderModule: "customProviderModule" in coverage ? coverage.customProviderModule : void 0
- };
- })(config.coverage),
- fakeTimers: config.fakeTimers,
- deps: {
- web: config.deps.web || {},
- optimizer: Object.entries(optimizer).reduce((acc, [name, option]) => {
- acc[name] = { enabled: option?.enabled ?? false };
- return acc;
- }, {}),
- interopDefault: config.deps.interopDefault,
- moduleDirectories: config.deps.moduleDirectories
- },
- snapshotOptions: {
- snapshotEnvironment: void 0,
- updateSnapshot: globalConfig.snapshotOptions.updateSnapshot,
- snapshotFormat: { ...globalConfig.snapshotOptions.snapshotFormat },
- expand: config.snapshotOptions.expand ?? globalConfig.snapshotOptions.expand
- },
- sequence: {
- shuffle: globalConfig.sequence.shuffle,
- concurrent: globalConfig.sequence.concurrent,
- seed: globalConfig.sequence.seed,
- hooks: globalConfig.sequence.hooks,
- setupFiles: globalConfig.sequence.setupFiles
- },
- inspect: globalConfig.inspect,
- inspectBrk: globalConfig.inspectBrk,
- inspector: globalConfig.inspector,
- watch: config.watch,
- includeTaskLocation: config.includeTaskLocation ?? globalConfig.includeTaskLocation,
- env: {
- ...viteConfig?.env,
- ...config.env
- },
- browser: ((browser) => {
- const provider = project.browser?.provider;
- return {
- name: browser.name,
- headless: browser.headless,
- isolate: browser.isolate,
- fileParallelism: browser.fileParallelism,
- ui: browser.ui,
- viewport: browser.viewport,
- screenshotFailures: browser.screenshotFailures,
- locators: { testIdAttribute: browser.locators.testIdAttribute },
- providerOptions: provider?.name === "playwright" ? { actionTimeout: provider?.options?.actionTimeout } : {},
- trackUnhandledErrors: browser.trackUnhandledErrors ?? true,
- trace: browser.trace.mode
- };
- })(config.browser),
- standalone: config.standalone,
- printConsoleTrace: config.printConsoleTrace ?? globalConfig.printConsoleTrace,
- benchmark: config.benchmark && { includeSamples: config.benchmark.includeSamples },
- serializedDefines: config.browser.enabled ? "" : project._serializedDefines || "",
- experimental: {
- fsModuleCache: config.experimental.fsModuleCache ?? false,
- printImportBreakdown: config.experimental.printImportBreakdown,
- openTelemetry: config.experimental.openTelemetry
- }
- };
-}
-
-async function loadGlobalSetupFiles(runner, globalSetup) {
- const globalSetupFiles = toArray(globalSetup);
- return Promise.all(globalSetupFiles.map((file) => loadGlobalSetupFile(file, runner)));
-}
-async function loadGlobalSetupFile(file, runner) {
- const m = await runner.import(file);
- for (const exp of [
- "default",
- "setup",
- "teardown"
- ]) if (m[exp] != null && typeof m[exp] !== "function") throw new Error(`invalid export in globalSetup file ${file}: ${exp} must be a function`);
- if (m.default) return {
- file,
- setup: m.default
- };
- else if (m.setup || m.teardown) return {
- file,
- setup: m.setup,
- teardown: m.teardown
- };
- else throw new Error(`invalid globalSetup file ${file}. Must export setup, teardown or have a default export`);
-}
-
-function CoverageTransform(ctx) {
- return {
- name: "vitest:coverage-transform",
- enforce: "post",
- transform(srcCode, id) {
- return ctx.coverageProvider?.onFileTransform?.(srcCode, id, this);
- }
- };
-}
-
-var jsTokens_1;
-var hasRequiredJsTokens;
-
-function requireJsTokens () {
- if (hasRequiredJsTokens) return jsTokens_1;
- hasRequiredJsTokens = 1;
- // Copyright 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Simon Lydell
- // License: MIT.
- var HashbangComment, Identifier, JSXIdentifier, JSXPunctuator, JSXString, JSXText, KeywordsWithExpressionAfter, KeywordsWithNoLineTerminatorAfter, LineTerminatorSequence, MultiLineComment, Newline, NumericLiteral, Punctuator, RegularExpressionLiteral, SingleLineComment, StringLiteral, Template, TokensNotPrecedingObjectLiteral, TokensPrecedingExpression, WhiteSpace;
- RegularExpressionLiteral = /\/(?![*\/])(?:\[(?:[^\]\\\n\r\u2028\u2029]+|\\.)*\]?|[^\/[\\\n\r\u2028\u2029]+|\\.)*(\/[$_\u200C\u200D\p{ID_Continue}]*|\\)?/yu;
- Punctuator = /--|\+\+|=>|\.{3}|\??\.(?!\d)|(?:&&|\|\||\?\?|[+\-%&|^]|\*{1,2}|<{1,2}|>{1,3}|!=?|={1,2}|\/(?![\/*]))=?|[?~,:;[\](){}]/y;
- Identifier = /(\x23?)(?=[$_\p{ID_Start}\\])(?:[$_\u200C\u200D\p{ID_Continue}]+|\\u[\da-fA-F]{4}|\\u\{[\da-fA-F]+\})+/yu;
- StringLiteral = /(['"])(?:[^'"\\\n\r]+|(?!\1)['"]|\\(?:\r\n|[^]))*(\1)?/y;
- NumericLiteral = /(?:0[xX][\da-fA-F](?:_?[\da-fA-F])*|0[oO][0-7](?:_?[0-7])*|0[bB][01](?:_?[01])*)n?|0n|[1-9](?:_?\d)*n|(?:(?:0(?!\d)|0\d*[89]\d*|[1-9](?:_?\d)*)(?:\.(?:\d(?:_?\d)*)?)?|\.\d(?:_?\d)*)(?:[eE][+-]?\d(?:_?\d)*)?|0[0-7]+/y;
- Template = /[`}](?:[^`\\$]+|\\[^]|\$(?!\{))*(`|\$\{)?/y;
- WhiteSpace = /[\t\v\f\ufeff\p{Zs}]+/yu;
- LineTerminatorSequence = /\r?\n|[\r\u2028\u2029]/y;
- MultiLineComment = /\/\*(?:[^*]+|\*(?!\/))*(\*\/)?/y;
- SingleLineComment = /\/\/.*/y;
- HashbangComment = /^#!.*/;
- JSXPunctuator = /[<>.:={}]|\/(?![\/*])/y;
- JSXIdentifier = /[$_\p{ID_Start}][$_\u200C\u200D\p{ID_Continue}-]*/yu;
- JSXString = /(['"])(?:[^'"]+|(?!\1)['"])*(\1)?/y;
- JSXText = /[^<>{}]+/y;
- TokensPrecedingExpression = /^(?:[\/+-]|\.{3}|\?(?:InterpolationIn(?:JSX|Template)|NoLineTerminatorHere|NonExpressionParenEnd|UnaryIncDec))?$|[{}([,;<>=*%&|^!~?:]$/;
- TokensNotPrecedingObjectLiteral = /^(?:=>|[;\]){}]|else|\?(?:NoLineTerminatorHere|NonExpressionParenEnd))?$/;
- KeywordsWithExpressionAfter = /^(?:await|case|default|delete|do|else|instanceof|new|return|throw|typeof|void|yield)$/;
- KeywordsWithNoLineTerminatorAfter = /^(?:return|throw|yield)$/;
- Newline = RegExp(LineTerminatorSequence.source);
- jsTokens_1 = function*(input, {jsx = false} = {}) {
- var braces, firstCodePoint, isExpression, lastIndex, lastSignificantToken, length, match, mode, nextLastIndex, nextLastSignificantToken, parenNesting, postfixIncDec, punctuator, stack;
- ({length} = input);
- lastIndex = 0;
- lastSignificantToken = "";
- stack = [
- {tag: "JS"}
- ];
- braces = [];
- parenNesting = 0;
- postfixIncDec = false;
- if (match = HashbangComment.exec(input)) {
- yield ({
- type: "HashbangComment",
- value: match[0]
- });
- lastIndex = match[0].length;
- }
- while (lastIndex < length) {
- mode = stack[stack.length - 1];
- switch (mode.tag) {
- case "JS":
- case "JSNonExpressionParen":
- case "InterpolationInTemplate":
- case "InterpolationInJSX":
- if (input[lastIndex] === "/" && (TokensPrecedingExpression.test(lastSignificantToken) || KeywordsWithExpressionAfter.test(lastSignificantToken))) {
- RegularExpressionLiteral.lastIndex = lastIndex;
- if (match = RegularExpressionLiteral.exec(input)) {
- lastIndex = RegularExpressionLiteral.lastIndex;
- lastSignificantToken = match[0];
- postfixIncDec = true;
- yield ({
- type: "RegularExpressionLiteral",
- value: match[0],
- closed: match[1] !== void 0 && match[1] !== "\\"
- });
- continue;
- }
- }
- Punctuator.lastIndex = lastIndex;
- if (match = Punctuator.exec(input)) {
- punctuator = match[0];
- nextLastIndex = Punctuator.lastIndex;
- nextLastSignificantToken = punctuator;
- switch (punctuator) {
- case "(":
- if (lastSignificantToken === "?NonExpressionParenKeyword") {
- stack.push({
- tag: "JSNonExpressionParen",
- nesting: parenNesting
- });
- }
- parenNesting++;
- postfixIncDec = false;
- break;
- case ")":
- parenNesting--;
- postfixIncDec = true;
- if (mode.tag === "JSNonExpressionParen" && parenNesting === mode.nesting) {
- stack.pop();
- nextLastSignificantToken = "?NonExpressionParenEnd";
- postfixIncDec = false;
- }
- break;
- case "{":
- Punctuator.lastIndex = 0;
- isExpression = !TokensNotPrecedingObjectLiteral.test(lastSignificantToken) && (TokensPrecedingExpression.test(lastSignificantToken) || KeywordsWithExpressionAfter.test(lastSignificantToken));
- braces.push(isExpression);
- postfixIncDec = false;
- break;
- case "}":
- switch (mode.tag) {
- case "InterpolationInTemplate":
- if (braces.length === mode.nesting) {
- Template.lastIndex = lastIndex;
- match = Template.exec(input);
- lastIndex = Template.lastIndex;
- lastSignificantToken = match[0];
- if (match[1] === "${") {
- lastSignificantToken = "?InterpolationInTemplate";
- postfixIncDec = false;
- yield ({
- type: "TemplateMiddle",
- value: match[0]
- });
- } else {
- stack.pop();
- postfixIncDec = true;
- yield ({
- type: "TemplateTail",
- value: match[0],
- closed: match[1] === "`"
- });
- }
- continue;
- }
- break;
- case "InterpolationInJSX":
- if (braces.length === mode.nesting) {
- stack.pop();
- lastIndex += 1;
- lastSignificantToken = "}";
- yield ({
- type: "JSXPunctuator",
- value: "}"
- });
- continue;
- }
- }
- postfixIncDec = braces.pop();
- nextLastSignificantToken = postfixIncDec ? "?ExpressionBraceEnd" : "}";
- break;
- case "]":
- postfixIncDec = true;
- break;
- case "++":
- case "--":
- nextLastSignificantToken = postfixIncDec ? "?PostfixIncDec" : "?UnaryIncDec";
- break;
- case "<":
- if (jsx && (TokensPrecedingExpression.test(lastSignificantToken) || KeywordsWithExpressionAfter.test(lastSignificantToken))) {
- stack.push({tag: "JSXTag"});
- lastIndex += 1;
- lastSignificantToken = "<";
- yield ({
- type: "JSXPunctuator",
- value: punctuator
- });
- continue;
- }
- postfixIncDec = false;
- break;
- default:
- postfixIncDec = false;
- }
- lastIndex = nextLastIndex;
- lastSignificantToken = nextLastSignificantToken;
- yield ({
- type: "Punctuator",
- value: punctuator
- });
- continue;
- }
- Identifier.lastIndex = lastIndex;
- if (match = Identifier.exec(input)) {
- lastIndex = Identifier.lastIndex;
- nextLastSignificantToken = match[0];
- switch (match[0]) {
- case "for":
- case "if":
- case "while":
- case "with":
- if (lastSignificantToken !== "." && lastSignificantToken !== "?.") {
- nextLastSignificantToken = "?NonExpressionParenKeyword";
- }
- }
- lastSignificantToken = nextLastSignificantToken;
- postfixIncDec = !KeywordsWithExpressionAfter.test(match[0]);
- yield ({
- type: match[1] === "#" ? "PrivateIdentifier" : "IdentifierName",
- value: match[0]
- });
- continue;
- }
- StringLiteral.lastIndex = lastIndex;
- if (match = StringLiteral.exec(input)) {
- lastIndex = StringLiteral.lastIndex;
- lastSignificantToken = match[0];
- postfixIncDec = true;
- yield ({
- type: "StringLiteral",
- value: match[0],
- closed: match[2] !== void 0
- });
- continue;
- }
- NumericLiteral.lastIndex = lastIndex;
- if (match = NumericLiteral.exec(input)) {
- lastIndex = NumericLiteral.lastIndex;
- lastSignificantToken = match[0];
- postfixIncDec = true;
- yield ({
- type: "NumericLiteral",
- value: match[0]
- });
- continue;
- }
- Template.lastIndex = lastIndex;
- if (match = Template.exec(input)) {
- lastIndex = Template.lastIndex;
- lastSignificantToken = match[0];
- if (match[1] === "${") {
- lastSignificantToken = "?InterpolationInTemplate";
- stack.push({
- tag: "InterpolationInTemplate",
- nesting: braces.length
- });
- postfixIncDec = false;
- yield ({
- type: "TemplateHead",
- value: match[0]
- });
- } else {
- postfixIncDec = true;
- yield ({
- type: "NoSubstitutionTemplate",
- value: match[0],
- closed: match[1] === "`"
- });
- }
- continue;
- }
- break;
- case "JSXTag":
- case "JSXTagEnd":
- JSXPunctuator.lastIndex = lastIndex;
- if (match = JSXPunctuator.exec(input)) {
- lastIndex = JSXPunctuator.lastIndex;
- nextLastSignificantToken = match[0];
- switch (match[0]) {
- case "<":
- stack.push({tag: "JSXTag"});
- break;
- case ">":
- stack.pop();
- if (lastSignificantToken === "/" || mode.tag === "JSXTagEnd") {
- nextLastSignificantToken = "?JSX";
- postfixIncDec = true;
- } else {
- stack.push({tag: "JSXChildren"});
- }
- break;
- case "{":
- stack.push({
- tag: "InterpolationInJSX",
- nesting: braces.length
- });
- nextLastSignificantToken = "?InterpolationInJSX";
- postfixIncDec = false;
- break;
- case "/":
- if (lastSignificantToken === "<") {
- stack.pop();
- if (stack[stack.length - 1].tag === "JSXChildren") {
- stack.pop();
- }
- stack.push({tag: "JSXTagEnd"});
- }
- }
- lastSignificantToken = nextLastSignificantToken;
- yield ({
- type: "JSXPunctuator",
- value: match[0]
- });
- continue;
- }
- JSXIdentifier.lastIndex = lastIndex;
- if (match = JSXIdentifier.exec(input)) {
- lastIndex = JSXIdentifier.lastIndex;
- lastSignificantToken = match[0];
- yield ({
- type: "JSXIdentifier",
- value: match[0]
- });
- continue;
- }
- JSXString.lastIndex = lastIndex;
- if (match = JSXString.exec(input)) {
- lastIndex = JSXString.lastIndex;
- lastSignificantToken = match[0];
- yield ({
- type: "JSXString",
- value: match[0],
- closed: match[2] !== void 0
- });
- continue;
- }
- break;
- case "JSXChildren":
- JSXText.lastIndex = lastIndex;
- if (match = JSXText.exec(input)) {
- lastIndex = JSXText.lastIndex;
- lastSignificantToken = match[0];
- yield ({
- type: "JSXText",
- value: match[0]
- });
- continue;
- }
- switch (input[lastIndex]) {
- case "<":
- stack.push({tag: "JSXTag"});
- lastIndex++;
- lastSignificantToken = "<";
- yield ({
- type: "JSXPunctuator",
- value: "<"
- });
- continue;
- case "{":
- stack.push({
- tag: "InterpolationInJSX",
- nesting: braces.length
- });
- lastIndex++;
- lastSignificantToken = "?InterpolationInJSX";
- postfixIncDec = false;
- yield ({
- type: "JSXPunctuator",
- value: "{"
- });
- continue;
- }
- }
- WhiteSpace.lastIndex = lastIndex;
- if (match = WhiteSpace.exec(input)) {
- lastIndex = WhiteSpace.lastIndex;
- yield ({
- type: "WhiteSpace",
- value: match[0]
- });
- continue;
- }
- LineTerminatorSequence.lastIndex = lastIndex;
- if (match = LineTerminatorSequence.exec(input)) {
- lastIndex = LineTerminatorSequence.lastIndex;
- postfixIncDec = false;
- if (KeywordsWithNoLineTerminatorAfter.test(lastSignificantToken)) {
- lastSignificantToken = "?NoLineTerminatorHere";
- }
- yield ({
- type: "LineTerminatorSequence",
- value: match[0]
- });
- continue;
- }
- MultiLineComment.lastIndex = lastIndex;
- if (match = MultiLineComment.exec(input)) {
- lastIndex = MultiLineComment.lastIndex;
- if (Newline.test(match[0])) {
- postfixIncDec = false;
- if (KeywordsWithNoLineTerminatorAfter.test(lastSignificantToken)) {
- lastSignificantToken = "?NoLineTerminatorHere";
- }
- }
- yield ({
- type: "MultiLineComment",
- value: match[0],
- closed: match[1] !== void 0
- });
- continue;
- }
- SingleLineComment.lastIndex = lastIndex;
- if (match = SingleLineComment.exec(input)) {
- lastIndex = SingleLineComment.lastIndex;
- postfixIncDec = false;
- yield ({
- type: "SingleLineComment",
- value: match[0]
- });
- continue;
- }
- firstCodePoint = String.fromCodePoint(input.codePointAt(lastIndex));
- lastIndex += firstCodePoint.length;
- lastSignificantToken = firstCodePoint;
- postfixIncDec = false;
- yield ({
- type: mode.tag.startsWith("JSX") ? "JSXInvalid" : "Invalid",
- value: firstCodePoint
- });
- }
- return void 0;
- };
- return jsTokens_1;
-}
-
-var jsTokensExports = requireJsTokens();
-var jsTokens = /*@__PURE__*/getDefaultExportFromCjs(jsTokensExports);
-
-const FILL_COMMENT = " ";
-function stripLiteralFromToken(token, fillChar, filter) {
- if (token.type === "SingleLineComment") {
- return FILL_COMMENT.repeat(token.value.length);
- }
- if (token.type === "MultiLineComment") {
- return token.value.replace(/[^\n]/g, FILL_COMMENT);
- }
- if (token.type === "StringLiteral") {
- if (!token.closed) {
- return token.value;
- }
- const body = token.value.slice(1, -1);
- if (filter(body)) {
- return token.value[0] + fillChar.repeat(body.length) + token.value[token.value.length - 1];
- }
- }
- if (token.type === "NoSubstitutionTemplate") {
- const body = token.value.slice(1, -1);
- if (filter(body)) {
- return `\`${body.replace(/[^\n]/g, fillChar)}\``;
- }
- }
- if (token.type === "RegularExpressionLiteral") {
- const body = token.value;
- if (filter(body)) {
- return body.replace(/\/(.*)\/(\w?)$/g, (_, $1, $2) => `/${fillChar.repeat($1.length)}/${$2}`);
- }
- }
- if (token.type === "TemplateHead") {
- const body = token.value.slice(1, -2);
- if (filter(body)) {
- return `\`${body.replace(/[^\n]/g, fillChar)}\${`;
- }
- }
- if (token.type === "TemplateTail") {
- const body = token.value.slice(0, -2);
- if (filter(body)) {
- return `}${body.replace(/[^\n]/g, fillChar)}\``;
- }
- }
- if (token.type === "TemplateMiddle") {
- const body = token.value.slice(1, -2);
- if (filter(body)) {
- return `}${body.replace(/[^\n]/g, fillChar)}\${`;
- }
- }
- return token.value;
-}
-function optionsWithDefaults(options) {
- return {
- fillChar: " ",
- filter: (() => true)
- };
-}
-function stripLiteral(code, options) {
- let result = "";
- const _options = optionsWithDefaults();
- for (const token of jsTokens(code, { jsx: false })) {
- result += stripLiteralFromToken(token, _options.fillChar, _options.filter);
- }
- return result;
-}
-
-// so people can reassign envs at runtime
-// import.meta.env.VITE_NAME = 'app' -> process.env.VITE_NAME = 'app'
-function MetaEnvReplacerPlugin() {
- return {
- name: "vitest:meta-env-replacer",
- enforce: "pre",
- transform(code, id) {
- if (!/\bimport\.meta\.env\b/.test(code)) return null;
- let s = null;
- const envs = stripLiteral(code).matchAll(/\bimport\.meta\.env\b/g);
- for (const env of envs) {
- s ||= new MagicString(code);
- const startIndex = env.index;
- const endIndex = startIndex + env[0].length;
- s.overwrite(startIndex, endIndex, `Object.assign(/* istanbul ignore next */ globalThis.__vitest_worker__?.metaEnv ?? import.meta.env)`);
- }
- if (s) return {
- code: s.toString(),
- map: s.generateMap({
- hires: "boundary",
- source: cleanUrl(id)
- })
- };
- }
- };
-}
-
-function MocksPlugins(options = {}) {
- const normalizedDistDir = normalize(distDir);
- return [hoistMocksPlugin({
- filter(id) {
- if (id.includes(normalizedDistDir)) return false;
- if (options.filter) return options.filter(id);
- return true;
- },
- codeFrameGenerator(node, id, code) {
- return generateCodeFrame(code, 4, node.start + 1);
- }
- }), automockPlugin()];
-}
-
-function generateCssFilenameHash(filepath) {
- return hash("sha1", filepath, "hex").slice(0, 6);
-}
-function generateScopedClassName(strategy, name, filename) {
- // should be configured by Vite defaults
- if (strategy === "scoped") return null;
- if (strategy === "non-scoped") return name;
- return `_${name}_${generateCssFilenameHash(filename)}`;
-}
-
-const LogLevels = {
- silent: 0,
- error: 1,
- warn: 2,
- info: 3
-};
-function clearScreen(logger) {
- const repeatCount = process.stdout.rows - 2;
- const blank = repeatCount > 0 ? "\n".repeat(repeatCount) : "";
- logger.clearScreen(blank);
-}
-let lastType;
-let lastMsg;
-let sameCount = 0;
-// Only initialize the timeFormatter when the timestamp option is used, and
-// reuse it across all loggers
-let timeFormatter;
-function getTimeFormatter() {
- timeFormatter ??= new Intl.DateTimeFormat(void 0, {
- hour: "numeric",
- minute: "numeric",
- second: "numeric"
- });
- return timeFormatter;
-}
-// This is copy-pasted and needs to be synced from time to time. Ideally, Vite's `createLogger` should accept a custom `console`
-// https://github.com/vitejs/vite/blob/main/packages/vite/src/node/logger.ts?rgh-link-date=2024-10-16T23%3A29%3A19Z
-// When Vitest supports only Vite 6 and above, we can use Vite's `createLogger({ console })`
-// https://github.com/vitejs/vite/pull/18379
-function createViteLogger(console, level = "info", options = {}) {
- const loggedErrors = /* @__PURE__ */ new WeakSet();
- const { prefix = "[vite]", allowClearScreen = true } = options;
- const thresh = LogLevels[level];
- const canClearScreen = allowClearScreen && process.stdout.isTTY && !process.env.CI;
- const clear = canClearScreen ? clearScreen : () => {};
- function format(type, msg, options = {}) {
- if (options.timestamp) {
- let tag = "";
- if (type === "info") tag = c.cyan(c.bold(prefix));
- else if (type === "warn") tag = c.yellow(c.bold(prefix));
- else tag = c.red(c.bold(prefix));
- const environment = options.environment ? `${options.environment} ` : "";
- return `${c.dim(getTimeFormatter().format(/* @__PURE__ */ new Date()))} ${tag} ${environment}${msg}`;
- } else return msg;
- }
- function output(type, msg, options = {}) {
- if (thresh >= LogLevels[type]) {
- const method = type === "info" ? "log" : type;
- if (options.error) loggedErrors.add(options.error);
- if (canClearScreen) if (type === lastType && msg === lastMsg) {
- sameCount++;
- clear(console);
- console[method](format(type, msg, options), c.yellow(`(x${sameCount + 1})`));
- } else {
- sameCount = 0;
- lastMsg = msg;
- lastType = type;
- if (options.clear) clear(console);
- console[method](format(type, msg, options));
- }
- else console[method](format(type, msg, options));
- }
- }
- const warnedMessages = /* @__PURE__ */ new Set();
- const logger = {
- hasWarned: false,
- info(msg, opts) {
- output("info", msg, opts);
- },
- warn(msg, opts) {
- logger.hasWarned = true;
- output("warn", msg, opts);
- },
- warnOnce(msg, opts) {
- if (warnedMessages.has(msg)) return;
- logger.hasWarned = true;
- output("warn", msg, opts);
- warnedMessages.add(msg);
- },
- error(msg, opts) {
- logger.hasWarned = true;
- output("error", msg, opts);
- },
- clearScreen(type) {
- if (thresh >= LogLevels[type]) clear(console);
- },
- hasErrorLogged(error) {
- return loggedErrors.has(error);
- }
- };
- return logger;
-}
-// silence warning by Vite for statically not analyzable dynamic import
-function silenceImportViteIgnoreWarning(logger) {
- return {
- ...logger,
- warn(msg, options) {
- if (msg.includes("The above dynamic import cannot be analyzed by Vite")) return;
- logger.warn(msg, options);
- }
- };
-}
-
-const cssLangs = "\\.(?:css|less|sass|scss|styl|stylus|pcss|postcss)(?:$|\\?)";
-const cssLangRE = new RegExp(cssLangs);
-const cssModuleRE = /* @__PURE__ */ new RegExp(`\\.module${cssLangs}`);
-const cssInlineRE = /[?&]inline(?:&|$)/;
-function isCSS(id) {
- return cssLangRE.test(id);
-}
-function isCSSModule(id) {
- return cssModuleRE.test(id);
-}
-// inline css requests are expected to just return the
-// string content directly and not the proxy module
-function isInline(id) {
- return cssInlineRE.test(id);
-}
-function getCSSModuleProxyReturn(strategy, filename) {
- if (strategy === "non-scoped") return "style";
- return `\`_\${style}_${generateCssFilenameHash(filename)}\``;
-}
-function CSSEnablerPlugin(ctx) {
- const shouldProcessCSS = (id) => {
- const { css } = ctx.config;
- if (typeof css === "boolean") return css;
- if (toArray(css.exclude).some((re) => re.test(id))) return false;
- if (toArray(css.include).some((re) => re.test(id))) return true;
- return false;
- };
- return [{
- name: "vitest:css-disable",
- enforce: "pre",
- transform(code, id) {
- if (!isCSS(id)) return;
- // css plugin inside Vite won't do anything if the code is empty
- // but it will put __vite__updateStyle anyway
- if (!shouldProcessCSS(id)) return { code: "" };
- }
- }, {
- name: "vitest:css-empty-post",
- enforce: "post",
- transform(_, id) {
- if (!isCSS(id) || shouldProcessCSS(id)) return;
- if (isCSSModule(id) && !isInline(id)) return { code: `export default new Proxy(Object.create(null), {
- get(_, style) {
- return ${getCSSModuleProxyReturn(typeof ctx.config.css !== "boolean" && ctx.config.css.modules?.classNameStrategy || "stable", relative(ctx.config.root, id))};
- },
- })` };
- return { code: "export default \"\"" };
- }
- }];
-}
-
-const metaUrlLength = 15;
-const locationString = "self.location".padEnd(metaUrlLength, " ");
-// Vite transforms new URL('./path', import.meta.url) to new URL('/path.js', import.meta.url)
-// This makes "href" equal to "http://localhost:3000/path.js" in the browser, but if we keep it like this,
-// then in tests the URL will become "file:///path.js".
-// To battle this, we replace "import.meta.url" with "self.location" in the code to keep the browser behavior.
-function NormalizeURLPlugin() {
- return {
- name: "vitest:normalize-url",
- enforce: "post",
- transform(code) {
- if (this.environment.name !== "client" || !code.includes("new URL") || !code.includes("import.meta.url")) return;
- const cleanString = stripLiteral(code);
- const assetImportMetaUrlRE = /\bnew\s+URL\s*\(\s*(?:'[^']+'|"[^"]+"|`[^`]+`)\s*,\s*(?:'' \+ )?import\.meta\.url\s*(?:,\s*)?\)/g;
- let updatedCode = code;
- let match;
- // eslint-disable-next-line no-cond-assign
- while (match = assetImportMetaUrlRE.exec(cleanString)) {
- const { 0: exp, index } = match;
- const metaUrlIndex = index + exp.indexOf("import.meta.url");
- updatedCode = updatedCode.slice(0, metaUrlIndex) + locationString + updatedCode.slice(metaUrlIndex + metaUrlLength);
- }
- return {
- code: updatedCode,
- map: null
- };
- }
- };
-}
-
-function VitestOptimizer() {
- return {
- name: "vitest:normalize-optimizer",
- config: {
- order: "post",
- handler(viteConfig) {
- const testConfig = viteConfig.test || {};
- const root = resolve(viteConfig.root || process.cwd());
- const name = viteConfig.test?.name;
- const label = typeof name === "string" ? name : name?.label || "";
- viteConfig.cacheDir = VitestCache.resolveCacheDir(resolve(root || process.cwd()), testConfig.cache != null && testConfig.cache !== false ? testConfig.cache.dir : viteConfig.cacheDir, label);
- }
- }
- };
-}
-
-function resolveOptimizerConfig(_testOptions, viteOptions) {
- const testOptions = _testOptions || {};
- let optimizeDeps;
- if (testOptions.enabled !== true) {
- testOptions.enabled ??= false;
- optimizeDeps = {
- disabled: true,
- entries: []
- };
- } else {
- const currentInclude = testOptions.include || viteOptions?.include || [];
- const exclude = [
- "vitest",
- "react",
- "vue",
- ...testOptions.exclude || viteOptions?.exclude || []
- ];
- const runtime = currentInclude.filter((n) => n.endsWith("jsx-dev-runtime") || n.endsWith("jsx-runtime"));
- exclude.push(...runtime);
- const include = (testOptions.include || viteOptions?.include || []).filter((n) => !exclude.includes(n));
- optimizeDeps = {
- ...viteOptions,
- ...testOptions,
- noDiscovery: true,
- disabled: false,
- entries: [],
- exclude,
- include
- };
- }
- // `optimizeDeps.disabled` is deprecated since v5.1.0-beta.1
- // https://github.com/vitejs/vite/pull/15184
- if (optimizeDeps.disabled) {
- optimizeDeps.noDiscovery = true;
- optimizeDeps.include = [];
- }
- delete optimizeDeps.disabled;
- return optimizeDeps;
-}
-function deleteDefineConfig(viteConfig) {
- const defines = {};
- if (viteConfig.define) {
- delete viteConfig.define["import.meta.vitest"];
- delete viteConfig.define["process.env"];
- delete viteConfig.define.process;
- delete viteConfig.define.global;
- }
- for (const key in viteConfig.define) {
- const val = viteConfig.define[key];
- let replacement;
- try {
- replacement = typeof val === "string" ? JSON.parse(val) : val;
- } catch {
- // probably means it contains reference to some variable,
- // like this: "__VAR__": "process.env.VAR"
- continue;
- }
- if (key.startsWith("import.meta.env.")) {
- const envKey = key.slice(16);
- process.env[envKey] = replacement;
- delete viteConfig.define[key];
- } else if (key.startsWith("process.env.")) {
- const envKey = key.slice(12);
- process.env[envKey] = replacement;
- delete viteConfig.define[key];
- } else if (!key.includes(".")) {
- defines[key] = replacement;
- delete viteConfig.define[key];
- }
- }
- return defines;
-}
-function resolveFsAllow(projectRoot, rootConfigFile) {
- if (!rootConfigFile) return [searchForWorkspaceRoot(projectRoot), rootDir];
- return [
- dirname(rootConfigFile),
- searchForWorkspaceRoot(projectRoot),
- rootDir
- ];
-}
-function getDefaultResolveOptions() {
- return {
- mainFields: [],
- conditions: getDefaultServerConditions()
- };
-}
-function getDefaultServerConditions() {
- if (Number(version.split(".")[0]) >= 6) return vite.defaultServerConditions.filter((c) => c !== "module");
- return ["node"];
-}
-
-function ModuleRunnerTransform() {
- // make sure Vite always applies the module runner transform
- return {
- name: "vitest:environments-module-runner",
- config: {
- order: "post",
- handler(config) {
- const testConfig = config.test || {};
- config.environments ??= {};
- const names = new Set(Object.keys(config.environments));
- names.add("client");
- names.add("ssr");
- const pool = config.test?.pool;
- if (pool === "vmForks" || pool === "vmThreads") names.add("__vitest_vm__");
- let moduleDirectories = testConfig.deps?.moduleDirectories || [];
- const envModuleDirectories = process.env.VITEST_MODULE_DIRECTORIES || process.env.npm_config_VITEST_MODULE_DIRECTORIES;
- if (envModuleDirectories) moduleDirectories.push(...envModuleDirectories.split(","));
- moduleDirectories = moduleDirectories.map((dir) => {
- if (dir[0] !== "/") dir = `/${dir}`;
- if (!dir.endsWith("/")) dir += "/";
- return normalize(dir);
- });
- if (!moduleDirectories.includes("/node_modules/")) moduleDirectories.push("/node_modules/");
- testConfig.deps ??= {};
- testConfig.deps.moduleDirectories = moduleDirectories;
- const external = [];
- const noExternal = [];
- let noExternalAll;
- for (const name of names) {
- config.environments[name] ??= {};
- const environment = config.environments[name];
- environment.dev ??= {};
- // vm tests run using the native import mechanism
- if (name === "__vitest_vm__") {
- environment.dev.moduleRunnerTransform = false;
- environment.consumer = "client";
- } else environment.dev.moduleRunnerTransform = true;
- environment.dev.preTransformRequests = false;
- environment.keepProcessEnv = true;
- const resolveExternal = name === "client" ? config.resolve?.external : [];
- const resolveNoExternal = name === "client" ? config.resolve?.noExternal : [];
- const topLevelResolveOptions = {};
- if (resolveExternal != null) topLevelResolveOptions.external = resolveExternal;
- if (resolveNoExternal != null) topLevelResolveOptions.noExternal = resolveNoExternal;
- const currentResolveOptions = mergeConfig(topLevelResolveOptions, environment.resolve || {});
- const envNoExternal = resolveViteResolveOptions("noExternal", currentResolveOptions, moduleDirectories);
- if (envNoExternal === true) noExternalAll = true;
- else if (envNoExternal.length) noExternal.push(...envNoExternal);
- else if (name === "client" || name === "ssr") {
- const deprecatedNoExternal = resolveDeprecatedOptions(name === "client" ? config.resolve?.noExternal : config.ssr?.noExternal, moduleDirectories);
- if (deprecatedNoExternal === true) noExternalAll = true;
- else noExternal.push(...deprecatedNoExternal);
- }
- const envExternal = resolveViteResolveOptions("external", currentResolveOptions, moduleDirectories);
- if (envExternal !== true && envExternal.length) external.push(...envExternal);
- else if (name === "client" || name === "ssr") {
- const deprecatedExternal = resolveDeprecatedOptions(name === "client" ? config.resolve?.external : config.ssr?.external, moduleDirectories);
- if (deprecatedExternal !== true) external.push(...deprecatedExternal);
- }
- // remove Vite's externalization logic because we have our own (unfortunetly)
- environment.resolve ??= {};
- environment.resolve.external = [...builtinModules, ...builtinModules.map((m) => `node:${m}`)];
- // by setting `noExternal` to `true`, we make sure that
- // Vite will never use its own externalization mechanism
- // to externalize modules and always resolve static imports
- // in both SSR and Client environments
- environment.resolve.noExternal = true;
- // Workaround `noExternal` merging bug on Vite 6
- // https://github.com/vitejs/vite/pull/20502
- if (name === "ssr") {
- delete config.ssr?.noExternal;
- delete config.ssr?.external;
- }
- if (name === "__vitest_vm__" || name === "__vitest__") continue;
- const currentOptimizeDeps = environment.optimizeDeps || (name === "client" ? config.optimizeDeps : name === "ssr" ? config.ssr?.optimizeDeps : void 0);
- const optimizeDeps = resolveOptimizerConfig(testConfig.deps?.optimizer?.[name], currentOptimizeDeps);
- // Vite respects the root level optimize deps, so we override it instead
- if (name === "client") {
- config.optimizeDeps = optimizeDeps;
- environment.optimizeDeps = void 0;
- } else if (name === "ssr") {
- config.ssr ??= {};
- config.ssr.optimizeDeps = optimizeDeps;
- environment.optimizeDeps = void 0;
- } else environment.optimizeDeps = optimizeDeps;
- }
- testConfig.server ??= {};
- testConfig.server.deps ??= {};
- if (testConfig.server.deps.inline !== true) {
- if (noExternalAll) testConfig.server.deps.inline = true;
- else if (noExternal.length) {
- testConfig.server.deps.inline ??= [];
- testConfig.server.deps.inline.push(...noExternal);
- }
- }
- if (external.length) {
- testConfig.server.deps.external ??= [];
- testConfig.server.deps.external.push(...external);
- }
- }
- }
- };
-}
-function resolveViteResolveOptions(key, options, moduleDirectories) {
- if (Array.isArray(options[key])) {
- // mergeConfig will merge a custom `true` into an array
- if (options[key].some((p) => p === true)) return true;
- return options[key].map((dep) => processWildcard(dep, moduleDirectories));
- } else if (typeof options[key] === "string" || options[key] instanceof RegExp) return [options[key]].map((dep) => processWildcard(dep, moduleDirectories));
- else if (typeof options[key] === "boolean") return true;
- return [];
-}
-function resolveDeprecatedOptions(options, moduleDirectories) {
- if (options === true) return true;
- else if (Array.isArray(options)) return options.map((dep) => processWildcard(dep, moduleDirectories));
- else if (options != null) return [processWildcard(options, moduleDirectories)];
- return [];
-}
-function processWildcard(dep, moduleDirectories) {
- if (typeof dep !== "string") return dep;
- if (typeof dep === "string" && dep.includes("*")) {
- const directories = (moduleDirectories || ["/node_modules/"]).map((r) => escapeRegExp(r));
- return /* @__PURE__ */ new RegExp(`(${directories.join("|")})${dep.replace(/\*/g, "[\\w/]+")}`);
- }
- return dep;
-}
-
-function VitestProjectResolver(ctx) {
- const plugin = {
- name: "vitest:resolve-root",
- enforce: "pre",
- config: {
- order: "post",
- handler() {
- return { base: "/" };
- }
- },
- async resolveId(id, _, { ssr }) {
- if (id === "vitest" || id.startsWith("@vitest/") || id.startsWith("vitest/")) return await ctx.vite.pluginContainer.resolveId(id, void 0, {
- skip: new Set([plugin]),
- ssr
- });
- }
- };
- return plugin;
-}
-function VitestCoreResolver(ctx) {
- return {
- name: "vitest:resolve-core",
- enforce: "pre",
- config: {
- order: "post",
- handler() {
- return { base: "/" };
- }
- },
- async resolveId(id) {
- if (id === "vitest") return resolve(distDir, "index.js");
- if (id.startsWith("@vitest/") || id.startsWith("vitest/"))
- // ignore actual importer, we want it to be resolved relative to the root
- return this.resolve(id, join(ctx.config.root, "index.html"), { skipSelf: true });
- }
- };
-}
-
-function WorkspaceVitestPlugin(project, options) {
- return [
- {
- name: "vitest:project:name",
- enforce: "post",
- config(viteConfig) {
- const testConfig = viteConfig.test || {};
- let { label: name, color } = typeof testConfig.name === "string" ? { label: testConfig.name } : {
- label: "",
- ...testConfig.name
- };
- if (!name) if (typeof options.workspacePath === "string") {
- // if there is a package.json, read the name from it
- const dir = options.workspacePath.endsWith("/") ? options.workspacePath.slice(0, -1) : dirname(options.workspacePath);
- const pkgJsonPath = resolve(dir, "package.json");
- if (existsSync(pkgJsonPath)) name = JSON.parse(readFileSync(pkgJsonPath, "utf-8")).name;
- if (typeof name !== "string" || !name) name = basename(dir);
- } else name = options.workspacePath.toString();
- const isBrowserEnabled = viteConfig.test?.browser?.enabled ?? (viteConfig.test?.browser && project.vitest._cliOptions.browser?.enabled);
- // keep project names to potentially filter it out
- const workspaceNames = [name];
- const browser = viteConfig.test.browser || {};
- if (isBrowserEnabled && browser.name && !browser.instances?.length)
- // vitest injects `instances` in this case later on
- workspaceNames.push(name ? `${name} (${browser.name})` : browser.name);
- viteConfig.test?.browser?.instances?.forEach((instance) => {
- // every instance is a potential project
- instance.name ??= name ? `${name} (${instance.browser})` : instance.browser;
- if (isBrowserEnabled) workspaceNames.push(instance.name);
- });
- // if there is `--project=...` filter, check if any of the potential projects match
- // if projects don't match, we ignore the test project altogether
- // if some of them match, they will later be filtered again by `resolveWorkspace`
- if (project.vitest.config.project.length) {
- if (!workspaceNames.some((name) => {
- return project.vitest.matchesProjectFilter(name);
- })) throw new VitestFilteredOutProjectError();
- }
- const vitestConfig = { name: {
- label: name,
- color
- } };
- // always inherit the global `fsModuleCache` value even without `extends: true`
- if (testConfig.experimental?.fsModuleCache == null && project.vitest.config.experimental?.fsModuleCache !== null) {
- vitestConfig.experimental ??= {};
- vitestConfig.experimental.fsModuleCache = project.vitest.config.experimental.fsModuleCache;
- }
- if (testConfig.experimental?.fsModuleCachePath == null && project.vitest.config.experimental?.fsModuleCachePath !== null) {
- vitestConfig.experimental ??= {};
- vitestConfig.experimental.fsModuleCachePath = project.vitest.config.experimental.fsModuleCachePath;
- }
- return {
- base: "/",
- environments: { __vitest__: { dev: {} } },
- test: vitestConfig
- };
- }
- },
- {
- name: "vitest:project",
- enforce: "pre",
- options() {
- this.meta.watchMode = false;
- },
- config(viteConfig) {
- const originalDefine = { ...viteConfig.define };
- const defines = deleteDefineConfig(viteConfig);
- const testConfig = viteConfig.test || {};
- const root = testConfig.root || viteConfig.root || options.root;
- const resolveOptions = getDefaultResolveOptions();
- let config = {
- root,
- define: { "process.env.NODE_ENV": "process.env.NODE_ENV" },
- resolve: {
- ...resolveOptions,
- alias: testConfig.alias
- },
- server: {
- watch: null,
- open: false,
- hmr: false,
- ws: false,
- preTransformRequests: false,
- middlewareMode: true,
- fs: { allow: resolveFsAllow(project.vitest.config.root, project.vitest.vite.config.configFile) }
- },
- environments: { ssr: { resolve: resolveOptions } },
- test: {}
- };
- if ("rolldownVersion" in vite) config = {
- ...config,
- oxc: viteConfig.oxc === false ? false : { target: viteConfig.oxc?.target || "node18" }
- };
- else config = {
- ...config,
- esbuild: viteConfig.esbuild === false ? false : {
- target: viteConfig.esbuild?.target || "node18",
- sourcemap: "external",
- legalComments: "inline"
- }
- };
- config.test.defines = defines;
- config.test.viteDefine = originalDefine;
- const classNameStrategy = typeof testConfig.css !== "boolean" && testConfig.css?.modules?.classNameStrategy || "stable";
- if (classNameStrategy !== "scoped") {
- config.css ??= {};
- config.css.modules ??= {};
- if (config.css.modules) config.css.modules.generateScopedName = (name, filename) => {
- const root = project.config.root;
- return generateScopedClassName(classNameStrategy, name, relative(root, filename));
- };
- }
- config.customLogger = createViteLogger(project.vitest.logger, viteConfig.logLevel || "warn", { allowClearScreen: false });
- config.customLogger = silenceImportViteIgnoreWarning(config.customLogger);
- return config;
- }
- },
- {
- name: "vitest:project:server",
- enforce: "post",
- async configureServer(server) {
- const options = deepMerge({}, configDefaults, server.config.test || {});
- await project._configureServer(options, server);
- await server.watcher.close();
- }
- },
- MetaEnvReplacerPlugin(),
- ...CSSEnablerPlugin(project),
- CoverageTransform(project.vitest),
- ...MocksPlugins(),
- VitestProjectResolver(project.vitest),
- VitestOptimizer(),
- NormalizeURLPlugin(),
- ModuleRunnerTransform()
- ];
-}
-
-class VitestResolver {
- options;
- externalizeConcurrentCache = /* @__PURE__ */ new Map();
- externalizeCache = /* @__PURE__ */ new Map();
- constructor(cacheDir, config) {
- // sorting to make cache consistent
- const inline = config.server.deps?.inline;
- if (Array.isArray(inline)) inline.sort();
- const external = config.server.deps?.external;
- if (Array.isArray(external)) external.sort();
- this.options = {
- moduleDirectories: config.deps.moduleDirectories?.sort(),
- inlineFiles: config.setupFiles.flatMap((file) => {
- if (file.startsWith("file://")) return file;
- const resolvedId = resolve(file);
- return [resolvedId, pathToFileURL(resolvedId).href];
- }),
- cacheDir,
- inline,
- external
- };
- }
- wasExternalized(file) {
- const normalizedFile = normalizeId(file);
- if (!this.externalizeCache.has(normalizedFile)) return false;
- return this.externalizeCache.get(normalizedFile) ?? false;
- }
- async shouldExternalize(file) {
- const normalizedFile = normalizeId(file);
- if (this.externalizeCache.has(normalizedFile)) return this.externalizeCache.get(normalizedFile);
- return shouldExternalize(normalizeId(file), this.options, this.externalizeConcurrentCache).then((result) => {
- this.externalizeCache.set(normalizedFile, result);
- return result;
- }).finally(() => {
- this.externalizeConcurrentCache.delete(normalizedFile);
- });
- }
-}
-function normalizeId(id) {
- if (id.startsWith("/@fs/")) id = id.slice(isWindows ? 5 : 4);
- return id;
-}
-const BUILTIN_EXTENSIONS = new Set([
- ".mjs",
- ".cjs",
- ".node",
- ".wasm"
-]);
-const ESM_EXT_RE = /\.(es|esm|esm-browser|esm-bundler|es6|module)\.js$/;
-const ESM_FOLDER_RE = /\/(es|esm)\/(.*\.js)$/;
-const defaultInline = [
- /virtual:/,
- /\.[mc]?ts$/,
- /[?&](init|raw|url|inline)\b/,
- KNOWN_ASSET_RE,
- /^(?!.*node_modules).*\.mjs$/,
- /^(?!.*node_modules).*\.cjs\.js$/,
- /vite\w*\/dist\/client\/env.mjs/
-];
-const depsExternal = [/\/node_modules\/.*\.cjs\.js$/, /\/node_modules\/.*\.mjs$/];
-function guessCJSversion(id) {
- if (id.match(ESM_EXT_RE)) {
- for (const i of [
- id.replace(ESM_EXT_RE, ".mjs"),
- id.replace(ESM_EXT_RE, ".umd.js"),
- id.replace(ESM_EXT_RE, ".cjs.js"),
- id.replace(ESM_EXT_RE, ".js")
- ]) if (existsSync(i)) return i;
- }
- if (id.match(ESM_FOLDER_RE)) {
- for (const i of [
- id.replace(ESM_FOLDER_RE, "/umd/$1"),
- id.replace(ESM_FOLDER_RE, "/cjs/$1"),
- id.replace(ESM_FOLDER_RE, "/lib/$1"),
- id.replace(ESM_FOLDER_RE, "/$1")
- ]) if (existsSync(i)) return i;
- }
-}
-// The code from https://github.com/unjs/mlly/blob/c5bcca0cda175921344fd6de1bc0c499e73e5dac/src/syntax.ts#L51-L98
-async function isValidNodeImport(id) {
- // clean url to strip off `?v=...` query etc.
- // node can natively import files with query params, so externalizing them is safe.
- id = cleanUrl(id);
- const extension = extname(id);
- if (BUILTIN_EXTENSIONS.has(extension)) return true;
- if (extension !== ".js") return false;
- id = id.replace("file:///", "");
- if (findNearestPackageData(dirname(id)).type === "module") return true;
- if (/\.(?:\w+-)?esm?(?:-\w+)?\.js$|\/esm?\//.test(id)) return false;
- try {
- await esModuleLexer.init;
- const code = await promises.readFile(id, "utf8");
- const [, , , hasModuleSyntax] = esModuleLexer.parse(code);
- return !hasModuleSyntax;
- } catch {
- return false;
- }
-}
-async function shouldExternalize(id, options, cache) {
- if (!cache.has(id)) cache.set(id, _shouldExternalize(id, options));
- return cache.get(id);
-}
-async function _shouldExternalize(id, options) {
- if (isBuiltin$1(id)) return id;
- // data: should be processed by native import,
- // since it is a feature of ESM.
- // also externalize network imports since nodejs allows it when --experimental-network-imports
- if (id.startsWith("data:") || /^(?:https?:)?\/\//.test(id)) return id;
- const moduleDirectories = options?.moduleDirectories || ["/node_modules/"];
- if (matchPattern(id, moduleDirectories, options?.inline)) return false;
- if (options?.inlineFiles && options?.inlineFiles.includes(id)) return false;
- if (matchPattern(id, moduleDirectories, options?.external)) return id;
- // Unless the user explicitly opted to inline them, externalize Vite deps.
- // They are too big to inline by default.
- if (options?.cacheDir && id.includes(options.cacheDir)) return id;
- const isLibraryModule = moduleDirectories.some((dir) => id.includes(dir));
- id = isLibraryModule && options?.fallbackCJS ? guessCJSversion(id) || id : id;
- if (matchPattern(id, moduleDirectories, defaultInline)) return false;
- if (matchPattern(id, moduleDirectories, depsExternal)) return id;
- if (isLibraryModule && await isValidNodeImport(id)) return id;
-}
-function matchPattern(id, moduleDirectories, patterns) {
- if (patterns == null) return false;
- if (patterns === true) return true;
- for (const ex of patterns) if (typeof ex === "string") {
- if (moduleDirectories.some((dir) => id.includes(join(dir, ex)))) return true;
- } else if (ex.test(id)) return true;
- return false;
-}
-
-class TestSpecification {
- /**
- * The task ID associated with the test module.
- */
- taskId;
- /**
- * The test project that the module belongs to.
- */
- project;
- /**
- * The ID of the module in the Vite module graph. It is usually an absolute file path.
- */
- moduleId;
- /**
- * The current test pool. It's possible to have multiple pools in a single test project with `poolMatchGlob` and `typecheck.enabled`.
- * @experimental In Vitest 4, the project will only support a single pool and this property will be removed.
- */
- pool;
- /**
- * Line numbers of the test locations to run.
- */
- testLines;
- constructor(project, moduleId, pool, testLines) {
- const name = project.config.name;
- const hashName = pool !== "typescript" ? name : name ? `${name}:__typecheck__` : "__typecheck__";
- this.taskId = generateFileHash(relative(project.config.root, moduleId), hashName);
- this.project = project;
- this.moduleId = moduleId;
- this.pool = pool;
- this.testLines = testLines;
- }
- /**
- * Test module associated with the specification.
- */
- get testModule() {
- const task = this.project.vitest.state.idMap.get(this.taskId);
- if (!task) return;
- return this.project.vitest.state.getReportedEntity(task);
- }
- toJSON() {
- return [
- {
- name: this.project.config.name,
- root: this.project.config.root
- },
- this.moduleId,
- {
- pool: this.pool,
- testLines: this.testLines
- }
- ];
- }
-}
-
-async function createViteServer(inlineConfig) {
- // Vite prints an error (https://github.com/vitejs/vite/issues/14328)
- // But Vitest works correctly either way
- const error = console.error;
- console.error = (...args) => {
- if (typeof args[0] === "string" && args[0].includes("WebSocket server error:")) return;
- error(...args);
- };
- const server = await createServer(inlineConfig);
- console.error = error;
- return server;
-}
-function isFileServingAllowed(configOrUrl, urlOrServer) {
- const config = typeof urlOrServer === "string" ? configOrUrl : urlOrServer.config;
- const url = typeof urlOrServer === "string" ? urlOrServer : configOrUrl;
- if (!config.server.fs.strict) return true;
- return isFileLoadingAllowed(config, fsPathFromUrl(url));
-}
-const FS_PREFIX = "/@fs/";
-const VOLUME_RE = /^[A-Z]:/i;
-function fsPathFromId(id) {
- const fsPath = normalizePath(id.startsWith(FS_PREFIX) ? id.slice(5) : id);
- return fsPath[0] === "/" || VOLUME_RE.test(fsPath) ? fsPath : `/${fsPath}`;
-}
-function fsPathFromUrl(url) {
- return fsPathFromId(cleanUrl(url));
-}
-
-class TestProject {
- /**
- * The global Vitest instance.
- */
- vitest;
- /**
- * Resolved global configuration. If there are no workspace projects, this will be the same as `config`.
- */
- globalConfig;
- /**
- * Browser instance if the browser is enabled. This is initialized when the tests run for the first time.
- */
- browser;
- /**
- * Temporary directory for the project. This is unique for each project. Vitest stores transformed content here.
- */
- tmpDir;
- /** @internal */ typechecker;
- /** @internal */ _config;
- /** @internal */ _vite;
- /** @internal */ _hash;
- /** @internal */ _resolver;
- /** @internal */ _fetcher;
- /** @internal */ _serializedDefines;
- /** @inetrnal */ testFilesList = null;
- runner;
- closingPromise;
- typecheckFilesList = null;
- _globalSetups;
- _provided = {};
- constructor(vitest, options, tmpDir) {
- this.options = options;
- this.vitest = vitest;
- this.globalConfig = vitest.config;
- this.tmpDir = tmpDir || join(tmpdir(), nanoid());
- }
- /**
- * The unique hash of this project. This value is consistent between the reruns.
- *
- * It is based on the root of the project (not consistent between OS) and its name.
- */
- get hash() {
- if (!this._hash) throw new Error("The server was not set. It means that `project.hash` was called before the Vite server was established.");
- return this._hash;
- }
- // "provide" is a property, not a method to keep the context when destructed in the global setup,
- // making it a method would be a breaking change, and can be done in Vitest 3 at minimum
- /**
- * Provide a value to the test context. This value will be available to all tests with `inject`.
- */
- provide = (key, value) => {
- try {
- structuredClone(value);
- } catch (err) {
- throw new Error(`Cannot provide "${key}" because it's not serializable.`, { cause: err });
- }
- // casting `any` because the default type is `never` since `ProvidedContext` is empty
- this._provided[key] = value;
- };
- /**
- * Get the provided context. The project context is merged with the global context.
- */
- getProvidedContext() {
- if (this.isRootProject()) return this._provided;
- // globalSetup can run even if core workspace is not part of the test run
- // so we need to inherit its provided context
- return {
- ...this.vitest.getRootProject().getProvidedContext(),
- ...this._provided
- };
- }
- /**
- * Creates a new test specification. Specifications describe how to run tests.
- * @param moduleId The file path
- */
- createSpecification(moduleId, locations, pool) {
- return new TestSpecification(this, moduleId, pool || getFilePoolName(this), locations);
- }
- toJSON() {
- return {
- name: this.name,
- serializedConfig: this.serializedConfig,
- context: this.getProvidedContext()
- };
- }
- /**
- * Vite's dev server instance. Every workspace project has its own server.
- */
- get vite() {
- if (!this._vite) throw new Error("The server was not set. It means that `project.vite` was called before the Vite server was established.");
- // checking it once should be enough
- Object.defineProperty(this, "vite", {
- configurable: true,
- writable: true,
- value: this._vite
- });
- return this._vite;
- }
- /**
- * Resolved project configuration.
- */
- get config() {
- if (!this._config) throw new Error("The config was not set. It means that `project.config` was called before the Vite server was established.");
- // checking it once should be enough
- // Object.defineProperty(this, 'config', {
- // configurable: true,
- // writable: true,
- // value: this._config,
- // })
- return this._config;
- }
- /**
- * The name of the project or an empty string if not set.
- */
- get name() {
- return this.config.name || "";
- }
- /**
- * The color used when reporting tasks of this project.
- */
- get color() {
- return this.config.color;
- }
- /**
- * Serialized project configuration. This is the config that tests receive.
- */
- get serializedConfig() {
- return this._serializeOverriddenConfig();
- }
- /**
- * Check if this is the root project. The root project is the one that has the root config.
- */
- isRootProject() {
- return this.vitest.getRootProject() === this;
- }
- /** @internal */
- async _initializeGlobalSetup() {
- if (this._globalSetups) return;
- this._globalSetups = await loadGlobalSetupFiles(this.runner, this.config.globalSetup);
- for (const globalSetupFile of this._globalSetups) {
- const teardown = await globalSetupFile.setup?.(this);
- if (teardown == null || !!globalSetupFile.teardown) continue;
- if (typeof teardown !== "function") throw new TypeError(`invalid return value in globalSetup file ${globalSetupFile.file}. Must return a function`);
- globalSetupFile.teardown = teardown;
- }
- }
- onTestsRerun(cb) {
- this.vitest.onTestsRerun(cb);
- }
- /** @internal */
- async _teardownGlobalSetup() {
- if (!this._globalSetups) return;
- for (const globalSetupFile of [...this._globalSetups].reverse()) await globalSetupFile.teardown?.();
- }
- /**
- * Get all files in the project that match the globs in the config and the filters.
- * @param filters String filters to match the test files.
- */
- async globTestFiles(filters = []) {
- return this.vitest._traces.$("vitest.config.resolve_include_project", async (span) => {
- const dir = this.config.dir || this.config.root;
- const { include, exclude, includeSource } = this.config;
- const typecheck = this.config.typecheck;
- span.setAttributes({
- cwd: dir,
- include,
- exclude,
- includeSource,
- typecheck: typecheck.enabled ? typecheck.include : []
- });
- const [testFiles, typecheckTestFiles] = await Promise.all([typecheck.enabled && typecheck.only ? [] : this.globAllTestFiles(include, exclude, includeSource, dir), typecheck.enabled ? this.typecheckFilesList || this.globFiles(typecheck.include, typecheck.exclude, dir) : []]);
- this.typecheckFilesList = typecheckTestFiles;
- return {
- testFiles: this.filterFiles(testFiles, filters, dir),
- typecheckTestFiles: this.filterFiles(typecheckTestFiles, filters, dir)
- };
- });
- }
- async globAllTestFiles(include, exclude, includeSource, cwd) {
- if (this.testFilesList) return this.testFilesList;
- const testFiles = await this.globFiles(include, exclude, cwd);
- if (includeSource?.length) {
- const files = await this.globFiles(includeSource, exclude, cwd);
- await Promise.all(files.map(async (file) => {
- try {
- const code = await promises.readFile(file, "utf-8");
- if (this.isInSourceTestCode(code)) testFiles.push(file);
- } catch {
- return null;
- }
- }));
- }
- this.testFilesList = testFiles;
- return testFiles;
- }
- isBrowserEnabled() {
- return isBrowserEnabled(this.config);
- }
- markTestFile(testPath) {
- this.testFilesList?.push(testPath);
- }
- /** @internal */
- _removeCachedTestFile(testPath) {
- if (this.testFilesList) this.testFilesList = this.testFilesList.filter((file) => file !== testPath);
- }
- /**
- * Returns if the file is a test file. Requires `.globTestFiles()` to be called first.
- * @internal
- */
- _isCachedTestFile(testPath) {
- return !!this.testFilesList && this.testFilesList.includes(testPath);
- }
- /**
- * Returns if the file is a typecheck test file. Requires `.globTestFiles()` to be called first.
- * @internal
- */
- _isCachedTypecheckFile(testPath) {
- return !!this.typecheckFilesList && this.typecheckFilesList.includes(testPath);
- }
- /** @internal */
- async globFiles(include, exclude, cwd) {
- // keep the slashes consistent with Vite
- // we are not using the pathe here because it normalizes the drive letter on Windows
- // and we want to keep it the same as working dir
- return (await glob(include, {
- dot: true,
- cwd,
- ignore: exclude,
- expandDirectories: false
- })).map((file) => slash(path.resolve(cwd, file)));
- }
- /**
- * Test if a file matches the test globs. This does the actual glob matching if the test is not cached, unlike `isCachedTestFile`.
- */
- matchesTestGlob(moduleId, source) {
- if (this._isCachedTestFile(moduleId)) return true;
- const relativeId = relative(this.config.dir || this.config.root, moduleId);
- if (pm.isMatch(relativeId, this.config.exclude)) return false;
- if (pm.isMatch(relativeId, this.config.include)) {
- this.markTestFile(moduleId);
- return true;
- }
- if (this.config.includeSource?.length && pm.isMatch(relativeId, this.config.includeSource)) {
- const code = source?.() || readFileSync(moduleId, "utf-8");
- if (this.isInSourceTestCode(code)) {
- this.markTestFile(moduleId);
- return true;
- }
- }
- return false;
- }
- isInSourceTestCode(code) {
- return code.includes("import.meta.vitest");
- }
- filterFiles(testFiles, filters, dir) {
- if (filters.length && process.platform === "win32") filters = filters.map((f) => slash(f));
- if (filters.length) return testFiles.filter((t) => {
- const testFile = relative(dir, t).toLocaleLowerCase();
- return filters.some((f) => {
- // if filter is a full file path, we should include it if it's in the same folder
- if (isAbsolute(f) && t.startsWith(f)) return true;
- const relativePath = f.endsWith("/") ? join(relative(dir, f), "/") : relative(dir, f);
- return testFile.includes(f.toLocaleLowerCase()) || testFile.includes(relativePath.toLocaleLowerCase());
- });
- });
- return testFiles;
- }
- _parentBrowser;
- /** @internal */
- _parent;
- /** @internal */
- _initParentBrowser = deduped(async (childProject) => {
- if (!this.isBrowserEnabled() || this._parentBrowser) return;
- const provider = this.config.browser.provider || childProject.config.browser.provider;
- if (provider == null) throw new Error(`Provider was not specified in the "browser.provider" setting. Please, pass down playwright(), webdriverio() or preview() from "@vitest/browser-playwright", "@vitest/browser-webdriverio" or "@vitest/browser-preview" package respectively.`);
- if (typeof provider.serverFactory !== "function") throw new TypeError(`The browser provider options do not return a "serverFactory" function. Are you using the latest "@vitest/browser-${provider.name}" package?`);
- const browser = await provider.serverFactory({
- project: this,
- mocksPlugins: (options) => MocksPlugins(options),
- metaEnvReplacer: () => MetaEnvReplacerPlugin(),
- coveragePlugin: () => CoverageTransform(this.vitest)
- });
- this._parentBrowser = browser;
- if (this.config.browser.ui) setup(this.vitest, browser.vite);
- });
- /** @internal */
- _initBrowserServer = deduped(async () => {
- await this._parent?._initParentBrowser(this);
- if (!this.browser && this._parent?._parentBrowser) {
- this.browser = this._parent._parentBrowser.spawn(this);
- await this.vitest.report("onBrowserInit", this);
- }
- });
- /**
- * Closes the project and all associated resources. This can only be called once; the closing promise is cached until the server restarts.
- * If the resources are needed again, create a new project.
- */
- close() {
- if (!this.closingPromise) this.closingPromise = Promise.all([
- this.vite?.close(),
- this.typechecker?.stop(),
- this.browser?.close(),
- this.clearTmpDir()
- ].filter(Boolean)).then(() => {
- if (!this.runner.isClosed()) return this.runner.close();
- }).then(() => {
- this._provided = {};
- this._vite = void 0;
- });
- return this.closingPromise;
- }
- /**
- * Import a file using Vite module runner.
- * @param moduleId The ID of the module in Vite module graph
- */
- import(moduleId) {
- return this.runner.import(moduleId);
- }
- _setHash() {
- this._hash = generateHash(this._config.root + this._config.name);
- }
- /** @internal */
- async _configureServer(options, server) {
- this._config = resolveConfig(this.vitest, {
- ...options,
- coverage: this.vitest.config.coverage
- }, server.config);
- this._config.api.token = this.vitest.config.api.token;
- this._setHash();
- for (const _providedKey in this.config.provide) {
- const providedKey = _providedKey;
- // type is very strict here, so we cast it to any
- this.provide(providedKey, this.config.provide[providedKey]);
- }
- this.closingPromise = void 0;
- this._resolver = new VitestResolver(server.config.cacheDir, this._config);
- this._vite = server;
- this._serializedDefines = createDefinesScript(server.config.define);
- this._fetcher = createFetchModuleFunction(this._resolver, this._config, this.vitest._fsCache, this.vitest._traces, this.tmpDir);
- const environment = server.environments.__vitest__;
- this.runner = new ServerModuleRunner(environment, this._fetcher, this._config);
- }
- _serializeOverriddenConfig() {
- // TODO: serialize the config _once_ or when needed
- const config = serializeConfig(this);
- if (!this.vitest.configOverride) return config;
- return deepMerge(config, this.vitest.configOverride);
- }
- async clearTmpDir() {
- try {
- await rm(this.tmpDir, { recursive: true });
- } catch {}
- }
- /** @internal */
- _initBrowserProvider = deduped(async () => {
- if (!this.isBrowserEnabled() || this.browser?.provider) return;
- if (!this.browser) await this._initBrowserServer();
- await this.browser?.initBrowserProvider(this);
- });
- /** @internal */
- _provideObject(context) {
- for (const _providedKey in context) {
- const providedKey = _providedKey;
- // type is very strict here, so we cast it to any
- this.provide(providedKey, context[providedKey]);
- }
- }
- /** @internal */
- static _createBasicProject(vitest) {
- const project = new TestProject(vitest, void 0, vitest._tmpDir);
- project.runner = vitest.runner;
- project._vite = vitest.vite;
- project._config = vitest.config;
- project._resolver = vitest._resolver;
- project._fetcher = vitest._fetcher;
- project._serializedDefines = createDefinesScript(vitest.vite.config.define);
- project._setHash();
- project._provideObject(vitest.config.provide);
- return project;
- }
- /** @internal */
- static _cloneBrowserProject(parent, config) {
- const clone = new TestProject(parent.vitest, void 0, parent.tmpDir);
- clone.runner = parent.runner;
- clone._vite = parent._vite;
- clone._resolver = parent._resolver;
- clone._fetcher = parent._fetcher;
- clone._config = config;
- clone._setHash();
- clone._parent = parent;
- clone._serializedDefines = parent._serializedDefines;
- clone._provideObject(config.provide);
- return clone;
- }
-}
-function deduped(cb) {
- let _promise;
- return ((...args) => {
- if (!_promise) _promise = cb(...args).finally(() => {
- _promise = void 0;
- });
- return _promise;
- });
-}
-async function initializeProject(workspacePath, ctx, options) {
- const project = new TestProject(ctx, options);
- const { configFile, ...restOptions } = options;
- await createViteServer({
- ...restOptions,
- configFile,
- configLoader: ctx.vite.config.inlineConfig.configLoader,
- mode: options.test?.mode || options.mode || ctx.config.mode,
- plugins: [...options.plugins || [], WorkspaceVitestPlugin(project, {
- ...options,
- workspacePath
- })]
- });
- return project;
-}
-function generateHash(str) {
- let hash = 0;
- if (str.length === 0) return `${hash}`;
- for (let i = 0; i < str.length; i++) {
- const char = str.charCodeAt(i);
- hash = (hash << 5) - hash + char;
- hash = hash & hash;
- }
- return `${hash}`;
-}
-
-// vitest.config.*
-// vite.config.*
-// vitest.unit.config.*
-// vite.unit.config.*
-const CONFIG_REGEXP = /^vite(?:st)?(?:\.\w+)?\.config\./;
-async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projectsDefinition, names) {
- const { configFiles, projectConfigs, nonConfigDirectories } = await resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDefinition);
- const cliOverrides = [
- "logHeapUsage",
- "allowOnly",
- "sequence",
- "testTimeout",
- "pool",
- "update",
- "globals",
- "expandSnapshotDiff",
- "disableConsoleIntercept",
- "retry",
- "testNamePattern",
- "passWithNoTests",
- "bail",
- "isolate",
- "printConsoleTrace",
- "inspect",
- "inspectBrk",
- "fileParallelism"
- ].reduce((acc, name) => {
- if (name in cliOptions) acc[name] = cliOptions[name];
- return acc;
- }, {});
- const projectPromises = [];
- const fileProjects = [...configFiles, ...nonConfigDirectories];
- const concurrent = limitConcurrency(nodeos__default.availableParallelism?.() || nodeos__default.cpus().length || 5);
- projectConfigs.forEach((options, index) => {
- const configRoot = vitest.config.root;
- // if extends a config file, resolve the file path
- const configFile = typeof options.extends === "string" ? resolve(configRoot, options.extends) : options.extends === true ? vitest.vite.config.configFile || false : false;
- // if `root` is configured, resolve it relative to the workspace file or vite root (like other options)
- // if `root` is not specified, inline configs use the same root as the root project
- const root = options.root ? resolve(configRoot, options.root) : vitest.config.root;
- projectPromises.push(concurrent(() => initializeProject(index, vitest, {
- ...options,
- root,
- configFile,
- test: {
- ...options.test,
- ...cliOverrides
- }
- })));
- });
- for (const path of fileProjects) {
- // if file leads to the root config, then we can just reuse it because we already initialized it
- if (vitest.vite.config.configFile === path) {
- const project = getDefaultTestProject(vitest);
- if (project) projectPromises.push(Promise.resolve(project));
- continue;
- }
- const configFile = path.endsWith("/") ? false : path;
- const root = path.endsWith("/") ? path : dirname(path);
- projectPromises.push(concurrent(() => initializeProject(path, vitest, {
- root,
- configFile,
- test: cliOverrides
- })));
- }
- // pretty rare case - the glob didn't match anything and there are no inline configs
- if (!projectPromises.length) throw new Error([
- "No projects were found. Make sure your configuration is correct. ",
- vitest.config.project.length ? `The filter matched no projects: ${vitest.config.project.join(", ")}. ` : "",
- `The projects definition: ${JSON.stringify(projectsDefinition, null, 4)}.`
- ].join(""));
- const resolvedProjectsPromises = await Promise.allSettled(projectPromises);
- const errors = [];
- const resolvedProjects = [];
- for (const result of resolvedProjectsPromises) if (result.status === "rejected") {
- if (result.reason instanceof VitestFilteredOutProjectError)
- // filter out filtered out projects
- continue;
- errors.push(result.reason);
- } else resolvedProjects.push(result.value);
- if (errors.length) throw new AggregateError(errors, "Failed to initialize projects. There were errors during projects setup. See below for more details.");
- // project names are guaranteed to be unique
- for (const project of resolvedProjects) {
- const name = project.name;
- if (names.has(name)) {
- const duplicate = resolvedProjects.find((p) => p.name === name && p !== project);
- const filesError = fileProjects.length ? [
- "\n\nYour config matched these files:\n",
- fileProjects.map((p) => ` - ${relative(vitest.config.root, p)}`).join("\n"),
- "\n\n"
- ].join("") : " ";
- throw new Error([
- `Project name "${name}"`,
- project.vite.config.configFile ? ` from "${relative(vitest.config.root, project.vite.config.configFile)}"` : "",
- " is not unique.",
- duplicate?.vite.config.configFile ? ` The project is already defined by "${relative(vitest.config.root, duplicate.vite.config.configFile)}".` : "",
- filesError,
- "All projects should have unique names. Make sure your configuration is correct."
- ].join(""));
- }
- names.add(name);
- }
- return resolveBrowserProjects(vitest, names, resolvedProjects);
-}
-async function resolveBrowserProjects(vitest, names, resolvedProjects) {
- const removeProjects = /* @__PURE__ */ new Set();
- resolvedProjects.forEach((project) => {
- if (!project.config.browser.enabled) return;
- const instances = project.config.browser.instances || [];
- if (instances.length === 0) {
- removeProjects.add(project);
- return;
- }
- const originalName = project.config.name;
- // if original name is in the --project=name filter, keep all instances
- const filteredInstances = vitest.matchesProjectFilter(originalName) ? instances : instances.filter((instance) => {
- const newName = instance.name;
- return vitest.matchesProjectFilter(newName);
- });
- // every project was filtered out
- if (!filteredInstances.length) {
- removeProjects.add(project);
- return;
- }
- filteredInstances.forEach((config, index) => {
- const browser = config.browser;
- if (!browser) {
- const nth = index + 1;
- const ending = nth === 2 ? "nd" : nth === 3 ? "rd" : "th";
- throw new Error(`The browser configuration must have a "browser" property. The ${nth}${ending} item in "browser.instances" doesn't have it. Make sure your${originalName ? ` "${originalName}"` : ""} configuration is correct.`);
- }
- const name = config.name;
- if (name == null) throw new Error(`The browser configuration must have a "name" property. This is a bug in Vitest. Please, open a new issue with reproduction`);
- if (config.provider?.name != null && project.config.browser.provider?.name != null && config.provider?.name !== project.config.browser.provider?.name) throw new Error(`The instance cannot have a different provider from its parent. The "${name}" instance specifies "${config.provider?.name}" provider, but its parent has a "${project.config.browser.provider?.name}" provider.`);
- if (names.has(name)) throw new Error([
- `Cannot define a nested project for a ${browser} browser. The project name "${name}" was already defined. `,
- "If you have multiple instances for the same browser, make sure to define a custom \"name\". ",
- "All projects should have unique names. Make sure your configuration is correct."
- ].join(""));
- names.add(name);
- const clonedConfig = cloneConfig(project, config);
- clonedConfig.name = name;
- const clone = TestProject._cloneBrowserProject(project, clonedConfig);
- resolvedProjects.push(clone);
- });
- removeProjects.add(project);
- });
- return resolvedProjects.filter((project) => !removeProjects.has(project));
-}
-function cloneConfig(project, { browser, ...config }) {
- const { locators, viewport, testerHtmlPath, headless, screenshotDirectory, screenshotFailures, fileParallelism, browser: _browser, name, provider, ...overrideConfig } = config;
- const currentConfig = project.config.browser;
- const clonedConfig = deepClone(project.config);
- return mergeConfig({
- ...clonedConfig,
- browser: {
- ...project.config.browser,
- locators: locators ? { testIdAttribute: locators.testIdAttribute ?? currentConfig.locators.testIdAttribute } : project.config.browser.locators,
- viewport: viewport ?? currentConfig.viewport,
- testerHtmlPath: testerHtmlPath ?? currentConfig.testerHtmlPath,
- screenshotDirectory: screenshotDirectory ?? currentConfig.screenshotDirectory,
- screenshotFailures: screenshotFailures ?? currentConfig.screenshotFailures,
- headless: headless ?? currentConfig.headless,
- provider: provider ?? currentConfig.provider,
- fileParallelism: fileParallelism ?? currentConfig.fileParallelism,
- name: browser,
- instances: []
- },
- include: overrideConfig.include && overrideConfig.include.length > 0 ? [] : clonedConfig.include,
- exclude: overrideConfig.exclude && overrideConfig.exclude.length > 0 ? [] : clonedConfig.exclude,
- includeSource: overrideConfig.includeSource && overrideConfig.includeSource.length > 0 ? [] : clonedConfig.includeSource
- }, overrideConfig);
-}
-async function resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDefinition) {
- // project configurations that were specified directly
- const projectsOptions = [];
- // custom config files that were specified directly or resolved from a directory
- const projectsConfigFiles = [];
- // custom glob matches that should be resolved as directories or config files
- const projectsGlobMatches = [];
- // directories that don't have a config file inside, but should be treated as projects
- const nonConfigProjectDirectories = [];
- for (const definition of projectsDefinition) if (typeof definition === "string") {
- const stringOption = definition.replace("<rootDir>", vitest.config.root);
- // if the string doesn't contain a glob, we can resolve it directly
- // ['./vitest.config.js']
- if (!isDynamicPattern(stringOption)) {
- const file = resolve(vitest.config.root, stringOption);
- if (!existsSync(file)) {
- const note = "Projects definition";
- throw new Error(`${note} references a non-existing file or a directory: ${file}`);
- }
- const stats = statSync(file);
- // user can specify a config file directly
- if (stats.isFile()) {
- const name = basename(file);
- if (!CONFIG_REGEXP.test(name)) throw new Error(`The file "${relative(vitest.config.root, file)}" must start with "vitest.config"/"vite.config" or match the pattern "(vitest|vite).*.config.*" to be a valid project config.`);
- projectsConfigFiles.push(file);
- } else if (stats.isDirectory()) {
- const configFile = resolveDirectoryConfig(file);
- if (configFile) projectsConfigFiles.push(configFile);
- else {
- const directory = file.at(-1) === "/" ? file : `${file}/`;
- nonConfigProjectDirectories.push(directory);
- }
- } else
- // should never happen
- throw new TypeError(`Unexpected file type: ${file}`);
- } else projectsGlobMatches.push(stringOption);
- } else if (typeof definition === "function") projectsOptions.push(await definition({
- command: vitest.vite.config.command,
- mode: vitest.vite.config.mode,
- isPreview: false,
- isSsrBuild: false
- }));
- else projectsOptions.push(await definition);
- if (projectsGlobMatches.length) (await glob(projectsGlobMatches, {
- absolute: true,
- dot: true,
- onlyFiles: false,
- cwd: vitest.config.root,
- expandDirectories: false,
- ignore: [
- "**/node_modules/**",
- "**/*.timestamp-*",
- "**/.DS_Store"
- ]
- })).forEach((path) => {
- // directories are allowed with a glob like `packages/*`
- // in this case every directory is treated as a project
- if (path.endsWith("/")) {
- const configFile = resolveDirectoryConfig(path);
- if (configFile) projectsConfigFiles.push(configFile);
- else nonConfigProjectDirectories.push(path);
- } else {
- const name = basename(path);
- if (!CONFIG_REGEXP.test(name)) throw new Error(`The projects glob matched a file "${relative(vitest.config.root, path)}", but it should also either start with "vitest.config"/"vite.config" or match the pattern "(vitest|vite).*.config.*".`);
- projectsConfigFiles.push(path);
- }
- });
- return {
- projectConfigs: projectsOptions,
- nonConfigDirectories: nonConfigProjectDirectories,
- configFiles: Array.from(new Set(projectsConfigFiles))
- };
-}
-function resolveDirectoryConfig(directory) {
- const files = new Set(readdirSync(directory));
- // default resolution looks for vitest.config.* or vite.config.* files
- // this simulates how `findUp` works in packages/vitest/src/node/create.ts:29
- const configFile = configFiles.find((file) => files.has(file));
- if (configFile) return resolve(directory, configFile);
- return null;
-}
-function getDefaultTestProject(vitest) {
- const filter = vitest.config.project;
- const project = vitest._ensureRootProject();
- if (!filter.length) return project;
- if (getPotentialProjectNames(project).some((p) => vitest.matchesProjectFilter(p))) return project;
- return null;
-}
-function getPotentialProjectNames(project) {
- const names = [project.name];
- if (project.config.browser.instances) names.push(...project.config.browser.instances.map((i) => i.name));
- else if (project.config.browser.name) names.push(project.config.browser.name);
- return names;
-}
-
-async function loadCustomReporterModule(path, runner) {
- let customReporterModule;
- try {
- customReporterModule = await runner.import(path);
- } catch (customReporterModuleError) {
- throw new Error(`Failed to load custom Reporter from ${path}`, { cause: customReporterModuleError });
- }
- if (customReporterModule.default === null || customReporterModule.default === void 0) throw new Error(`Custom reporter loaded from ${path} was not the default export`);
- return customReporterModule.default;
-}
-function createReporters(reporterReferences, ctx) {
- const runner = ctx.runner;
- const promisedReporters = reporterReferences.map(async (referenceOrInstance) => {
- if (Array.isArray(referenceOrInstance)) {
- const [reporterName, reporterOptions] = referenceOrInstance;
- if (reporterName === "html") {
- await ctx.packageInstaller.ensureInstalled("@vitest/ui", ctx.config.root, ctx.version);
- return new (await (loadCustomReporterModule("@vitest/ui/reporter", runner)))(reporterOptions);
- } else if (reporterName in ReportersMap) {
- const BuiltinReporter = ReportersMap[reporterName];
- return new BuiltinReporter(reporterOptions);
- } else return new (await (loadCustomReporterModule(reporterName, runner)))(reporterOptions);
- }
- return referenceOrInstance;
- });
- return Promise.all(promisedReporters);
-}
-function createBenchmarkReporters(reporterReferences, runner) {
- const promisedReporters = reporterReferences.map(async (referenceOrInstance) => {
- if (typeof referenceOrInstance === "string") if (referenceOrInstance in BenchmarkReportsMap) {
- const BuiltinReporter = BenchmarkReportsMap[referenceOrInstance];
- return new BuiltinReporter();
- } else return new (await (loadCustomReporterModule(referenceOrInstance, runner)))();
- return referenceOrInstance;
- });
- return Promise.all(promisedReporters);
-}
-
-function parseFilter(filter) {
- const colonIndex = filter.lastIndexOf(":");
- if (colonIndex === -1) return { filename: filter };
- const [parsedFilename, lineNumber] = [filter.substring(0, colonIndex), filter.substring(colonIndex + 1)];
- if (lineNumber.match(/^\d+$/)) return {
- filename: parsedFilename,
- lineNumber: Number.parseInt(lineNumber)
- };
- else if (lineNumber.match(/^\d+-\d+$/)) throw new RangeLocationFilterProvidedError(filter);
- else return { filename: filter };
-}
-function groupFilters(filters) {
- const groupedFilters_ = groupBy(filters, (f) => f.filename);
- return Object.fromEntries(Object.entries(groupedFilters_).map((entry) => {
- const [filename, filters] = entry;
- return [filename, filters.map((f) => f.lineNumber).filter((l) => l !== void 0)];
- }));
-}
-
-class VitestSpecifications {
- _cachedSpecs = /* @__PURE__ */ new Map();
- constructor(vitest) {
- this.vitest = vitest;
- }
- getModuleSpecifications(moduleId) {
- const _cached = this.getCachedSpecifications(moduleId);
- if (_cached) return _cached;
- const specs = [];
- for (const project of this.vitest.projects) {
- if (project._isCachedTestFile(moduleId)) specs.push(project.createSpecification(moduleId));
- if (project._isCachedTypecheckFile(moduleId)) specs.push(project.createSpecification(moduleId, [], "typescript"));
- }
- specs.forEach((spec) => this.ensureSpecificationCached(spec));
- return specs;
- }
- async getRelevantTestSpecifications(filters = []) {
- return this.filterTestsBySource(await this.globTestSpecifications(filters));
- }
- async globTestSpecifications(filters = []) {
- const files = [];
- const dir = process.cwd();
- const parsedFilters = filters.map((f) => parseFilter(f));
- // Require includeTaskLocation when a location filter is passed
- if (!this.vitest.config.includeTaskLocation && parsedFilters.some((f) => f.lineNumber !== void 0)) throw new IncludeTaskLocationDisabledError();
- const testLines = groupFilters(parsedFilters.map((f) => ({
- ...f,
- filename: resolve(dir, f.filename)
- })));
- // Key is file and val specifies whether we have matched this file with testLocation
- const testLocHasMatch = {};
- await Promise.all(this.vitest.projects.map(async (project) => {
- const { testFiles, typecheckTestFiles } = await project.globTestFiles(parsedFilters.map((f) => f.filename));
- testFiles.forEach((file) => {
- const lines = testLines[file];
- testLocHasMatch[file] = true;
- const spec = project.createSpecification(file, lines);
- this.ensureSpecificationCached(spec);
- files.push(spec);
- });
- typecheckTestFiles.forEach((file) => {
- const lines = testLines[file];
- testLocHasMatch[file] = true;
- const spec = project.createSpecification(file, lines, "typescript");
- this.ensureSpecificationCached(spec);
- files.push(spec);
- });
- }));
- Object.entries(testLines).forEach(([filepath, loc]) => {
- if (loc.length !== 0 && !testLocHasMatch[filepath]) throw new LocationFilterFileNotFoundError(relative(dir, filepath));
- });
- return files;
- }
- clearCache(moduleId) {
- if (moduleId) this._cachedSpecs.delete(moduleId);
- else this._cachedSpecs.clear();
- }
- getCachedSpecifications(moduleId) {
- return this._cachedSpecs.get(moduleId);
- }
- ensureSpecificationCached(spec) {
- const file = spec.moduleId;
- const specs = this._cachedSpecs.get(file) || [];
- const index = specs.findIndex((_s) => _s.project === spec.project && _s.pool === spec.pool);
- if (index === -1) {
- specs.push(spec);
- this._cachedSpecs.set(file, specs);
- } else specs.splice(index, 1, spec);
- return specs;
- }
- async filterTestsBySource(specs) {
- if (this.vitest.config.changed && !this.vitest.config.related) {
- const { VitestGit } = await import('./git.Bm2pzPAa.js');
- const related = await new VitestGit(this.vitest.config.root).findChangedFiles({ changedSince: this.vitest.config.changed });
- if (!related) {
- process.exitCode = 1;
- throw new GitNotFoundError();
- }
- this.vitest.config.related = Array.from(new Set(related));
- }
- const related = this.vitest.config.related;
- if (!related) return specs;
- const forceRerunTriggers = this.vitest.config.forceRerunTriggers;
- const matcher = forceRerunTriggers.length ? pm(forceRerunTriggers) : void 0;
- if (matcher && related.some((file) => matcher(file))) return specs;
- // don't run anything if no related sources are found
- // if we are in watch mode, we want to process all tests
- if (!this.vitest.config.watch && !related.length) return [];
- const testGraphs = await Promise.all(specs.map(async (spec) => {
- return [spec, await this.getTestDependencies(spec)];
- }));
- const runningTests = [];
- for (const [specification, deps] of testGraphs)
- // if deps or the test itself were changed
- if (related.some((path) => path === specification.moduleId || deps.has(path))) runningTests.push(specification);
- return runningTests;
- }
- async getTestDependencies(spec, deps = /* @__PURE__ */ new Set()) {
- const addImports = async (project, filepath) => {
- if (deps.has(filepath)) return;
- deps.add(filepath);
- const transformed = project.vite.environments.ssr.moduleGraph.getModuleById(filepath)?.transformResult || await project.vite.environments.ssr.transformRequest(filepath);
- if (!transformed) return;
- const dependencies = [...transformed.deps || [], ...transformed.dynamicDeps || []];
- await Promise.all(dependencies.map(async (dep) => {
- const fsPath = dep.startsWith("/@fs/") ? dep.slice(isWindows ? 5 : 4) : join(project.config.root, dep);
- if (!fsPath.includes("node_modules") && !deps.has(fsPath) && existsSync(fsPath)) await addImports(project, fsPath);
- }));
- };
- await addImports(spec.project, spec.moduleId);
- deps.delete(spec.moduleId);
- return deps;
- }
-}
-
-class ReportedTaskImplementation {
- /**
- * Task instance.
- * @internal
- */
- task;
- /**
- * The project associated with the test or suite.
- */
- project;
- /**
- * Unique identifier.
- * This ID is deterministic and will be the same for the same test across multiple runs.
- * The ID is based on the project name, module url and test order.
- */
- id;
- /**
- * Location in the module where the test or suite is defined.
- */
- location;
- /** @internal */
- constructor(task, project) {
- this.task = task;
- this.project = project;
- this.id = task.id;
- this.location = task.location;
- }
- /**
- * Checks if the test did not fail the suite.
- * If the test is not finished yet or was skipped, it will return `true`.
- */
- ok() {
- const result = this.task.result;
- return !result || result.state !== "fail";
- }
- /**
- * Custom metadata that was attached to the test during its execution.
- */
- meta() {
- return this.task.meta;
- }
- /**
- * Creates a new reported task instance and stores it in the project's state for future use.
- * @internal
- */
- static register(task, project) {
- const state = new this(task, project);
- storeTask(project, task, state);
- return state;
- }
-}
-class TestCase extends ReportedTaskImplementation {
- #fullName;
- type = "test";
- /**
- * Direct reference to the test module where the test or suite is defined.
- */
- module;
- /**
- * Name of the test.
- */
- name;
- /**
- * Options that the test was initiated with.
- */
- options;
- /**
- * Parent suite. If the test was called directly inside the module, the parent will be the module itself.
- */
- parent;
- /** @internal */
- constructor(task, project) {
- super(task, project);
- this.name = task.name;
- this.module = getReportedTask(project, task.file);
- const suite = this.task.suite;
- if (suite) this.parent = getReportedTask(project, suite);
- else this.parent = this.module;
- this.options = buildOptions(task);
- }
- /**
- * Full name of the test including all parent suites separated with `>`.
- */
- get fullName() {
- if (this.#fullName === void 0) if (this.parent.type !== "module") this.#fullName = `${this.parent.fullName} > ${this.name}`;
- else this.#fullName = this.name;
- return this.#fullName;
- }
- /**
- * Test results.
- * - **pending**: Test was collected, but didn't finish running yet.
- * - **passed**: Test passed successfully
- * - **failed**: Test failed to execute
- * - **skipped**: Test was skipped during collection or dynamically with `ctx.skip()`.
- */
- result() {
- const result = this.task.result;
- const mode = result?.state || this.task.mode;
- if (!result && (mode === "skip" || mode === "todo")) return {
- state: "skipped",
- note: void 0,
- errors: void 0
- };
- if (!result || result.state === "run" || result.state === "queued") return {
- state: "pending",
- errors: void 0
- };
- const state = result.state === "fail" ? "failed" : result.state === "pass" ? "passed" : "skipped";
- if (state === "skipped") return {
- state,
- note: result.note,
- errors: void 0
- };
- if (state === "passed") return {
- state,
- errors: result.errors
- };
- return {
- state,
- errors: result.errors || []
- };
- }
- /**
- * Test annotations added via the `task.annotate` API during the test execution.
- */
- annotations() {
- return [...this.task.annotations];
- }
- /**
- * @experimental
- *
- * Test artifacts recorded via the `recordArtifact` API during the test execution.
- */
- artifacts() {
- return [...this.task.artifacts];
- }
- /**
- * Useful information about the test like duration, memory usage, etc.
- * Diagnostic is only available after the test has finished.
- */
- diagnostic() {
- const result = this.task.result;
- // startTime should always be available if the test has properly finished
- if (!result || !result.startTime) return;
- const duration = result.duration || 0;
- return {
- slow: duration > this.project.globalConfig.slowTestThreshold,
- heap: result.heap,
- duration,
- startTime: result.startTime,
- retryCount: result.retryCount ?? 0,
- repeatCount: result.repeatCount ?? 0,
- flaky: !!result.retryCount && result.state === "pass" && result.retryCount > 0
- };
- }
-}
-class TestCollection {
- #task;
- #project;
- constructor(task, project) {
- this.#task = task;
- this.#project = project;
- }
- /**
- * Returns the test or suite at a specific index.
- */
- at(index) {
- if (index < 0) index = this.size + index;
- return getReportedTask(this.#project, this.#task.tasks[index]);
- }
- /**
- * The number of tests and suites in the collection.
- */
- get size() {
- return this.#task.tasks.length;
- }
- /**
- * Returns the collection in array form for easier manipulation.
- */
- array() {
- return Array.from(this);
- }
- /**
- * Filters all tests that are part of this collection and its children.
- */
- *allTests(state) {
- for (const child of this) if (child.type === "suite") yield* child.children.allTests(state);
- else if (state) {
- if (state === child.result().state) yield child;
- } else yield child;
- }
- /**
- * Filters only the tests that are part of this collection.
- */
- *tests(state) {
- for (const child of this) {
- if (child.type !== "test") continue;
- if (state) {
- if (state === child.result().state) yield child;
- } else yield child;
- }
- }
- /**
- * Filters only the suites that are part of this collection.
- */
- *suites() {
- for (const child of this) if (child.type === "suite") yield child;
- }
- /**
- * Filters all suites that are part of this collection and its children.
- */
- *allSuites() {
- for (const child of this) if (child.type === "suite") {
- yield child;
- yield* child.children.allSuites();
- }
- }
- *[Symbol.iterator]() {
- for (const task of this.#task.tasks) yield getReportedTask(this.#project, task);
- }
-}
-class SuiteImplementation extends ReportedTaskImplementation {
- /**
- * Collection of suites and tests that are part of this suite.
- */
- children;
- /** @internal */
- constructor(task, project) {
- super(task, project);
- this.children = new TestCollection(task, project);
- }
- /**
- * Errors that happened outside of the test run during collection, like syntax errors.
- */
- errors() {
- return this.task.result?.errors || [];
- }
-}
-class TestSuite extends SuiteImplementation {
- #fullName;
- type = "suite";
- /**
- * Name of the test or the suite.
- */
- name;
- /**
- * Direct reference to the test module where the test or suite is defined.
- */
- module;
- /**
- * Parent suite. If suite was called directly inside the module, the parent will be the module itself.
- */
- parent;
- /**
- * Options that suite was initiated with.
- */
- options;
- /** @internal */
- constructor(task, project) {
- super(task, project);
- this.name = task.name;
- this.module = getReportedTask(project, task.file);
- const suite = this.task.suite;
- if (suite) this.parent = getReportedTask(project, suite);
- else this.parent = this.module;
- this.options = buildOptions(task);
- }
- /**
- * Checks the running state of the suite.
- */
- state() {
- return getSuiteState(this.task);
- }
- /**
- * Full name of the suite including all parent suites separated with `>`.
- */
- get fullName() {
- if (this.#fullName === void 0) if (this.parent.type !== "module") this.#fullName = `${this.parent.fullName} > ${this.name}`;
- else this.#fullName = this.name;
- return this.#fullName;
- }
-}
-class TestModule extends SuiteImplementation {
- type = "module";
- /**
- * The Vite environment that processes files on the server.
- *
- * Can be empty if test module did not run yet.
- */
- viteEnvironment;
- /**
- * This is usually an absolute UNIX file path.
- * It can be a virtual ID if the file is not on the disk.
- * This value corresponds to the ID in the Vite's module graph.
- */
- moduleId;
- /**
- * Module id relative to the project. This is the same as `task.name`.
- */
- relativeModuleId;
- /** @internal */
- constructor(task, project) {
- super(task, project);
- this.moduleId = task.filepath;
- this.relativeModuleId = task.name;
- if (task.viteEnvironment === "__browser__") this.viteEnvironment = project.browser?.vite.environments.client;
- else if (typeof task.viteEnvironment === "string") this.viteEnvironment = project.vite.environments[task.viteEnvironment];
- }
- /**
- * Checks the running state of the test file.
- */
- state() {
- if (this.task.result?.state === "queued") return "queued";
- return getSuiteState(this.task);
- }
- /**
- * Useful information about the module like duration, memory usage, etc.
- * If the module was not executed yet, all diagnostic values will return `0`.
- */
- diagnostic() {
- const setupDuration = this.task.setupDuration || 0;
- const collectDuration = this.task.collectDuration || 0;
- const prepareDuration = this.task.prepareDuration || 0;
- return {
- environmentSetupDuration: this.task.environmentLoad || 0,
- prepareDuration,
- collectDuration,
- setupDuration,
- duration: this.task.result?.duration || 0,
- heap: this.task.result?.heap,
- importDurations: this.task.importDurations ?? {}
- };
- }
-}
-function buildOptions(task) {
- return {
- each: task.each,
- fails: task.type === "test" && task.fails,
- concurrent: task.concurrent,
- shuffle: task.shuffle,
- retry: task.retry,
- repeats: task.repeats,
- mode: task.mode
- };
-}
-function storeTask(project, runnerTask, reportedTask) {
- project.vitest.state.reportedTasksMap.set(runnerTask, reportedTask);
-}
-function getReportedTask(project, runnerTask) {
- const reportedTask = project.vitest.state.getReportedEntity(runnerTask);
- if (!reportedTask) throw new Error(`Task instance was not found for ${runnerTask.type} "${runnerTask.name}"`);
- return reportedTask;
-}
-function getSuiteState(task) {
- const mode = task.mode;
- const state = task.result?.state;
- if (mode === "skip" || mode === "todo" || state === "skip" || state === "todo") return "skipped";
- if (state == null || state === "run" || state === "only") return "pending";
- if (state === "fail") return "failed";
- if (state === "pass") return "passed";
- throw new Error(`Unknown suite state: ${state}`);
-}
-function experimental_getRunnerTask(entity) {
- return entity.task;
-}
-
-function isAggregateError(err) {
- if (typeof AggregateError !== "undefined" && err instanceof AggregateError) return true;
- return err instanceof Error && "errors" in err;
-}
-class StateManager {
- filesMap = /* @__PURE__ */ new Map();
- pathsSet = /* @__PURE__ */ new Set();
- idMap = /* @__PURE__ */ new Map();
- taskFileMap = /* @__PURE__ */ new WeakMap();
- errorsSet = /* @__PURE__ */ new Set();
- reportedTasksMap = /* @__PURE__ */ new WeakMap();
- blobs;
- transformTime = 0;
- metadata = {};
- onUnhandledError;
- /** @internal */
- _data = {
- browserLastPort: defaultBrowserPort,
- timeoutIncreased: false
- };
- constructor(options) {
- this.onUnhandledError = options.onUnhandledError;
- }
- catchError(error, type) {
- if (isAggregateError(error)) return error.errors.forEach((error) => this.catchError(error, type));
- if (typeof error === "object" && error !== null) error.type = type;
- else error = {
- type,
- message: error
- };
- const _error = error;
- if (_error && typeof _error === "object" && _error.code === "VITEST_PENDING") {
- const task = this.idMap.get(_error.taskId);
- if (task) {
- task.mode = "skip";
- task.result ??= { state: "skip" };
- task.result.state = "skip";
- task.result.note = _error.note;
- }
- return;
- }
- if (!this.onUnhandledError || this.onUnhandledError(error) !== false) this.errorsSet.add(error);
- }
- clearErrors() {
- this.errorsSet.clear();
- }
- getUnhandledErrors() {
- return Array.from(this.errorsSet);
- }
- getPaths() {
- return Array.from(this.pathsSet);
- }
- /**
- * Return files that were running or collected.
- */
- getFiles(keys) {
- if (keys) return keys.map((key) => this.filesMap.get(key)).flat().filter((file) => file && !file.local);
- return Array.from(this.filesMap.values()).flat().filter((file) => !file.local).sort((f1, f2) => {
- // print typecheck files first
- if (f1.meta?.typecheck && f2.meta?.typecheck) return 0;
- if (f1.meta?.typecheck) return -1;
- return 1;
- });
- }
- getTestModules(keys) {
- return this.getFiles(keys).map((file) => this.getReportedEntity(file));
- }
- getFilepaths() {
- return Array.from(this.filesMap.keys());
- }
- getFailedFilepaths() {
- return this.getFiles().filter((i) => i.result?.state === "fail").map((i) => i.filepath);
- }
- collectPaths(paths = []) {
- paths.forEach((path) => {
- this.pathsSet.add(path);
- });
- }
- collectFiles(project, files = []) {
- files.forEach((file) => {
- const existing = this.filesMap.get(file.filepath) || [];
- const otherFiles = existing.filter((i) => i.projectName !== file.projectName || i.meta.typecheck !== file.meta.typecheck);
- const currentFile = existing.find((i) => i.projectName === file.projectName);
- // keep logs for the previous file because it should always be initiated before the collections phase
- // which means that all logs are collected during the collection and not inside tests
- if (currentFile) file.logs = currentFile.logs;
- otherFiles.push(file);
- this.filesMap.set(file.filepath, otherFiles);
- this.updateId(file, project);
- });
- }
- clearFiles(project, paths = []) {
- paths.forEach((path) => {
- const files = this.filesMap.get(path);
- const fileTask = createFileTask$1(path, project.config.root, project.config.name);
- fileTask.local = true;
- TestModule.register(fileTask, project);
- this.idMap.set(fileTask.id, fileTask);
- if (!files) {
- this.filesMap.set(path, [fileTask]);
- return;
- }
- const filtered = files.filter((file) => file.projectName !== project.config.name);
- // always keep a File task, so we can associate logs with it
- if (!filtered.length) this.filesMap.set(path, [fileTask]);
- else this.filesMap.set(path, [...filtered, fileTask]);
- });
- }
- updateId(task, project) {
- if (this.idMap.get(task.id) === task) return;
- if (task.type === "suite" && "filepath" in task) TestModule.register(task, project);
- else if (task.type === "suite") TestSuite.register(task, project);
- else TestCase.register(task, project);
- this.idMap.set(task.id, task);
- if (task.type === "suite") task.tasks.forEach((task) => {
- this.updateId(task, project);
- });
- }
- getReportedEntity(task) {
- return this.reportedTasksMap.get(task);
- }
- getReportedEntityById(taskId) {
- const task = this.idMap.get(taskId);
- return task ? this.reportedTasksMap.get(task) : void 0;
- }
- updateTasks(packs) {
- for (const [id, result, meta] of packs) {
- const task = this.idMap.get(id);
- if (task) {
- task.result = result;
- task.meta = meta;
- // skipped with new PendingError
- if (result?.state === "skip") task.mode = "skip";
- }
- }
- }
- updateUserLog(log) {
- const task = log.taskId && this.idMap.get(log.taskId);
- if (task) {
- if (!task.logs) task.logs = [];
- task.logs.push(log);
- }
- }
- getCountOfFailedTests() {
- return Array.from(this.idMap.values()).filter((t) => t.result?.state === "fail").length;
- }
- cancelFiles(files, project) {
- // if we don't filter existing modules, they will be overriden by `collectFiles`
- const nonRegisteredFiles = files.filter(({ filepath }) => {
- const id = generateFileHash(relative(project.config.root, filepath), project.name);
- return !this.idMap.has(id);
- });
- this.collectFiles(project, nonRegisteredFiles.map((file) => createFileTask$1(file.filepath, project.config.root, project.config.name)));
- }
-}
-
-const types = {
- 'application/andrew-inset': ['ez'],
- 'application/appinstaller': ['appinstaller'],
- 'application/applixware': ['aw'],
- 'application/appx': ['appx'],
- 'application/appxbundle': ['appxbundle'],
- 'application/atom+xml': ['atom'],
- 'application/atomcat+xml': ['atomcat'],
- 'application/atomdeleted+xml': ['atomdeleted'],
- 'application/atomsvc+xml': ['atomsvc'],
- 'application/atsc-dwd+xml': ['dwd'],
- 'application/atsc-held+xml': ['held'],
- 'application/atsc-rsat+xml': ['rsat'],
- 'application/automationml-aml+xml': ['aml'],
- 'application/automationml-amlx+zip': ['amlx'],
- 'application/bdoc': ['bdoc'],
- 'application/calendar+xml': ['xcs'],
- 'application/ccxml+xml': ['ccxml'],
- 'application/cdfx+xml': ['cdfx'],
- 'application/cdmi-capability': ['cdmia'],
- 'application/cdmi-container': ['cdmic'],
- 'application/cdmi-domain': ['cdmid'],
- 'application/cdmi-object': ['cdmio'],
- 'application/cdmi-queue': ['cdmiq'],
- 'application/cpl+xml': ['cpl'],
- 'application/cu-seeme': ['cu'],
- 'application/cwl': ['cwl'],
- 'application/dash+xml': ['mpd'],
- 'application/dash-patch+xml': ['mpp'],
- 'application/davmount+xml': ['davmount'],
- 'application/dicom': ['dcm'],
- 'application/docbook+xml': ['dbk'],
- 'application/dssc+der': ['dssc'],
- 'application/dssc+xml': ['xdssc'],
- 'application/ecmascript': ['ecma'],
- 'application/emma+xml': ['emma'],
- 'application/emotionml+xml': ['emotionml'],
- 'application/epub+zip': ['epub'],
- 'application/exi': ['exi'],
- 'application/express': ['exp'],
- 'application/fdf': ['fdf'],
- 'application/fdt+xml': ['fdt'],
- 'application/font-tdpfr': ['pfr'],
- 'application/geo+json': ['geojson'],
- 'application/gml+xml': ['gml'],
- 'application/gpx+xml': ['gpx'],
- 'application/gxf': ['gxf'],
- 'application/gzip': ['gz'],
- 'application/hjson': ['hjson'],
- 'application/hyperstudio': ['stk'],
- 'application/inkml+xml': ['ink', 'inkml'],
- 'application/ipfix': ['ipfix'],
- 'application/its+xml': ['its'],
- 'application/java-archive': ['jar', 'war', 'ear'],
- 'application/java-serialized-object': ['ser'],
- 'application/java-vm': ['class'],
- 'application/javascript': ['*js'],
- 'application/json': ['json', 'map'],
- 'application/json5': ['json5'],
- 'application/jsonml+json': ['jsonml'],
- 'application/ld+json': ['jsonld'],
- 'application/lgr+xml': ['lgr'],
- 'application/lost+xml': ['lostxml'],
- 'application/mac-binhex40': ['hqx'],
- 'application/mac-compactpro': ['cpt'],
- 'application/mads+xml': ['mads'],
- 'application/manifest+json': ['webmanifest'],
- 'application/marc': ['mrc'],
- 'application/marcxml+xml': ['mrcx'],
- 'application/mathematica': ['ma', 'nb', 'mb'],
- 'application/mathml+xml': ['mathml'],
- 'application/mbox': ['mbox'],
- 'application/media-policy-dataset+xml': ['mpf'],
- 'application/mediaservercontrol+xml': ['mscml'],
- 'application/metalink+xml': ['metalink'],
- 'application/metalink4+xml': ['meta4'],
- 'application/mets+xml': ['mets'],
- 'application/mmt-aei+xml': ['maei'],
- 'application/mmt-usd+xml': ['musd'],
- 'application/mods+xml': ['mods'],
- 'application/mp21': ['m21', 'mp21'],
- 'application/mp4': ['*mp4', '*mpg4', 'mp4s', 'm4p'],
- 'application/msix': ['msix'],
- 'application/msixbundle': ['msixbundle'],
- 'application/msword': ['doc', 'dot'],
- 'application/mxf': ['mxf'],
- 'application/n-quads': ['nq'],
- 'application/n-triples': ['nt'],
- 'application/node': ['cjs'],
- 'application/octet-stream': [
- 'bin',
- 'dms',
- 'lrf',
- 'mar',
- 'so',
- 'dist',
- 'distz',
- 'pkg',
- 'bpk',
- 'dump',
- 'elc',
- 'deploy',
- 'exe',
- 'dll',
- 'deb',
- 'dmg',
- 'iso',
- 'img',
- 'msi',
- 'msp',
- 'msm',
- 'buffer',
- ],
- 'application/oda': ['oda'],
- 'application/oebps-package+xml': ['opf'],
- 'application/ogg': ['ogx'],
- 'application/omdoc+xml': ['omdoc'],
- 'application/onenote': [
- 'onetoc',
- 'onetoc2',
- 'onetmp',
- 'onepkg',
- 'one',
- 'onea',
- ],
- 'application/oxps': ['oxps'],
- 'application/p2p-overlay+xml': ['relo'],
- 'application/patch-ops-error+xml': ['xer'],
- 'application/pdf': ['pdf'],
- 'application/pgp-encrypted': ['pgp'],
- 'application/pgp-keys': ['asc'],
- 'application/pgp-signature': ['sig', '*asc'],
- 'application/pics-rules': ['prf'],
- 'application/pkcs10': ['p10'],
- 'application/pkcs7-mime': ['p7m', 'p7c'],
- 'application/pkcs7-signature': ['p7s'],
- 'application/pkcs8': ['p8'],
- 'application/pkix-attr-cert': ['ac'],
- 'application/pkix-cert': ['cer'],
- 'application/pkix-crl': ['crl'],
- 'application/pkix-pkipath': ['pkipath'],
- 'application/pkixcmp': ['pki'],
- 'application/pls+xml': ['pls'],
- 'application/postscript': ['ai', 'eps', 'ps'],
- 'application/provenance+xml': ['provx'],
- 'application/pskc+xml': ['pskcxml'],
- 'application/raml+yaml': ['raml'],
- 'application/rdf+xml': ['rdf', 'owl'],
- 'application/reginfo+xml': ['rif'],
- 'application/relax-ng-compact-syntax': ['rnc'],
- 'application/resource-lists+xml': ['rl'],
- 'application/resource-lists-diff+xml': ['rld'],
- 'application/rls-services+xml': ['rs'],
- 'application/route-apd+xml': ['rapd'],
- 'application/route-s-tsid+xml': ['sls'],
- 'application/route-usd+xml': ['rusd'],
- 'application/rpki-ghostbusters': ['gbr'],
- 'application/rpki-manifest': ['mft'],
- 'application/rpki-roa': ['roa'],
- 'application/rsd+xml': ['rsd'],
- 'application/rss+xml': ['rss'],
- 'application/rtf': ['rtf'],
- 'application/sbml+xml': ['sbml'],
- 'application/scvp-cv-request': ['scq'],
- 'application/scvp-cv-response': ['scs'],
- 'application/scvp-vp-request': ['spq'],
- 'application/scvp-vp-response': ['spp'],
- 'application/sdp': ['sdp'],
- 'application/senml+xml': ['senmlx'],
- 'application/sensml+xml': ['sensmlx'],
- 'application/set-payment-initiation': ['setpay'],
- 'application/set-registration-initiation': ['setreg'],
- 'application/shf+xml': ['shf'],
- 'application/sieve': ['siv', 'sieve'],
- 'application/smil+xml': ['smi', 'smil'],
- 'application/sparql-query': ['rq'],
- 'application/sparql-results+xml': ['srx'],
- 'application/sql': ['sql'],
- 'application/srgs': ['gram'],
- 'application/srgs+xml': ['grxml'],
- 'application/sru+xml': ['sru'],
- 'application/ssdl+xml': ['ssdl'],
- 'application/ssml+xml': ['ssml'],
- 'application/swid+xml': ['swidtag'],
- 'application/tei+xml': ['tei', 'teicorpus'],
- 'application/thraud+xml': ['tfi'],
- 'application/timestamped-data': ['tsd'],
- 'application/toml': ['toml'],
- 'application/trig': ['trig'],
- 'application/ttml+xml': ['ttml'],
- 'application/ubjson': ['ubj'],
- 'application/urc-ressheet+xml': ['rsheet'],
- 'application/urc-targetdesc+xml': ['td'],
- 'application/voicexml+xml': ['vxml'],
- 'application/wasm': ['wasm'],
- 'application/watcherinfo+xml': ['wif'],
- 'application/widget': ['wgt'],
- 'application/winhlp': ['hlp'],
- 'application/wsdl+xml': ['wsdl'],
- 'application/wspolicy+xml': ['wspolicy'],
- 'application/xaml+xml': ['xaml'],
- 'application/xcap-att+xml': ['xav'],
- 'application/xcap-caps+xml': ['xca'],
- 'application/xcap-diff+xml': ['xdf'],
- 'application/xcap-el+xml': ['xel'],
- 'application/xcap-ns+xml': ['xns'],
- 'application/xenc+xml': ['xenc'],
- 'application/xfdf': ['xfdf'],
- 'application/xhtml+xml': ['xhtml', 'xht'],
- 'application/xliff+xml': ['xlf'],
- 'application/xml': ['xml', 'xsl', 'xsd', 'rng'],
- 'application/xml-dtd': ['dtd'],
- 'application/xop+xml': ['xop'],
- 'application/xproc+xml': ['xpl'],
- 'application/xslt+xml': ['*xsl', 'xslt'],
- 'application/xspf+xml': ['xspf'],
- 'application/xv+xml': ['mxml', 'xhvml', 'xvml', 'xvm'],
- 'application/yang': ['yang'],
- 'application/yin+xml': ['yin'],
- 'application/zip': ['zip'],
- 'application/zip+dotlottie': ['lottie'],
- 'audio/3gpp': ['*3gpp'],
- 'audio/aac': ['adts', 'aac'],
- 'audio/adpcm': ['adp'],
- 'audio/amr': ['amr'],
- 'audio/basic': ['au', 'snd'],
- 'audio/midi': ['mid', 'midi', 'kar', 'rmi'],
- 'audio/mobile-xmf': ['mxmf'],
- 'audio/mp3': ['*mp3'],
- 'audio/mp4': ['m4a', 'mp4a', 'm4b'],
- 'audio/mpeg': ['mpga', 'mp2', 'mp2a', 'mp3', 'm2a', 'm3a'],
- 'audio/ogg': ['oga', 'ogg', 'spx', 'opus'],
- 'audio/s3m': ['s3m'],
- 'audio/silk': ['sil'],
- 'audio/wav': ['wav'],
- 'audio/wave': ['*wav'],
- 'audio/webm': ['weba'],
- 'audio/xm': ['xm'],
- 'font/collection': ['ttc'],
- 'font/otf': ['otf'],
- 'font/ttf': ['ttf'],
- 'font/woff': ['woff'],
- 'font/woff2': ['woff2'],
- 'image/aces': ['exr'],
- 'image/apng': ['apng'],
- 'image/avci': ['avci'],
- 'image/avcs': ['avcs'],
- 'image/avif': ['avif'],
- 'image/bmp': ['bmp', 'dib'],
- 'image/cgm': ['cgm'],
- 'image/dicom-rle': ['drle'],
- 'image/dpx': ['dpx'],
- 'image/emf': ['emf'],
- 'image/fits': ['fits'],
- 'image/g3fax': ['g3'],
- 'image/gif': ['gif'],
- 'image/heic': ['heic'],
- 'image/heic-sequence': ['heics'],
- 'image/heif': ['heif'],
- 'image/heif-sequence': ['heifs'],
- 'image/hej2k': ['hej2'],
- 'image/ief': ['ief'],
- 'image/jaii': ['jaii'],
- 'image/jais': ['jais'],
- 'image/jls': ['jls'],
- 'image/jp2': ['jp2', 'jpg2'],
- 'image/jpeg': ['jpg', 'jpeg', 'jpe'],
- 'image/jph': ['jph'],
- 'image/jphc': ['jhc'],
- 'image/jpm': ['jpm', 'jpgm'],
- 'image/jpx': ['jpx', 'jpf'],
- 'image/jxl': ['jxl'],
- 'image/jxr': ['jxr'],
- 'image/jxra': ['jxra'],
- 'image/jxrs': ['jxrs'],
- 'image/jxs': ['jxs'],
- 'image/jxsc': ['jxsc'],
- 'image/jxsi': ['jxsi'],
- 'image/jxss': ['jxss'],
- 'image/ktx': ['ktx'],
- 'image/ktx2': ['ktx2'],
- 'image/pjpeg': ['jfif'],
- 'image/png': ['png'],
- 'image/sgi': ['sgi'],
- 'image/svg+xml': ['svg', 'svgz'],
- 'image/t38': ['t38'],
- 'image/tiff': ['tif', 'tiff'],
- 'image/tiff-fx': ['tfx'],
- 'image/webp': ['webp'],
- 'image/wmf': ['wmf'],
- 'message/disposition-notification': ['disposition-notification'],
- 'message/global': ['u8msg'],
- 'message/global-delivery-status': ['u8dsn'],
- 'message/global-disposition-notification': ['u8mdn'],
- 'message/global-headers': ['u8hdr'],
- 'message/rfc822': ['eml', 'mime', 'mht', 'mhtml'],
- 'model/3mf': ['3mf'],
- 'model/gltf+json': ['gltf'],
- 'model/gltf-binary': ['glb'],
- 'model/iges': ['igs', 'iges'],
- 'model/jt': ['jt'],
- 'model/mesh': ['msh', 'mesh', 'silo'],
- 'model/mtl': ['mtl'],
- 'model/obj': ['obj'],
- 'model/prc': ['prc'],
- 'model/step': ['step', 'stp', 'stpnc', 'p21', '210'],
- 'model/step+xml': ['stpx'],
- 'model/step+zip': ['stpz'],
- 'model/step-xml+zip': ['stpxz'],
- 'model/stl': ['stl'],
- 'model/u3d': ['u3d'],
- 'model/vrml': ['wrl', 'vrml'],
- 'model/x3d+binary': ['*x3db', 'x3dbz'],
- 'model/x3d+fastinfoset': ['x3db'],
- 'model/x3d+vrml': ['*x3dv', 'x3dvz'],
- 'model/x3d+xml': ['x3d', 'x3dz'],
- 'model/x3d-vrml': ['x3dv'],
- 'text/cache-manifest': ['appcache', 'manifest'],
- 'text/calendar': ['ics', 'ifb'],
- 'text/coffeescript': ['coffee', 'litcoffee'],
- 'text/css': ['css'],
- 'text/csv': ['csv'],
- 'text/html': ['html', 'htm', 'shtml'],
- 'text/jade': ['jade'],
- 'text/javascript': ['js', 'mjs'],
- 'text/jsx': ['jsx'],
- 'text/less': ['less'],
- 'text/markdown': ['md', 'markdown'],
- 'text/mathml': ['mml'],
- 'text/mdx': ['mdx'],
- 'text/n3': ['n3'],
- 'text/plain': ['txt', 'text', 'conf', 'def', 'list', 'log', 'in', 'ini'],
- 'text/richtext': ['rtx'],
- 'text/rtf': ['*rtf'],
- 'text/sgml': ['sgml', 'sgm'],
- 'text/shex': ['shex'],
- 'text/slim': ['slim', 'slm'],
- 'text/spdx': ['spdx'],
- 'text/stylus': ['stylus', 'styl'],
- 'text/tab-separated-values': ['tsv'],
- 'text/troff': ['t', 'tr', 'roff', 'man', 'me', 'ms'],
- 'text/turtle': ['ttl'],
- 'text/uri-list': ['uri', 'uris', 'urls'],
- 'text/vcard': ['vcard'],
- 'text/vtt': ['vtt'],
- 'text/wgsl': ['wgsl'],
- 'text/xml': ['*xml'],
- 'text/yaml': ['yaml', 'yml'],
- 'video/3gpp': ['3gp', '3gpp'],
- 'video/3gpp2': ['3g2'],
- 'video/h261': ['h261'],
- 'video/h263': ['h263'],
- 'video/h264': ['h264'],
- 'video/iso.segment': ['m4s'],
- 'video/jpeg': ['jpgv'],
- 'video/jpm': ['*jpm', '*jpgm'],
- 'video/mj2': ['mj2', 'mjp2'],
- 'video/mp2t': ['ts', 'm2t', 'm2ts', 'mts'],
- 'video/mp4': ['mp4', 'mp4v', 'mpg4'],
- 'video/mpeg': ['mpeg', 'mpg', 'mpe', 'm1v', 'm2v'],
- 'video/ogg': ['ogv'],
- 'video/quicktime': ['qt', 'mov'],
- 'video/webm': ['webm'],
-};
-Object.freeze(types);
-
-var __classPrivateFieldGet = ({} && {}.__classPrivateFieldGet) || function (receiver, state, kind, f) {
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
-};
-var _Mime_extensionToType, _Mime_typeToExtension, _Mime_typeToExtensions;
-class Mime {
- constructor(...args) {
- _Mime_extensionToType.set(this, new Map());
- _Mime_typeToExtension.set(this, new Map());
- _Mime_typeToExtensions.set(this, new Map());
- for (const arg of args) {
- this.define(arg);
- }
- }
- define(typeMap, force = false) {
- for (let [type, extensions] of Object.entries(typeMap)) {
- type = type.toLowerCase();
- extensions = extensions.map((ext) => ext.toLowerCase());
- if (!__classPrivateFieldGet(this, _Mime_typeToExtensions, "f").has(type)) {
- __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").set(type, new Set());
- }
- const allExtensions = __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").get(type);
- let first = true;
- for (let extension of extensions) {
- const starred = extension.startsWith('*');
- extension = starred ? extension.slice(1) : extension;
- allExtensions?.add(extension);
- if (first) {
- __classPrivateFieldGet(this, _Mime_typeToExtension, "f").set(type, extension);
- }
- first = false;
- if (starred)
- continue;
- const currentType = __classPrivateFieldGet(this, _Mime_extensionToType, "f").get(extension);
- if (currentType && currentType != type && !force) {
- throw new Error(`"${type} -> ${extension}" conflicts with "${currentType} -> ${extension}". Pass \`force=true\` to override this definition.`);
- }
- __classPrivateFieldGet(this, _Mime_extensionToType, "f").set(extension, type);
- }
- }
- return this;
- }
- getType(path) {
- if (typeof path !== 'string')
- return null;
- const last = path.replace(/^.*[/\\]/s, '').toLowerCase();
- const ext = last.replace(/^.*\./s, '').toLowerCase();
- const hasPath = last.length < path.length;
- const hasDot = ext.length < last.length - 1;
- if (!hasDot && hasPath)
- return null;
- return __classPrivateFieldGet(this, _Mime_extensionToType, "f").get(ext) ?? null;
- }
- getExtension(type) {
- if (typeof type !== 'string')
- return null;
- type = type?.split?.(';')[0];
- return ((type && __classPrivateFieldGet(this, _Mime_typeToExtension, "f").get(type.trim().toLowerCase())) ?? null);
- }
- getAllExtensions(type) {
- if (typeof type !== 'string')
- return null;
- return __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").get(type.toLowerCase()) ?? null;
- }
- _freeze() {
- this.define = () => {
- throw new Error('define() not allowed for built-in Mime objects. See https://github.com/broofa/mime/blob/main/README.md#custom-mime-instances');
- };
- Object.freeze(this);
- for (const extensions of __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").values()) {
- Object.freeze(extensions);
- }
- return this;
- }
- _getTestState() {
- return {
- types: __classPrivateFieldGet(this, _Mime_extensionToType, "f"),
- extensions: __classPrivateFieldGet(this, _Mime_typeToExtension, "f"),
- };
- }
-}
-_Mime_extensionToType = new WeakMap(), _Mime_typeToExtension = new WeakMap(), _Mime_typeToExtensions = new WeakMap();
-
-var mime = new Mime(types)._freeze();
-
-class TestRun {
- constructor(vitest) {
- this.vitest = vitest;
- }
- async start(specifications) {
- const filepaths = specifications.map((spec) => spec.moduleId);
- this.vitest.state.collectPaths(filepaths);
- await this.vitest.report("onTestRunStart", [...specifications]);
- }
- async enqueued(project, file) {
- this.vitest.state.collectFiles(project, [file]);
- const testModule = this.vitest.state.getReportedEntity(file);
- await this.vitest.report("onTestModuleQueued", testModule);
- }
- async collected(project, files) {
- this.vitest.state.collectFiles(project, files);
- await Promise.all(files.map((file) => {
- const testModule = this.vitest.state.getReportedEntity(file);
- return this.vitest.report("onTestModuleCollected", testModule);
- }));
- }
- async log(log) {
- this.vitest.state.updateUserLog(log);
- await this.vitest.report("onUserConsoleLog", log);
- }
- async recordArtifact(testId, artifact) {
- const task = this.vitest.state.idMap.get(testId);
- const entity = task && this.vitest.state.getReportedEntity(task);
- assert$1(task && entity, `Entity must be found for task ${task?.name || testId}`);
- assert$1(entity.type === "test", `Artifacts can only be recorded on a test, instead got ${entity.type}`);
- // annotations won't resolve as artifacts for backwards compatibility until next major
- if (artifact.type === "internal:annotation") {
- await this.resolveTestAttachment(entity, artifact.annotation.attachment, artifact.annotation.message);
- entity.task.annotations.push(artifact.annotation);
- await this.vitest.report("onTestCaseAnnotate", entity, artifact.annotation);
- return artifact;
- }
- if (Array.isArray(artifact.attachments)) await Promise.all(artifact.attachments.map((attachment) => this.resolveTestAttachment(entity, attachment)));
- entity.task.artifacts.push(artifact);
- await this.vitest.report("onTestCaseArtifactRecord", entity, artifact);
- return artifact;
- }
- async updated(update, events) {
- this.syncUpdateStacks(update);
- this.vitest.state.updateTasks(update);
- for (const [id, event, data] of events) await this.reportEvent(id, event, data).catch((error) => {
- this.vitest.state.catchError(serializeValue(error), "Unhandled Reporter Error");
- });
- // TODO: what is the order or reports here?
- // "onTaskUpdate" in parallel with others or before all or after all?
- // TODO: error handling - what happens if custom reporter throws an error?
- await this.vitest.report("onTaskUpdate", update, events);
- }
- async end(specifications, errors, coverage) {
- if (coverage) await this.vitest.report("onCoverage", coverage);
- // specification won't have the File task if they were filtered by the --shard command
- const modules = specifications.map((spec) => spec.testModule).filter((s) => s != null);
- const state = this.vitest.isCancelling ? "interrupted" : this.hasFailed(modules) ? "failed" : "passed";
- if (state !== "passed") process.exitCode = 1;
- await this.vitest.report("onTestRunEnd", modules, [...errors], state);
- for (const project in this.vitest.state.metadata) {
- const meta = this.vitest.state.metadata[project];
- if (!meta?.dumpDir) continue;
- const path = resolve(meta.dumpDir, "vitest-metadata.json");
- meta.outline = {
- externalized: Object.keys(meta.externalized).length,
- inlined: Object.keys(meta.tmps).length
- };
- await writeFile(path, JSON.stringify(meta, null, 2), "utf-8");
- this.vitest.logger.log(`Metadata written to ${path}`);
- }
- }
- hasFailed(modules) {
- if (!modules.length) return !this.vitest.config.passWithNoTests;
- return modules.some((m) => !m.ok());
- }
- // make sure the error always has a "stacks" property
- syncUpdateStacks(update) {
- update.forEach(([taskId, result]) => {
- const task = this.vitest.state.idMap.get(taskId);
- const isBrowser = task && task.file.pool === "browser";
- result?.errors?.forEach((error) => {
- if (isPrimitive(error)) return;
- const project = this.vitest.getProjectByName(task.file.projectName || "");
- if (isBrowser) error.stacks = project.browser?.parseErrorStacktrace(error, { frameFilter: project.config.onStackTrace }) || [];
- else error.stacks = parseErrorStacktrace(error, { frameFilter: project.config.onStackTrace });
- });
- });
- }
- async reportEvent(id, event, data) {
- const task = this.vitest.state.idMap.get(id);
- const entity = task && this.vitest.state.getReportedEntity(task);
- assert$1(task && entity, `Entity must be found for task ${task?.name || id}`);
- if (event === "suite-failed-early" && entity.type === "module") {
- // the file failed during import
- await this.vitest.report("onTestModuleStart", entity);
- await this.vitest.report("onTestModuleEnd", entity);
- return;
- }
- if (event === "suite-prepare" && entity.type === "suite") return await this.vitest.report("onTestSuiteReady", entity);
- if (event === "suite-prepare" && entity.type === "module") return await this.vitest.report("onTestModuleStart", entity);
- if (event === "suite-finished") {
- assert$1(entity.type === "suite" || entity.type === "module", "Entity type must be suite or module");
- if (entity.state() === "skipped")
- // everything inside suite or a module is skipped,
- // so we won't get any children events
- // we need to report everything manually
- await this.reportChildren(entity.children);
- if (entity.type === "module") await this.vitest.report("onTestModuleEnd", entity);
- else await this.vitest.report("onTestSuiteResult", entity);
- return;
- }
- if (event === "test-prepare" && entity.type === "test") return await this.vitest.report("onTestCaseReady", entity);
- if (event === "test-finished" && entity.type === "test") return await this.vitest.report("onTestCaseResult", entity);
- if (event.startsWith("before-hook") || event.startsWith("after-hook")) {
- const isBefore = event.startsWith("before-hook");
- const hook = entity.type === "test" ? {
- name: isBefore ? "beforeEach" : "afterEach",
- entity
- } : {
- name: isBefore ? "beforeAll" : "afterAll",
- entity
- };
- if (event.endsWith("-start")) await this.vitest.report("onHookStart", hook);
- else await this.vitest.report("onHookEnd", hook);
- // this can only happen in --merge-reports, and annotation is already resolved
- if (event === "test-annotation") {
- const annotation = data?.annotation;
- assert$1(annotation && entity.type === "test");
- await this.vitest.report("onTestCaseAnnotate", entity, annotation);
- }
- }
- }
- async resolveTestAttachment(test, attachment, filename) {
- const project = test.project;
- if (!attachment) return attachment;
- const path = attachment.path;
- if (path && !path.startsWith("http://") && !path.startsWith("https://")) {
- const currentPath = resolve(project.config.root, path);
- const hash = createHash("sha1").update(currentPath).digest("hex");
- const newPath = resolve(project.config.attachmentsDir, `${filename ? `${sanitizeFilePath(filename)}-` : ""}${hash}${extname(currentPath)}`);
- if (!existsSync(project.config.attachmentsDir)) await mkdir(project.config.attachmentsDir, { recursive: true });
- await copyFile(currentPath, newPath);
- attachment.path = newPath;
- attachment.contentType = (attachment.contentType ?? mime.getType(basename(currentPath))) || void 0;
- }
- return attachment;
- }
- async reportChildren(children) {
- for (const child of children) if (child.type === "test") {
- await this.vitest.report("onTestCaseReady", child);
- await this.vitest.report("onTestCaseResult", child);
- } else {
- await this.vitest.report("onTestSuiteReady", child);
- await this.reportChildren(child.children);
- await this.vitest.report("onTestSuiteResult", child);
- }
- }
-}
-function sanitizeFilePath(s) {
- // eslint-disable-next-line no-control-regex
- return s.replace(/[\x00-\x2C\x2E\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+/g, "-");
-}
-
-class VitestWatcher {
- /**
- * Modules that will be invalidated on the next run.
- */
- invalidates = /* @__PURE__ */ new Set();
- /**
- * Test files that have changed and need to be rerun.
- */
- changedTests = /* @__PURE__ */ new Set();
- _onRerun = [];
- constructor(vitest) {
- this.vitest = vitest;
- }
- /**
- * Register a handler that will be called when test files need to be rerun.
- * The callback can receive several files in case the changed file is imported by several test files.
- * Several invocations of this method will add multiple handlers.
- * @internal
- */
- onWatcherRerun(cb) {
- this._onRerun.push(cb);
- return this;
- }
- unregisterWatcher = noop;
- registerWatcher() {
- const watcher = this.vitest.vite.watcher;
- if (this.vitest.config.forceRerunTriggers.length) watcher.add(this.vitest.config.forceRerunTriggers);
- watcher.on("change", this.onFileChange);
- watcher.on("unlink", this.onFileDelete);
- watcher.on("add", this.onFileCreate);
- this.unregisterWatcher = () => {
- watcher.off("change", this.onFileChange);
- watcher.off("unlink", this.onFileDelete);
- watcher.off("add", this.onFileCreate);
- this.unregisterWatcher = noop;
- };
- return this;
- }
- scheduleRerun(file) {
- this._onRerun.forEach((cb) => cb(file));
- }
- getTestFilesFromWatcherTrigger(id) {
- if (!this.vitest.config.watchTriggerPatterns) return false;
- let triggered = false;
- this.vitest.config.watchTriggerPatterns.forEach((definition) => {
- const exec = definition.pattern.exec(id);
- if (exec) {
- const files = definition.testsToRun(id, exec);
- if (Array.isArray(files)) {
- triggered = true;
- files.forEach((file) => this.changedTests.add(resolve(this.vitest.config.root, file)));
- } else if (typeof files === "string") {
- triggered = true;
- this.changedTests.add(resolve(this.vitest.config.root, files));
- }
- }
- });
- return triggered;
- }
- onFileChange = (id) => {
- id = slash(id);
- this.vitest.logger.clearHighlightCache(id);
- this.vitest.invalidateFile(id);
- if (this.getTestFilesFromWatcherTrigger(id)) this.scheduleRerun(id);
- else if (this.handleFileChanged(id)) this.scheduleRerun(id);
- };
- onFileDelete = (id) => {
- id = slash(id);
- this.vitest.logger.clearHighlightCache(id);
- this.invalidates.add(id);
- if (this.vitest.state.filesMap.has(id)) {
- this.vitest.projects.forEach((project) => project._removeCachedTestFile(id));
- this.vitest.state.filesMap.delete(id);
- this.vitest.cache.results.removeFromCache(id);
- this.vitest.cache.stats.removeStats(id);
- this.changedTests.delete(id);
- this.vitest.report("onTestRemoved", id);
- }
- };
- onFileCreate = (id) => {
- id = slash(id);
- this.vitest.invalidateFile(id);
- if (this.getTestFilesFromWatcherTrigger(id)) {
- this.scheduleRerun(id);
- return;
- }
- let fileContent;
- const matchingProjects = [];
- this.vitest.projects.forEach((project) => {
- if (project.matchesTestGlob(id, () => fileContent ??= readFileSync(id, "utf-8"))) matchingProjects.push(project);
- });
- if (matchingProjects.length > 0) {
- this.changedTests.add(id);
- this.scheduleRerun(id);
- } else if (this.handleFileChanged(id)) this.scheduleRerun(id);
- };
- handleSetupFile(filepath) {
- let isSetupFile = false;
- this.vitest.projects.forEach((project) => {
- if (!project.config.setupFiles.includes(filepath)) return;
- this.vitest.state.filesMap.forEach((files) => {
- files.forEach((file) => {
- if (file.projectName === project.name) {
- isSetupFile = true;
- this.changedTests.add(file.filepath);
- }
- });
- });
- });
- return isSetupFile;
- }
- /**
- * @returns A value indicating whether rerun is needed (changedTests was mutated)
- */
- handleFileChanged(filepath) {
- if (this.changedTests.has(filepath) || this.invalidates.has(filepath)) return false;
- if (pm.isMatch(filepath, this.vitest.config.forceRerunTriggers)) {
- this.vitest.state.getFilepaths().forEach((file) => this.changedTests.add(file));
- return true;
- }
- if (this.handleSetupFile(filepath)) return true;
- const projects = this.vitest.projects.filter((project) => {
- return (project.browser?.vite.moduleGraph || project.vite.moduleGraph).getModulesByFile(filepath)?.size;
- });
- if (!projects.length) {
- // if there are no modules it's possible that server was restarted
- // we don't have information about importers anymore, so let's check if the file is a test file at least
- if (this.vitest.state.filesMap.has(filepath) || this.vitest.projects.some((project) => project._isCachedTestFile(filepath))) {
- this.changedTests.add(filepath);
- return true;
- }
- return false;
- }
- const files = [];
- for (const project of projects) {
- const mods = project.browser?.vite.moduleGraph.getModulesByFile(filepath) || project.vite.moduleGraph.getModulesByFile(filepath);
- if (!mods || !mods.size) continue;
- this.invalidates.add(filepath);
- // one of test files that we already run, or one of test files that we can run
- if (this.vitest.state.filesMap.has(filepath) || project._isCachedTestFile(filepath)) {
- this.changedTests.add(filepath);
- files.push(filepath);
- continue;
- }
- let rerun = false;
- for (const mod of mods) mod.importers.forEach((i) => {
- if (!i.file) return;
- if (this.handleFileChanged(i.file)) rerun = true;
- });
- if (rerun) files.push(filepath);
- }
- return !!files.length;
- }
-}
-
-const WATCHER_DEBOUNCE = 100;
-class Vitest {
- /**
- * Current Vitest version.
- * @example '2.0.0'
- */
- version = version$1;
- static version = version$1;
- /**
- * The logger instance used to log messages. It's recommended to use this logger instead of `console`.
- * It's possible to override stdout and stderr streams when initiating Vitest.
- * @example
- * new Vitest('test', {
- * stdout: new Writable(),
- * })
- */
- logger;
- /**
- * The package installer instance used to install Vitest packages.
- * @example
- * await vitest.packageInstaller.ensureInstalled('@vitest/browser', process.cwd())
- */
- packageInstaller;
- /**
- * A path to the built Vitest directory. This is usually a folder in `node_modules`.
- */
- distPath = distDir;
- /**
- * A list of projects that are currently running.
- * If projects were filtered with `--project` flag, they won't appear here.
- */
- projects = [];
- /**
- * A watcher handler. This is not the file system watcher. The handler only
- * exposes methods to handle changed files.
- *
- * If you have your own watcher, you can use these methods to replicate
- * Vitest behaviour.
- */
- watcher;
- /** @internal */ configOverride = {};
- /** @internal */ filenamePattern;
- /** @internal */ runningPromise;
- /** @internal */ closingPromise;
- /** @internal */ cancelPromise;
- /** @internal */ isCancelling = false;
- /** @internal */ coreWorkspaceProject;
- /** @internal */ _browserSessions = new BrowserSessions();
- /** @internal */ _cliOptions = {};
- /** @internal */ reporters = [];
- /** @internal */ runner;
- /** @internal */ _testRun = void 0;
- /** @internal */ _resolver;
- /** @internal */ _fetcher;
- /** @internal */ _fsCache;
- /** @internal */ _tmpDir = join(tmpdir(), nanoid());
- /** @internal */ _traces;
- isFirstRun = true;
- restartsCount = 0;
- specifications;
- pool;
- _config;
- _vite;
- _state;
- _cache;
- _snapshot;
- _coverageProvider;
- constructor(mode, cliOptions, options = {}) {
- this.mode = mode;
- this._cliOptions = cliOptions;
- this.logger = new Logger(this, options.stdout, options.stderr);
- this.packageInstaller = options.packageInstaller || new VitestPackageInstaller();
- this.specifications = new VitestSpecifications(this);
- this.watcher = new VitestWatcher(this).onWatcherRerun((file) => this.scheduleRerun(file));
- }
- _onRestartListeners = [];
- _onClose = [];
- _onSetServer = [];
- _onCancelListeners = /* @__PURE__ */ new Set();
- _onUserTestsRerun = [];
- _onFilterWatchedSpecification = [];
- /**
- * The global config.
- */
- get config() {
- assert(this._config, "config");
- return this._config;
- }
- /**
- * Global Vite's dev server instance.
- */
- get vite() {
- assert(this._vite, "vite", "server");
- return this._vite;
- }
- /**
- * The global test state manager.
- * @experimental The State API is experimental and not subject to semver.
- */
- get state() {
- assert(this._state, "state");
- return this._state;
- }
- /**
- * The global snapshot manager. You can access the current state on `snapshot.summary`.
- */
- get snapshot() {
- assert(this._snapshot, "snapshot", "snapshot manager");
- return this._snapshot;
- }
- /**
- * Test results and test file stats cache. Primarily used by the sequencer to sort tests.
- */
- get cache() {
- assert(this._cache, "cache");
- return this._cache;
- }
- /** @internal */
- async _setServer(options, server) {
- this.watcher.unregisterWatcher();
- clearTimeout(this._rerunTimer);
- this.restartsCount += 1;
- this.pool?.close?.();
- this.pool = void 0;
- this.closingPromise = void 0;
- this.projects = [];
- this.runningPromise = void 0;
- this.coreWorkspaceProject = void 0;
- this.specifications.clearCache();
- this._coverageProvider = void 0;
- this._onUserTestsRerun = [];
- this._vite = server;
- const resolved = resolveConfig(this, options, server.config);
- this._config = resolved;
- this._state = new StateManager({ onUnhandledError: resolved.onUnhandledError });
- this._cache = new VitestCache(this.logger);
- this._snapshot = new SnapshotManager({ ...resolved.snapshotOptions });
- this._testRun = new TestRun(this);
- const otelSdkPath = resolved.experimental.openTelemetry?.sdkPath;
- this._traces = new Traces({
- enabled: !!resolved.experimental.openTelemetry?.enabled,
- sdkPath: otelSdkPath,
- watchMode: resolved.watch
- });
- if (this.config.watch) this.watcher.registerWatcher();
- this._resolver = new VitestResolver(server.config.cacheDir, resolved);
- this._fsCache = new FileSystemModuleCache(this);
- this._fetcher = createFetchModuleFunction(this._resolver, this._config, this._fsCache, this._traces, this._tmpDir);
- const environment = server.environments.__vitest__;
- this.runner = new ServerModuleRunner(environment, this._fetcher, resolved);
- if (this.config.watch) {
- // hijack server restart
- const serverRestart = server.restart;
- server.restart = async (...args) => {
- await Promise.all(this._onRestartListeners.map((fn) => fn()));
- this.report("onServerRestart");
- await this.close();
- await serverRestart(...args);
- };
- // since we set `server.hmr: false`, Vite does not auto restart itself
- server.watcher.on("change", async (file) => {
- file = normalize(file);
- if (file === server.config.configFile || this.projects.some((p) => p.vite.config.configFile === file)) {
- await Promise.all(this._onRestartListeners.map((fn) => fn("config")));
- this.report("onServerRestart", "config");
- await this.close();
- await serverRestart();
- }
- });
- }
- this.cache.results.setConfig(resolved.root, resolved.cache);
- try {
- await this.cache.results.readFromCache();
- } catch {}
- const projects = await this.resolveProjects(this._cliOptions);
- this.projects = projects;
- await Promise.all(projects.flatMap((project) => {
- return project.vite.config.getSortedPluginHooks("configureVitest").map((hook) => hook({
- project,
- vitest: this,
- injectTestProjects: this.injectTestProject,
- experimental_defineCacheKeyGenerator: (callback) => this._fsCache.defineCacheKeyGenerator(callback)
- }));
- }));
- if (this._cliOptions.browser?.enabled) {
- if (!this.projects.filter((p) => p.config.browser.enabled).length) throw new Error(`Vitest received --browser flag, but no project had a browser configuration.`);
- }
- if (!this.projects.length) {
- const filter = toArray(resolved.project).join("\", \"");
- if (filter) throw new Error(`No projects matched the filter "${filter}".`);
- else {
- let error = `Vitest wasn't able to resolve any project.`;
- if (this.config.browser.enabled && !this.config.browser.instances?.length) error += ` Please, check that you specified the "browser.instances" option.`;
- throw new Error(error);
- }
- }
- if (!this.coreWorkspaceProject) this.coreWorkspaceProject = TestProject._createBasicProject(this);
- if (this.config.testNamePattern) this.configOverride.testNamePattern = this.config.testNamePattern;
- this.reporters = resolved.mode === "benchmark" ? await createBenchmarkReporters(toArray(resolved.benchmark?.reporters), this.runner) : await createReporters(resolved.reporters, this);
- await this._fsCache.ensureCacheIntegrity();
- await Promise.all([...this._onSetServer.map((fn) => fn()), this._traces.waitInit()]);
- }
- /** @internal */
- get coverageProvider() {
- if (this.configOverride.coverage?.enabled === false) return null;
- return this._coverageProvider;
- }
- async enableCoverage() {
- this.configOverride.coverage = {};
- this.configOverride.coverage.enabled = true;
- await this.createCoverageProvider();
- await this.coverageProvider?.onEnabled?.();
- // onFileTransform is the only thing that affects hash
- if (this.coverageProvider?.onFileTransform) this.clearAllCachePaths();
- }
- disableCoverage() {
- this.configOverride.coverage ??= {};
- this.configOverride.coverage.enabled = false;
- // onFileTransform is the only thing that affects hash
- if (this.coverageProvider?.onFileTransform) this.clearAllCachePaths();
- }
- clearAllCachePaths() {
- this.projects.forEach(({ vite, browser }) => {
- [...Object.values(vite.environments), ...Object.values(browser?.vite.environments || {})].forEach((environment) => this._fsCache.invalidateAllCachePaths(environment));
- });
- }
- _coverageOverrideCache = /* @__PURE__ */ new WeakMap();
- /** @internal */
- get _coverageOptions() {
- if (!this.configOverride.coverage) return this.config.coverage;
- if (!this._coverageOverrideCache.has(this.configOverride.coverage)) {
- const options = deepMerge(deepClone(this.config.coverage), this.configOverride.coverage);
- this._coverageOverrideCache.set(this.configOverride.coverage, options);
- }
- return this._coverageOverrideCache.get(this.configOverride.coverage);
- }
- /**
- * Inject new test projects into the workspace.
- * @param config Glob, config path or a custom config options.
- * @returns An array of new test projects. Can be empty if the name was filtered out.
- */
- injectTestProject = async (config) => {
- const currentNames = new Set(this.projects.map((p) => p.name));
- const projects = await resolveProjects(this, this._cliOptions, void 0, Array.isArray(config) ? config : [config], currentNames);
- this.projects.push(...projects);
- return projects;
- };
- /**
- * Provide a value to the test context. This value will be available to all tests with `inject`.
- */
- provide = (key, value) => {
- this.getRootProject().provide(key, value);
- };
- /**
- * Get global provided context.
- */
- getProvidedContext() {
- return this.getRootProject().getProvidedContext();
- }
- /** @internal */
- _ensureRootProject() {
- if (this.coreWorkspaceProject) return this.coreWorkspaceProject;
- this.coreWorkspaceProject = TestProject._createBasicProject(this);
- return this.coreWorkspaceProject;
- }
- /**
- * Return project that has the root (or "global") config.
- */
- getRootProject() {
- if (!this.coreWorkspaceProject) throw new Error(`Root project is not initialized. This means that the Vite server was not established yet and the the workspace config is not resolved.`);
- return this.coreWorkspaceProject;
- }
- getProjectByName(name) {
- const project = this.projects.find((p) => p.name === name) || this.coreWorkspaceProject || this.projects[0];
- if (!project) throw new Error(`Project "${name}" was not found.`);
- return project;
- }
- /**
- * Import a file using Vite module runner. The file will be transformed by Vite and executed in a separate context.
- * @param moduleId The ID of the module in Vite module graph
- */
- import(moduleId) {
- return this.runner.import(moduleId);
- }
- /**
- * Creates a coverage provider if `coverage` is enabled in the config.
- */
- async createCoverageProvider() {
- if (this._coverageProvider) return this._coverageProvider;
- const coverageProvider = await this.initCoverageProvider();
- if (coverageProvider) await coverageProvider.clean(this._coverageOptions.clean);
- return coverageProvider || null;
- }
- async resolveProjects(cliOptions) {
- const names = /* @__PURE__ */ new Set();
- if (this.config.projects) return resolveProjects(this, cliOptions, void 0, this.config.projects, names);
- if ("workspace" in this.config) throw new Error("The `test.workspace` option was removed in Vitest 4. Please, migrate to `test.projects` instead. See https://vitest.dev/guide/projects for examples.");
- // user can filter projects with --project flag, `getDefaultTestProject`
- // returns the project only if it matches the filter
- const project = getDefaultTestProject(this);
- if (!project) return [];
- return resolveBrowserProjects(this, new Set([project.name]), [project]);
- }
- /**
- * Glob test files in every project and create a TestSpecification for each file and pool.
- * @param filters String filters to match the test files.
- */
- async globTestSpecifications(filters = []) {
- return this.specifications.globTestSpecifications(filters);
- }
- async initCoverageProvider() {
- if (this._coverageProvider != null) return;
- this._coverageProvider = await getCoverageProvider(this.configOverride.coverage ? this.getRootProject().serializedConfig.coverage : this.config.coverage, this.runner);
- if (this._coverageProvider) {
- await this._coverageProvider.initialize(this);
- this.config.coverage = this._coverageProvider.resolveOptions();
- }
- return this._coverageProvider;
- }
- /**
- * Deletes all Vitest caches, including `experimental.fsModuleCache`.
- * @experimental
- */
- async experimental_clearCache() {
- await this.cache.results.clearCache();
- await this._fsCache.clearCache();
- }
- /**
- * Merge reports from multiple runs located in the specified directory (value from `--merge-reports` if not specified).
- */
- async mergeReports(directory) {
- return this._traces.$("vitest.merge_reports", async () => {
- if (this.reporters.some((r) => r instanceof BlobReporter)) throw new Error("Cannot merge reports when `--reporter=blob` is used. Remove blob reporter from the config first.");
- const { files, errors, coverages, executionTimes } = await readBlobs(this.version, directory || this.config.mergeReports, this.projects);
- this.state.blobs = {
- files,
- errors,
- coverages,
- executionTimes
- };
- await this.report("onInit", this);
- const specifications = [];
- for (const file of files) {
- const specification = this.getProjectByName(file.projectName || "").createSpecification(file.filepath, void 0, file.pool);
- specifications.push(specification);
- }
- await this._testRun.start(specifications).catch(noop);
- for (const file of files) await this._reportFileTask(file);
- this._checkUnhandledErrors(errors);
- await this._testRun.end(specifications, errors).catch(noop);
- await this.initCoverageProvider();
- await this.coverageProvider?.mergeReports?.(coverages);
- return {
- testModules: this.state.getTestModules(),
- unhandledErrors: this.state.getUnhandledErrors()
- };
- });
- }
- /**
- * Returns the seed, if tests are running in a random order.
- */
- getSeed() {
- return this.config.sequence.seed ?? null;
- }
- /** @internal */
- async _reportFileTask(file) {
- const project = this.getProjectByName(file.projectName || "");
- await this._testRun.enqueued(project, file).catch(noop);
- await this._testRun.collected(project, [file]).catch(noop);
- const logs = [];
- const { packs, events } = convertTasksToEvents(file, (task) => {
- if (task.logs) logs.push(...task.logs);
- });
- logs.sort((log1, log2) => log1.time - log2.time);
- for (const log of logs) await this._testRun.log(log).catch(noop);
- await this._testRun.updated(packs, events).catch(noop);
- }
- async collect(filters) {
- return this._traces.$("vitest.collect", async (collectSpan) => {
- const filenamePattern = filters && filters?.length > 0 ? filters : [];
- collectSpan.setAttribute("vitest.collect.filters", filenamePattern);
- const files = await this._traces.$("vitest.config.resolve_include_glob", async () => {
- const specifications = await this.specifications.getRelevantTestSpecifications(filters);
- collectSpan.setAttribute("vitest.collect.specifications", specifications.map((s) => {
- const relativeModuleId = relative(s.project.config.root, s.moduleId);
- if (s.project.name) return `|${s.project.name}| ${relativeModuleId}`;
- return relativeModuleId;
- }));
- return specifications;
- });
- // if run with --changed, don't exit if no tests are found
- if (!files.length) return {
- testModules: [],
- unhandledErrors: []
- };
- return this.collectTests(files);
- });
- }
- /**
- * Returns the list of test files that match the config and filters.
- * @param filters String filters to match the test files
- */
- getRelevantTestSpecifications(filters) {
- return this.specifications.getRelevantTestSpecifications(filters);
- }
- /**
- * Initialize reporters, the coverage provider, and run tests.
- * This method can throw an error:
- * - `FilesNotFoundError` if no tests are found
- * - `GitNotFoundError` if `--related` flag is used, but git repository is not initialized
- * - `Error` from the user reporters
- * @param filters String filters to match the test files
- */
- async start(filters) {
- return this._traces.$("vitest.start", { context: this._traces.getContextFromEnv(process.env) }, async (startSpan) => {
- startSpan.setAttributes({ config: this.vite.config.configFile });
- try {
- await this._traces.$("vitest.coverage.init", async () => {
- await this.initCoverageProvider();
- await this.coverageProvider?.clean(this._coverageOptions.clean);
- });
- } finally {
- await this.report("onInit", this);
- }
- this.filenamePattern = filters && filters?.length > 0 ? filters : void 0;
- startSpan.setAttribute("vitest.start.filters", this.filenamePattern || []);
- const files = await this._traces.$("vitest.config.resolve_include_glob", async () => {
- const specifications = await this.specifications.getRelevantTestSpecifications(filters);
- startSpan.setAttribute("vitest.start.specifications", specifications.map((s) => {
- const relativeModuleId = relative(s.project.config.root, s.moduleId);
- if (s.project.name) return `|${s.project.name}| ${relativeModuleId}`;
- return relativeModuleId;
- }));
- return specifications;
- });
- // if run with --changed, don't exit if no tests are found
- if (!files.length) {
- await this._traces.$("vitest.test_run", async () => {
- await this._testRun.start([]);
- const coverage = await this.coverageProvider?.generateCoverage?.({ allTestsRun: true });
- await this._testRun.end([], [], coverage);
- // Report coverage for uncovered files
- await this.reportCoverage(coverage, true);
- });
- if (!this.config.watch || !(this.config.changed || this.config.related?.length)) throw new FilesNotFoundError(this.mode);
- }
- let testModules = {
- testModules: [],
- unhandledErrors: []
- };
- if (files.length) {
- // populate once, update cache on watch
- await this.cache.stats.populateStats(this.config.root, files);
- testModules = await this.runFiles(files, true);
- }
- if (this.config.watch) await this.report("onWatcherStart");
- return testModules;
- });
- }
- /**
- * Initialize reporters and the coverage provider. This method doesn't run any tests.
- * If the `--watch` flag is provided, Vitest will still run changed tests even if this method was not called.
- */
- async init() {
- await this._traces.$("vitest.init", async () => {
- try {
- await this.initCoverageProvider();
- await this.coverageProvider?.clean(this._coverageOptions.clean);
- } finally {
- await this.report("onInit", this);
- }
- // populate test files cache so watch mode can trigger a file rerun
- await this.globTestSpecifications();
- if (this.config.watch) await this.report("onWatcherStart");
- });
- }
- /**
- * If there is a test run happening, returns a promise that will
- * resolve when the test run is finished.
- */
- async waitForTestRunEnd() {
- if (!this.runningPromise) return;
- await this.runningPromise;
- }
- /**
- * Get test specifications associated with the given module. If module is not a test file, an empty array is returned.
- *
- * **Note:** this method relies on a cache generated by `globTestSpecifications`. If the file was not processed yet, use `project.matchesGlobPattern` instead.
- * @param moduleId The module ID to get test specifications for.
- */
- getModuleSpecifications(moduleId) {
- return this.specifications.getModuleSpecifications(moduleId);
- }
- /**
- * Vitest automatically caches test specifications for each file. This method clears the cache for the given file or the whole cache altogether.
- */
- clearSpecificationsCache(moduleId) {
- this.specifications.clearCache(moduleId);
- if (!moduleId) this.projects.forEach((project) => {
- project.testFilesList = null;
- });
- }
- /**
- * Run tests for the given test specifications. This does not trigger `onWatcher*` events.
- * @param specifications A list of specifications to run.
- * @param allTestsRun Indicates whether all tests were run. This only matters for coverage.
- */
- runTestSpecifications(specifications, allTestsRun = false) {
- specifications.forEach((spec) => this.specifications.ensureSpecificationCached(spec));
- return this.runFiles(specifications, allTestsRun);
- }
- /**
- * Rerun files and trigger `onWatcherRerun`, `onWatcherStart` and `onTestsRerun` events.
- * @param specifications A list of specifications to run.
- * @param allTestsRun Indicates whether all tests were run. This only matters for coverage.
- */
- async rerunTestSpecifications(specifications, allTestsRun = false) {
- const files = specifications.map((spec) => spec.moduleId);
- await Promise.all([this.report("onWatcherRerun", files, "rerun test"), ...this._onUserTestsRerun.map((fn) => fn(specifications))]);
- const result = await this.runTestSpecifications(specifications, allTestsRun);
- await this.report("onWatcherStart", this.state.getFiles(files));
- return result;
- }
- async runFiles(specs, allTestsRun) {
- return this._traces.$("vitest.test_run", async () => {
- await this._testRun.start(specs);
- // previous run
- await this.cancelPromise;
- await this.runningPromise;
- this._onCancelListeners.clear();
- this.isCancelling = false;
- // schedule the new run
- this.runningPromise = (async () => {
- try {
- if (!this.pool) this.pool = createPool(this);
- const invalidates = Array.from(this.watcher.invalidates);
- this.watcher.invalidates.clear();
- this.snapshot.clear();
- this.state.clearErrors();
- if (!this.isFirstRun && this._coverageOptions.cleanOnRerun) await this.coverageProvider?.clean();
- await this.initializeGlobalSetup(specs);
- try {
- await this.pool.runTests(specs, invalidates);
- } catch (err) {
- this.state.catchError(err, "Unhandled Error");
- }
- const files = this.state.getFiles();
- this.cache.results.updateResults(files);
- try {
- await this.cache.results.writeToCache();
- } catch {}
- return {
- testModules: this.state.getTestModules(),
- unhandledErrors: this.state.getUnhandledErrors()
- };
- } finally {
- const coverage = await this.coverageProvider?.generateCoverage({ allTestsRun });
- const errors = this.state.getUnhandledErrors();
- this._checkUnhandledErrors(errors);
- await this._testRun.end(specs, errors, coverage);
- await this.reportCoverage(coverage, allTestsRun);
- }
- })().finally(() => {
- this.runningPromise = void 0;
- this.isFirstRun = false;
- // all subsequent runs will treat this as a fresh run
- this.config.changed = false;
- this.config.related = void 0;
- });
- return await this.runningPromise;
- });
- }
- /**
- * Returns module's diagnostic. If `testModule` is not provided, `selfTime` and `totalTime` will be aggregated across all tests.
- *
- * If the module was not transformed or executed, the diagnostic will be empty.
- * @experimental
- * @see {@link https://vitest.dev/api/advanced/vitest#getsourcemodulediagnostic}
- */
- async experimental_getSourceModuleDiagnostic(moduleId, testModule) {
- if (testModule) {
- const viteEnvironment = testModule.viteEnvironment;
- // if there is no viteEnvironment, it means the file did not run yet
- if (!viteEnvironment) return {
- modules: [],
- untrackedModules: []
- };
- const moduleLocations = await collectSourceModulesLocations(moduleId, viteEnvironment.moduleGraph);
- return collectModuleDurationsDiagnostic(moduleId, this.state, moduleLocations, testModule);
- }
- const environments = this.projects.flatMap((p) => {
- return Object.values(p.vite.environments);
- });
- const aggregatedLocationsResult = await Promise.all(environments.map((environment) => collectSourceModulesLocations(moduleId, environment.moduleGraph)));
- return collectModuleDurationsDiagnostic(moduleId, this.state, aggregatedLocationsResult.reduce((acc, locations) => {
- if (locations) {
- acc.modules.push(...locations.modules);
- acc.untracked.push(...locations.untracked);
- }
- return acc;
- }, {
- modules: [],
- untracked: []
- }));
- }
- async experimental_parseSpecifications(specifications, options) {
- if (this.mode !== "test") throw new Error(`The \`experimental_parseSpecifications\` does not support "${this.mode}" mode.`);
- const limit = limitConcurrency(options?.concurrency ?? (typeof nodeos__default.availableParallelism === "function" ? nodeos__default.availableParallelism() : nodeos__default.cpus().length));
- const promises = specifications.map((specification) => limit(() => this.experimental_parseSpecification(specification)));
- return Promise.all(promises);
- }
- async experimental_parseSpecification(specification) {
- if (this.mode !== "test") throw new Error(`The \`experimental_parseSpecification\` does not support "${this.mode}" mode.`);
- const file = await astCollectTests(specification.project, specification.moduleId).catch((error) => {
- return createFailedFileTask(specification.project, specification.moduleId, error);
- });
- // register in state, so it can be retrieved by "getReportedEntity"
- this.state.collectFiles(specification.project, [file]);
- return this.state.getReportedEntity(file);
- }
- /**
- * Collect tests in specified modules. Vitest will run the files to collect tests.
- * @param specifications A list of specifications to run.
- */
- async collectTests(specifications) {
- const filepaths = specifications.map((spec) => spec.moduleId);
- this.state.collectPaths(filepaths);
- // previous run
- await this.cancelPromise;
- await this.runningPromise;
- this._onCancelListeners.clear();
- this.isCancelling = false;
- // schedule the new run
- this.runningPromise = (async () => {
- if (!this.pool) this.pool = createPool(this);
- const invalidates = Array.from(this.watcher.invalidates);
- this.watcher.invalidates.clear();
- this.snapshot.clear();
- this.state.clearErrors();
- await this.initializeGlobalSetup(specifications);
- try {
- await this.pool.collectTests(specifications, invalidates);
- } catch (err) {
- this.state.catchError(err, "Unhandled Error");
- }
- // can only happen if there was a syntax error in describe block
- // or there was an error importing a file
- if (hasFailed(this.state.getFiles())) process.exitCode = 1;
- return {
- testModules: this.state.getTestModules(),
- unhandledErrors: this.state.getUnhandledErrors()
- };
- })().finally(() => {
- this.runningPromise = void 0;
- // all subsequent runs will treat this as a fresh run
- this.config.changed = false;
- this.config.related = void 0;
- });
- return await this.runningPromise;
- }
- /**
- * Gracefully cancel the current test run. Vitest will wait until all running tests are finished before cancelling.
- */
- async cancelCurrentRun(reason) {
- this.isCancelling = true;
- this.cancelPromise = Promise.all([...this._onCancelListeners].map((listener) => listener(reason)));
- await this.cancelPromise.finally(() => this.cancelPromise = void 0);
- await this.runningPromise;
- }
- /** @internal */
- async _initBrowserServers() {
- await Promise.all(this.projects.map((p) => p._initBrowserServer()));
- }
- async initializeGlobalSetup(paths) {
- const projects = new Set(paths.map((spec) => spec.project));
- const coreProject = this.getRootProject();
- if (!projects.has(coreProject)) projects.add(coreProject);
- for (const project of projects) await project._initializeGlobalSetup();
- }
- /** @internal */
- async rerunFiles(files = this.state.getFilepaths(), trigger, allTestsRun = true, resetTestNamePattern = false) {
- if (resetTestNamePattern) this.configOverride.testNamePattern = void 0;
- if (this.filenamePattern) {
- const filteredFiles = await this.globTestSpecifications(this.filenamePattern);
- files = files.filter((file) => filteredFiles.some((f) => f.moduleId === file));
- }
- const specifications = files.flatMap((file) => this.getModuleSpecifications(file));
- await Promise.all([this.report("onWatcherRerun", files, trigger), ...this._onUserTestsRerun.map((fn) => fn(specifications))]);
- const testResult = await this.runFiles(specifications, allTestsRun);
- await this.report("onWatcherStart", this.state.getFiles(files));
- return testResult;
- }
- /** @internal */
- async rerunTask(id) {
- const task = this.state.idMap.get(id);
- if (!task) throw new Error(`Task ${id} was not found`);
- const taskNamePattern = task.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
- await this.changeNamePattern(taskNamePattern, [task.file.filepath], "tasks" in task ? "rerun suite" : "rerun test");
- }
- /** @internal */
- async changeProjectName(pattern) {
- if (pattern === "") this.configOverride.project = void 0;
- else this.configOverride.project = [pattern];
- await this.vite.restart();
- }
- /** @internal */
- async changeNamePattern(pattern, files = this.state.getFilepaths(), trigger) {
- // Empty test name pattern should reset filename pattern as well
- if (pattern === "") this.filenamePattern = void 0;
- const testNamePattern = pattern ? new RegExp(pattern) : void 0;
- this.configOverride.testNamePattern = testNamePattern;
- // filter only test files that have tests matching the pattern
- if (testNamePattern) files = files.filter((filepath) => {
- const files = this.state.getFiles([filepath]);
- return !files.length || files.some((file) => {
- const tasks = getTasks(file);
- return !tasks.length || tasks.some((task) => testNamePattern.test(task.name));
- });
- });
- await this.rerunFiles(files, trigger, pattern === "");
- }
- /** @internal */
- async changeFilenamePattern(pattern, files = this.state.getFilepaths()) {
- this.filenamePattern = pattern ? [pattern] : [];
- const trigger = this.filenamePattern.length ? "change filename pattern" : "reset filename pattern";
- await this.rerunFiles(files, trigger, pattern === "");
- }
- /** @internal */
- async rerunFailed() {
- await this.rerunFiles(this.state.getFailedFilepaths(), "rerun failed", false);
- }
- /**
- * Update snapshots in specified files. If no files are provided, it will update files with failed tests and obsolete snapshots.
- * @param files The list of files on the file system
- */
- async updateSnapshot(files) {
- // default to failed files
- files = files || [...this.state.getFailedFilepaths(), ...this.snapshot.summary.uncheckedKeysByFile.map((s) => s.filePath)];
- this.enableSnapshotUpdate();
- try {
- return await this.rerunFiles(files, "update snapshot", false);
- } finally {
- this.resetSnapshotUpdate();
- }
- }
- /**
- * Enable the mode that allows updating snapshots when running tests.
- * This method doesn't run any tests.
- *
- * Every test that runs after this method is called will update snapshots.
- * To disable the mode, call `resetSnapshotUpdate`.
- */
- enableSnapshotUpdate() {
- this.configOverride.snapshotOptions = {
- updateSnapshot: "all",
- snapshotEnvironment: null
- };
- this.snapshot.options.updateSnapshot = "all";
- }
- /**
- * Disable the mode that allows updating snapshots when running tests.
- */
- resetSnapshotUpdate() {
- delete this.configOverride.snapshotOptions;
- this.snapshot.options.updateSnapshot = this.config.snapshotOptions.updateSnapshot;
- }
- /**
- * Set the global test name pattern to a regexp.
- * This method doesn't run any tests.
- */
- setGlobalTestNamePattern(pattern) {
- if (pattern instanceof RegExp) this.configOverride.testNamePattern = pattern;
- else this.configOverride.testNamePattern = pattern ? new RegExp(pattern) : void 0;
- }
- /**
- * Returns the regexp used for the global test name pattern.
- */
- getGlobalTestNamePattern() {
- if (this.configOverride.testNamePattern != null) return this.configOverride.testNamePattern;
- return this.config.testNamePattern;
- }
- /**
- * Resets the global test name pattern. This method doesn't run any tests.
- */
- resetGlobalTestNamePattern() {
- this.configOverride.testNamePattern = void 0;
- }
- _rerunTimer;
- async scheduleRerun(triggerId) {
- const currentCount = this.restartsCount;
- clearTimeout(this._rerunTimer);
- await this.cancelPromise;
- await this.runningPromise;
- clearTimeout(this._rerunTimer);
- // server restarted
- if (this.restartsCount !== currentCount) return;
- this._rerunTimer = setTimeout(async () => {
- if (this.watcher.changedTests.size === 0) {
- this.watcher.invalidates.clear();
- return;
- }
- // server restarted
- if (this.restartsCount !== currentCount) return;
- this.isFirstRun = false;
- this.snapshot.clear();
- let files = Array.from(this.watcher.changedTests);
- if (this.filenamePattern) {
- const filteredFiles = await this.globTestSpecifications(this.filenamePattern);
- files = files.filter((file) => filteredFiles.some((f) => f.moduleId === file));
- // A file that does not match the current filename pattern was changed
- if (files.length === 0) return;
- }
- this.watcher.changedTests.clear();
- const triggerLabel = relative(this.config.root, triggerId);
- // get file specifications and filter them if needed
- const specifications = files.flatMap((file) => this.getModuleSpecifications(file)).filter((specification) => {
- if (this._onFilterWatchedSpecification.length === 0) return true;
- return this._onFilterWatchedSpecification.every((fn) => fn(specification));
- });
- await Promise.all([this.report("onWatcherRerun", files, triggerLabel), ...this._onUserTestsRerun.map((fn) => fn(specifications))]);
- await this.runFiles(specifications, false);
- await this.report("onWatcherStart", this.state.getFiles(files));
- }, WATCHER_DEBOUNCE);
- }
- /**
- * Invalidate a file in all projects.
- */
- invalidateFile(filepath) {
- this.projects.forEach(({ vite, browser }) => {
- [...Object.values(vite.environments), ...Object.values(browser?.vite.environments || {})].forEach((environment) => {
- const { moduleGraph } = environment;
- const modules = moduleGraph.getModulesByFile(filepath);
- if (!modules) return;
- modules.forEach((module) => {
- moduleGraph.invalidateModule(module);
- this._fsCache.invalidateCachePath(environment, module.id);
- });
- });
- });
- }
- /** @internal */
- _checkUnhandledErrors(errors) {
- if (errors.length && !this.config.dangerouslyIgnoreUnhandledErrors) process.exitCode = 1;
- }
- async reportCoverage(coverage, allTestsRun) {
- if (this.state.getCountOfFailedTests() > 0) {
- await this.coverageProvider?.onTestFailure?.();
- if (!this._coverageOptions.reportOnFailure) return;
- }
- if (this.coverageProvider) {
- await this.coverageProvider.reportCoverage(coverage, { allTestsRun });
- // notify coverage iframe reload
- for (const reporter of this.reporters) if (reporter instanceof WebSocketReporter) reporter.onFinishedReportCoverage();
- }
- }
- /**
- * Closes all projects and their associated resources.
- * This can only be called once; the closing promise is cached until the server restarts.
- */
- async close() {
- if (!this.closingPromise) this.closingPromise = (async () => {
- const teardownProjects = [...this.projects];
- if (this.coreWorkspaceProject && !teardownProjects.includes(this.coreWorkspaceProject)) teardownProjects.push(this.coreWorkspaceProject);
- // do teardown before closing the server
- for (const project of teardownProjects.reverse()) await project._teardownGlobalSetup();
- const closePromises = this.projects.map((w) => w.close());
- // close the core workspace server only once
- // it's possible that it's not initialized at all because it's not running any tests
- if (this.coreWorkspaceProject && !this.projects.includes(this.coreWorkspaceProject)) closePromises.push(this.coreWorkspaceProject.close().then(() => this._vite = void 0));
- if (this.pool) closePromises.push((async () => {
- await this.pool?.close?.();
- this.pool = void 0;
- })());
- closePromises.push(...this._onClose.map((fn) => fn()));
- await Promise.allSettled(closePromises).then((results) => {
- results.forEach((r) => {
- if (r.status === "rejected") this.logger.error("error during close", r.reason);
- });
- });
- await this._traces?.finish();
- })();
- return this.closingPromise;
- }
- /**
- * Closes all projects and exit the process
- * @param force If true, the process will exit immediately after closing the projects.
- */
- async exit(force = false) {
- setTimeout(() => {
- this.report("onProcessTimeout").then(() => {
- console.warn(`close timed out after ${this.config.teardownTimeout}ms`);
- if (!this.pool) {
- const runningServers = [this._vite, ...this.projects.map((p) => p._vite)].filter(Boolean).length;
- if (runningServers === 1) console.warn("Tests closed successfully but something prevents Vite server from exiting");
- else if (runningServers > 1) console.warn(`Tests closed successfully but something prevents ${runningServers} Vite servers from exiting`);
- else console.warn("Tests closed successfully but something prevents the main process from exiting");
- if (!this.reporters.some((r) => r instanceof HangingProcessReporter)) console.warn("You can try to identify the cause by enabling \"hanging-process\" reporter. See https://vitest.dev/config/#reporters");
- }
- process.exit();
- });
- }, this.config.teardownTimeout).unref();
- await this.close();
- if (force) process.exit();
- }
- /** @internal */
- async report(name, ...args) {
- await Promise.all(this.reporters.map((r) => r[name]?.(
- // @ts-expect-error let me go
- ...args
- )));
- }
- /** @internal */
- async _globTestFilepaths() {
- const specifications = await this.globTestSpecifications();
- return Array.from(new Set(specifications.map((spec) => spec.moduleId)));
- }
- /**
- * Should the server be kept running after the tests are done.
- */
- shouldKeepServer() {
- return !!this.config?.watch;
- }
- /**
- * Register a handler that will be called when the server is restarted due to a config change.
- */
- onServerRestart(fn) {
- this._onRestartListeners.push(fn);
- }
- /**
- * Register a handler that will be called when the test run is cancelled with `vitest.cancelCurrentRun`.
- */
- onCancel(fn) {
- this._onCancelListeners.add(fn);
- return () => {
- this._onCancelListeners.delete(fn);
- };
- }
- /**
- * Register a handler that will be called when the server is closed.
- */
- onClose(fn) {
- this._onClose.push(fn);
- }
- /**
- * Register a handler that will be called when the tests are rerunning.
- */
- onTestsRerun(fn) {
- this._onUserTestsRerun.push(fn);
- }
- /**
- * Register a handler that will be called when a file is changed.
- * This callback should return `true` of `false` indicating whether the test file needs to be rerun.
- * @example
- * const testsToRun = [resolve('./test.spec.ts')]
- * vitest.onFilterWatchedSpecification(specification => testsToRun.includes(specification.moduleId))
- */
- onFilterWatchedSpecification(fn) {
- this._onFilterWatchedSpecification.push(fn);
- }
- /** @internal */
- onAfterSetServer(fn) {
- this._onSetServer.push(fn);
- }
- /**
- * Check if the project with a given name should be included.
- */
- matchesProjectFilter(name) {
- const projects = this._config?.project || this._cliOptions?.project;
- // no filters applied, any project can be included
- if (!projects || !projects.length) return true;
- return toArray(projects).some((project) => {
- return wildcardPatternToRegExp(project).test(name);
- });
- }
-}
-function assert(condition, property, name = property) {
- if (!condition) throw new Error(`The ${name} was not set. It means that \`vitest.${property}\` was called before the Vite server was established. Await the Vitest promise before accessing \`vitest.${property}\`.`);
-}
-
-async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(options))) {
- const userConfig = deepMerge({}, options);
- async function UIPlugin() {
- await vitest.packageInstaller.ensureInstalled("@vitest/ui", options.root || process.cwd(), vitest.version);
- return (await import('@vitest/ui')).default(vitest);
- }
- return [
- {
- name: "vitest",
- enforce: "pre",
- options() {
- this.meta.watchMode = false;
- },
- async config(viteConfig) {
- if (options.watch)
- // Earlier runs have overwritten values of the `options`.
- // Reset it back to initial user config before setting up the server again.
- options = deepMerge({}, userConfig);
- // preliminary merge of options to be able to create server options for vite
- // however to allow vitest plugins to modify vitest config values
- // this is repeated in configResolved where the config is final
- const testConfig = deepMerge({}, configDefaults, removeUndefinedValues(viteConfig.test ?? {}), options);
- testConfig.api = resolveApiServerConfig(testConfig, defaultPort);
- // store defines for globalThis to make them
- // reassignable when running in worker in src/runtime/setup.ts
- const originalDefine = { ...viteConfig.define };
- options.defines = deleteDefineConfig(viteConfig);
- options.viteDefine = originalDefine;
- let open = false;
- if (testConfig.ui && testConfig.open) open = testConfig.uiBase ?? "/__vitest__/";
- const resolveOptions = getDefaultResolveOptions();
- let config = {
- base: "/",
- root: viteConfig.test?.root || options.root,
- define: { "process.env.NODE_ENV": "process.env.NODE_ENV" },
- resolve: {
- ...resolveOptions,
- alias: testConfig.alias
- },
- server: {
- ...testConfig.api,
- open,
- hmr: false,
- ws: testConfig.api?.middlewareMode ? false : void 0,
- preTransformRequests: false,
- fs: { allow: resolveFsAllow(options.root || process.cwd(), testConfig.config) }
- },
- build: {
- outDir: "dummy-non-existing-folder",
- emptyOutDir: false
- },
- environments: {
- ssr: { resolve: resolveOptions },
- __vitest__: { dev: {} }
- },
- test: {
- root: testConfig.root ?? viteConfig.test?.root,
- deps: testConfig.deps ?? viteConfig.test?.deps
- }
- };
- if ("rolldownVersion" in vite) config = {
- ...config,
- oxc: viteConfig.oxc === false ? false : { target: viteConfig.oxc?.target || "node18" }
- };
- else config = {
- ...config,
- esbuild: viteConfig.esbuild === false ? false : {
- target: viteConfig.esbuild?.target || "node18",
- sourcemap: "external",
- legalComments: "inline"
- }
- };
- // inherit so it's available in VitestOptimizer
- // I cannot wait to rewrite all of this in Vitest 4
- if (options.cache != null) config.test.cache = options.cache;
- if (vitest.configOverride.project)
- // project filter was set by the user, so we need to filter the project
- options.project = vitest.configOverride.project;
- config.customLogger = createViteLogger(vitest.logger, viteConfig.logLevel || "warn", { allowClearScreen: false });
- config.customLogger = silenceImportViteIgnoreWarning(config.customLogger);
- // chokidar fsevents is unstable on macos when emitting "ready" event
- if (process.platform === "darwin" && false);
- const classNameStrategy = typeof testConfig.css !== "boolean" && testConfig.css?.modules?.classNameStrategy || "stable";
- if (classNameStrategy !== "scoped") {
- config.css ??= {};
- config.css.modules ??= {};
- if (config.css.modules) config.css.modules.generateScopedName = (name, filename) => {
- return generateScopedClassName(classNameStrategy, name, relative(vitest.config.root || options.root || process.cwd(), filename));
- };
- }
- return config;
- },
- async configResolved(viteConfig) {
- const viteConfigTest = viteConfig.test || {};
- if (viteConfigTest.watch === false) viteConfigTest.run = true;
- if ("alias" in viteConfigTest) delete viteConfigTest.alias;
- // viteConfig.test is final now, merge it for real
- options = deepMerge({}, configDefaults, viteConfigTest, options);
- options.api = resolveApiServerConfig(options, defaultPort);
- // we replace every "import.meta.env" with "process.env"
- // to allow reassigning, so we need to put all envs on process.env
- const { PROD, DEV, ...envs } = viteConfig.env;
- // process.env can have only string values and will cast string on it if we pass other type,
- // so we are making them truthy
- process.env.PROD ??= PROD ? "1" : "";
- process.env.DEV ??= DEV ? "1" : "";
- for (const name in envs) process.env[name] ??= envs[name];
- // don't watch files in run mode
- if (!options.watch) viteConfig.server.watch = null;
- if (options.ui)
- // @ts-expect-error mutate readonly
- viteConfig.plugins.push(await UIPlugin());
- Object.defineProperty(viteConfig, "_vitest", {
- value: options,
- enumerable: false,
- configurable: true
- });
- const originalName = options.name;
- if (options.browser?.instances) options.browser.instances.forEach((instance) => {
- instance.name ??= originalName ? `${originalName} (${instance.browser})` : instance.browser;
- });
- },
- configureServer: {
- order: "post",
- async handler(server) {
- if (options.watch && false);
- await vitest._setServer(options, server);
- if (options.api && options.watch) (await Promise.resolve().then(function () { return setup$1; })).setup(vitest);
- // #415, in run mode we don't need the watcher, close it would improve the performance
- if (!options.watch) await server.watcher.close();
- }
- }
- },
- MetaEnvReplacerPlugin(),
- ...CSSEnablerPlugin(vitest),
- CoverageTransform(vitest),
- VitestCoreResolver(vitest),
- ...MocksPlugins(),
- VitestOptimizer(),
- NormalizeURLPlugin(),
- ModuleRunnerTransform()
- ].filter(notNullish);
-}
-function removeUndefinedValues(obj) {
- for (const key in Object.keys(obj)) if (obj[key] === void 0) delete obj[key];
- return obj;
-}
-
-async function createVitest(mode, options, viteOverrides = {}, vitestOptions = {}) {
- const ctx = new Vitest(mode, deepClone(options), vitestOptions);
- const root = slash(resolve$1(options.root || process.cwd()));
- const configPath = options.config === false ? false : options.config ? resolveModule(options.config, { paths: [root] }) ?? resolve$1(root, options.config) : any(configFiles, { cwd: root });
- options.config = configPath;
- const { browser: _removeBrowser, ...restOptions } = options;
- const server = await createViteServer(mergeConfig({
- configFile: configPath,
- configLoader: options.configLoader,
- mode: options.mode || mode,
- plugins: await VitestPlugin(restOptions, ctx)
- }, mergeConfig(viteOverrides, { root: options.root })));
- if (ctx.config.api?.port) await server.listen();
- return ctx;
-}
-
-const MAX_RESULT_COUNT = 10;
-const SELECTION_MAX_INDEX = 7;
-const ESC = "\x1B[";
-class WatchFilter {
- filterRL;
- currentKeyword = void 0;
- message;
- results = [];
- selectionIndex = -1;
- onKeyPress;
- stdin;
- stdout;
- constructor(message, stdin = process.stdin, stdout$1 = stdout()) {
- this.message = message;
- this.stdin = stdin;
- this.stdout = stdout$1;
- this.filterRL = readline.createInterface({
- input: this.stdin,
- escapeCodeTimeout: 50
- });
- readline.emitKeypressEvents(this.stdin, this.filterRL);
- if (this.stdin.isTTY) this.stdin.setRawMode(true);
- }
- async filter(filterFunc) {
- this.write(this.promptLine());
- const resultPromise = createDefer();
- this.onKeyPress = this.filterHandler(filterFunc, (result) => {
- resultPromise.resolve(result);
- });
- this.stdin.on("keypress", this.onKeyPress);
- try {
- return await resultPromise;
- } finally {
- this.close();
- }
- }
- filterHandler(filterFunc, onSubmit) {
- return async (str, key) => {
- switch (true) {
- case key.sequence === "":
- if (this.currentKeyword && this.currentKeyword?.length > 1) this.currentKeyword = this.currentKeyword?.slice(0, -1);
- else this.currentKeyword = void 0;
- break;
- case key?.ctrl && key?.name === "c":
- case key?.name === "escape":
- this.write(`${ESC}1G${ESC}0J`);
- onSubmit(void 0);
- return;
- case key?.name === "enter":
- case key?.name === "return": {
- const selection = this.results[this.selectionIndex];
- onSubmit((typeof selection === "string" ? selection : selection?.key) || this.currentKeyword || "");
- this.currentKeyword = void 0;
- break;
- }
- case key?.name === "up":
- if (this.selectionIndex && this.selectionIndex > 0) this.selectionIndex--;
- else this.selectionIndex = -1;
- break;
- case key?.name === "down":
- if (this.selectionIndex < this.results.length - 1) this.selectionIndex++;
- else if (this.selectionIndex >= this.results.length - 1) this.selectionIndex = this.results.length - 1;
- break;
- case !key?.ctrl && !key?.meta:
- if (this.currentKeyword === void 0) this.currentKeyword = str;
- else this.currentKeyword += str || "";
- break;
- }
- if (this.currentKeyword) this.results = await filterFunc(this.currentKeyword);
- this.render();
- };
- }
- render() {
- let printStr = this.promptLine();
- if (!this.currentKeyword) printStr += "\nPlease input filter pattern";
- else if (this.currentKeyword && this.results.length === 0) printStr += "\nPattern matches no results";
- else {
- const resultCountLine = this.results.length === 1 ? `Pattern matches ${this.results.length} result` : `Pattern matches ${this.results.length} results`;
- let resultBody = "";
- if (this.results.length > MAX_RESULT_COUNT) {
- const offset = this.selectionIndex > SELECTION_MAX_INDEX ? this.selectionIndex - SELECTION_MAX_INDEX : 0;
- const displayResults = this.results.slice(offset, MAX_RESULT_COUNT + offset);
- const remainingResultCount = this.results.length - offset - displayResults.length;
- resultBody = `${displayResults.map((result, index) => index + offset === this.selectionIndex ? c.green(` › ${result}`) : c.dim(` › ${result}`)).join("\n")}`;
- if (remainingResultCount > 0) resultBody += `
-${c.dim(` ...and ${remainingResultCount} more ${remainingResultCount === 1 ? "result" : "results"}`)}`;
- } else resultBody = this.results.map((result, index) => index === this.selectionIndex ? c.green(` › ${result}`) : c.dim(` › ${result}`)).join("\n");
- printStr += `\n${resultCountLine}\n${resultBody}`;
- }
- this.eraseAndPrint(printStr);
- this.restoreCursor();
- }
- keywordOffset() {
- return `? ${this.message} › `.length + 1;
- }
- promptLine() {
- return `${c.cyan("?")} ${c.bold(this.message)} › ${this.currentKeyword || ""}`;
- }
- eraseAndPrint(str) {
- let rows = 0;
- const lines = str.split(/\r?\n/);
- for (const line of lines) {
- const columns = "columns" in this.stdout ? this.stdout.columns : 80;
- // We have to take care of screen width in case of long lines
- rows += 1 + Math.floor(Math.max(stripVTControlCharacters(line).length - 1, 0) / columns);
- }
- this.write(`${ESC}1G`);
- this.write(`${ESC}J`);
- this.write(str);
- this.write(`${ESC}${rows - 1}A`);
- }
- close() {
- this.filterRL.close();
- if (this.onKeyPress) this.stdin.removeListener("keypress", this.onKeyPress);
- if (this.stdin.isTTY) this.stdin.setRawMode(false);
- }
- restoreCursor() {
- const cursortPos = this.keywordOffset() + (this.currentKeyword?.length || 0);
- this.write(`${ESC}${cursortPos}G`);
- }
- write(data) {
- this.stdout.write(data);
- }
- getLastResults() {
- return this.results.map((r) => typeof r === "string" ? r : r.toString());
- }
-}
-
-const keys = [
- [["a", "return"], "rerun all tests"],
- ["r", "rerun current pattern tests"],
- ["f", "rerun only failed tests"],
- ["u", "update snapshot"],
- ["p", "filter by a filename"],
- ["t", "filter by a test name regex pattern"],
- ["w", "filter by a project name"],
- ["b", "start the browser server if not started yet"],
- ["q", "quit"]
-];
-const cancelKeys = [
- "space",
- "c",
- "h",
- ...keys.map((key) => key[0]).flat()
-];
-function printShortcutsHelp() {
- stdout().write(`
-${c.bold(" Watch Usage")}
-${keys.map((i) => c.dim(" press ") + c.reset([i[0]].flat().map(c.bold).join(", ")) + c.dim(` to ${i[1]}`)).join("\n")}
-`);
-}
-function* traverseFilteredTestNames(parentName, filter, t) {
- if (isTestCase(t)) {
- if (t.name.match(filter)) {
- const displayName = `${parentName} > ${t.name}`;
- yield {
- key: t.name,
- toString: () => displayName
- };
- }
- } else {
- parentName = parentName.length ? `${parentName} > ${t.name}` : t.name;
- for (const task of t.tasks) yield* traverseFilteredTestNames(parentName, filter, task);
- }
-}
-function* getFilteredTestNames(pattern, suite) {
- try {
- const reg = new RegExp(pattern);
- // TODO: we cannot run tests per workspace yet: filtering files
- const files = /* @__PURE__ */ new Set();
- for (const file of suite) if (!files.has(file.name)) {
- files.add(file.name);
- yield* traverseFilteredTestNames("", reg, file);
- }
- } catch {}
-}
-function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
- let latestFilename = "";
- async function _keypressHandler(str, key) {
- // Cancel run and exit when ctrl-c or esc is pressed.
- // If cancelling takes long and key is pressed multiple times, exit forcefully.
- if (str === "" || str === "\x1B" || key && key.ctrl && key.name === "c") {
- if (!ctx.isCancelling) {
- ctx.logger.log(c.red("Cancelling test run. Press CTRL+c again to exit forcefully.\n"));
- process.exitCode = 130;
- await ctx.cancelCurrentRun("keyboard-input");
- }
- return ctx.exit(true);
- }
- // window not support suspend
- if (!isWindows && key && key.ctrl && key.name === "z") {
- process.kill(process.ppid, "SIGTSTP");
- process.kill(process.pid, "SIGTSTP");
- return;
- }
- const name = key?.name;
- if (ctx.runningPromise) {
- if (cancelKeys.includes(name)) await ctx.cancelCurrentRun("keyboard-input");
- return;
- }
- // quit
- if (name === "q") return ctx.exit(true);
- // help
- if (name === "h") return printShortcutsHelp();
- // update snapshot
- if (name === "u") return ctx.updateSnapshot();
- // rerun all tests
- if (name === "a" || name === "return") {
- const files = await ctx._globTestFilepaths();
- return ctx.changeNamePattern("", files, "rerun all tests");
- }
- // rerun current pattern tests
- if (name === "r") return ctx.rerunFiles();
- // rerun only failed tests
- if (name === "f") return ctx.rerunFailed();
- // change project filter
- if (name === "w") return inputProjectName();
- // change testNamePattern
- if (name === "t") return inputNamePattern();
- // change fileNamePattern
- if (name === "p") return inputFilePattern();
- if (name === "b") {
- await ctx._initBrowserServers();
- ctx.projects.forEach((project) => {
- ctx.logger.log();
- ctx.logger.printBrowserBanner(project);
- });
- return null;
- }
- }
- async function keypressHandler(str, key) {
- await _keypressHandler(str, key);
- }
- async function inputNamePattern() {
- off();
- const filter = await new WatchFilter("Input test name pattern (RegExp)", stdin, stdout).filter((str) => {
- return [...getFilteredTestNames(str, ctx.state.getFiles())];
- });
- on();
- if (typeof filter === "undefined") return;
- const files = ctx.state.getFilepaths();
- // if running in standalone mode, Vitest instance doesn't know about any test file
- const cliFiles = ctx.config.standalone && !files.length ? await ctx._globTestFilepaths() : void 0;
- await ctx.changeNamePattern(filter?.trim() || "", cliFiles, "change pattern");
- }
- async function inputProjectName() {
- off();
- const { filter = "" } = await prompt([{
- name: "filter",
- type: "text",
- message: "Input a single project name",
- initial: ctx.config.project[0] || ""
- }]);
- on();
- await ctx.changeProjectName(filter.trim());
- }
- async function inputFilePattern() {
- off();
- const watchFilter = new WatchFilter("Input filename pattern", stdin, stdout);
- const filter = await watchFilter.filter(async (str) => {
- return (await ctx.globTestSpecifications([str])).map((specification) => relative(ctx.config.root, specification.moduleId)).filter((file, index, all) => all.indexOf(file) === index);
- });
- on();
- if (typeof filter === "undefined") return;
- latestFilename = filter?.trim() || "";
- const lastResults = watchFilter.getLastResults();
- await ctx.changeFilenamePattern(latestFilename, filter && lastResults.length ? lastResults.map((i) => resolve(ctx.config.root, i)) : void 0);
- }
- let rl;
- function on() {
- off();
- rl = readline.createInterface({
- input: stdin,
- escapeCodeTimeout: 50
- });
- readline.emitKeypressEvents(stdin, rl);
- if (stdin.isTTY) stdin.setRawMode(true);
- stdin.on("keypress", keypressHandler);
- }
- function off() {
- rl?.close();
- rl = void 0;
- stdin.removeListener("keypress", keypressHandler);
- if (stdin.isTTY) stdin.setRawMode(false);
- }
- on();
- return function cleanup() {
- off();
- };
-}
-
-/**
-* Start Vitest programmatically
-*
-* Returns a Vitest instance if initialized successfully.
-*/
-async function startVitest(mode, cliFilters = [], options = {}, viteOverrides, vitestOptions) {
- const root = resolve(options.root || process.cwd());
- const ctx = await prepareVitest(mode, options, viteOverrides, vitestOptions, cliFilters);
- if (mode === "test" && ctx._coverageOptions.enabled) {
- const requiredPackages = CoverageProviderMap[ctx._coverageOptions.provider || "v8"];
- if (requiredPackages) {
- if (!await ctx.packageInstaller.ensureInstalled(requiredPackages, root, ctx.version)) {
- process.exitCode = 1;
- return ctx;
- }
- }
- }
- const stdin = vitestOptions?.stdin || process.stdin;
- const stdout = vitestOptions?.stdout || process.stdout;
- let stdinCleanup;
- if (stdin.isTTY && ctx.config.watch) stdinCleanup = registerConsoleShortcuts(ctx, stdin, stdout);
- ctx.onAfterSetServer(() => {
- if (ctx.config.standalone) ctx.init();
- else ctx.start(cliFilters);
- });
- try {
- if (ctx.config.clearCache) await ctx.experimental_clearCache();
- else if (ctx.config.mergeReports) await ctx.mergeReports();
- else if (ctx.config.standalone) await ctx.init();
- else await ctx.start(cliFilters);
- } catch (e) {
- if (e instanceof FilesNotFoundError) return ctx;
- if (e instanceof GitNotFoundError) {
- ctx.logger.error(e.message);
- return ctx;
- }
- if (e instanceof IncludeTaskLocationDisabledError || e instanceof RangeLocationFilterProvidedError || e instanceof LocationFilterFileNotFoundError) {
- ctx.logger.printError(e, { verbose: false });
- return ctx;
- }
- process.exitCode = 1;
- ctx.logger.printError(e, {
- fullStack: true,
- type: "Unhandled Error"
- });
- ctx.logger.error("\n\n");
- return ctx;
- }
- if (ctx.shouldKeepServer()) return ctx;
- stdinCleanup?.();
- await ctx.close();
- return ctx;
-}
-async function prepareVitest(mode, options = {}, viteOverrides, vitestOptions, cliFilters) {
- process.env.TEST = "true";
- process.env.VITEST = "true";
- process.env.NODE_ENV ??= "test";
- if (options.run) options.watch = false;
- if (options.standalone && (cliFilters?.length || 0) > 0) options.standalone = false;
- // this shouldn't affect _application root_ that can be changed inside config
- const root = resolve(options.root || process.cwd());
- const ctx = await createVitest(mode, options, viteOverrides, vitestOptions);
- const environmentPackage = getEnvPackageName(ctx.config.environment);
- if (environmentPackage && !await ctx.packageInstaller.ensureInstalled(environmentPackage, root)) {
- process.exitCode = 1;
- return ctx;
- }
- return ctx;
-}
-function processCollected(ctx, files, options) {
- let errorsPrinted = false;
- forEachSuite(files, (suite) => {
- suite.errors().forEach((error) => {
- errorsPrinted = true;
- ctx.logger.printError(error, { project: suite.project });
- });
- });
- if (errorsPrinted) return;
- if (typeof options.json !== "undefined") return processJsonOutput(files, options);
- return formatCollectedAsString(files).forEach((test) => console.log(test));
-}
-function outputFileList(files, options) {
- if (typeof options.json !== "undefined") return outputJsonFileList(files, options);
- formatFilesAsString(files, options).map((file) => console.log(file));
-}
-function outputJsonFileList(files, options) {
- if (typeof options.json === "boolean") return console.log(JSON.stringify(formatFilesAsJSON(files), null, 2));
- if (typeof options.json === "string") {
- const jsonPath = resolve(options.root || process.cwd(), options.json);
- mkdirSync(dirname(jsonPath), { recursive: true });
- writeFileSync(jsonPath, JSON.stringify(formatFilesAsJSON(files), null, 2));
- }
-}
-function formatFilesAsJSON(files) {
- return files.map((file) => {
- const result = { file: file.moduleId };
- if (file.project.name) result.projectName = file.project.name;
- return result;
- });
-}
-function formatFilesAsString(files, options) {
- return files.map((file) => {
- let name = relative(options.root || process.cwd(), file.moduleId);
- if (file.project.name) name = `[${file.project.name}] ${name}`;
- return name;
- });
-}
-function processJsonOutput(files, options) {
- if (typeof options.json === "boolean") return console.log(JSON.stringify(formatCollectedAsJSON(files), null, 2));
- if (typeof options.json === "string") {
- const jsonPath = resolve(options.root || process.cwd(), options.json);
- mkdirSync(dirname(jsonPath), { recursive: true });
- writeFileSync(jsonPath, JSON.stringify(formatCollectedAsJSON(files), null, 2));
- }
-}
-function forEachSuite(modules, callback) {
- modules.forEach((testModule) => {
- callback(testModule);
- for (const suite of testModule.children.allSuites()) callback(suite);
- });
-}
-function formatCollectedAsJSON(files) {
- const results = [];
- files.forEach((file) => {
- for (const test of file.children.allTests()) {
- if (test.result().state === "skipped") continue;
- const result = {
- name: test.fullName,
- file: test.module.moduleId
- };
- if (test.project.name) result.projectName = test.project.name;
- if (test.location) result.location = test.location;
- results.push(result);
- }
- });
- return results;
-}
-function formatCollectedAsString(testModules) {
- const results = [];
- testModules.forEach((testModule) => {
- for (const test of testModule.children.allTests()) {
- if (test.result().state === "skipped") continue;
- const fullName = `${test.module.task.name} > ${test.fullName}`;
- results.push((test.project.name ? `[${test.project.name}] ` : "") + fullName);
- }
- });
- return results;
-}
-const envPackageNames = {
- "jsdom": "jsdom",
- "happy-dom": "happy-dom",
- "edge-runtime": "@edge-runtime/vm"
-};
-function getEnvPackageName(env) {
- if (env === "node") return null;
- if (env in envPackageNames) return envPackageNames[env];
- if (env[0] === "." || isAbsolute(env)) return null;
- return `vitest-environment-${env}`;
-}
-
-var cliApi = /*#__PURE__*/Object.freeze({
- __proto__: null,
- formatCollectedAsJSON: formatCollectedAsJSON,
- formatCollectedAsString: formatCollectedAsString,
- outputFileList: outputFileList,
- prepareVitest: prepareVitest,
- processCollected: processCollected,
- startVitest: startVitest
-});
-
-export { FilesNotFoundError as F, GitNotFoundError as G, ThreadsPoolWorker as T, Vitest as V, VitestPlugin as a, VitestPackageInstaller as b, createVitest as c, createMethodsRPC as d, escapeTestName as e, ForksPoolWorker as f, getFilePoolName as g, TypecheckPoolWorker as h, isValidApiRequest as i, VmForksPoolWorker as j, VmThreadsPoolWorker as k, experimental_getRunnerTask as l, registerConsoleShortcuts as m, isFileServingAllowed as n, createViteLogger as o, createDebugger as p, cliApi as q, resolveFsAllow as r, startVitest as s };
diff --git a/vanilla/node_modules/vitest/dist/chunks/config.d.Cy95HiCx.d.ts b/vanilla/node_modules/vitest/dist/chunks/config.d.Cy95HiCx.d.ts
deleted file mode 100644
index b38b1e2..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/config.d.Cy95HiCx.d.ts
+++ /dev/null
@@ -1,210 +0,0 @@
-import { PrettyFormatOptions } from '@vitest/pretty-format';
-import { SequenceHooks, SequenceSetupFiles } from '@vitest/runner';
-import { SnapshotUpdateState, SnapshotEnvironment } from '@vitest/snapshot';
-import { SerializedDiffOptions } from '@vitest/utils/diff';
-
-/**
- * Names of clock methods that may be faked by install.
- */
-type FakeMethod =
- | "setTimeout"
- | "clearTimeout"
- | "setImmediate"
- | "clearImmediate"
- | "setInterval"
- | "clearInterval"
- | "Date"
- | "nextTick"
- | "hrtime"
- | "requestAnimationFrame"
- | "cancelAnimationFrame"
- | "requestIdleCallback"
- | "cancelIdleCallback"
- | "performance"
- | "queueMicrotask";
-
-interface FakeTimerInstallOpts {
- /**
- * Installs fake timers with the specified unix epoch (default: 0)
- */
- now?: number | Date | undefined;
-
- /**
- * An array with names of global methods and APIs to fake.
- * For instance, `vi.useFakeTimer({ toFake: ['setTimeout', 'performance'] })` will fake only `setTimeout()` and `performance.now()`
- * @default everything available globally except `nextTick`
- */
- toFake?: FakeMethod[] | undefined;
-
- /**
- * The maximum number of timers that will be run when calling runAll()
- * @default 10000
- */
- loopLimit?: number | undefined;
-
- /**
- * Tells @sinonjs/fake-timers to increment mocked time automatically based on the real system time shift (e.g. the mocked time will be incremented by
- * 20ms for every 20ms change in the real system time) (default: false)
- */
- shouldAdvanceTime?: boolean | undefined;
-
- /**
- * Relevant only when using with shouldAdvanceTime: true. increment mocked time by advanceTimeDelta ms every advanceTimeDelta ms change
- * in the real system time (default: 20)
- */
- advanceTimeDelta?: number | undefined;
-
- /**
- * Tells FakeTimers to clear 'native' (i.e. not fake) timers by delegating to their respective handlers.
- * @default true
- */
- shouldClearNativeTimers?: boolean | undefined;
-
- /**
- * Don't throw error when asked to fake timers that are not present.
- * @default false
- */
- ignoreMissingTimers?: boolean | undefined;
-}
-
-/**
-* Config that tests have access to.
-*/
-interface SerializedConfig {
- name: string | undefined;
- globals: boolean;
- base: string | undefined;
- snapshotEnvironment?: string;
- disableConsoleIntercept: boolean | undefined;
- runner: string | undefined;
- isolate: boolean;
- maxWorkers: number;
- mode: "test" | "benchmark";
- bail: number | undefined;
- environmentOptions?: Record<string, any>;
- root: string;
- setupFiles: string[];
- passWithNoTests: boolean;
- testNamePattern: RegExp | undefined;
- allowOnly: boolean;
- testTimeout: number;
- hookTimeout: number;
- clearMocks: boolean;
- mockReset: boolean;
- restoreMocks: boolean;
- unstubGlobals: boolean;
- unstubEnvs: boolean;
- fakeTimers: FakeTimerInstallOpts;
- maxConcurrency: number;
- defines: Record<string, any>;
- expect: {
- requireAssertions?: boolean;
- poll?: {
- timeout?: number;
- interval?: number;
- };
- };
- printConsoleTrace: boolean | undefined;
- sequence: {
- shuffle?: boolean;
- concurrent?: boolean;
- seed: number;
- hooks: SequenceHooks;
- setupFiles: SequenceSetupFiles;
- };
- deps: {
- web: {
- transformAssets?: boolean;
- transformCss?: boolean;
- transformGlobPattern?: RegExp | RegExp[];
- };
- optimizer: Record<string, {
- enabled: boolean;
- }>;
- interopDefault: boolean | undefined;
- moduleDirectories: string[] | undefined;
- };
- snapshotOptions: {
- updateSnapshot: SnapshotUpdateState;
- expand: boolean | undefined;
- snapshotFormat: PrettyFormatOptions | undefined;
- /**
- * only exists for tests, not available in the main process
- */
- snapshotEnvironment: SnapshotEnvironment;
- };
- pool: string;
- snapshotSerializers: string[];
- chaiConfig: {
- includeStack?: boolean;
- showDiff?: boolean;
- truncateThreshold?: number;
- } | undefined;
- diff: string | SerializedDiffOptions | undefined;
- retry: number;
- includeTaskLocation: boolean | undefined;
- inspect: boolean | string | undefined;
- inspectBrk: boolean | string | undefined;
- inspector: {
- enabled?: boolean;
- port?: number;
- host?: string;
- waitForDebugger?: boolean;
- };
- watch: boolean;
- env: Record<string, any>;
- browser: {
- name: string;
- headless: boolean;
- isolate: boolean;
- fileParallelism: boolean;
- ui: boolean;
- viewport: {
- width: number;
- height: number;
- };
- locators: {
- testIdAttribute: string;
- };
- screenshotFailures: boolean;
- providerOptions: {
- actionTimeout?: number;
- };
- trace: BrowserTraceViewMode;
- trackUnhandledErrors: boolean;
- };
- standalone: boolean;
- logHeapUsage: boolean | undefined;
- coverage: SerializedCoverageConfig;
- benchmark: {
- includeSamples: boolean;
- } | undefined;
- serializedDefines: string;
- experimental: {
- fsModuleCache: boolean;
- printImportBreakdown: boolean | undefined;
- openTelemetry: {
- enabled: boolean;
- sdkPath?: string;
- browserSdkPath?: string;
- } | undefined;
- };
-}
-interface SerializedCoverageConfig {
- provider: "istanbul" | "v8" | "custom" | undefined;
- reportsDirectory: string;
- htmlReporter: {
- subdir: string | undefined;
- } | undefined;
- enabled: boolean;
- customProviderModule: string | undefined;
-}
-type RuntimeConfig = Pick<SerializedConfig, "allowOnly" | "testTimeout" | "hookTimeout" | "clearMocks" | "mockReset" | "restoreMocks" | "fakeTimers" | "maxConcurrency" | "expect" | "printConsoleTrace"> & {
- sequence?: {
- hooks?: SequenceHooks;
- };
-};
-type RuntimeOptions = Partial<RuntimeConfig>;
-type BrowserTraceViewMode = "on" | "off" | "on-first-retry" | "on-all-retries" | "retain-on-failure";
-
-export type { BrowserTraceViewMode as B, FakeTimerInstallOpts as F, RuntimeOptions as R, SerializedConfig as S, SerializedCoverageConfig as a, RuntimeConfig as b };
diff --git a/vanilla/node_modules/vitest/dist/chunks/console.Cf-YriPC.js b/vanilla/node_modules/vitest/dist/chunks/console.Cf-YriPC.js
deleted file mode 100644
index 0c72553..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/console.Cf-YriPC.js
+++ /dev/null
@@ -1,146 +0,0 @@
-import { Console } from 'node:console';
-import { relative } from 'node:path';
-import { Writable } from 'node:stream';
-import { getSafeTimers } from '@vitest/utils/timers';
-import c from 'tinyrainbow';
-import { R as RealDate } from './date.Bq6ZW5rf.js';
-import { g as getWorkerState } from './utils.DvEY5TfP.js';
-
-const UNKNOWN_TEST_ID = "__vitest__unknown_test__";
-function getTaskIdByStack(root) {
- const stack = (/* @__PURE__ */ new Error("STACK_TRACE_ERROR")).stack?.split("\n");
- if (!stack) return UNKNOWN_TEST_ID;
- const index = stack.findIndex((line) => line.includes("at Console.value"));
- const line = index === -1 ? null : stack[index + 2];
- if (!line) return UNKNOWN_TEST_ID;
- const filepath = line.match(/at\s(.*)\s?/)?.[1];
- if (filepath) return relative(root, filepath);
- return UNKNOWN_TEST_ID;
-}
-function createCustomConsole(defaultState) {
- const stdoutBuffer = /* @__PURE__ */ new Map();
- const stderrBuffer = /* @__PURE__ */ new Map();
- const timers = /* @__PURE__ */ new Map();
- const { queueMicrotask } = getSafeTimers();
- function queueCancelableMicrotask(callback) {
- let canceled = false;
- queueMicrotask(() => {
- if (!canceled) callback();
- });
- return () => {
- canceled = true;
- };
- }
- const state = () => defaultState || getWorkerState();
- // group sync console.log calls with micro task
- function schedule(taskId) {
- const timer = timers.get(taskId);
- const { stdoutTime, stderrTime } = timer;
- timer.cancel?.();
- timer.cancel = queueCancelableMicrotask(() => {
- if (stderrTime < stdoutTime) {
- sendStderr(taskId);
- sendStdout(taskId);
- } else {
- sendStdout(taskId);
- sendStderr(taskId);
- }
- });
- }
- function sendStdout(taskId) {
- sendBuffer("stdout", taskId);
- }
- function sendStderr(taskId) {
- sendBuffer("stderr", taskId);
- }
- function sendBuffer(type, taskId) {
- const buffers = type === "stdout" ? stdoutBuffer : stderrBuffer;
- const buffer = buffers.get(taskId);
- if (!buffer) return;
- if (state().config.printConsoleTrace) buffer.forEach(([buffer, origin]) => {
- sendLog(type, taskId, String(buffer), buffer.length, origin);
- });
- else sendLog(type, taskId, buffer.map((i) => String(i[0])).join(""), buffer.length);
- const timer = timers.get(taskId);
- buffers.delete(taskId);
- if (type === "stderr") timer.stderrTime = 0;
- else timer.stdoutTime = 0;
- }
- function sendLog(type, taskId, content, size, origin) {
- const timer = timers.get(taskId);
- const time = type === "stderr" ? timer.stderrTime : timer.stdoutTime;
- state().rpc.onUserConsoleLog({
- type,
- content: content || "<empty line>",
- taskId,
- time: time || RealDate.now(),
- size,
- origin
- });
- }
- return new Console({
- stdout: new Writable({ write(data, encoding, callback) {
- const s = state();
- const id = s?.current?.id || s?.current?.suite?.id || s.current?.file.id || getTaskIdByStack(s.config.root);
- let timer = timers.get(id);
- if (timer) timer.stdoutTime = timer.stdoutTime || RealDate.now();
- else {
- timer = {
- stdoutTime: RealDate.now(),
- stderrTime: RealDate.now()
- };
- timers.set(id, timer);
- }
- let buffer = stdoutBuffer.get(id);
- if (!buffer) {
- buffer = [];
- stdoutBuffer.set(id, buffer);
- }
- if (state().config.printConsoleTrace) {
- const limit = Error.stackTraceLimit;
- Error.stackTraceLimit = limit + 6;
- const trace = (/* @__PURE__ */ new Error("STACK_TRACE")).stack?.split("\n").slice(7).join("\n");
- Error.stackTraceLimit = limit;
- buffer.push([data, trace]);
- } else buffer.push([data, void 0]);
- schedule(id);
- callback();
- } }),
- stderr: new Writable({ write(data, encoding, callback) {
- const s = state();
- const id = s?.current?.id || s?.current?.suite?.id || s.current?.file.id || getTaskIdByStack(s.config.root);
- let timer = timers.get(id);
- if (timer) timer.stderrTime = timer.stderrTime || RealDate.now();
- else {
- timer = {
- stderrTime: RealDate.now(),
- stdoutTime: RealDate.now()
- };
- timers.set(id, timer);
- }
- let buffer = stderrBuffer.get(id);
- if (!buffer) {
- buffer = [];
- stderrBuffer.set(id, buffer);
- }
- if (state().config.printConsoleTrace) {
- const limit = Error.stackTraceLimit;
- Error.stackTraceLimit = limit + 6;
- const stack = (/* @__PURE__ */ new Error("STACK_TRACE")).stack?.split("\n");
- Error.stackTraceLimit = limit;
- if (stack?.some((line) => line.includes("at Console.trace"))) buffer.push([data, void 0]);
- else {
- const trace = stack?.slice(7).join("\n");
- Error.stackTraceLimit = limit;
- buffer.push([data, trace]);
- }
- } else buffer.push([data, void 0]);
- schedule(id);
- callback();
- } }),
- colorMode: c.isColorSupported,
- groupIndentation: 2
- });
-}
-
-export { UNKNOWN_TEST_ID, createCustomConsole };
diff --git a/vanilla/node_modules/vitest/dist/chunks/constants.D_Q9UYh-.js b/vanilla/node_modules/vitest/dist/chunks/constants.D_Q9UYh-.js
deleted file mode 100644
index 6447c76..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/constants.D_Q9UYh-.js
+++ /dev/null
@@ -1,36 +0,0 @@
-// if changed, update also jsdocs and docs
-const defaultPort = 51204;
-const defaultBrowserPort = 63315;
-const defaultInspectPort = 9229;
-const API_PATH = "/__vitest_api__";
-const CONFIG_NAMES = ["vitest.config", "vite.config"];
-const CONFIG_EXTENSIONS = [
- ".ts",
- ".mts",
- ".cts",
- ".js",
- ".mjs",
- ".cjs"
-];
-const configFiles = CONFIG_NAMES.flatMap((name) => CONFIG_EXTENSIONS.map((ext) => name + ext));
-const globalApis = [
- "suite",
- "test",
- "describe",
- "it",
- "chai",
- "expect",
- "assert",
- "expectTypeOf",
- "assertType",
- "vitest",
- "vi",
- "beforeAll",
- "afterAll",
- "beforeEach",
- "afterEach",
- "onTestFinished",
- "onTestFailed"
-];
-
-export { API_PATH as A, defaultPort as a, defaultInspectPort as b, configFiles as c, defaultBrowserPort as d, globalApis as g };
diff --git a/vanilla/node_modules/vitest/dist/chunks/coverage.AVPTjMgw.js b/vanilla/node_modules/vitest/dist/chunks/coverage.AVPTjMgw.js
deleted file mode 100644
index 9226d79..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/coverage.AVPTjMgw.js
+++ /dev/null
@@ -1,3292 +0,0 @@
-import fs, { statSync, realpathSync, existsSync, promises, readdirSync, writeFileSync } from 'node:fs';
-import path, { win32, dirname, join } from 'node:path';
-import { slash, shuffle, toArray } from '@vitest/utils/helpers';
-import { isAbsolute, resolve, relative, normalize } from 'pathe';
-import pm from 'picomatch';
-import { glob } from 'tinyglobby';
-import c from 'tinyrainbow';
-import { c as configDefaults, e as benchmarkConfigDefaults, a as coverageConfigDefaults } from './defaults.BOqNVLsY.js';
-import crypto from 'node:crypto';
-import { fileURLToPath as fileURLToPath$1, pathToFileURL as pathToFileURL$1, URL as URL$1 } from 'node:url';
-import { builtinModules, createRequire } from 'node:module';
-import process$1 from 'node:process';
-import fs$1 from 'node:fs/promises';
-import assert from 'node:assert';
-import v8 from 'node:v8';
-import { format, inspect } from 'node:util';
-import { mergeConfig } from 'vite';
-import { c as configFiles, d as defaultBrowserPort, b as defaultInspectPort, a as defaultPort } from './constants.D_Q9UYh-.js';
-import './env.D4Lgay0q.js';
-import nodeos__default from 'node:os';
-import { isCI, provider } from 'std-env';
-import { r as resolveCoverageProviderModule } from './coverage.D_JHT54q.js';
-
-const hash = crypto.hash ?? ((algorithm, data, outputEncoding) => crypto.createHash(algorithm).update(data).digest(outputEncoding));
-
-const JOIN_LEADING_SLASH_RE = /^\.?\//;
-function withTrailingSlash(input = "", respectQueryAndFragment) {
- {
- return input.endsWith("/") ? input : input + "/";
- }
-}
-function isNonEmptyURL(url) {
- return url && url !== "/";
-}
-function joinURL(base, ...input) {
- let url = base || "";
- for (const segment of input.filter((url2) => isNonEmptyURL(url2))) {
- if (url) {
- const _segment = segment.replace(JOIN_LEADING_SLASH_RE, "");
- url = withTrailingSlash(url) + _segment;
- } else {
- url = segment;
- }
- }
- return url;
-}
-
-const BUILTIN_MODULES = new Set(builtinModules);
-function normalizeSlash(path) {
- return path.replace(/\\/g, "/");
-}
-
-/**
- * @typedef ErrnoExceptionFields
- * @property {number | undefined} [errnode]
- * @property {string | undefined} [code]
- * @property {string | undefined} [path]
- * @property {string | undefined} [syscall]
- * @property {string | undefined} [url]
- *
- * @typedef {Error & ErrnoExceptionFields} ErrnoException
- */
-
-
-const own$1 = {}.hasOwnProperty;
-
-const classRegExp = /^([A-Z][a-z\d]*)+$/;
-// Sorted by a rough estimate on most frequently used entries.
-const kTypes = new Set([
- 'string',
- 'function',
- 'number',
- 'object',
- // Accept 'Function' and 'Object' as alternative to the lower cased version.
- 'Function',
- 'Object',
- 'boolean',
- 'bigint',
- 'symbol'
-]);
-
-const codes = {};
-
-/**
- * Create a list string in the form like 'A and B' or 'A, B, ..., and Z'.
- * We cannot use Intl.ListFormat because it's not available in
- * --without-intl builds.
- *
- * @param {Array<string>} array
- * An array of strings.
- * @param {string} [type]
- * The list type to be inserted before the last element.
- * @returns {string}
- */
-function formatList(array, type = 'and') {
- return array.length < 3
- ? array.join(` ${type} `)
- : `${array.slice(0, -1).join(', ')}, ${type} ${array[array.length - 1]}`
-}
-
-/** @type {Map<string, MessageFunction | string>} */
-const messages = new Map();
-const nodeInternalPrefix = '__node_internal_';
-/** @type {number} */
-let userStackTraceLimit;
-
-codes.ERR_INVALID_ARG_TYPE = createError(
- 'ERR_INVALID_ARG_TYPE',
- /**
- * @param {string} name
- * @param {Array<string> | string} expected
- * @param {unknown} actual
- */
- (name, expected, actual) => {
- assert(typeof name === 'string', "'name' must be a string");
- if (!Array.isArray(expected)) {
- expected = [expected];
- }
-
- let message = 'The ';
- if (name.endsWith(' argument')) {
- // For cases like 'first argument'
- message += `${name} `;
- } else {
- const type = name.includes('.') ? 'property' : 'argument';
- message += `"${name}" ${type} `;
- }
-
- message += 'must be ';
-
- /** @type {Array<string>} */
- const types = [];
- /** @type {Array<string>} */
- const instances = [];
- /** @type {Array<string>} */
- const other = [];
-
- for (const value of expected) {
- assert(
- typeof value === 'string',
- 'All expected entries have to be of type string'
- );
-
- if (kTypes.has(value)) {
- types.push(value.toLowerCase());
- } else if (classRegExp.exec(value) === null) {
- assert(
- value !== 'object',
- 'The value "object" should be written as "Object"'
- );
- other.push(value);
- } else {
- instances.push(value);
- }
- }
-
- // Special handle `object` in case other instances are allowed to outline
- // the differences between each other.
- if (instances.length > 0) {
- const pos = types.indexOf('object');
- if (pos !== -1) {
- types.slice(pos, 1);
- instances.push('Object');
- }
- }
-
- if (types.length > 0) {
- message += `${types.length > 1 ? 'one of type' : 'of type'} ${formatList(
- types,
- 'or'
- )}`;
- if (instances.length > 0 || other.length > 0) message += ' or ';
- }
-
- if (instances.length > 0) {
- message += `an instance of ${formatList(instances, 'or')}`;
- if (other.length > 0) message += ' or ';
- }
-
- if (other.length > 0) {
- if (other.length > 1) {
- message += `one of ${formatList(other, 'or')}`;
- } else {
- if (other[0].toLowerCase() !== other[0]) message += 'an ';
- message += `${other[0]}`;
- }
- }
-
- message += `. Received ${determineSpecificType(actual)}`;
-
- return message
- },
- TypeError
-);
-
-codes.ERR_INVALID_MODULE_SPECIFIER = createError(
- 'ERR_INVALID_MODULE_SPECIFIER',
- /**
- * @param {string} request
- * @param {string} reason
- * @param {string} [base]
- */
- (request, reason, base = undefined) => {
- return `Invalid module "${request}" ${reason}${
- base ? ` imported from ${base}` : ''
- }`
- },
- TypeError
-);
-
-codes.ERR_INVALID_PACKAGE_CONFIG = createError(
- 'ERR_INVALID_PACKAGE_CONFIG',
- /**
- * @param {string} path
- * @param {string} [base]
- * @param {string} [message]
- */
- (path, base, message) => {
- return `Invalid package config ${path}${
- base ? ` while importing ${base}` : ''
- }${message ? `. ${message}` : ''}`
- },
- Error
-);
-
-codes.ERR_INVALID_PACKAGE_TARGET = createError(
- 'ERR_INVALID_PACKAGE_TARGET',
- /**
- * @param {string} packagePath
- * @param {string} key
- * @param {unknown} target
- * @param {boolean} [isImport=false]
- * @param {string} [base]
- */
- (packagePath, key, target, isImport = false, base = undefined) => {
- const relatedError =
- typeof target === 'string' &&
- !isImport &&
- target.length > 0 &&
- !target.startsWith('./');
- if (key === '.') {
- assert(isImport === false);
- return (
- `Invalid "exports" main target ${JSON.stringify(target)} defined ` +
- `in the package config ${packagePath}package.json${
- base ? ` imported from ${base}` : ''
- }${relatedError ? '; targets must start with "./"' : ''}`
- )
- }
-
- return `Invalid "${
- isImport ? 'imports' : 'exports'
- }" target ${JSON.stringify(
- target
- )} defined for '${key}' in the package config ${packagePath}package.json${
- base ? ` imported from ${base}` : ''
- }${relatedError ? '; targets must start with "./"' : ''}`
- },
- Error
-);
-
-codes.ERR_MODULE_NOT_FOUND = createError(
- 'ERR_MODULE_NOT_FOUND',
- /**
- * @param {string} path
- * @param {string} base
- * @param {boolean} [exactUrl]
- */
- (path, base, exactUrl = false) => {
- return `Cannot find ${
- exactUrl ? 'module' : 'package'
- } '${path}' imported from ${base}`
- },
- Error
-);
-
-codes.ERR_NETWORK_IMPORT_DISALLOWED = createError(
- 'ERR_NETWORK_IMPORT_DISALLOWED',
- "import of '%s' by %s is not supported: %s",
- Error
-);
-
-codes.ERR_PACKAGE_IMPORT_NOT_DEFINED = createError(
- 'ERR_PACKAGE_IMPORT_NOT_DEFINED',
- /**
- * @param {string} specifier
- * @param {string} packagePath
- * @param {string} base
- */
- (specifier, packagePath, base) => {
- return `Package import specifier "${specifier}" is not defined${
- packagePath ? ` in package ${packagePath}package.json` : ''
- } imported from ${base}`
- },
- TypeError
-);
-
-codes.ERR_PACKAGE_PATH_NOT_EXPORTED = createError(
- 'ERR_PACKAGE_PATH_NOT_EXPORTED',
- /**
- * @param {string} packagePath
- * @param {string} subpath
- * @param {string} [base]
- */
- (packagePath, subpath, base = undefined) => {
- if (subpath === '.')
- return `No "exports" main defined in ${packagePath}package.json${
- base ? ` imported from ${base}` : ''
- }`
- return `Package subpath '${subpath}' is not defined by "exports" in ${packagePath}package.json${
- base ? ` imported from ${base}` : ''
- }`
- },
- Error
-);
-
-codes.ERR_UNSUPPORTED_DIR_IMPORT = createError(
- 'ERR_UNSUPPORTED_DIR_IMPORT',
- "Directory import '%s' is not supported " +
- 'resolving ES modules imported from %s',
- Error
-);
-
-codes.ERR_UNSUPPORTED_RESOLVE_REQUEST = createError(
- 'ERR_UNSUPPORTED_RESOLVE_REQUEST',
- 'Failed to resolve module specifier "%s" from "%s": Invalid relative URL or base scheme is not hierarchical.',
- TypeError
-);
-
-codes.ERR_UNKNOWN_FILE_EXTENSION = createError(
- 'ERR_UNKNOWN_FILE_EXTENSION',
- /**
- * @param {string} extension
- * @param {string} path
- */
- (extension, path) => {
- return `Unknown file extension "${extension}" for ${path}`
- },
- TypeError
-);
-
-codes.ERR_INVALID_ARG_VALUE = createError(
- 'ERR_INVALID_ARG_VALUE',
- /**
- * @param {string} name
- * @param {unknown} value
- * @param {string} [reason='is invalid']
- */
- (name, value, reason = 'is invalid') => {
- let inspected = inspect(value);
-
- if (inspected.length > 128) {
- inspected = `${inspected.slice(0, 128)}...`;
- }
-
- const type = name.includes('.') ? 'property' : 'argument';
-
- return `The ${type} '${name}' ${reason}. Received ${inspected}`
- },
- TypeError
- // Note: extra classes have been shaken out.
- // , RangeError
-);
-
-/**
- * Utility function for registering the error codes. Only used here. Exported
- * *only* to allow for testing.
- * @param {string} sym
- * @param {MessageFunction | string} value
- * @param {ErrorConstructor} constructor
- * @returns {new (...parameters: Array<any>) => Error}
- */
-function createError(sym, value, constructor) {
- // Special case for SystemError that formats the error message differently
- // The SystemErrors only have SystemError as their base classes.
- messages.set(sym, value);
-
- return makeNodeErrorWithCode(constructor, sym)
-}
-
-/**
- * @param {ErrorConstructor} Base
- * @param {string} key
- * @returns {ErrorConstructor}
- */
-function makeNodeErrorWithCode(Base, key) {
- // @ts-expect-error It’s a Node error.
- return NodeError
- /**
- * @param {Array<unknown>} parameters
- */
- function NodeError(...parameters) {
- const limit = Error.stackTraceLimit;
- if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0;
- const error = new Base();
- // Reset the limit and setting the name property.
- if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = limit;
- const message = getMessage(key, parameters, error);
- Object.defineProperties(error, {
- // Note: no need to implement `kIsNodeError` symbol, would be hard,
- // probably.
- message: {
- value: message,
- enumerable: false,
- writable: true,
- configurable: true
- },
- toString: {
- /** @this {Error} */
- value() {
- return `${this.name} [${key}]: ${this.message}`
- },
- enumerable: false,
- writable: true,
- configurable: true
- }
- });
-
- captureLargerStackTrace(error);
- // @ts-expect-error It’s a Node error.
- error.code = key;
- return error
- }
-}
-
-/**
- * @returns {boolean}
- */
-function isErrorStackTraceLimitWritable() {
- // Do no touch Error.stackTraceLimit as V8 would attempt to install
- // it again during deserialization.
- try {
- if (v8.startupSnapshot.isBuildingSnapshot()) {
- return false
- }
- } catch {}
-
- const desc = Object.getOwnPropertyDescriptor(Error, 'stackTraceLimit');
- if (desc === undefined) {
- return Object.isExtensible(Error)
- }
-
- return own$1.call(desc, 'writable') && desc.writable !== undefined
- ? desc.writable
- : desc.set !== undefined
-}
-
-/**
- * This function removes unnecessary frames from Node.js core errors.
- * @template {(...parameters: unknown[]) => unknown} T
- * @param {T} wrappedFunction
- * @returns {T}
- */
-function hideStackFrames(wrappedFunction) {
- // We rename the functions that will be hidden to cut off the stacktrace
- // at the outermost one
- const hidden = nodeInternalPrefix + wrappedFunction.name;
- Object.defineProperty(wrappedFunction, 'name', {value: hidden});
- return wrappedFunction
-}
-
-const captureLargerStackTrace = hideStackFrames(
- /**
- * @param {Error} error
- * @returns {Error}
- */
- // @ts-expect-error: fine
- function (error) {
- const stackTraceLimitIsWritable = isErrorStackTraceLimitWritable();
- if (stackTraceLimitIsWritable) {
- userStackTraceLimit = Error.stackTraceLimit;
- Error.stackTraceLimit = Number.POSITIVE_INFINITY;
- }
-
- Error.captureStackTrace(error);
-
- // Reset the limit
- if (stackTraceLimitIsWritable) Error.stackTraceLimit = userStackTraceLimit;
-
- return error
- }
-);
-
-/**
- * @param {string} key
- * @param {Array<unknown>} parameters
- * @param {Error} self
- * @returns {string}
- */
-function getMessage(key, parameters, self) {
- const message = messages.get(key);
- assert(message !== undefined, 'expected `message` to be found');
-
- if (typeof message === 'function') {
- assert(
- message.length <= parameters.length, // Default options do not count.
- `Code: ${key}; The provided arguments length (${parameters.length}) does not ` +
- `match the required ones (${message.length}).`
- );
- return Reflect.apply(message, self, parameters)
- }
-
- const regex = /%[dfijoOs]/g;
- let expectedLength = 0;
- while (regex.exec(message) !== null) expectedLength++;
- assert(
- expectedLength === parameters.length,
- `Code: ${key}; The provided arguments length (${parameters.length}) does not ` +
- `match the required ones (${expectedLength}).`
- );
- if (parameters.length === 0) return message
-
- parameters.unshift(message);
- return Reflect.apply(format, null, parameters)
-}
-
-/**
- * Determine the specific type of a value for type-mismatch errors.
- * @param {unknown} value
- * @returns {string}
- */
-function determineSpecificType(value) {
- if (value === null || value === undefined) {
- return String(value)
- }
-
- if (typeof value === 'function' && value.name) {
- return `function ${value.name}`
- }
-
- if (typeof value === 'object') {
- if (value.constructor && value.constructor.name) {
- return `an instance of ${value.constructor.name}`
- }
-
- return `${inspect(value, {depth: -1})}`
- }
-
- let inspected = inspect(value, {colors: false});
-
- if (inspected.length > 28) {
- inspected = `${inspected.slice(0, 25)}...`;
- }
-
- return `type ${typeof value} (${inspected})`
-}
-
-// Manually “tree shaken” from:
-// <https://github.com/nodejs/node/blob/7c3dce0/lib/internal/modules/package_json_reader.js>
-// Last checked on: Apr 29, 2023.
-// Removed the native dependency.
-// Also: no need to cache, we do that in resolve already.
-
-
-const hasOwnProperty$1 = {}.hasOwnProperty;
-
-const {ERR_INVALID_PACKAGE_CONFIG: ERR_INVALID_PACKAGE_CONFIG$1} = codes;
-
-/** @type {Map<string, PackageConfig>} */
-const cache = new Map();
-
-/**
- * @param {string} jsonPath
- * @param {{specifier: URL | string, base?: URL}} options
- * @returns {PackageConfig}
- */
-function read(jsonPath, {base, specifier}) {
- const existing = cache.get(jsonPath);
-
- if (existing) {
- return existing
- }
-
- /** @type {string | undefined} */
- let string;
-
- try {
- string = fs.readFileSync(path.toNamespacedPath(jsonPath), 'utf8');
- } catch (error) {
- const exception = /** @type {ErrnoException} */ (error);
-
- if (exception.code !== 'ENOENT') {
- throw exception
- }
- }
-
- /** @type {PackageConfig} */
- const result = {
- exists: false,
- pjsonPath: jsonPath,
- main: undefined,
- name: undefined,
- type: 'none', // Ignore unknown types for forwards compatibility
- exports: undefined,
- imports: undefined
- };
-
- if (string !== undefined) {
- /** @type {Record<string, unknown>} */
- let parsed;
-
- try {
- parsed = JSON.parse(string);
- } catch (error_) {
- const cause = /** @type {ErrnoException} */ (error_);
- const error = new ERR_INVALID_PACKAGE_CONFIG$1(
- jsonPath,
- (base ? `"${specifier}" from ` : '') + fileURLToPath$1(base || specifier),
- cause.message
- );
- error.cause = cause;
- throw error
- }
-
- result.exists = true;
-
- if (
- hasOwnProperty$1.call(parsed, 'name') &&
- typeof parsed.name === 'string'
- ) {
- result.name = parsed.name;
- }
-
- if (
- hasOwnProperty$1.call(parsed, 'main') &&
- typeof parsed.main === 'string'
- ) {
- result.main = parsed.main;
- }
-
- if (hasOwnProperty$1.call(parsed, 'exports')) {
- // @ts-expect-error: assume valid.
- result.exports = parsed.exports;
- }
-
- if (hasOwnProperty$1.call(parsed, 'imports')) {
- // @ts-expect-error: assume valid.
- result.imports = parsed.imports;
- }
-
- // Ignore unknown types for forwards compatibility
- if (
- hasOwnProperty$1.call(parsed, 'type') &&
- (parsed.type === 'commonjs' || parsed.type === 'module')
- ) {
- result.type = parsed.type;
- }
- }
-
- cache.set(jsonPath, result);
-
- return result
-}
-
-/**
- * @param {URL | string} resolved
- * @returns {PackageConfig}
- */
-function getPackageScopeConfig(resolved) {
- // Note: in Node, this is now a native module.
- let packageJSONUrl = new URL('package.json', resolved);
-
- while (true) {
- const packageJSONPath = packageJSONUrl.pathname;
- if (packageJSONPath.endsWith('node_modules/package.json')) {
- break
- }
-
- const packageConfig = read(fileURLToPath$1(packageJSONUrl), {
- specifier: resolved
- });
-
- if (packageConfig.exists) {
- return packageConfig
- }
-
- const lastPackageJSONUrl = packageJSONUrl;
- packageJSONUrl = new URL('../package.json', packageJSONUrl);
-
- // Terminates at root where ../package.json equals ../../package.json
- // (can't just check "/package.json" for Windows support).
- if (packageJSONUrl.pathname === lastPackageJSONUrl.pathname) {
- break
- }
- }
-
- const packageJSONPath = fileURLToPath$1(packageJSONUrl);
- // ^^ Note: in Node, this is now a native module.
-
- return {
- pjsonPath: packageJSONPath,
- exists: false,
- type: 'none'
- }
-}
-
-/**
- * Returns the package type for a given URL.
- * @param {URL} url - The URL to get the package type for.
- * @returns {PackageType}
- */
-function getPackageType(url) {
- // To do @anonrig: Write a C++ function that returns only "type".
- return getPackageScopeConfig(url).type
-}
-
-// Manually “tree shaken” from:
-// <https://github.com/nodejs/node/blob/7c3dce0/lib/internal/modules/esm/get_format.js>
-// Last checked on: Apr 29, 2023.
-
-
-const {ERR_UNKNOWN_FILE_EXTENSION} = codes;
-
-const hasOwnProperty = {}.hasOwnProperty;
-
-/** @type {Record<string, string>} */
-const extensionFormatMap = {
- // @ts-expect-error: hush.
- __proto__: null,
- '.cjs': 'commonjs',
- '.js': 'module',
- '.json': 'json',
- '.mjs': 'module'
-};
-
-/**
- * @param {string | null} mime
- * @returns {string | null}
- */
-function mimeToFormat(mime) {
- if (
- mime &&
- /\s*(text|application)\/javascript\s*(;\s*charset=utf-?8\s*)?/i.test(mime)
- )
- return 'module'
- if (mime === 'application/json') return 'json'
- return null
-}
-
-/**
- * @callback ProtocolHandler
- * @param {URL} parsed
- * @param {{parentURL: string, source?: Buffer}} context
- * @param {boolean} ignoreErrors
- * @returns {string | null | void}
- */
-
-/**
- * @type {Record<string, ProtocolHandler>}
- */
-const protocolHandlers = {
- // @ts-expect-error: hush.
- __proto__: null,
- 'data:': getDataProtocolModuleFormat,
- 'file:': getFileProtocolModuleFormat,
- 'http:': getHttpProtocolModuleFormat,
- 'https:': getHttpProtocolModuleFormat,
- 'node:'() {
- return 'builtin'
- }
-};
-
-/**
- * @param {URL} parsed
- */
-function getDataProtocolModuleFormat(parsed) {
- const {1: mime} = /^([^/]+\/[^;,]+)[^,]*?(;base64)?,/.exec(
- parsed.pathname
- ) || [null, null, null];
- return mimeToFormat(mime)
-}
-
-/**
- * Returns the file extension from a URL.
- *
- * Should give similar result to
- * `require('node:path').extname(require('node:url').fileURLToPath(url))`
- * when used with a `file:` URL.
- *
- * @param {URL} url
- * @returns {string}
- */
-function extname(url) {
- const pathname = url.pathname;
- let index = pathname.length;
-
- while (index--) {
- const code = pathname.codePointAt(index);
-
- if (code === 47 /* `/` */) {
- return ''
- }
-
- if (code === 46 /* `.` */) {
- return pathname.codePointAt(index - 1) === 47 /* `/` */
- ? ''
- : pathname.slice(index)
- }
- }
-
- return ''
-}
-
-/**
- * @type {ProtocolHandler}
- */
-function getFileProtocolModuleFormat(url, _context, ignoreErrors) {
- const value = extname(url);
-
- if (value === '.js') {
- const packageType = getPackageType(url);
-
- if (packageType !== 'none') {
- return packageType
- }
-
- return 'commonjs'
- }
-
- if (value === '') {
- const packageType = getPackageType(url);
-
- // Legacy behavior
- if (packageType === 'none' || packageType === 'commonjs') {
- return 'commonjs'
- }
-
- // Note: we don’t implement WASM, so we don’t need
- // `getFormatOfExtensionlessFile` from `formats`.
- return 'module'
- }
-
- const format = extensionFormatMap[value];
- if (format) return format
-
- // Explicit undefined return indicates load hook should rerun format check
- if (ignoreErrors) {
- return undefined
- }
-
- const filepath = fileURLToPath$1(url);
- throw new ERR_UNKNOWN_FILE_EXTENSION(value, filepath)
-}
-
-function getHttpProtocolModuleFormat() {
- // To do: HTTPS imports.
-}
-
-/**
- * @param {URL} url
- * @param {{parentURL: string}} context
- * @returns {string | null}
- */
-function defaultGetFormatWithoutErrors(url, context) {
- const protocol = url.protocol;
-
- if (!hasOwnProperty.call(protocolHandlers, protocol)) {
- return null
- }
-
- return protocolHandlers[protocol](url, context, true) || null
-}
-
-// Manually “tree shaken” from:
-// <https://github.com/nodejs/node/blob/81a9a97/lib/internal/modules/esm/resolve.js>
-// Last checked on: Apr 29, 2023.
-
-
-const RegExpPrototypeSymbolReplace = RegExp.prototype[Symbol.replace];
-
-const {
- ERR_INVALID_MODULE_SPECIFIER,
- ERR_INVALID_PACKAGE_CONFIG,
- ERR_INVALID_PACKAGE_TARGET,
- ERR_MODULE_NOT_FOUND,
- ERR_PACKAGE_IMPORT_NOT_DEFINED,
- ERR_PACKAGE_PATH_NOT_EXPORTED,
- ERR_UNSUPPORTED_DIR_IMPORT,
- ERR_UNSUPPORTED_RESOLVE_REQUEST
-} = codes;
-
-const own = {}.hasOwnProperty;
-
-const invalidSegmentRegEx =
- /(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))?(\\|\/|$)/i;
-const deprecatedInvalidSegmentRegEx =
- /(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))(\\|\/|$)/i;
-const invalidPackageNameRegEx = /^\.|%|\\/;
-const patternRegEx = /\*/g;
-const encodedSeparatorRegEx = /%2f|%5c/i;
-/** @type {Set<string>} */
-const emittedPackageWarnings = new Set();
-
-const doubleSlashRegEx = /[/\\]{2}/;
-
-/**
- *
- * @param {string} target
- * @param {string} request
- * @param {string} match
- * @param {URL} packageJsonUrl
- * @param {boolean} internal
- * @param {URL} base
- * @param {boolean} isTarget
- */
-function emitInvalidSegmentDeprecation(
- target,
- request,
- match,
- packageJsonUrl,
- internal,
- base,
- isTarget
-) {
- // @ts-expect-error: apparently it does exist, TS.
- if (process$1.noDeprecation) {
- return
- }
-
- const pjsonPath = fileURLToPath$1(packageJsonUrl);
- const double = doubleSlashRegEx.exec(isTarget ? target : request) !== null;
- process$1.emitWarning(
- `Use of deprecated ${
- double ? 'double slash' : 'leading or trailing slash matching'
- } resolving "${target}" for module ` +
- `request "${request}" ${
- request === match ? '' : `matched to "${match}" `
- }in the "${
- internal ? 'imports' : 'exports'
- }" field module resolution of the package at ${pjsonPath}${
- base ? ` imported from ${fileURLToPath$1(base)}` : ''
- }.`,
- 'DeprecationWarning',
- 'DEP0166'
- );
-}
-
-/**
- * @param {URL} url
- * @param {URL} packageJsonUrl
- * @param {URL} base
- * @param {string} [main]
- * @returns {void}
- */
-function emitLegacyIndexDeprecation(url, packageJsonUrl, base, main) {
- // @ts-expect-error: apparently it does exist, TS.
- if (process$1.noDeprecation) {
- return
- }
-
- const format = defaultGetFormatWithoutErrors(url, {parentURL: base.href});
- if (format !== 'module') return
- const urlPath = fileURLToPath$1(url.href);
- const packagePath = fileURLToPath$1(new URL$1('.', packageJsonUrl));
- const basePath = fileURLToPath$1(base);
- if (!main) {
- process$1.emitWarning(
- `No "main" or "exports" field defined in the package.json for ${packagePath} resolving the main entry point "${urlPath.slice(
- packagePath.length
- )}", imported from ${basePath}.\nDefault "index" lookups for the main are deprecated for ES modules.`,
- 'DeprecationWarning',
- 'DEP0151'
- );
- } else if (path.resolve(packagePath, main) !== urlPath) {
- process$1.emitWarning(
- `Package ${packagePath} has a "main" field set to "${main}", ` +
- `excluding the full filename and extension to the resolved file at "${urlPath.slice(
- packagePath.length
- )}", imported from ${basePath}.\n Automatic extension resolution of the "main" field is ` +
- 'deprecated for ES modules.',
- 'DeprecationWarning',
- 'DEP0151'
- );
- }
-}
-
-/**
- * @param {string} path
- * @returns {Stats | undefined}
- */
-function tryStatSync(path) {
- // Note: from Node 15 onwards we can use `throwIfNoEntry: false` instead.
- try {
- return statSync(path)
- } catch {
- // Note: in Node code this returns `new Stats`,
- // but in Node 22 that’s marked as a deprecated internal API.
- // Which, well, we kinda are, but still to prevent that warning,
- // just yield `undefined`.
- }
-}
-
-/**
- * Legacy CommonJS main resolution:
- * 1. let M = pkg_url + (json main field)
- * 2. TRY(M, M.js, M.json, M.node)
- * 3. TRY(M/index.js, M/index.json, M/index.node)
- * 4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node)
- * 5. NOT_FOUND
- *
- * @param {URL} url
- * @returns {boolean}
- */
-function fileExists(url) {
- const stats = statSync(url, {throwIfNoEntry: false});
- const isFile = stats ? stats.isFile() : undefined;
- return isFile === null || isFile === undefined ? false : isFile
-}
-
-/**
- * @param {URL} packageJsonUrl
- * @param {PackageConfig} packageConfig
- * @param {URL} base
- * @returns {URL}
- */
-function legacyMainResolve(packageJsonUrl, packageConfig, base) {
- /** @type {URL | undefined} */
- let guess;
- if (packageConfig.main !== undefined) {
- guess = new URL$1(packageConfig.main, packageJsonUrl);
- // Note: fs check redundances will be handled by Descriptor cache here.
- if (fileExists(guess)) return guess
-
- const tries = [
- `./${packageConfig.main}.js`,
- `./${packageConfig.main}.json`,
- `./${packageConfig.main}.node`,
- `./${packageConfig.main}/index.js`,
- `./${packageConfig.main}/index.json`,
- `./${packageConfig.main}/index.node`
- ];
- let i = -1;
-
- while (++i < tries.length) {
- guess = new URL$1(tries[i], packageJsonUrl);
- if (fileExists(guess)) break
- guess = undefined;
- }
-
- if (guess) {
- emitLegacyIndexDeprecation(
- guess,
- packageJsonUrl,
- base,
- packageConfig.main
- );
- return guess
- }
- // Fallthrough.
- }
-
- const tries = ['./index.js', './index.json', './index.node'];
- let i = -1;
-
- while (++i < tries.length) {
- guess = new URL$1(tries[i], packageJsonUrl);
- if (fileExists(guess)) break
- guess = undefined;
- }
-
- if (guess) {
- emitLegacyIndexDeprecation(guess, packageJsonUrl, base, packageConfig.main);
- return guess
- }
-
- // Not found.
- throw new ERR_MODULE_NOT_FOUND(
- fileURLToPath$1(new URL$1('.', packageJsonUrl)),
- fileURLToPath$1(base)
- )
-}
-
-/**
- * @param {URL} resolved
- * @param {URL} base
- * @param {boolean} [preserveSymlinks]
- * @returns {URL}
- */
-function finalizeResolution(resolved, base, preserveSymlinks) {
- if (encodedSeparatorRegEx.exec(resolved.pathname) !== null) {
- throw new ERR_INVALID_MODULE_SPECIFIER(
- resolved.pathname,
- 'must not include encoded "/" or "\\" characters',
- fileURLToPath$1(base)
- )
- }
-
- /** @type {string} */
- let filePath;
-
- try {
- filePath = fileURLToPath$1(resolved);
- } catch (error) {
- const cause = /** @type {ErrnoException} */ (error);
- Object.defineProperty(cause, 'input', {value: String(resolved)});
- Object.defineProperty(cause, 'module', {value: String(base)});
- throw cause
- }
-
- const stats = tryStatSync(
- filePath.endsWith('/') ? filePath.slice(-1) : filePath
- );
-
- if (stats && stats.isDirectory()) {
- const error = new ERR_UNSUPPORTED_DIR_IMPORT(filePath, fileURLToPath$1(base));
- // @ts-expect-error Add this for `import.meta.resolve`.
- error.url = String(resolved);
- throw error
- }
-
- if (!stats || !stats.isFile()) {
- const error = new ERR_MODULE_NOT_FOUND(
- filePath || resolved.pathname,
- base && fileURLToPath$1(base),
- true
- );
- // @ts-expect-error Add this for `import.meta.resolve`.
- error.url = String(resolved);
- throw error
- }
-
- {
- const real = realpathSync(filePath);
- const {search, hash} = resolved;
- resolved = pathToFileURL$1(real + (filePath.endsWith(path.sep) ? '/' : ''));
- resolved.search = search;
- resolved.hash = hash;
- }
-
- return resolved
-}
-
-/**
- * @param {string} specifier
- * @param {URL | undefined} packageJsonUrl
- * @param {URL} base
- * @returns {Error}
- */
-function importNotDefined(specifier, packageJsonUrl, base) {
- return new ERR_PACKAGE_IMPORT_NOT_DEFINED(
- specifier,
- packageJsonUrl && fileURLToPath$1(new URL$1('.', packageJsonUrl)),
- fileURLToPath$1(base)
- )
-}
-
-/**
- * @param {string} subpath
- * @param {URL} packageJsonUrl
- * @param {URL} base
- * @returns {Error}
- */
-function exportsNotFound(subpath, packageJsonUrl, base) {
- return new ERR_PACKAGE_PATH_NOT_EXPORTED(
- fileURLToPath$1(new URL$1('.', packageJsonUrl)),
- subpath,
- base && fileURLToPath$1(base)
- )
-}
-
-/**
- * @param {string} request
- * @param {string} match
- * @param {URL} packageJsonUrl
- * @param {boolean} internal
- * @param {URL} [base]
- * @returns {never}
- */
-function throwInvalidSubpath(request, match, packageJsonUrl, internal, base) {
- const reason = `request is not a valid match in pattern "${match}" for the "${
- internal ? 'imports' : 'exports'
- }" resolution of ${fileURLToPath$1(packageJsonUrl)}`;
- throw new ERR_INVALID_MODULE_SPECIFIER(
- request,
- reason,
- base && fileURLToPath$1(base)
- )
-}
-
-/**
- * @param {string} subpath
- * @param {unknown} target
- * @param {URL} packageJsonUrl
- * @param {boolean} internal
- * @param {URL} [base]
- * @returns {Error}
- */
-function invalidPackageTarget(subpath, target, packageJsonUrl, internal, base) {
- target =
- typeof target === 'object' && target !== null
- ? JSON.stringify(target, null, '')
- : `${target}`;
-
- return new ERR_INVALID_PACKAGE_TARGET(
- fileURLToPath$1(new URL$1('.', packageJsonUrl)),
- subpath,
- target,
- internal,
- base && fileURLToPath$1(base)
- )
-}
-
-/**
- * @param {string} target
- * @param {string} subpath
- * @param {string} match
- * @param {URL} packageJsonUrl
- * @param {URL} base
- * @param {boolean} pattern
- * @param {boolean} internal
- * @param {boolean} isPathMap
- * @param {Set<string> | undefined} conditions
- * @returns {URL}
- */
-function resolvePackageTargetString(
- target,
- subpath,
- match,
- packageJsonUrl,
- base,
- pattern,
- internal,
- isPathMap,
- conditions
-) {
- if (subpath !== '' && !pattern && target[target.length - 1] !== '/')
- throw invalidPackageTarget(match, target, packageJsonUrl, internal, base)
-
- if (!target.startsWith('./')) {
- if (internal && !target.startsWith('../') && !target.startsWith('/')) {
- let isURL = false;
-
- try {
- new URL$1(target);
- isURL = true;
- } catch {
- // Continue regardless of error.
- }
-
- if (!isURL) {
- const exportTarget = pattern
- ? RegExpPrototypeSymbolReplace.call(
- patternRegEx,
- target,
- () => subpath
- )
- : target + subpath;
-
- return packageResolve(exportTarget, packageJsonUrl, conditions)
- }
- }
-
- throw invalidPackageTarget(match, target, packageJsonUrl, internal, base)
- }
-
- if (invalidSegmentRegEx.exec(target.slice(2)) !== null) {
- if (deprecatedInvalidSegmentRegEx.exec(target.slice(2)) === null) {
- if (!isPathMap) {
- const request = pattern
- ? match.replace('*', () => subpath)
- : match + subpath;
- const resolvedTarget = pattern
- ? RegExpPrototypeSymbolReplace.call(
- patternRegEx,
- target,
- () => subpath
- )
- : target;
- emitInvalidSegmentDeprecation(
- resolvedTarget,
- request,
- match,
- packageJsonUrl,
- internal,
- base,
- true
- );
- }
- } else {
- throw invalidPackageTarget(match, target, packageJsonUrl, internal, base)
- }
- }
-
- const resolved = new URL$1(target, packageJsonUrl);
- const resolvedPath = resolved.pathname;
- const packagePath = new URL$1('.', packageJsonUrl).pathname;
-
- if (!resolvedPath.startsWith(packagePath))
- throw invalidPackageTarget(match, target, packageJsonUrl, internal, base)
-
- if (subpath === '') return resolved
-
- if (invalidSegmentRegEx.exec(subpath) !== null) {
- const request = pattern
- ? match.replace('*', () => subpath)
- : match + subpath;
- if (deprecatedInvalidSegmentRegEx.exec(subpath) === null) {
- if (!isPathMap) {
- const resolvedTarget = pattern
- ? RegExpPrototypeSymbolReplace.call(
- patternRegEx,
- target,
- () => subpath
- )
- : target;
- emitInvalidSegmentDeprecation(
- resolvedTarget,
- request,
- match,
- packageJsonUrl,
- internal,
- base,
- false
- );
- }
- } else {
- throwInvalidSubpath(request, match, packageJsonUrl, internal, base);
- }
- }
-
- if (pattern) {
- return new URL$1(
- RegExpPrototypeSymbolReplace.call(
- patternRegEx,
- resolved.href,
- () => subpath
- )
- )
- }
-
- return new URL$1(subpath, resolved)
-}
-
-/**
- * @param {string} key
- * @returns {boolean}
- */
-function isArrayIndex(key) {
- const keyNumber = Number(key);
- if (`${keyNumber}` !== key) return false
- return keyNumber >= 0 && keyNumber < 0xff_ff_ff_ff
-}
-
-/**
- * @param {URL} packageJsonUrl
- * @param {unknown} target
- * @param {string} subpath
- * @param {string} packageSubpath
- * @param {URL} base
- * @param {boolean} pattern
- * @param {boolean} internal
- * @param {boolean} isPathMap
- * @param {Set<string> | undefined} conditions
- * @returns {URL | null}
- */
-function resolvePackageTarget(
- packageJsonUrl,
- target,
- subpath,
- packageSubpath,
- base,
- pattern,
- internal,
- isPathMap,
- conditions
-) {
- if (typeof target === 'string') {
- return resolvePackageTargetString(
- target,
- subpath,
- packageSubpath,
- packageJsonUrl,
- base,
- pattern,
- internal,
- isPathMap,
- conditions
- )
- }
-
- if (Array.isArray(target)) {
- /** @type {Array<unknown>} */
- const targetList = target;
- if (targetList.length === 0) return null
-
- /** @type {ErrnoException | null | undefined} */
- let lastException;
- let i = -1;
-
- while (++i < targetList.length) {
- const targetItem = targetList[i];
- /** @type {URL | null} */
- let resolveResult;
- try {
- resolveResult = resolvePackageTarget(
- packageJsonUrl,
- targetItem,
- subpath,
- packageSubpath,
- base,
- pattern,
- internal,
- isPathMap,
- conditions
- );
- } catch (error) {
- const exception = /** @type {ErrnoException} */ (error);
- lastException = exception;
- if (exception.code === 'ERR_INVALID_PACKAGE_TARGET') continue
- throw error
- }
-
- if (resolveResult === undefined) continue
-
- if (resolveResult === null) {
- lastException = null;
- continue
- }
-
- return resolveResult
- }
-
- if (lastException === undefined || lastException === null) {
- return null
- }
-
- throw lastException
- }
-
- if (typeof target === 'object' && target !== null) {
- const keys = Object.getOwnPropertyNames(target);
- let i = -1;
-
- while (++i < keys.length) {
- const key = keys[i];
- if (isArrayIndex(key)) {
- throw new ERR_INVALID_PACKAGE_CONFIG(
- fileURLToPath$1(packageJsonUrl),
- base,
- '"exports" cannot contain numeric property keys.'
- )
- }
- }
-
- i = -1;
-
- while (++i < keys.length) {
- const key = keys[i];
- if (key === 'default' || (conditions && conditions.has(key))) {
- // @ts-expect-error: indexable.
- const conditionalTarget = /** @type {unknown} */ (target[key]);
- const resolveResult = resolvePackageTarget(
- packageJsonUrl,
- conditionalTarget,
- subpath,
- packageSubpath,
- base,
- pattern,
- internal,
- isPathMap,
- conditions
- );
- if (resolveResult === undefined) continue
- return resolveResult
- }
- }
-
- return null
- }
-
- if (target === null) {
- return null
- }
-
- throw invalidPackageTarget(
- packageSubpath,
- target,
- packageJsonUrl,
- internal,
- base
- )
-}
-
-/**
- * @param {unknown} exports
- * @param {URL} packageJsonUrl
- * @param {URL} base
- * @returns {boolean}
- */
-function isConditionalExportsMainSugar(exports$1, packageJsonUrl, base) {
- if (typeof exports$1 === 'string' || Array.isArray(exports$1)) return true
- if (typeof exports$1 !== 'object' || exports$1 === null) return false
-
- const keys = Object.getOwnPropertyNames(exports$1);
- let isConditionalSugar = false;
- let i = 0;
- let keyIndex = -1;
- while (++keyIndex < keys.length) {
- const key = keys[keyIndex];
- const currentIsConditionalSugar = key === '' || key[0] !== '.';
- if (i++ === 0) {
- isConditionalSugar = currentIsConditionalSugar;
- } else if (isConditionalSugar !== currentIsConditionalSugar) {
- throw new ERR_INVALID_PACKAGE_CONFIG(
- fileURLToPath$1(packageJsonUrl),
- base,
- '"exports" cannot contain some keys starting with \'.\' and some not.' +
- ' The exports object must either be an object of package subpath keys' +
- ' or an object of main entry condition name keys only.'
- )
- }
- }
-
- return isConditionalSugar
-}
-
-/**
- * @param {string} match
- * @param {URL} pjsonUrl
- * @param {URL} base
- */
-function emitTrailingSlashPatternDeprecation(match, pjsonUrl, base) {
- // @ts-expect-error: apparently it does exist, TS.
- if (process$1.noDeprecation) {
- return
- }
-
- const pjsonPath = fileURLToPath$1(pjsonUrl);
- if (emittedPackageWarnings.has(pjsonPath + '|' + match)) return
- emittedPackageWarnings.add(pjsonPath + '|' + match);
- process$1.emitWarning(
- `Use of deprecated trailing slash pattern mapping "${match}" in the ` +
- `"exports" field module resolution of the package at ${pjsonPath}${
- base ? ` imported from ${fileURLToPath$1(base)}` : ''
- }. Mapping specifiers ending in "/" is no longer supported.`,
- 'DeprecationWarning',
- 'DEP0155'
- );
-}
-
-/**
- * @param {URL} packageJsonUrl
- * @param {string} packageSubpath
- * @param {Record<string, unknown>} packageConfig
- * @param {URL} base
- * @param {Set<string> | undefined} conditions
- * @returns {URL}
- */
-function packageExportsResolve(
- packageJsonUrl,
- packageSubpath,
- packageConfig,
- base,
- conditions
-) {
- let exports$1 = packageConfig.exports;
-
- if (isConditionalExportsMainSugar(exports$1, packageJsonUrl, base)) {
- exports$1 = {'.': exports$1};
- }
-
- if (
- own.call(exports$1, packageSubpath) &&
- !packageSubpath.includes('*') &&
- !packageSubpath.endsWith('/')
- ) {
- // @ts-expect-error: indexable.
- const target = exports$1[packageSubpath];
- const resolveResult = resolvePackageTarget(
- packageJsonUrl,
- target,
- '',
- packageSubpath,
- base,
- false,
- false,
- false,
- conditions
- );
- if (resolveResult === null || resolveResult === undefined) {
- throw exportsNotFound(packageSubpath, packageJsonUrl, base)
- }
-
- return resolveResult
- }
-
- let bestMatch = '';
- let bestMatchSubpath = '';
- const keys = Object.getOwnPropertyNames(exports$1);
- let i = -1;
-
- while (++i < keys.length) {
- const key = keys[i];
- const patternIndex = key.indexOf('*');
-
- if (
- patternIndex !== -1 &&
- packageSubpath.startsWith(key.slice(0, patternIndex))
- ) {
- // When this reaches EOL, this can throw at the top of the whole function:
- //
- // if (StringPrototypeEndsWith(packageSubpath, '/'))
- // throwInvalidSubpath(packageSubpath)
- //
- // To match "imports" and the spec.
- if (packageSubpath.endsWith('/')) {
- emitTrailingSlashPatternDeprecation(
- packageSubpath,
- packageJsonUrl,
- base
- );
- }
-
- const patternTrailer = key.slice(patternIndex + 1);
-
- if (
- packageSubpath.length >= key.length &&
- packageSubpath.endsWith(patternTrailer) &&
- patternKeyCompare(bestMatch, key) === 1 &&
- key.lastIndexOf('*') === patternIndex
- ) {
- bestMatch = key;
- bestMatchSubpath = packageSubpath.slice(
- patternIndex,
- packageSubpath.length - patternTrailer.length
- );
- }
- }
- }
-
- if (bestMatch) {
- // @ts-expect-error: indexable.
- const target = /** @type {unknown} */ (exports$1[bestMatch]);
- const resolveResult = resolvePackageTarget(
- packageJsonUrl,
- target,
- bestMatchSubpath,
- bestMatch,
- base,
- true,
- false,
- packageSubpath.endsWith('/'),
- conditions
- );
-
- if (resolveResult === null || resolveResult === undefined) {
- throw exportsNotFound(packageSubpath, packageJsonUrl, base)
- }
-
- return resolveResult
- }
-
- throw exportsNotFound(packageSubpath, packageJsonUrl, base)
-}
-
-/**
- * @param {string} a
- * @param {string} b
- */
-function patternKeyCompare(a, b) {
- const aPatternIndex = a.indexOf('*');
- const bPatternIndex = b.indexOf('*');
- const baseLengthA = aPatternIndex === -1 ? a.length : aPatternIndex + 1;
- const baseLengthB = bPatternIndex === -1 ? b.length : bPatternIndex + 1;
- if (baseLengthA > baseLengthB) return -1
- if (baseLengthB > baseLengthA) return 1
- if (aPatternIndex === -1) return 1
- if (bPatternIndex === -1) return -1
- if (a.length > b.length) return -1
- if (b.length > a.length) return 1
- return 0
-}
-
-/**
- * @param {string} name
- * @param {URL} base
- * @param {Set<string>} [conditions]
- * @returns {URL}
- */
-function packageImportsResolve(name, base, conditions) {
- if (name === '#' || name.startsWith('#/') || name.endsWith('/')) {
- const reason = 'is not a valid internal imports specifier name';
- throw new ERR_INVALID_MODULE_SPECIFIER(name, reason, fileURLToPath$1(base))
- }
-
- /** @type {URL | undefined} */
- let packageJsonUrl;
-
- const packageConfig = getPackageScopeConfig(base);
-
- if (packageConfig.exists) {
- packageJsonUrl = pathToFileURL$1(packageConfig.pjsonPath);
- const imports = packageConfig.imports;
- if (imports) {
- if (own.call(imports, name) && !name.includes('*')) {
- const resolveResult = resolvePackageTarget(
- packageJsonUrl,
- imports[name],
- '',
- name,
- base,
- false,
- true,
- false,
- conditions
- );
- if (resolveResult !== null && resolveResult !== undefined) {
- return resolveResult
- }
- } else {
- let bestMatch = '';
- let bestMatchSubpath = '';
- const keys = Object.getOwnPropertyNames(imports);
- let i = -1;
-
- while (++i < keys.length) {
- const key = keys[i];
- const patternIndex = key.indexOf('*');
-
- if (patternIndex !== -1 && name.startsWith(key.slice(0, -1))) {
- const patternTrailer = key.slice(patternIndex + 1);
- if (
- name.length >= key.length &&
- name.endsWith(patternTrailer) &&
- patternKeyCompare(bestMatch, key) === 1 &&
- key.lastIndexOf('*') === patternIndex
- ) {
- bestMatch = key;
- bestMatchSubpath = name.slice(
- patternIndex,
- name.length - patternTrailer.length
- );
- }
- }
- }
-
- if (bestMatch) {
- const target = imports[bestMatch];
- const resolveResult = resolvePackageTarget(
- packageJsonUrl,
- target,
- bestMatchSubpath,
- bestMatch,
- base,
- true,
- true,
- false,
- conditions
- );
-
- if (resolveResult !== null && resolveResult !== undefined) {
- return resolveResult
- }
- }
- }
- }
- }
-
- throw importNotDefined(name, packageJsonUrl, base)
-}
-
-/**
- * @param {string} specifier
- * @param {URL} base
- */
-function parsePackageName(specifier, base) {
- let separatorIndex = specifier.indexOf('/');
- let validPackageName = true;
- let isScoped = false;
- if (specifier[0] === '@') {
- isScoped = true;
- if (separatorIndex === -1 || specifier.length === 0) {
- validPackageName = false;
- } else {
- separatorIndex = specifier.indexOf('/', separatorIndex + 1);
- }
- }
-
- const packageName =
- separatorIndex === -1 ? specifier : specifier.slice(0, separatorIndex);
-
- // Package name cannot have leading . and cannot have percent-encoding or
- // \\ separators.
- if (invalidPackageNameRegEx.exec(packageName) !== null) {
- validPackageName = false;
- }
-
- if (!validPackageName) {
- throw new ERR_INVALID_MODULE_SPECIFIER(
- specifier,
- 'is not a valid package name',
- fileURLToPath$1(base)
- )
- }
-
- const packageSubpath =
- '.' + (separatorIndex === -1 ? '' : specifier.slice(separatorIndex));
-
- return {packageName, packageSubpath, isScoped}
-}
-
-/**
- * @param {string} specifier
- * @param {URL} base
- * @param {Set<string> | undefined} conditions
- * @returns {URL}
- */
-function packageResolve(specifier, base, conditions) {
- if (builtinModules.includes(specifier)) {
- return new URL$1('node:' + specifier)
- }
-
- const {packageName, packageSubpath, isScoped} = parsePackageName(
- specifier,
- base
- );
-
- // ResolveSelf
- const packageConfig = getPackageScopeConfig(base);
-
- // Can’t test.
- /* c8 ignore next 16 */
- if (packageConfig.exists) {
- const packageJsonUrl = pathToFileURL$1(packageConfig.pjsonPath);
- if (
- packageConfig.name === packageName &&
- packageConfig.exports !== undefined &&
- packageConfig.exports !== null
- ) {
- return packageExportsResolve(
- packageJsonUrl,
- packageSubpath,
- packageConfig,
- base,
- conditions
- )
- }
- }
-
- let packageJsonUrl = new URL$1(
- './node_modules/' + packageName + '/package.json',
- base
- );
- let packageJsonPath = fileURLToPath$1(packageJsonUrl);
- /** @type {string} */
- let lastPath;
- do {
- const stat = tryStatSync(packageJsonPath.slice(0, -13));
- if (!stat || !stat.isDirectory()) {
- lastPath = packageJsonPath;
- packageJsonUrl = new URL$1(
- (isScoped ? '../../../../node_modules/' : '../../../node_modules/') +
- packageName +
- '/package.json',
- packageJsonUrl
- );
- packageJsonPath = fileURLToPath$1(packageJsonUrl);
- continue
- }
-
- // Package match.
- const packageConfig = read(packageJsonPath, {base, specifier});
- if (packageConfig.exports !== undefined && packageConfig.exports !== null) {
- return packageExportsResolve(
- packageJsonUrl,
- packageSubpath,
- packageConfig,
- base,
- conditions
- )
- }
-
- if (packageSubpath === '.') {
- return legacyMainResolve(packageJsonUrl, packageConfig, base)
- }
-
- return new URL$1(packageSubpath, packageJsonUrl)
- // Cross-platform root check.
- } while (packageJsonPath.length !== lastPath.length)
-
- throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath$1(base), false)
-}
-
-/**
- * @param {string} specifier
- * @returns {boolean}
- */
-function isRelativeSpecifier(specifier) {
- if (specifier[0] === '.') {
- if (specifier.length === 1 || specifier[1] === '/') return true
- if (
- specifier[1] === '.' &&
- (specifier.length === 2 || specifier[2] === '/')
- ) {
- return true
- }
- }
-
- return false
-}
-
-/**
- * @param {string} specifier
- * @returns {boolean}
- */
-function shouldBeTreatedAsRelativeOrAbsolutePath(specifier) {
- if (specifier === '') return false
- if (specifier[0] === '/') return true
- return isRelativeSpecifier(specifier)
-}
-
-/**
- * The “Resolver Algorithm Specification” as detailed in the Node docs (which is
- * sync and slightly lower-level than `resolve`).
- *
- * @param {string} specifier
- * `/example.js`, `./example.js`, `../example.js`, `some-package`, `fs`, etc.
- * @param {URL} base
- * Full URL (to a file) that `specifier` is resolved relative from.
- * @param {Set<string>} [conditions]
- * Conditions.
- * @param {boolean} [preserveSymlinks]
- * Keep symlinks instead of resolving them.
- * @returns {URL}
- * A URL object to the found thing.
- */
-function moduleResolve(specifier, base, conditions, preserveSymlinks) {
- // Note: The Node code supports `base` as a string (in this internal API) too,
- // we don’t.
- const protocol = base.protocol;
- const isData = protocol === 'data:';
- const isRemote = isData || protocol === 'http:' || protocol === 'https:';
- // Order swapped from spec for minor perf gain.
- // Ok since relative URLs cannot parse as URLs.
- /** @type {URL | undefined} */
- let resolved;
-
- if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) {
- try {
- resolved = new URL$1(specifier, base);
- } catch (error_) {
- const error = new ERR_UNSUPPORTED_RESOLVE_REQUEST(specifier, base);
- error.cause = error_;
- throw error
- }
- } else if (protocol === 'file:' && specifier[0] === '#') {
- resolved = packageImportsResolve(specifier, base, conditions);
- } else {
- try {
- resolved = new URL$1(specifier);
- } catch (error_) {
- // Note: actual code uses `canBeRequiredWithoutScheme`.
- if (isRemote && !builtinModules.includes(specifier)) {
- const error = new ERR_UNSUPPORTED_RESOLVE_REQUEST(specifier, base);
- error.cause = error_;
- throw error
- }
-
- resolved = packageResolve(specifier, base, conditions);
- }
- }
-
- assert(resolved !== undefined, 'expected to be defined');
-
- if (resolved.protocol !== 'file:') {
- return resolved
- }
-
- return finalizeResolution(resolved, base)
-}
-
-function fileURLToPath(id) {
- if (typeof id === "string" && !id.startsWith("file://")) {
- return normalizeSlash(id);
- }
- return normalizeSlash(fileURLToPath$1(id));
-}
-function pathToFileURL(id) {
- return pathToFileURL$1(fileURLToPath(id)).toString();
-}
-function normalizeid(id) {
- if (typeof id !== "string") {
- id = id.toString();
- }
- if (/(?:node|data|http|https|file):/.test(id)) {
- return id;
- }
- if (BUILTIN_MODULES.has(id)) {
- return "node:" + id;
- }
- return "file://" + encodeURI(normalizeSlash(id));
-}
-
-const DEFAULT_CONDITIONS_SET = /* @__PURE__ */ new Set(["node", "import"]);
-const DEFAULT_EXTENSIONS = [".mjs", ".cjs", ".js", ".json"];
-const NOT_FOUND_ERRORS = /* @__PURE__ */ new Set([
- "ERR_MODULE_NOT_FOUND",
- "ERR_UNSUPPORTED_DIR_IMPORT",
- "MODULE_NOT_FOUND",
- "ERR_PACKAGE_PATH_NOT_EXPORTED"
-]);
-function _tryModuleResolve(id, url, conditions) {
- try {
- return moduleResolve(id, url, conditions);
- } catch (error) {
- if (!NOT_FOUND_ERRORS.has(error?.code)) {
- throw error;
- }
- }
-}
-function _resolve$1(id, options = {}) {
- if (typeof id !== "string") {
- if (id instanceof URL) {
- id = fileURLToPath(id);
- } else {
- throw new TypeError("input must be a `string` or `URL`");
- }
- }
- if (/(?:node|data|http|https):/.test(id)) {
- return id;
- }
- if (BUILTIN_MODULES.has(id)) {
- return "node:" + id;
- }
- if (id.startsWith("file://")) {
- id = fileURLToPath(id);
- }
- if (isAbsolute(id)) {
- try {
- const stat = statSync(id);
- if (stat.isFile()) {
- return pathToFileURL(id);
- }
- } catch (error) {
- if (error?.code !== "ENOENT") {
- throw error;
- }
- }
- }
- const conditionsSet = options.conditions ? new Set(options.conditions) : DEFAULT_CONDITIONS_SET;
- const _urls = (Array.isArray(options.url) ? options.url : [options.url]).filter(Boolean).map((url) => new URL(normalizeid(url.toString())));
- if (_urls.length === 0) {
- _urls.push(new URL(pathToFileURL(process.cwd())));
- }
- const urls = [..._urls];
- for (const url of _urls) {
- if (url.protocol === "file:") {
- urls.push(
- new URL("./", url),
- // If url is directory
- new URL(joinURL(url.pathname, "_index.js"), url),
- // TODO: Remove in next major version?
- new URL("node_modules", url)
- );
- }
- }
- let resolved;
- for (const url of urls) {
- resolved = _tryModuleResolve(id, url, conditionsSet);
- if (resolved) {
- break;
- }
- for (const prefix of ["", "/index"]) {
- for (const extension of options.extensions || DEFAULT_EXTENSIONS) {
- resolved = _tryModuleResolve(
- joinURL(id, prefix) + extension,
- url,
- conditionsSet
- );
- if (resolved) {
- break;
- }
- }
- if (resolved) {
- break;
- }
- }
- if (resolved) {
- break;
- }
- }
- if (!resolved) {
- const error = new Error(
- `Cannot find module ${id} imported from ${urls.join(", ")}`
- );
- error.code = "ERR_MODULE_NOT_FOUND";
- throw error;
- }
- return pathToFileURL(resolved);
-}
-function resolveSync(id, options) {
- return _resolve$1(id, options);
-}
-function resolvePathSync(id, options) {
- return fileURLToPath(resolveSync(id, options));
-}
-
-const GET_IS_ASYNC = Symbol.for("quansync.getIsAsync");
-class QuansyncError extends Error {
- constructor(message = "Unexpected promise in sync context") {
- super(message);
- this.name = "QuansyncError";
- }
-}
-function isThenable(value) {
- return value && typeof value === "object" && typeof value.then === "function";
-}
-function isQuansyncGenerator(value) {
- return value && typeof value === "object" && typeof value[Symbol.iterator] === "function" && "__quansync" in value;
-}
-function fromObject(options) {
- const generator = function* (...args) {
- const isAsync = yield GET_IS_ASYNC;
- if (isAsync)
- return yield options.async.apply(this, args);
- return options.sync.apply(this, args);
- };
- function fn(...args) {
- const iter = generator.apply(this, args);
- iter.then = (...thenArgs) => options.async.apply(this, args).then(...thenArgs);
- iter.__quansync = true;
- return iter;
- }
- fn.sync = options.sync;
- fn.async = options.async;
- return fn;
-}
-function fromPromise(promise) {
- return fromObject({
- async: () => Promise.resolve(promise),
- sync: () => {
- if (isThenable(promise))
- throw new QuansyncError();
- return promise;
- }
- });
-}
-function unwrapYield(value, isAsync) {
- if (value === GET_IS_ASYNC)
- return isAsync;
- if (isQuansyncGenerator(value))
- return isAsync ? iterateAsync(value) : iterateSync(value);
- if (!isAsync && isThenable(value))
- throw new QuansyncError();
- return value;
-}
-const DEFAULT_ON_YIELD = (value) => value;
-function iterateSync(generator, onYield = DEFAULT_ON_YIELD) {
- let current = generator.next();
- while (!current.done) {
- try {
- current = generator.next(unwrapYield(onYield(current.value, false)));
- } catch (err) {
- current = generator.throw(err);
- }
- }
- return unwrapYield(current.value);
-}
-async function iterateAsync(generator, onYield = DEFAULT_ON_YIELD) {
- let current = generator.next();
- while (!current.done) {
- try {
- current = generator.next(await unwrapYield(onYield(current.value, true), true));
- } catch (err) {
- current = generator.throw(err);
- }
- }
- return current.value;
-}
-function fromGeneratorFn(generatorFn, options) {
- return fromObject({
- name: generatorFn.name,
- async(...args) {
- return iterateAsync(generatorFn.apply(this, args), options?.onYield);
- },
- sync(...args) {
- return iterateSync(generatorFn.apply(this, args), options?.onYield);
- }
- });
-}
-function quansync$1(input, options) {
- if (isThenable(input))
- return fromPromise(input);
- if (typeof input === "function")
- return fromGeneratorFn(input, options);
- else
- return fromObject(input);
-}
-quansync$1({
- async: () => Promise.resolve(true),
- sync: () => false
-});
-
-const quansync = quansync$1;
-
-const toPath = urlOrPath => urlOrPath instanceof URL ? fileURLToPath$1(urlOrPath) : urlOrPath;
-
-async function findUp$1(name, {
- cwd = process$1.cwd(),
- type = 'file',
- stopAt,
-} = {}) {
- let directory = path.resolve(toPath(cwd) ?? '');
- const {root} = path.parse(directory);
- stopAt = path.resolve(directory, toPath(stopAt ?? root));
- const isAbsoluteName = path.isAbsolute(name);
-
- while (directory) {
- const filePath = isAbsoluteName ? name : path.join(directory, name);
- try {
- const stats = await fs$1.stat(filePath); // eslint-disable-line no-await-in-loop
- if ((type === 'file' && stats.isFile()) || (type === 'directory' && stats.isDirectory())) {
- return filePath;
- }
- } catch {}
-
- if (directory === stopAt || directory === root) {
- break;
- }
-
- directory = path.dirname(directory);
- }
-}
-
-function findUpSync(name, {
- cwd = process$1.cwd(),
- type = 'file',
- stopAt,
-} = {}) {
- let directory = path.resolve(toPath(cwd) ?? '');
- const {root} = path.parse(directory);
- stopAt = path.resolve(directory, toPath(stopAt) ?? root);
- const isAbsoluteName = path.isAbsolute(name);
-
- while (directory) {
- const filePath = isAbsoluteName ? name : path.join(directory, name);
-
- try {
- const stats = fs.statSync(filePath, {throwIfNoEntry: false});
- if ((type === 'file' && stats?.isFile()) || (type === 'directory' && stats?.isDirectory())) {
- return filePath;
- }
- } catch {}
-
- if (directory === stopAt || directory === root) {
- break;
- }
-
- directory = path.dirname(directory);
- }
-}
-
-function _resolve(path, options = {}) {
- if (options.platform === "auto" || !options.platform)
- options.platform = process$1.platform === "win32" ? "win32" : "posix";
- if (process$1.versions.pnp) {
- const paths = options.paths || [];
- if (paths.length === 0)
- paths.push(process$1.cwd());
- const targetRequire = createRequire(import.meta.url);
- try {
- return targetRequire.resolve(path, { paths });
- } catch {
- }
- }
- const modulePath = resolvePathSync(path, {
- url: options.paths
- });
- if (options.platform === "win32")
- return win32.normalize(modulePath);
- return modulePath;
-}
-function resolveModule(name, options = {}) {
- try {
- return _resolve(name, options);
- } catch {
- return void 0;
- }
-}
-function isPackageExists(name, options = {}) {
- return !!resolvePackage(name, options);
-}
-function getPackageJsonPath(name, options = {}) {
- const entry = resolvePackage(name, options);
- if (!entry)
- return;
- return searchPackageJSON(entry);
-}
-const readFile = quansync({
- async: (id) => fs.promises.readFile(id, "utf8"),
- sync: (id) => fs.readFileSync(id, "utf8")
-});
-const getPackageInfo = quansync(function* (name, options = {}) {
- const packageJsonPath = getPackageJsonPath(name, options);
- if (!packageJsonPath)
- return;
- const packageJson = JSON.parse(yield readFile(packageJsonPath));
- return {
- name,
- version: packageJson.version,
- rootPath: dirname(packageJsonPath),
- packageJsonPath,
- packageJson
- };
-});
-getPackageInfo.sync;
-function resolvePackage(name, options = {}) {
- try {
- return _resolve(`${name}/package.json`, options);
- } catch {
- }
- try {
- return _resolve(name, options);
- } catch (e) {
- if (e.code !== "MODULE_NOT_FOUND" && e.code !== "ERR_MODULE_NOT_FOUND")
- console.error(e);
- return false;
- }
-}
-function searchPackageJSON(dir) {
- let packageJsonPath;
- while (true) {
- if (!dir)
- return;
- const newDir = dirname(dir);
- if (newDir === dir)
- return;
- dir = newDir;
- packageJsonPath = join(dir, "package.json");
- if (fs.existsSync(packageJsonPath))
- break;
- }
- return packageJsonPath;
-}
-const findUp = quansync({
- sync: findUpSync,
- async: findUp$1
-});
-const loadPackageJSON = quansync(function* (cwd = process$1.cwd()) {
- const path = yield findUp("package.json", { cwd });
- if (!path || !fs.existsSync(path))
- return null;
- return JSON.parse(yield readFile(path));
-});
-loadPackageJSON.sync;
-const isPackageListed = quansync(function* (name, cwd) {
- const pkg = (yield loadPackageJSON(cwd)) || {};
- return name in (pkg.dependencies || {}) || name in (pkg.devDependencies || {});
-});
-isPackageListed.sync;
-
-function getWorkersCountByPercentage(percent) {
- const maxWorkersCount = nodeos__default.availableParallelism?.() ?? nodeos__default.cpus().length;
- const workersCountByPercentage = Math.round(Number.parseInt(percent) / 100 * maxWorkersCount);
- return Math.max(1, Math.min(maxWorkersCount, workersCountByPercentage));
-}
-
-class BaseSequencer {
- ctx;
- constructor(ctx) {
- this.ctx = ctx;
- }
- // async so it can be extended by other sequelizers
- async shard(files) {
- const { config } = this.ctx;
- const { index, count } = config.shard;
- const [shardStart, shardEnd] = this.calculateShardRange(files.length, index, count);
- return [...files].map((spec) => {
- const specPath = resolve(slash(config.root), slash(spec.moduleId))?.slice(config.root.length);
- return {
- spec,
- hash: hash("sha1", specPath, "hex")
- };
- }).sort((a, b) => a.hash < b.hash ? -1 : a.hash > b.hash ? 1 : 0).slice(shardStart, shardEnd).map(({ spec }) => spec);
- }
- // async so it can be extended by other sequelizers
- async sort(files) {
- const cache = this.ctx.cache;
- return [...files].sort((a, b) => {
- // "sequence.groupOrder" is higher priority
- const groupOrderDiff = a.project.config.sequence.groupOrder - b.project.config.sequence.groupOrder;
- if (groupOrderDiff !== 0) return groupOrderDiff;
- // Projects run sequential
- if (a.project.name !== b.project.name) return a.project.name < b.project.name ? -1 : 1;
- // Isolated run first
- if (a.project.config.isolate && !b.project.config.isolate) return -1;
- if (!a.project.config.isolate && b.project.config.isolate) return 1;
- const keyA = `${a.project.name}:${relative(this.ctx.config.root, a.moduleId)}`;
- const keyB = `${b.project.name}:${relative(this.ctx.config.root, b.moduleId)}`;
- const aState = cache.getFileTestResults(keyA);
- const bState = cache.getFileTestResults(keyB);
- if (!aState || !bState) {
- const statsA = cache.getFileStats(keyA);
- const statsB = cache.getFileStats(keyB);
- // run unknown first
- if (!statsA || !statsB) return !statsA && statsB ? -1 : !statsB && statsA ? 1 : 0;
- // run larger files first
- return statsB.size - statsA.size;
- }
- // run failed first
- if (aState.failed && !bState.failed) return -1;
- if (!aState.failed && bState.failed) return 1;
- // run longer first
- return bState.duration - aState.duration;
- });
- }
- // Calculate distributed shard range [start, end] distributed equally
- calculateShardRange(filesCount, index, count) {
- const baseShardSize = Math.floor(filesCount / count);
- const remainderTestFilesCount = filesCount % count;
- if (remainderTestFilesCount >= index) {
- const shardSize = baseShardSize + 1;
- return [shardSize * (index - 1), shardSize * index];
- }
- const shardStart = remainderTestFilesCount * (baseShardSize + 1) + (index - remainderTestFilesCount - 1) * baseShardSize;
- return [shardStart, shardStart + baseShardSize];
- }
-}
-
-class RandomSequencer extends BaseSequencer {
- async sort(files) {
- const { sequence } = this.ctx.config;
- return shuffle(files, sequence.seed);
- }
-}
-
-function resolvePath(path, root) {
- return normalize(/* @__PURE__ */ resolveModule(path, { paths: [root] }) ?? resolve(root, path));
-}
-function parseInspector(inspect) {
- if (typeof inspect === "boolean" || inspect === void 0) return {};
- if (typeof inspect === "number") return { port: inspect };
- if (inspect.match(/https?:\//)) throw new Error(`Inspector host cannot be a URL. Use "host:port" instead of "${inspect}"`);
- const [host, port] = inspect.split(":");
- if (!port) return { host };
- return {
- host,
- port: Number(port) || defaultInspectPort
- };
-}
-function resolveApiServerConfig(options, defaultPort) {
- let api;
- if (options.ui && !options.api) api = { port: defaultPort };
- else if (options.api === true) api = { port: defaultPort };
- else if (typeof options.api === "number") api = { port: options.api };
- if (typeof options.api === "object") if (api) {
- if (options.api.port) api.port = options.api.port;
- if (options.api.strictPort) api.strictPort = options.api.strictPort;
- if (options.api.host) api.host = options.api.host;
- } else api = { ...options.api };
- if (api) {
- if (!api.port && !api.middlewareMode) api.port = defaultPort;
- } else api = { middlewareMode: true };
- return api;
-}
-function resolveInlineWorkerOption(value) {
- if (typeof value === "string" && value.trim().endsWith("%")) return getWorkersCountByPercentage(value);
- else return Number(value);
-}
-function resolveConfig$1(vitest, options, viteConfig) {
- const mode = vitest.mode;
- const logger = vitest.logger;
- if (options.dom) {
- if (viteConfig.test?.environment != null && viteConfig.test.environment !== "happy-dom") logger.console.warn(c.yellow(`${c.inverse(c.yellow(" Vitest "))} Your config.test.environment ("${viteConfig.test.environment}") conflicts with --dom flag ("happy-dom"), ignoring "${viteConfig.test.environment}"`));
- options.environment = "happy-dom";
- }
- const resolved = {
- ...configDefaults,
- ...options,
- root: viteConfig.root,
- mode
- };
- if (options.pool && typeof options.pool !== "string") {
- resolved.pool = options.pool.name;
- resolved.poolRunner = options.pool;
- }
- if ("poolOptions" in resolved) logger.deprecate("`test.poolOptions` was removed in Vitest 4. All previous `poolOptions` are now top-level options. Please, refer to the migration guide: https://vitest.dev/guide/migration#pool-rework");
- resolved.pool ??= "forks";
- resolved.project = toArray(resolved.project);
- resolved.provide ??= {};
- resolved.name = typeof options.name === "string" ? options.name : options.name?.label || "";
- resolved.color = typeof options.name !== "string" ? options.name?.color : void 0;
- if (resolved.environment === "browser") throw new Error(`Looks like you set "test.environment" to "browser". To enable Browser Mode, use "test.browser.enabled" instead.`);
- const inspector = resolved.inspect || resolved.inspectBrk;
- resolved.inspector = {
- ...resolved.inspector,
- ...parseInspector(inspector),
- enabled: !!inspector,
- waitForDebugger: options.inspector?.waitForDebugger ?? !!resolved.inspectBrk
- };
- if (viteConfig.base !== "/") resolved.base = viteConfig.base;
- resolved.clearScreen = resolved.clearScreen ?? viteConfig.clearScreen ?? true;
- if (options.shard) {
- if (resolved.watch) throw new Error("You cannot use --shard option with enabled watch");
- const [indexString, countString] = options.shard.split("/");
- const index = Math.abs(Number.parseInt(indexString, 10));
- const count = Math.abs(Number.parseInt(countString, 10));
- if (Number.isNaN(count) || count <= 0) throw new Error("--shard <count> must be a positive number");
- if (Number.isNaN(index) || index <= 0 || index > count) throw new Error("--shard <index> must be a positive number less then <count>");
- resolved.shard = {
- index,
- count
- };
- }
- if (resolved.standalone && !resolved.watch) throw new Error(`Vitest standalone mode requires --watch`);
- if (resolved.mergeReports && resolved.watch) throw new Error(`Cannot merge reports with --watch enabled`);
- if (resolved.maxWorkers) resolved.maxWorkers = resolveInlineWorkerOption(resolved.maxWorkers);
- if (!(options.fileParallelism ?? mode !== "benchmark"))
- // ignore user config, parallelism cannot be implemented without limiting workers
- resolved.maxWorkers = 1;
- if (resolved.maxConcurrency === 0) {
- logger.console.warn(c.yellow(`The option "maxConcurrency" cannot be set to 0. Using default value ${configDefaults.maxConcurrency} instead.`));
- resolved.maxConcurrency = configDefaults.maxConcurrency;
- }
- if (resolved.inspect || resolved.inspectBrk) {
- if (resolved.maxWorkers !== 1) {
- const inspectOption = `--inspect${resolved.inspectBrk ? "-brk" : ""}`;
- throw new Error(`You cannot use ${inspectOption} without "--no-file-parallelism"`);
- }
- }
- // apply browser CLI options only if the config already has the browser config and not disabled manually
- if (vitest._cliOptions.browser && resolved.browser && (resolved.browser.enabled !== false || vitest._cliOptions.browser.enabled)) resolved.browser = mergeConfig(resolved.browser, vitest._cliOptions.browser);
- resolved.browser ??= {};
- const browser = resolved.browser;
- if (browser.enabled) {
- const instances = browser.instances;
- if (!browser.instances) browser.instances = [];
- // use `chromium` by default when the preview provider is specified
- // for a smoother experience. if chromium is not available, it will
- // open the default browser anyway
- if (!browser.instances.length && browser.provider?.name === "preview") browser.instances = [{ browser: "chromium" }];
- if (browser.name && instances?.length) {
- // --browser=chromium filters configs to a single one
- browser.instances = browser.instances.filter((instance) => instance.browser === browser.name);
- // if `instances` were defined, but now they are empty,
- // let's throw an error because the filter is invalid
- if (!browser.instances.length) throw new Error([`"browser.instances" was set in the config, but the array is empty. Define at least one browser config.`, ` The "browser.name" was set to "${browser.name}" which filtered all configs (${instances.map((c) => c.browser).join(", ")}). Did you mean to use another name?`].join(""));
- }
- }
- const containsChromium = hasBrowserChromium(vitest, resolved);
- const hasOnlyChromium = hasOnlyBrowserChromium(vitest, resolved);
- // Browser-mode "Chromium" only features:
- if (browser.enabled && (!containsChromium || !hasOnlyChromium)) {
- const browserConfig = `
-{
- browser: {
- provider: ${browser.provider?.name || "preview"}(),
- instances: [
- ${(browser.instances || []).map((i) => `{ browser: '${i.browser}' }`).join(",\n ")}
- ],
- },
-}
- `.trim();
- const preferredProvider = !browser.provider?.name || browser.provider.name === "preview" ? "playwright" : browser.provider.name;
- const correctExample = `
-{
- browser: {
- provider: ${preferredProvider}(),
- instances: [
- { browser: '${preferredProvider === "playwright" ? "chromium" : "chrome"}' }
- ],
- },
-}
- `.trim();
- // requires all projects to be chromium
- if (!hasOnlyChromium && resolved.coverage.enabled && resolved.coverage.provider === "v8") {
- const coverageExample = `
-{
- coverage: {
- provider: 'istanbul',
- },
-}
- `.trim();
- throw new Error(`@vitest/coverage-v8 does not work with\n${browserConfig}\n\nUse either:\n${correctExample}\n\n...or change your coverage provider to:\n${coverageExample}\n`);
- }
- // ignores non-chromium browsers when there is at least one chromium project
- if (!containsChromium && (resolved.inspect || resolved.inspectBrk)) {
- const inspectOption = `--inspect${resolved.inspectBrk ? "-brk" : ""}`;
- throw new Error(`${inspectOption} does not work with\n${browserConfig}\n\nUse either:\n${correctExample}\n\n...or disable ${inspectOption}\n`);
- }
- }
- resolved.coverage.reporter = resolveCoverageReporters(resolved.coverage.reporter);
- if (resolved.coverage.enabled && resolved.coverage.reportsDirectory) {
- const reportsDirectory = resolve(resolved.root, resolved.coverage.reportsDirectory);
- if (reportsDirectory === resolved.root || reportsDirectory === process.cwd()) throw new Error(`You cannot set "coverage.reportsDirectory" as ${reportsDirectory}. Vitest needs to be able to remove this directory before test run`);
- }
- if (resolved.coverage.enabled && resolved.coverage.provider === "custom" && resolved.coverage.customProviderModule) resolved.coverage.customProviderModule = resolvePath(resolved.coverage.customProviderModule, resolved.root);
- resolved.expect ??= {};
- resolved.deps ??= {};
- resolved.deps.moduleDirectories ??= [];
- resolved.deps.optimizer ??= {};
- resolved.deps.optimizer.ssr ??= {};
- resolved.deps.optimizer.ssr.enabled ??= false;
- resolved.deps.optimizer.client ??= {};
- resolved.deps.optimizer.client.enabled ??= false;
- resolved.deps.web ??= {};
- resolved.deps.web.transformAssets ??= true;
- resolved.deps.web.transformCss ??= true;
- resolved.deps.web.transformGlobPattern ??= [];
- resolved.setupFiles = toArray(resolved.setupFiles || []).map((file) => resolvePath(file, resolved.root));
- resolved.globalSetup = toArray(resolved.globalSetup || []).map((file) => resolvePath(file, resolved.root));
- // Add hard-coded default coverage exclusions. These cannot be overidden by user config.
- // Override original exclude array for cases where user re-uses same object in test.exclude.
- resolved.coverage.exclude = [
- ...resolved.coverage.exclude,
- ...resolved.setupFiles.map((file) => `${resolved.coverage.allowExternal ? "**/" : ""}${relative(resolved.root, file)}`),
- ...resolved.include,
- resolved.config && slash(resolved.config),
- ...configFiles,
- "**/virtual:*",
- "**/__x00__*",
- "**/node_modules/**"
- ].filter((pattern) => typeof pattern === "string");
- resolved.forceRerunTriggers = [...resolved.forceRerunTriggers, ...resolved.setupFiles];
- if (resolved.cliExclude) resolved.exclude.push(...resolved.cliExclude);
- if (resolved.runner) resolved.runner = resolvePath(resolved.runner, resolved.root);
- resolved.attachmentsDir = resolve(resolved.root, resolved.attachmentsDir ?? ".vitest-attachments");
- if (resolved.snapshotEnvironment) resolved.snapshotEnvironment = resolvePath(resolved.snapshotEnvironment, resolved.root);
- resolved.testNamePattern = resolved.testNamePattern ? resolved.testNamePattern instanceof RegExp ? resolved.testNamePattern : new RegExp(resolved.testNamePattern) : void 0;
- if (resolved.snapshotFormat && "plugins" in resolved.snapshotFormat) {
- resolved.snapshotFormat.plugins = [];
- // TODO: support it via separate config (like DiffOptions) or via `Function.toString()`
- if (typeof resolved.snapshotFormat.compareKeys === "function") throw new TypeError(`"snapshotFormat.compareKeys" function is not supported.`);
- }
- const UPDATE_SNAPSHOT = resolved.update || process.env.UPDATE_SNAPSHOT;
- resolved.snapshotOptions = {
- expand: resolved.expandSnapshotDiff ?? false,
- snapshotFormat: resolved.snapshotFormat || {},
- updateSnapshot: isCI && !UPDATE_SNAPSHOT ? "none" : UPDATE_SNAPSHOT ? "all" : "new",
- resolveSnapshotPath: options.resolveSnapshotPath,
- snapshotEnvironment: null
- };
- resolved.snapshotSerializers ??= [];
- resolved.snapshotSerializers = resolved.snapshotSerializers.map((file) => resolvePath(file, resolved.root));
- resolved.forceRerunTriggers.push(...resolved.snapshotSerializers);
- if (options.resolveSnapshotPath) delete resolved.resolveSnapshotPath;
- resolved.execArgv ??= [];
- resolved.pool ??= "threads";
- if (resolved.pool === "vmForks" || resolved.pool === "vmThreads" || resolved.pool === "typescript") resolved.isolate = false;
- if (process.env.VITEST_MAX_WORKERS) resolved.maxWorkers = Number.parseInt(process.env.VITEST_MAX_WORKERS);
- if (mode === "benchmark") {
- resolved.benchmark = {
- ...benchmarkConfigDefaults,
- ...resolved.benchmark
- };
- // override test config
- resolved.coverage.enabled = false;
- resolved.typecheck.enabled = false;
- resolved.include = resolved.benchmark.include;
- resolved.exclude = resolved.benchmark.exclude;
- resolved.includeSource = resolved.benchmark.includeSource;
- const reporters = Array.from(new Set([...toArray(resolved.benchmark.reporters), ...toArray(options.reporter)])).filter(Boolean);
- if (reporters.length) resolved.benchmark.reporters = reporters;
- else resolved.benchmark.reporters = ["default"];
- if (options.outputFile) resolved.benchmark.outputFile = options.outputFile;
- // --compare from cli
- if (options.compare) resolved.benchmark.compare = options.compare;
- if (options.outputJson) resolved.benchmark.outputJson = options.outputJson;
- }
- if (typeof resolved.diff === "string") {
- resolved.diff = resolvePath(resolved.diff, resolved.root);
- resolved.forceRerunTriggers.push(resolved.diff);
- }
- resolved.api = {
- ...resolveApiServerConfig(options, defaultPort),
- token: crypto.randomUUID()
- };
- if (options.related) resolved.related = toArray(options.related).map((file) => resolve(resolved.root, file));
- /*
- * Reporters can be defined in many different ways:
- * { reporter: 'json' }
- * { reporter: { onFinish() { method() } } }
- * { reporter: ['json', { onFinish() { method() } }] }
- * { reporter: [[ 'json' ]] }
- * { reporter: [[ 'json' ], 'html'] }
- * { reporter: [[ 'json', { outputFile: 'test.json' } ], 'html'] }
- */
- if (options.reporters) if (!Array.isArray(options.reporters))
- // Reporter name, e.g. { reporters: 'json' }
- if (typeof options.reporters === "string") resolved.reporters = [[options.reporters, {}]];
- else resolved.reporters = [options.reporters];
- else {
- resolved.reporters = [];
- for (const reporter of options.reporters) if (Array.isArray(reporter))
- // Reporter with options, e.g. { reporters: [ [ 'json', { outputFile: 'test.json' } ] ] }
- resolved.reporters.push([reporter[0], reporter[1] || {}]);
- else if (typeof reporter === "string")
- // Reporter name in array, e.g. { reporters: ["html", "json"]}
- resolved.reporters.push([reporter, {}]);
- else
- // Inline reporter, e.g. { reporter: [{ onFinish() { method() } }] }
- resolved.reporters.push(reporter);
- }
- if (mode !== "benchmark") {
- // @ts-expect-error "reporter" is from CLI, should be absolute to the running directory
- // it is passed down as "vitest --reporter ../reporter.js"
- const reportersFromCLI = resolved.reporter;
- const cliReporters = toArray(reportersFromCLI || []).map((reporter) => {
- // ./reporter.js || ../reporter.js, but not .reporters/reporter.js
- if (/^\.\.?\//.test(reporter)) return resolve(process.cwd(), reporter);
- return reporter;
- });
- if (cliReporters.length) {
- // When CLI reporters are specified, preserve options from config file
- const configReportersMap = /* @__PURE__ */ new Map();
- // Build a map of reporter names to their options from the config
- for (const reporter of resolved.reporters) if (Array.isArray(reporter)) {
- const [reporterName, reporterOptions] = reporter;
- if (typeof reporterName === "string") configReportersMap.set(reporterName, reporterOptions);
- }
- resolved.reporters = Array.from(new Set(toArray(cliReporters))).filter(Boolean).map((reporter) => [reporter, configReportersMap.get(reporter) || {}]);
- }
- }
- if (!resolved.reporters.length) {
- resolved.reporters.push(["default", {}]);
- // also enable github-actions reporter as a default
- if (process.env.GITHUB_ACTIONS === "true") resolved.reporters.push(["github-actions", {}]);
- }
- if (resolved.changed) resolved.passWithNoTests ??= true;
- resolved.css ??= {};
- if (typeof resolved.css === "object") {
- resolved.css.modules ??= {};
- resolved.css.modules.classNameStrategy ??= "stable";
- }
- if (resolved.cache !== false) {
- if (resolved.cache && typeof resolved.cache.dir === "string") vitest.logger.deprecate(`"cache.dir" is deprecated, use Vite's "cacheDir" instead if you want to change the cache director. Note caches will be written to "cacheDir\/vitest"`);
- resolved.cache = { dir: viteConfig.cacheDir };
- }
- resolved.sequence ??= {};
- if (resolved.sequence.shuffle && typeof resolved.sequence.shuffle === "object") {
- const { files, tests } = resolved.sequence.shuffle;
- resolved.sequence.sequencer ??= files ? RandomSequencer : BaseSequencer;
- resolved.sequence.shuffle = tests;
- }
- if (!resolved.sequence?.sequencer)
- // CLI flag has higher priority
- resolved.sequence.sequencer = resolved.sequence.shuffle ? RandomSequencer : BaseSequencer;
- resolved.sequence.groupOrder ??= 0;
- resolved.sequence.hooks ??= "stack";
- if (resolved.sequence.sequencer === RandomSequencer) resolved.sequence.seed ??= Date.now();
- resolved.typecheck = {
- ...configDefaults.typecheck,
- ...resolved.typecheck
- };
- resolved.typecheck ??= {};
- resolved.typecheck.enabled ??= false;
- if (resolved.typecheck.enabled) logger.console.warn(c.yellow("Testing types with tsc and vue-tsc is an experimental feature.\nBreaking changes might not follow SemVer, please pin Vitest's version when using it."));
- resolved.browser.enabled ??= false;
- resolved.browser.headless ??= isCI;
- resolved.browser.isolate ??= resolved.isolate ?? true;
- resolved.browser.fileParallelism ??= options.fileParallelism ?? mode !== "benchmark";
- // disable in headless mode by default, and if CI is detected
- resolved.browser.ui ??= resolved.browser.headless === true ? false : !isCI;
- resolved.browser.commands ??= {};
- if (resolved.browser.screenshotDirectory) resolved.browser.screenshotDirectory = resolve(resolved.root, resolved.browser.screenshotDirectory);
- if (resolved.inspector.enabled) resolved.browser.trackUnhandledErrors ??= false;
- resolved.browser.viewport ??= {};
- resolved.browser.viewport.width ??= 414;
- resolved.browser.viewport.height ??= 896;
- resolved.browser.locators ??= {};
- resolved.browser.locators.testIdAttribute ??= "data-testid";
- if (typeof resolved.browser.provider === "string") {
- const source = `@vitest/browser-${resolved.browser.provider}`;
- throw new TypeError(`The \`browser.provider\` configuration was changed to accept a factory instead of a string. Add an import of "${resolved.browser.provider}" from "${source}" instead. See: https://vitest.dev/config/browser/provider`);
- }
- const isPreview = resolved.browser.provider?.name === "preview";
- if (!isPreview && resolved.browser.enabled && provider === "stackblitz") throw new Error(`stackblitz environment does not support the ${resolved.browser.provider?.name} provider. Please, use "@vitest/browser-preview" instead.`);
- if (isPreview && resolved.browser.screenshotFailures === true) {
- console.warn(c.yellow([
- `Browser provider "preview" doesn't support screenshots, `,
- `so "browser.screenshotFailures" option is forcefully disabled. `,
- `Set "browser.screenshotFailures" to false or remove it from the config to suppress this warning.`
- ].join("")));
- resolved.browser.screenshotFailures = false;
- } else resolved.browser.screenshotFailures ??= !isPreview && !resolved.browser.ui;
- if (resolved.browser.provider && resolved.browser.provider.options == null) resolved.browser.provider.options = {};
- resolved.browser.api = resolveApiServerConfig(resolved.browser, defaultBrowserPort) || { port: defaultBrowserPort };
- // enable includeTaskLocation by default in UI mode
- if (resolved.browser.enabled) {
- if (resolved.browser.ui) resolved.includeTaskLocation ??= true;
- } else if (resolved.ui) resolved.includeTaskLocation ??= true;
- if (typeof resolved.browser.trace === "string" || !resolved.browser.trace) resolved.browser.trace = { mode: resolved.browser.trace || "off" };
- if (resolved.browser.trace.tracesDir != null) resolved.browser.trace.tracesDir = resolvePath(resolved.browser.trace.tracesDir, resolved.root);
- if (toArray(resolved.reporters).some((reporter) => {
- if (Array.isArray(reporter)) return reporter[0] === "html";
- return false;
- })) resolved.includeTaskLocation ??= true;
- resolved.server ??= {};
- resolved.server.deps ??= {};
- if (resolved.server.debug?.dump || process.env.VITEST_DEBUG_DUMP) {
- const userFolder = resolved.server.debug?.dump || process.env.VITEST_DEBUG_DUMP;
- resolved.dumpDir = resolve(resolved.root, typeof userFolder === "string" && userFolder !== "true" ? userFolder : ".vitest-dump", resolved.name || "root");
- }
- resolved.testTimeout ??= resolved.browser.enabled ? 15e3 : 5e3;
- resolved.hookTimeout ??= resolved.browser.enabled ? 3e4 : 1e4;
- resolved.experimental ??= {};
- if (resolved.experimental.openTelemetry?.sdkPath) {
- const sdkPath = resolve(resolved.root, resolved.experimental.openTelemetry.sdkPath);
- resolved.experimental.openTelemetry.sdkPath = pathToFileURL$1(sdkPath).toString();
- }
- if (resolved.experimental.openTelemetry?.browserSdkPath) {
- const browserSdkPath = resolve(resolved.root, resolved.experimental.openTelemetry.browserSdkPath);
- resolved.experimental.openTelemetry.browserSdkPath = browserSdkPath;
- }
- if (resolved.experimental.fsModuleCachePath) resolved.experimental.fsModuleCachePath = resolve(resolved.root, resolved.experimental.fsModuleCachePath);
- return resolved;
-}
-function isBrowserEnabled(config) {
- return Boolean(config.browser?.enabled);
-}
-function resolveCoverageReporters(configReporters) {
- // E.g. { reporter: "html" }
- if (!Array.isArray(configReporters)) return [[configReporters, {}]];
- const resolvedReporters = [];
- for (const reporter of configReporters) if (Array.isArray(reporter))
- // E.g. { reporter: [ ["html", { skipEmpty: true }], ["lcov"], ["json", { file: "map.json" }] ]}
- resolvedReporters.push([reporter[0], reporter[1] || {}]);
- else
- // E.g. { reporter: ["html", "json"]}
- resolvedReporters.push([reporter, {}]);
- return resolvedReporters;
-}
-function isChromiumName(provider, name) {
- if (provider === "playwright") return name === "chromium";
- return name === "chrome" || name === "edge";
-}
-function hasBrowserChromium(vitest, config) {
- const browser = config.browser;
- if (!browser || !browser.provider || browser.provider.name === "preview" || !browser.enabled) return false;
- if (browser.name) return isChromiumName(browser.provider.name, browser.name);
- if (!browser.instances) return false;
- return browser.instances.some((instance) => {
- const name = instance.name || (config.name ? `${config.name} (${instance.browser})` : instance.browser);
- // browser config is filtered out
- if (!vitest.matchesProjectFilter(name)) return false;
- return isChromiumName(browser.provider.name, instance.browser);
- });
-}
-function hasOnlyBrowserChromium(vitest, config) {
- const browser = config.browser;
- if (!browser || !browser.provider || browser.provider.name === "preview" || !browser.enabled) return false;
- if (browser.name) return isChromiumName(browser.provider.name, browser.name);
- if (!browser.instances) return false;
- return browser.instances.every((instance) => {
- const name = instance.name || (config.name ? `${config.name} (${instance.browser})` : instance.browser);
- // browser config is filtered out
- if (!vitest.matchesProjectFilter(name)) return true;
- return isChromiumName(browser.provider.name, instance.browser);
- });
-}
-
-const THRESHOLD_KEYS = [
- "lines",
- "functions",
- "statements",
- "branches"
-];
-const GLOBAL_THRESHOLDS_KEY = "global";
-const DEFAULT_PROJECT = Symbol.for("default-project");
-let uniqueId = 0;
-async function getCoverageProvider(options, loader) {
- const coverageModule = await resolveCoverageProviderModule(options, loader);
- if (coverageModule) return coverageModule.getProvider();
- return null;
-}
-class BaseCoverageProvider {
- ctx;
- name;
- version;
- options;
- globCache = /* @__PURE__ */ new Map();
- coverageFiles = /* @__PURE__ */ new Map();
- pendingPromises = [];
- coverageFilesDirectory;
- roots = [];
- _initialize(ctx) {
- this.ctx = ctx;
- if (ctx.version !== this.version) ctx.logger.warn(c.yellow(`Loaded ${c.inverse(c.yellow(` vitest@${ctx.version} `))} and ${c.inverse(c.yellow(` @vitest/coverage-${this.name}@${this.version} `))}.
-Running mixed versions is not supported and may lead into bugs
-Update your dependencies and make sure the versions match.`));
- const config = ctx._coverageOptions;
- this.options = {
- ...coverageConfigDefaults,
- ...config,
- provider: this.name,
- reportsDirectory: resolve(ctx.config.root, config.reportsDirectory || coverageConfigDefaults.reportsDirectory),
- reporter: resolveCoverageReporters(config.reporter || coverageConfigDefaults.reporter),
- thresholds: config.thresholds && {
- ...config.thresholds,
- lines: config.thresholds["100"] ? 100 : config.thresholds.lines,
- branches: config.thresholds["100"] ? 100 : config.thresholds.branches,
- functions: config.thresholds["100"] ? 100 : config.thresholds.functions,
- statements: config.thresholds["100"] ? 100 : config.thresholds.statements
- }
- };
- const shard = this.ctx.config.shard;
- const tempDirectory = `.tmp${shard ? `-${shard.index}-${shard.count}` : ""}`;
- this.coverageFilesDirectory = resolve(this.options.reportsDirectory, tempDirectory);
- // If --project filter is set pick only roots of resolved projects
- this.roots = ctx.config.project?.length ? [...new Set(ctx.projects.map((project) => project.config.root))] : [ctx.config.root];
- }
- /**
- * Check if file matches `coverage.include` but not `coverage.exclude`
- */
- isIncluded(_filename, root) {
- const roots = root ? [root] : this.roots;
- const filename = slash(_filename);
- const cacheHit = this.globCache.get(filename);
- if (cacheHit !== void 0) return cacheHit;
- // File outside project root with default allowExternal
- if (this.options.allowExternal === false && roots.every((root) => !filename.startsWith(root))) {
- this.globCache.set(filename, false);
- return false;
- }
- // By default `coverage.include` matches all files, except "coverage.exclude"
- const glob = this.options.include || "**";
- const included = pm.isMatch(filename, glob, {
- contains: true,
- dot: true,
- ignore: this.options.exclude
- });
- this.globCache.set(filename, included);
- return included;
- }
- async getUntestedFilesByRoot(testedFiles, include, root) {
- let includedFiles = await glob(include, {
- cwd: root,
- ignore: [...this.options.exclude, ...testedFiles.map((file) => slash(file))],
- absolute: true,
- dot: true,
- onlyFiles: true
- });
- // Run again through picomatch as tinyglobby's exclude pattern is different ({ "exclude": ["math"] } should ignore "src/math.ts")
- includedFiles = includedFiles.filter((file) => this.isIncluded(file, root));
- if (this.ctx.config.changed) includedFiles = (this.ctx.config.related || []).filter((file) => includedFiles.includes(file));
- return includedFiles.map((file) => slash(path.resolve(root, file)));
- }
- async getUntestedFiles(testedFiles) {
- if (this.options.include == null) return [];
- const rootMapper = this.getUntestedFilesByRoot.bind(this, testedFiles, this.options.include);
- return (await Promise.all(this.roots.map(rootMapper))).flatMap((files) => files);
- }
- createCoverageMap() {
- throw new Error("BaseReporter's createCoverageMap was not overwritten");
- }
- async generateReports(_, __) {
- throw new Error("BaseReporter's generateReports was not overwritten");
- }
- async parseConfigModule(_) {
- throw new Error("BaseReporter's parseConfigModule was not overwritten");
- }
- resolveOptions() {
- return this.options;
- }
- async clean(clean = true) {
- if (clean && existsSync(this.options.reportsDirectory)) await promises.rm(this.options.reportsDirectory, {
- recursive: true,
- force: true,
- maxRetries: 10
- });
- if (existsSync(this.coverageFilesDirectory)) await promises.rm(this.coverageFilesDirectory, {
- recursive: true,
- force: true,
- maxRetries: 10
- });
- await promises.mkdir(this.coverageFilesDirectory, { recursive: true });
- this.coverageFiles = /* @__PURE__ */ new Map();
- this.pendingPromises = [];
- }
- onAfterSuiteRun({ coverage, environment, projectName, testFiles }) {
- if (!coverage) return;
- let entry = this.coverageFiles.get(projectName || DEFAULT_PROJECT);
- if (!entry) {
- entry = {};
- this.coverageFiles.set(projectName || DEFAULT_PROJECT, entry);
- }
- const testFilenames = testFiles.join();
- const filename = resolve(this.coverageFilesDirectory, `coverage-${uniqueId++}.json`);
- entry[environment] ??= {};
- // If there's a result from previous run, overwrite it
- entry[environment][testFilenames] = filename;
- const promise = promises.writeFile(filename, JSON.stringify(coverage), "utf-8");
- this.pendingPromises.push(promise);
- }
- async readCoverageFiles({ onFileRead, onFinished, onDebug }) {
- let index = 0;
- const total = this.pendingPromises.length;
- await Promise.all(this.pendingPromises);
- this.pendingPromises = [];
- for (const [projectName, coveragePerProject] of this.coverageFiles.entries()) for (const [environment, coverageByTestfiles] of Object.entries(coveragePerProject)) {
- const filenames = Object.values(coverageByTestfiles);
- const project = this.ctx.getProjectByName(projectName);
- for (const chunk of this.toSlices(filenames, this.options.processingConcurrency)) {
- if (onDebug.enabled) {
- index += chunk.length;
- onDebug(`Reading coverage results ${index}/${total}`);
- }
- await Promise.all(chunk.map(async (filename) => {
- const contents = await promises.readFile(filename, "utf-8");
- onFileRead(JSON.parse(contents));
- }));
- }
- await onFinished(project, environment);
- }
- }
- async cleanAfterRun() {
- this.coverageFiles = /* @__PURE__ */ new Map();
- await promises.rm(this.coverageFilesDirectory, { recursive: true });
- // Remove empty reports directory, e.g. when only text-reporter is used
- if (readdirSync(this.options.reportsDirectory).length === 0) await promises.rm(this.options.reportsDirectory, { recursive: true });
- }
- async onTestFailure() {
- if (!this.options.reportOnFailure) await this.cleanAfterRun();
- }
- async reportCoverage(coverageMap, { allTestsRun }) {
- await this.generateReports(coverageMap || this.createCoverageMap(), allTestsRun);
- if (!(!this.options.cleanOnRerun && this.ctx.config.watch)) await this.cleanAfterRun();
- }
- async reportThresholds(coverageMap, allTestsRun) {
- const resolvedThresholds = this.resolveThresholds(coverageMap);
- this.checkThresholds(resolvedThresholds);
- if (this.options.thresholds?.autoUpdate && allTestsRun) {
- if (!this.ctx.vite.config.configFile) throw new Error("Missing configurationFile. The \"coverage.thresholds.autoUpdate\" can only be enabled when configuration file is used.");
- const configFilePath = this.ctx.vite.config.configFile;
- const configModule = await this.parseConfigModule(configFilePath);
- await this.updateThresholds({
- thresholds: resolvedThresholds,
- configurationFile: configModule,
- onUpdate: () => writeFileSync(configFilePath, configModule.generate().code, "utf-8")
- });
- }
- }
- /**
- * Constructs collected coverage and users' threshold options into separate sets
- * where each threshold set holds their own coverage maps. Threshold set is either
- * for specific files defined by glob pattern or global for all other files.
- */
- resolveThresholds(coverageMap) {
- const resolvedThresholds = [];
- const files = coverageMap.files();
- const globalCoverageMap = this.createCoverageMap();
- for (const key of Object.keys(this.options.thresholds)) {
- if (key === "perFile" || key === "autoUpdate" || key === "100" || THRESHOLD_KEYS.includes(key)) continue;
- const glob = key;
- const globThresholds = resolveGlobThresholds(this.options.thresholds[glob]);
- const globCoverageMap = this.createCoverageMap();
- const matcher = pm(glob);
- const matchingFiles = files.filter((file) => matcher(relative(this.ctx.config.root, file)));
- for (const file of matchingFiles) {
- const fileCoverage = coverageMap.fileCoverageFor(file);
- globCoverageMap.addFileCoverage(fileCoverage);
- }
- resolvedThresholds.push({
- name: glob,
- coverageMap: globCoverageMap,
- thresholds: globThresholds
- });
- }
- // Global threshold is for all files, even if they are included by glob patterns
- for (const file of files) {
- const fileCoverage = coverageMap.fileCoverageFor(file);
- globalCoverageMap.addFileCoverage(fileCoverage);
- }
- resolvedThresholds.unshift({
- name: GLOBAL_THRESHOLDS_KEY,
- coverageMap: globalCoverageMap,
- thresholds: {
- branches: this.options.thresholds?.branches,
- functions: this.options.thresholds?.functions,
- lines: this.options.thresholds?.lines,
- statements: this.options.thresholds?.statements
- }
- });
- return resolvedThresholds;
- }
- /**
- * Check collected coverage against configured thresholds. Sets exit code to 1 when thresholds not reached.
- */
- checkThresholds(allThresholds) {
- for (const { coverageMap, thresholds, name } of allThresholds) {
- if (thresholds.branches === void 0 && thresholds.functions === void 0 && thresholds.lines === void 0 && thresholds.statements === void 0) continue;
- // Construct list of coverage summaries where thresholds are compared against
- const summaries = this.options.thresholds?.perFile ? coverageMap.files().map((file) => ({
- file,
- summary: coverageMap.fileCoverageFor(file).toSummary()
- })) : [{
- file: null,
- summary: coverageMap.getCoverageSummary()
- }];
- // Check thresholds of each summary
- for (const { summary, file } of summaries) for (const thresholdKey of THRESHOLD_KEYS) {
- const threshold = thresholds[thresholdKey];
- if (threshold === void 0) continue;
- /**
- * Positive thresholds are treated as minimum coverage percentages (X means: X% of lines must be covered),
- * while negative thresholds are treated as maximum uncovered counts (-X means: X lines may be uncovered).
- */
- if (threshold >= 0) {
- const coverage = summary.data[thresholdKey].pct;
- if (coverage < threshold) {
- process.exitCode = 1;
- /**
- * Generate error message based on perFile flag:
- * - ERROR: Coverage for statements (33.33%) does not meet threshold (85%) for src/math.ts
- * - ERROR: Coverage for statements (50%) does not meet global threshold (85%)
- */
- let errorMessage = `ERROR: Coverage for ${thresholdKey} (${coverage}%) does not meet ${name === GLOBAL_THRESHOLDS_KEY ? name : `"${name}"`} threshold (${threshold}%)`;
- if (this.options.thresholds?.perFile && file) errorMessage += ` for ${relative("./", file).replace(/\\/g, "/")}`;
- this.ctx.logger.error(errorMessage);
- }
- } else {
- const uncovered = summary.data[thresholdKey].total - summary.data[thresholdKey].covered;
- const absoluteThreshold = threshold * -1;
- if (uncovered > absoluteThreshold) {
- process.exitCode = 1;
- /**
- * Generate error message based on perFile flag:
- * - ERROR: Uncovered statements (33) exceed threshold (30) for src/math.ts
- * - ERROR: Uncovered statements (33) exceed global threshold (30)
- */
- let errorMessage = `ERROR: Uncovered ${thresholdKey} (${uncovered}) exceed ${name === GLOBAL_THRESHOLDS_KEY ? name : `"${name}"`} threshold (${absoluteThreshold})`;
- if (this.options.thresholds?.perFile && file) errorMessage += ` for ${relative("./", file).replace(/\\/g, "/")}`;
- this.ctx.logger.error(errorMessage);
- }
- }
- }
- }
- }
- /**
- * Check if current coverage is above configured thresholds and bump the thresholds if needed
- */
- async updateThresholds({ thresholds: allThresholds, onUpdate, configurationFile }) {
- let updatedThresholds = false;
- const config = resolveConfig(configurationFile);
- assertConfigurationModule(config);
- for (const { coverageMap, thresholds, name } of allThresholds) {
- const summaries = this.options.thresholds?.perFile ? coverageMap.files().map((file) => coverageMap.fileCoverageFor(file).toSummary()) : [coverageMap.getCoverageSummary()];
- const thresholdsToUpdate = [];
- for (const key of THRESHOLD_KEYS) {
- const threshold = thresholds[key] ?? 100;
- /**
- * Positive thresholds are treated as minimum coverage percentages (X means: X% of lines must be covered),
- * while negative thresholds are treated as maximum uncovered counts (-X means: X lines may be uncovered).
- */
- if (threshold >= 0) {
- const actual = Math.min(...summaries.map((summary) => summary[key].pct));
- if (actual > threshold) thresholdsToUpdate.push([key, actual]);
- } else {
- const absoluteThreshold = threshold * -1;
- const actual = Math.max(...summaries.map((summary) => summary[key].total - summary[key].covered));
- if (actual < absoluteThreshold) {
- // If everything was covered, set new threshold to 100% (since a threshold of 0 would be considered as 0%)
- const updatedThreshold = actual === 0 ? 100 : actual * -1;
- thresholdsToUpdate.push([key, updatedThreshold]);
- }
- }
- }
- if (thresholdsToUpdate.length === 0) continue;
- updatedThresholds = true;
- const thresholdFormatter = typeof this.options.thresholds?.autoUpdate === "function" ? this.options.thresholds?.autoUpdate : (value) => value;
- for (const [threshold, newValue] of thresholdsToUpdate) {
- const formattedValue = thresholdFormatter(newValue);
- if (name === GLOBAL_THRESHOLDS_KEY) config.test.coverage.thresholds[threshold] = formattedValue;
- else {
- const glob = config.test.coverage.thresholds[name];
- glob[threshold] = formattedValue;
- }
- }
- }
- if (updatedThresholds) {
- this.ctx.logger.log("Updating thresholds to configuration file. You may want to push with updated coverage thresholds.");
- onUpdate();
- }
- }
- async mergeReports(coverageMaps) {
- const coverageMap = this.createCoverageMap();
- for (const coverage of coverageMaps) coverageMap.merge(coverage);
- await this.generateReports(coverageMap, true);
- }
- hasTerminalReporter(reporters) {
- return reporters.some(([reporter]) => reporter === "text" || reporter === "text-summary" || reporter === "text-lcov" || reporter === "teamcity");
- }
- toSlices(array, size) {
- return array.reduce((chunks, item) => {
- const index = Math.max(0, chunks.length - 1);
- const lastChunk = chunks[index] || [];
- chunks[index] = lastChunk;
- if (lastChunk.length >= size) chunks.push([item]);
- else lastChunk.push(item);
- return chunks;
- }, []);
- }
- createUncoveredFileTransformer(ctx) {
- const servers = [...ctx.projects.map((project) => ({
- root: project.config.root,
- isBrowserEnabled: project.isBrowserEnabled(),
- vite: project.vite
- })), (
- // Check core last as it will match all files anyway
- {
- root: ctx.config.root,
- vite: ctx.vite,
- isBrowserEnabled: ctx.getRootProject().isBrowserEnabled()
- })];
- return async function transformFile(filename) {
- let lastError;
- for (const { root, vite, isBrowserEnabled } of servers) {
- // On Windows root doesn't start with "/" while filenames do
- if (!filename.startsWith(root) && !filename.startsWith(`/${root}`)) continue;
- if (isBrowserEnabled) {
- const result = await vite.environments.client.transformRequest(filename).catch(() => null);
- if (result) return result;
- }
- try {
- return await vite.environments.ssr.transformRequest(filename);
- } catch (error) {
- lastError = error;
- }
- }
- // All vite-node servers failed to transform the file
- throw lastError;
- };
- }
-}
-/**
-* Narrow down `unknown` glob thresholds to resolved ones
-*/
-function resolveGlobThresholds(thresholds) {
- if (!thresholds || typeof thresholds !== "object") return {};
- if (100 in thresholds && thresholds[100] === true) return {
- lines: 100,
- branches: 100,
- functions: 100,
- statements: 100
- };
- return {
- lines: "lines" in thresholds && typeof thresholds.lines === "number" ? thresholds.lines : void 0,
- branches: "branches" in thresholds && typeof thresholds.branches === "number" ? thresholds.branches : void 0,
- functions: "functions" in thresholds && typeof thresholds.functions === "number" ? thresholds.functions : void 0,
- statements: "statements" in thresholds && typeof thresholds.statements === "number" ? thresholds.statements : void 0
- };
-}
-function assertConfigurationModule(config) {
- try {
- // @ts-expect-error -- Intentional unsafe null pointer check as wrapped in try-catch
- if (typeof config.test.coverage.thresholds !== "object") throw new TypeError("Expected config.test.coverage.thresholds to be an object");
- } catch (error) {
- const message = error instanceof Error ? error.message : String(error);
- throw new Error(`Unable to parse thresholds from configuration file: ${message}`);
- }
-}
-function resolveConfig(configModule) {
- const mod = configModule.exports.default;
- try {
- // Check for "export default { test: {...} }"
- if (mod.$type === "object") return mod;
- // "export default defineConfig(...)"
- let config = resolveDefineConfig(mod);
- if (config) return config;
- // "export default mergeConfig(..., defineConfig(...))"
- if (mod.$type === "function-call" && mod.$callee === "mergeConfig") {
- config = resolveMergeConfig(mod);
- if (config) return config;
- }
- } catch (error) {
- // Reduce magicast's verbose errors to readable ones
- throw new Error(error instanceof Error ? error.message : String(error));
- }
- throw new Error("Failed to update coverage thresholds. Configuration file is too complex.");
-}
-function resolveDefineConfig(mod) {
- if (mod.$type === "function-call" && mod.$callee === "defineConfig") {
- // "export default defineConfig({ test: {...} })"
- if (mod.$args[0].$type === "object") return mod.$args[0];
- if (mod.$args[0].$type === "arrow-function-expression") {
- if (mod.$args[0].$body.$type === "object")
- // "export default defineConfig(() => ({ test: {...} }))"
- return mod.$args[0].$body;
- // "export default defineConfig(() => mergeConfig({...}, ...))"
- const config = resolveMergeConfig(mod.$args[0].$body);
- if (config) return config;
- }
- }
-}
-function resolveMergeConfig(mod) {
- if (mod.$type === "function-call" && mod.$callee === "mergeConfig") for (const arg of mod.$args) {
- const config = resolveDefineConfig(arg);
- if (config) return config;
- }
-}
-
-export { BaseCoverageProvider as B, RandomSequencer as R, resolveApiServerConfig as a, BaseSequencer as b, isBrowserEnabled as c, resolveModule as d, getCoverageProvider as g, hash as h, isPackageExists as i, resolveConfig$1 as r };
diff --git a/vanilla/node_modules/vitest/dist/chunks/coverage.D_JHT54q.js b/vanilla/node_modules/vitest/dist/chunks/coverage.D_JHT54q.js
deleted file mode 100644
index 5df66c9..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/coverage.D_JHT54q.js
+++ /dev/null
@@ -1,25 +0,0 @@
-const CoverageProviderMap = {
- v8: "@vitest/coverage-v8",
- istanbul: "@vitest/coverage-istanbul"
-};
-async function resolveCoverageProviderModule(options, loader) {
- if (!options?.enabled || !options.provider) return null;
- const provider = options.provider;
- if (provider === "v8" || provider === "istanbul") {
- let builtInModule = CoverageProviderMap[provider];
- if (provider === "v8" && loader.isBrowser) builtInModule += "/browser";
- const { default: coverageModule } = await loader.import(builtInModule);
- if (!coverageModule) throw new Error(`Failed to load ${CoverageProviderMap[provider]}. Default export is missing.`);
- return coverageModule;
- }
- let customProviderModule;
- try {
- customProviderModule = await loader.import(options.customProviderModule);
- } catch (error) {
- throw new Error(`Failed to load custom CoverageProviderModule from ${options.customProviderModule}`, { cause: error });
- }
- if (customProviderModule.default == null) throw new Error(`Custom CoverageProviderModule loaded from ${options.customProviderModule} was not the default export`);
- return customProviderModule.default;
-}
-
-export { CoverageProviderMap as C, resolveCoverageProviderModule as r };
diff --git a/vanilla/node_modules/vitest/dist/chunks/coverage.d.BZtK59WP.d.ts b/vanilla/node_modules/vitest/dist/chunks/coverage.d.BZtK59WP.d.ts
deleted file mode 100644
index 2b4d853..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/coverage.d.BZtK59WP.d.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-interface RuntimeCoverageModuleLoader {
- import: (id: string) => Promise<{
- default: RuntimeCoverageProviderModule;
- }>;
- isBrowser?: boolean;
- moduleExecutionInfo?: Map<string, {
- startOffset: number;
- }>;
-}
-interface RuntimeCoverageProviderModule {
- /**
- * Factory for creating a new coverage provider
- */
- getProvider: () => any;
- /**
- * Executed before tests are run in the worker thread.
- */
- startCoverage?: (runtimeOptions: {
- isolate: boolean;
- }) => unknown | Promise<unknown>;
- /**
- * Executed on after each run in the worker thread. Possible to return a payload passed to the provider
- */
- takeCoverage?: (runtimeOptions?: {
- moduleExecutionInfo?: Map<string, {
- startOffset: number;
- }>;
- }) => unknown | Promise<unknown>;
- /**
- * Executed after all tests have been run in the worker thread.
- */
- stopCoverage?: (runtimeOptions: {
- isolate: boolean;
- }) => unknown | Promise<unknown>;
-}
-
-export type { RuntimeCoverageModuleLoader as R, RuntimeCoverageProviderModule as a };
diff --git a/vanilla/node_modules/vitest/dist/chunks/creator.DAmOKTvJ.js b/vanilla/node_modules/vitest/dist/chunks/creator.DAmOKTvJ.js
deleted file mode 100644
index 1d47182..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/creator.DAmOKTvJ.js
+++ /dev/null
@@ -1,673 +0,0 @@
-import { existsSync, writeFileSync, readFileSync } from 'node:fs';
-import { mkdir, writeFile } from 'node:fs/promises';
-import { resolve, dirname, relative } from 'node:path';
-import { detectPackageManager, installPackage } from './index.D3XRDfWc.js';
-import { p as prompt, a as any } from './index.D4KonVSU.js';
-import { x } from 'tinyexec';
-import c from 'tinyrainbow';
-import { c as configFiles } from './constants.D_Q9UYh-.js';
-import 'node:process';
-import 'node:module';
-import 'node:url';
-import './_commonjsHelpers.D26ty3Ew.js';
-import 'readline';
-import 'events';
-
-const jsxExample = {
- name: "HelloWorld.jsx",
- js: `
-export default function HelloWorld({ name }) {
- return (
- <div>
- <h1>Hello {name}!</h1>
- </div>
- )
-}
-`,
- ts: `
-export default function HelloWorld({ name }: { name: string }) {
- return (
- <div>
- <h1>Hello {name}!</h1>
- </div>
- )
-}
-`,
- test: `
-import { expect, test } from 'vitest'
-import { render } from '@testing-library/jsx'
-import HelloWorld from './HelloWorld.<EXT>x'
-
-test('renders name', async () => {
- const { getByText } = await render(<HelloWorld name="Vitest" />)
- await expect.element(getByText('Hello Vitest!')).toBeInTheDocument()
-})
-`
-};
-const vueExample = {
- name: "HelloWorld.vue",
- js: `
-<script setup>
-defineProps({
- name: String
-})
-<\/script>
-
-<template>
- <div>
- <h1>Hello {{ name }}!</h1>
- </div>
-</template>
-`,
- ts: `
-<script setup lang="ts">
-defineProps<{
- name: string
-}>()
-<\/script>
-
-<template>
- <div>
- <h1>Hello {{ name }}!</h1>
- </div>
-</template>
-`,
- test: `
-import { expect, test } from 'vitest'
-import { render } from 'vitest-browser-vue'
-import HelloWorld from './HelloWorld.vue'
-
-test('renders name', async () => {
- const { getByText } = render(HelloWorld, {
- props: { name: 'Vitest' },
- })
- await expect.element(getByText('Hello Vitest!')).toBeInTheDocument()
-})
-`
-};
-const svelteExample = {
- name: "HelloWorld.svelte",
- js: `
-<script>
- export let name
-<\/script>
-
-<h1>Hello {name}!</h1>
-`,
- ts: `
-<script lang="ts">
- export let name: string
-<\/script>
-
-<h1>Hello {name}!</h1>
-`,
- test: `
-import { expect, test } from 'vitest'
-import { render } from 'vitest-browser-svelte'
-import HelloWorld from './HelloWorld.svelte'
-
-test('renders name', async () => {
- const { getByText } = render(HelloWorld, { name: 'Vitest' })
- await expect.element(getByText('Hello Vitest!')).toBeInTheDocument()
-})
-`
-};
-const markoExample = {
- name: "HelloWorld.marko",
- js: `
-class {
- onCreate() {
- this.state = { name: null }
- }
-}
-
-<h1>Hello \${state.name}!</h1>
-`,
- ts: `
-export interface Input {
- name: string
-}
-
-<h1>Hello \${input.name}!</h1>
-`,
- test: `
-import { expect, test } from 'vitest'
-import { render } from '@marko/testing-library'
-import HelloWorld from './HelloWorld.svelte'
-
-test('renders name', async () => {
- const { getByText } = await render(HelloWorld, { name: 'Vitest' })
- const element = getByText('Hello Vitest!')
- expect(element).toBeInTheDocument()
-})
-`
-};
-const litExample = {
- name: "HelloWorld.js",
- js: `
-import { html, LitElement } from 'lit'
-
-export class HelloWorld extends LitElement {
- static properties = {
- name: { type: String },
- }
-
- constructor() {
- super()
- this.name = 'World'
- }
-
- render() {
- return html\`<h1>Hello \${this.name}!</h1>\`
- }
-}
-
-customElements.define('hello-world', HelloWorld)
-`,
- ts: `
-import { html, LitElement } from 'lit'
-import { customElement, property } from 'lit/decorators.js'
-
-@customElement('hello-world')
-export class HelloWorld extends LitElement {
- @property({ type: String })
- name = 'World'
-
- render() {
- return html\`<h1>Hello \${this.name}!</h1>\`
- }
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- 'hello-world': HelloWorld
- }
-}
-`,
- test: `
-import { expect, test } from 'vitest'
-import { render } from 'vitest-browser-lit'
-import { html } from 'lit'
-import './HelloWorld.js'
-
-test('renders name', async () => {
- const screen = render(html\`<hello-world name="Vitest"></hello-world>\`)
- const element = screen.getByText('Hello Vitest!')
- await expect.element(element).toBeInTheDocument()
-})
-`
-};
-const qwikExample = {
- name: "HelloWorld.jsx",
- js: `
-import { component$ } from '@builder.io/qwik'
-
-export default component$(({ name }) => {
- return (
- <div>
- <h1>Hello {name}!</h1>
- </div>
- )
-})
-`,
- ts: `
-import { component$ } from '@builder.io/qwik'
-
-export default component$(({ name }: { name: string }) => {
- return (
- <div>
- <h1>Hello {name}!</h1>
- </div>
- )
-})
-`,
- test: `
-import { expect, test } from 'vitest'
-import { render } from 'vitest-browser-qwik'
-import HelloWorld from './HelloWorld.tsx'
-
-test('renders name', async () => {
- const { getByText } = render(<HelloWorld name="Vitest" />)
- await expect.element(getByText('Hello Vitest!')).toBeInTheDocument()
-})
-`
-};
-const vanillaExample = {
- name: "HelloWorld.js",
- js: `
-export default function HelloWorld({ name }) {
- const parent = document.createElement('div')
-
- const h1 = document.createElement('h1')
- h1.textContent = 'Hello ' + name + '!'
- parent.appendChild(h1)
-
- return parent
-}
-`,
- ts: `
-export default function HelloWorld({ name }: { name: string }): HTMLDivElement {
- const parent = document.createElement('div')
-
- const h1 = document.createElement('h1')
- h1.textContent = 'Hello ' + name + '!'
- parent.appendChild(h1)
-
- return parent
-}
-`,
- test: `
-import { expect, test } from 'vitest'
-import { getByText } from '@testing-library/dom'
-import HelloWorld from './HelloWorld.js'
-
-test('renders name', () => {
- const parent = HelloWorld({ name: 'Vitest' })
- document.body.appendChild(parent)
-
- const element = getByText(parent, 'Hello Vitest!')
- expect(element).toBeInTheDocument()
-})
-`
-};
-function getExampleTest(framework) {
- switch (framework) {
- case "solid": return {
- ...jsxExample,
- test: jsxExample.test.replace("@testing-library/jsx", `@testing-library/${framework}`)
- };
- case "preact":
- case "react": return {
- ...jsxExample,
- test: jsxExample.test.replace("@testing-library/jsx", `vitest-browser-${framework}`)
- };
- case "vue": return vueExample;
- case "svelte": return svelteExample;
- case "lit": return litExample;
- case "marko": return markoExample;
- case "qwik": return qwikExample;
- default: return vanillaExample;
- }
-}
-async function generateExampleFiles(framework, lang) {
- const example = getExampleTest(framework);
- let fileName = example.name;
- const folder = resolve(process.cwd(), "vitest-example");
- const fileContent = example[lang];
- if (!existsSync(folder)) await mkdir(folder, { recursive: true });
- const isJSX = fileName.endsWith(".jsx");
- if (isJSX && lang === "ts") fileName = fileName.replace(".jsx", ".tsx");
- else if (fileName.endsWith(".js") && lang === "ts") fileName = fileName.replace(".js", ".ts");
- example.test = example.test.replace("<EXT>", lang);
- const filePath = resolve(folder, fileName);
- const testPath = resolve(folder, `HelloWorld.test.${isJSX ? `${lang}x` : lang}`);
- writeFileSync(filePath, fileContent.trimStart(), "utf-8");
- writeFileSync(testPath, example.test.trimStart(), "utf-8");
- return testPath;
-}
-
-// eslint-disable-next-line no-console
-const log = console.log;
-function getProviderOptions() {
- return Object.entries({
- playwright: "Playwright relies on Chrome DevTools protocol. Read more: https://playwright.dev",
- webdriverio: "WebdriverIO uses WebDriver protocol. Read more: https://webdriver.io",
- preview: "Preview is useful to quickly run your tests in the browser, but not suitable for CI."
- }).map(([provider, description]) => {
- return {
- title: provider,
- description,
- value: provider
- };
- });
-}
-function getBrowserNames(provider) {
- switch (provider) {
- case "webdriverio": return [
- "chrome",
- "firefox",
- "edge",
- "safari"
- ];
- case "playwright": return [
- "chromium",
- "firefox",
- "webkit"
- ];
- case "preview": return [
- "chrome",
- "firefox",
- "safari"
- ];
- }
-}
-function getFramework() {
- return [
- {
- title: "vanilla",
- value: "vanilla",
- description: "No framework, just plain JavaScript or TypeScript."
- },
- {
- title: "vue",
- value: "vue",
- description: "\"The Progressive JavaScript Framework\""
- },
- {
- title: "svelte",
- value: "svelte",
- description: "\"Svelte: cybernetically enhanced web apps\""
- },
- {
- title: "react",
- value: "react",
- description: "\"The library for web and native user interfaces\""
- },
- {
- title: "lit",
- value: "lit",
- description: "\"A simple library for building fast, lightweight web components.\""
- },
- {
- title: "preact",
- value: "preact",
- description: "\"Fast 3kB alternative to React with the same modern API\""
- },
- {
- title: "solid",
- value: "solid",
- description: "\"Simple and performant reactivity for building user interfaces\""
- },
- {
- title: "marko",
- value: "marko",
- description: "\"A declarative, HTML-based language that makes building web apps fun\""
- },
- {
- title: "qwik",
- value: "qwik",
- description: "\"Instantly interactive web apps at scale\""
- }
- ];
-}
-function getFrameworkTestPackage(framework) {
- switch (framework) {
- case "vanilla": return null;
- case "vue": return "vitest-browser-vue";
- case "svelte": return "vitest-browser-svelte";
- case "react": return "vitest-browser-react";
- case "lit": return "vitest-browser-lit";
- case "preact": return "vitest-browser-preact";
- case "solid": return "@solidjs/testing-library";
- case "marko": return "@marko/testing-library";
- case "qwik": return "vitest-browser-qwik";
- }
- throw new Error(`Unsupported framework: ${framework}`);
-}
-function getFrameworkPluginPackage(framework) {
- switch (framework) {
- case "vue": return "@vitejs/plugin-vue";
- case "svelte": return "@sveltejs/vite-plugin-svelte";
- case "react": return "@vitejs/plugin-react";
- case "preact": return "@preact/preset-vite";
- case "solid": return "vite-plugin-solid";
- case "marko": return "@marko/vite";
- case "qwik": return "@builder.io/qwik/optimizer";
- }
- return null;
-}
-function getLanguageOptions() {
- return [{
- title: "TypeScript",
- description: "Use TypeScript.",
- value: "ts"
- }, {
- title: "JavaScript",
- description: "Use plain JavaScript.",
- value: "js"
- }];
-}
-async function installPackages(pkgManager, packages) {
- if (!packages.length) {
- log(c.green("✔"), c.bold("All packages are already installed."));
- return;
- }
- log(c.cyan("◼"), c.bold("Installing packages..."));
- log(c.cyan("◼"), packages.join(", "));
- log();
- await installPackage(packages, {
- dev: true,
- packageManager: pkgManager ?? void 0
- });
-}
-function readPkgJson(path) {
- if (!existsSync(path)) return null;
- const content = readFileSync(path, "utf-8");
- return JSON.parse(content);
-}
-function getPossibleDefaults(dependencies) {
- return {
- lang: "ts",
- provider: getPossibleProvider(dependencies),
- framework: getPossibleFramework(dependencies)
- };
-}
-function getPossibleFramework(dependencies) {
- if (dependencies.vue || dependencies["vue-tsc"] || dependencies["@vue/reactivity"]) return "vue";
- if (dependencies.react || dependencies["react-dom"]) return "react";
- if (dependencies.svelte || dependencies["@sveltejs/kit"]) return "svelte";
- if (dependencies.lit || dependencies["lit-html"]) return "lit";
- if (dependencies.preact) return "preact";
- if (dependencies["solid-js"] || dependencies["@solidjs/start"]) return "solid";
- if (dependencies.marko) return "marko";
- if (dependencies["@builder.io/qwik"] || dependencies["@qwik.dev/core"]) return "qwik";
- return "vanilla";
-}
-function getPossibleProvider(dependencies) {
- if (dependencies.webdriverio || dependencies["@wdio/cli"] || dependencies["@wdio/config"]) return "webdriverio";
- // playwright is the default recommendation
- return "playwright";
-}
-function getProviderDocsLink(provider) {
- switch (provider) {
- case "playwright": return "https://vitest.dev/config/browser/playwright";
- case "webdriverio": return "https://vitest.dev/config/browser/webdriverio";
- }
-}
-function sort(choices, value) {
- const index = choices.findIndex((i) => i.value === value);
- if (index === -1) return choices;
- return [choices.splice(index, 1)[0], ...choices];
-}
-function fail() {
- process.exitCode = 1;
-}
-function getFrameworkImportInfo(framework) {
- switch (framework) {
- case "svelte": return {
- importName: "svelte",
- isNamedExport: true
- };
- case "qwik": return {
- importName: "qwikVite",
- isNamedExport: true
- };
- default: return {
- importName: framework,
- isNamedExport: false
- };
- }
-}
-async function generateFrameworkConfigFile(options) {
- const { importName, isNamedExport } = getFrameworkImportInfo(options.framework);
- const frameworkImport = isNamedExport ? `import { ${importName} } from '${options.frameworkPlugin}'` : `import ${importName} from '${options.frameworkPlugin}'`;
- const configContent = [
- `import { defineConfig } from 'vitest/config'`,
- `import { ${options.provider} } from '@vitest/browser-${options.provider}'`,
- options.frameworkPlugin ? frameworkImport : null,
- ``,
- "export default defineConfig({",
- options.frameworkPlugin ? ` plugins: [${importName}()],` : null,
- ` test: {`,
- ` browser: {`,
- ` enabled: true,`,
- ` provider: ${options.provider}(),`,
- options.provider !== "preview" && ` // ${getProviderDocsLink(options.provider)}`,
- ` instances: [`,
- ...options.browsers.map((browser) => ` { browser: '${browser}' },`),
- ` ],`,
- ` },`,
- ` },`,
- `})`,
- ""
- ].filter((t) => typeof t === "string").join("\n");
- await writeFile(options.configPath, configContent);
-}
-async function updatePkgJsonScripts(pkgJsonPath, vitestScript) {
- if (!existsSync(pkgJsonPath)) {
- const pkg = { scripts: { "test:browser": vitestScript } };
- await writeFile(pkgJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, "utf-8");
- } else {
- const pkg = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
- pkg.scripts = pkg.scripts || {};
- pkg.scripts["test:browser"] = vitestScript;
- await writeFile(pkgJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, "utf-8");
- }
- log(c.green("✔"), "Added \"test:browser\" script to your package.json.");
-}
-function getRunScript(pkgManager) {
- switch (pkgManager) {
- case "yarn@berry":
- case "yarn": return "yarn test:browser";
- case "pnpm@6":
- case "pnpm": return "pnpm test:browser";
- case "bun": return "bun test:browser";
- default: return "npm run test:browser";
- }
-}
-function getPlaywrightRunArgs(pkgManager) {
- switch (pkgManager) {
- case "yarn@berry":
- case "yarn": return ["yarn", "exec"];
- case "pnpm@6":
- case "pnpm": return ["pnpx"];
- case "bun": return ["bunx"];
- default: return ["npx"];
- }
-}
-async function create() {
- log(c.cyan("◼"), "This utility will help you set up a browser testing environment.\n");
- const pkgJsonPath = resolve(process.cwd(), "package.json");
- const pkg = readPkgJson(pkgJsonPath) || {};
- const dependencies = {
- ...pkg.dependencies,
- ...pkg.devDependencies
- };
- const defaults = getPossibleDefaults(dependencies);
- const { lang } = await prompt({
- type: "select",
- name: "lang",
- message: "Choose a language for your tests",
- choices: sort(getLanguageOptions(), defaults?.lang)
- });
- if (!lang) return fail();
- const { provider } = await prompt({
- type: "select",
- name: "provider",
- message: "Choose a browser provider. Vitest will use its API to control the testing environment",
- choices: sort(getProviderOptions(), defaults?.provider)
- });
- if (!provider) return fail();
- const { browsers } = await prompt({
- type: "multiselect",
- name: "browsers",
- message: "Choose a browser",
- choices: getBrowserNames(provider).map((browser) => ({
- title: browser,
- value: browser
- }))
- });
- if (!provider) return fail();
- const { framework } = await prompt({
- type: "select",
- name: "framework",
- message: "Choose your framework",
- choices: sort(getFramework(), defaults?.framework)
- });
- if (!framework) return fail();
- let installPlaywright = false;
- if (provider === "playwright") ({installPlaywright} = await prompt({
- type: "confirm",
- name: "installPlaywright",
- message: `Install Playwright browsers (can be done manually via 'pnpm exec playwright install')?`
- }));
- if (installPlaywright == null) return fail();
- const dependenciesToInstall = [`@vitest/browser-${provider}`];
- const frameworkPackage = getFrameworkTestPackage(framework);
- if (frameworkPackage) dependenciesToInstall.push(frameworkPackage);
- const frameworkPlugin = getFrameworkPluginPackage(framework);
- if (frameworkPlugin) dependenciesToInstall.push(frameworkPlugin);
- const pkgManager = await detectPackageManager();
- log();
- await installPackages(pkgManager, dependenciesToInstall.filter((pkg) => !dependencies[pkg]));
- const rootConfig = any(configFiles, { cwd: process.cwd() });
- let scriptCommand = "vitest";
- log();
- if (rootConfig) {
- const configPath = resolve(dirname(rootConfig), `vitest.browser.config.${lang}`);
- scriptCommand = `vitest --config=${relative(process.cwd(), configPath)}`;
- await generateFrameworkConfigFile({
- configPath,
- framework,
- frameworkPlugin,
- provider,
- browsers
- });
- log(
- c.green("✔"),
- "Created a new config file for browser tests:",
- c.bold(relative(process.cwd(), configPath)),
- // TODO: Can we modify the config ourselves?
- "\nSince you already have a Vitest config file, it is recommended to copy the contents of the new file ",
- "into your existing config located at ",
- c.bold(relative(process.cwd(), rootConfig))
- );
- } else {
- const configPath = resolve(process.cwd(), `vitest.config.${lang}`);
- await generateFrameworkConfigFile({
- configPath,
- framework,
- frameworkPlugin,
- provider,
- browsers
- });
- log(c.green("✔"), "Created a config file for browser tests:", c.bold(relative(process.cwd(), configPath)));
- }
- log();
- await updatePkgJsonScripts(pkgJsonPath, scriptCommand);
- if (installPlaywright) {
- log();
- const [command, ...args] = getPlaywrightRunArgs(pkgManager);
- const allArgs = [
- ...args,
- "playwright",
- "install",
- "--with-deps"
- ];
- log(c.cyan("◼"), `Installing Playwright dependencies with \`${c.bold(command)} ${c.bold(allArgs.join(" "))}\`...`);
- log();
- await x(command, allArgs, { nodeOptions: { stdio: [
- "pipe",
- "inherit",
- "inherit"
- ] } });
- }
- log();
- const exampleTestFile = await generateExampleFiles(framework, lang);
- log(c.green("✔"), "Created example test file in", c.bold(relative(process.cwd(), exampleTestFile)));
- log(c.dim(" You can safely delete this file once you have written your own tests."));
- log();
- log(c.cyan("◼"), "All done! Run your tests with", c.bold(getRunScript(pkgManager)));
-}
-
-export { create };
diff --git a/vanilla/node_modules/vitest/dist/chunks/date.Bq6ZW5rf.js b/vanilla/node_modules/vitest/dist/chunks/date.Bq6ZW5rf.js
deleted file mode 100644
index 8bd2322..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/date.Bq6ZW5rf.js
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Ported from https://github.com/boblauer/MockDate/blob/master/src/mockdate.ts */
-/*
-The MIT License (MIT)
-
-Copyright (c) 2014 Bob Lauer
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-const RealDate = Date;
-let now = null;
-class MockDate extends RealDate {
- constructor(y, m, d, h, M, s, ms) {
- super();
- let date;
- switch (arguments.length) {
- case 0:
- if (now !== null) date = new RealDate(now.valueOf());
- else date = new RealDate();
- break;
- case 1:
- date = new RealDate(y);
- break;
- default:
- d = typeof d === "undefined" ? 1 : d;
- h = h || 0;
- M = M || 0;
- s = s || 0;
- ms = ms || 0;
- date = new RealDate(y, m, d, h, M, s, ms);
- break;
- }
- Object.setPrototypeOf(date, MockDate.prototype);
- return date;
- }
-}
-MockDate.UTC = RealDate.UTC;
-MockDate.now = function() {
- return new MockDate().valueOf();
-};
-MockDate.parse = function(dateString) {
- return RealDate.parse(dateString);
-};
-MockDate.toString = function() {
- return RealDate.toString();
-};
-function mockDate(date) {
- const dateObj = new RealDate(date.valueOf());
- if (Number.isNaN(dateObj.getTime())) throw new TypeError(`mockdate: The time set is an invalid date: ${date}`);
- // @ts-expect-error global
- globalThis.Date = MockDate;
- now = dateObj.valueOf();
-}
-function resetDate() {
- globalThis.Date = RealDate;
-}
-
-export { RealDate as R, mockDate as m, resetDate as r };
diff --git a/vanilla/node_modules/vitest/dist/chunks/defaults.BOqNVLsY.js b/vanilla/node_modules/vitest/dist/chunks/defaults.BOqNVLsY.js
deleted file mode 100644
index 54c6bd5..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/defaults.BOqNVLsY.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import nodeos__default from 'node:os';
-import './env.D4Lgay0q.js';
-import { isCI } from 'std-env';
-
-const defaultInclude = ["**/*.{test,spec}.?(c|m)[jt]s?(x)"];
-const defaultExclude = ["**/node_modules/**", "**/.git/**"];
-const benchmarkConfigDefaults = {
- include: ["**/*.{bench,benchmark}.?(c|m)[jt]s?(x)"],
- exclude: defaultExclude,
- includeSource: [],
- reporters: ["default"],
- includeSamples: false
-};
-// These are the generic defaults for coverage. Providers may also set some provider specific defaults.
-const coverageConfigDefaults = {
- provider: "v8",
- enabled: false,
- clean: true,
- cleanOnRerun: true,
- reportsDirectory: "./coverage",
- exclude: [],
- reportOnFailure: false,
- reporter: [
- ["text", {}],
- ["html", {}],
- ["clover", {}],
- ["json", {}]
- ],
- allowExternal: false,
- excludeAfterRemap: false,
- processingConcurrency: Math.min(20, nodeos__default.availableParallelism?.() ?? nodeos__default.cpus().length)
-};
-const fakeTimersDefaults = {
- loopLimit: 1e4,
- shouldClearNativeTimers: true
-};
-const configDefaults = Object.freeze({
- allowOnly: !isCI,
- isolate: true,
- watch: !isCI && process.stdin.isTTY,
- globals: false,
- environment: "node",
- clearMocks: false,
- restoreMocks: false,
- mockReset: false,
- unstubGlobals: false,
- unstubEnvs: false,
- include: defaultInclude,
- exclude: defaultExclude,
- teardownTimeout: 1e4,
- forceRerunTriggers: ["**/package.json/**", "**/{vitest,vite}.config.*/**"],
- update: false,
- reporters: [],
- silent: false,
- hideSkippedTests: false,
- api: false,
- ui: false,
- uiBase: "/__vitest__/",
- open: !isCI,
- css: { include: [] },
- coverage: coverageConfigDefaults,
- fakeTimers: fakeTimersDefaults,
- maxConcurrency: 5,
- dangerouslyIgnoreUnhandledErrors: false,
- typecheck: {
- checker: "tsc",
- include: ["**/*.{test,spec}-d.?(c|m)[jt]s?(x)"],
- exclude: defaultExclude
- },
- slowTestThreshold: 300,
- disableConsoleIntercept: false
-});
-
-export { coverageConfigDefaults as a, defaultInclude as b, configDefaults as c, defaultExclude as d, benchmarkConfigDefaults as e };
diff --git a/vanilla/node_modules/vitest/dist/chunks/env.D4Lgay0q.js b/vanilla/node_modules/vitest/dist/chunks/env.D4Lgay0q.js
deleted file mode 100644
index f3389f0..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/env.D4Lgay0q.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import { isCI } from 'std-env';
-
-const isNode = typeof process < "u" && typeof process.stdout < "u" && !process.versions?.deno && !globalThis.window;
-const isDeno = typeof process < "u" && typeof process.stdout < "u" && process.versions?.deno !== void 0;
-const isWindows = (isNode || isDeno) && process.platform === "win32";
-const isTTY = (isNode || isDeno) && process.stdout?.isTTY && !isCI;
-
-export { isWindows as a, isTTY as i };
diff --git a/vanilla/node_modules/vitest/dist/chunks/environment.d.CrsxCzP1.d.ts b/vanilla/node_modules/vitest/dist/chunks/environment.d.CrsxCzP1.d.ts
deleted file mode 100644
index 162cf76..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/environment.d.CrsxCzP1.d.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { Awaitable } from '@vitest/utils';
-
-interface EnvironmentReturn {
- teardown: (global: any) => Awaitable<void>;
-}
-interface VmEnvironmentReturn {
- getVmContext: () => {
- [key: string]: any;
- };
- teardown: () => Awaitable<void>;
-}
-interface Environment {
- name: string;
- /**
- * @deprecated use `viteEnvironment` instead. Uses `name` by default
- */
- transformMode?: "web" | "ssr";
- /**
- * Environment initiated by the Vite server. It is usually available
- * as `vite.server.environments.${name}`.
- *
- * By default, fallbacks to `name`.
- */
- viteEnvironment?: "client" | "ssr" | ({} & string);
- setupVM?: (options: Record<string, any>) => Awaitable<VmEnvironmentReturn>;
- setup: (global: any, options: Record<string, any>) => Awaitable<EnvironmentReturn>;
-}
-
-export type { Environment as E, VmEnvironmentReturn as V, EnvironmentReturn as a };
diff --git a/vanilla/node_modules/vitest/dist/chunks/evaluatedModules.Dg1zASAC.js b/vanilla/node_modules/vitest/dist/chunks/evaluatedModules.Dg1zASAC.js
deleted file mode 100644
index e2905f0..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/evaluatedModules.Dg1zASAC.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import { dirname, resolve } from 'pathe';
-import { EvaluatedModules } from 'vite/module-runner';
-
-// TODO: this is not needed in Vite 7.2+
-class VitestEvaluatedModules extends EvaluatedModules {
- getModuleSourceMapById(id) {
- const map = super.getModuleSourceMapById(id);
- if (map != null && !("_patched" in map)) {
- map._patched = true;
- const dir = dirname(map.url);
- map.resolvedSources = (map.map.sources || []).map((s) => resolve(dir, s || ""));
- }
- return map;
- }
-}
-
-export { VitestEvaluatedModules as V };
diff --git a/vanilla/node_modules/vitest/dist/chunks/evaluatedModules.d.BxJ5omdx.d.ts b/vanilla/node_modules/vitest/dist/chunks/evaluatedModules.d.BxJ5omdx.d.ts
deleted file mode 100644
index 970d151..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/evaluatedModules.d.BxJ5omdx.d.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { EvaluatedModules } from 'vite/module-runner';
-
-declare class VitestEvaluatedModules extends EvaluatedModules {
- getModuleSourceMapById(id: string): any;
-}
-
-export { VitestEvaluatedModules as V };
diff --git a/vanilla/node_modules/vitest/dist/chunks/git.Bm2pzPAa.js b/vanilla/node_modules/vitest/dist/chunks/git.Bm2pzPAa.js
deleted file mode 100644
index cc3c0a1..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/git.Bm2pzPAa.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import { resolve } from 'pathe';
-import { x } from 'tinyexec';
-
-class VitestGit {
- root;
- constructor(cwd) {
- this.cwd = cwd;
- }
- async resolveFilesWithGitCommand(args) {
- let result;
- try {
- result = await x("git", args, { nodeOptions: { cwd: this.root } });
- } catch (e) {
- e.message = e.stderr;
- throw e;
- }
- return result.stdout.split("\n").filter((s) => s !== "").map((changedPath) => resolve(this.root, changedPath));
- }
- async findChangedFiles(options) {
- const root = await this.getRoot(this.cwd);
- if (!root) return null;
- this.root = root;
- const changedSince = options.changedSince;
- if (typeof changedSince === "string") {
- const [committed, staged, unstaged] = await Promise.all([
- this.getFilesSince(changedSince),
- this.getStagedFiles(),
- this.getUnstagedFiles()
- ]);
- return [
- ...committed,
- ...staged,
- ...unstaged
- ];
- }
- const [staged, unstaged] = await Promise.all([this.getStagedFiles(), this.getUnstagedFiles()]);
- return [...staged, ...unstaged];
- }
- getFilesSince(hash) {
- return this.resolveFilesWithGitCommand([
- "diff",
- "--name-only",
- `${hash}...HEAD`
- ]);
- }
- getStagedFiles() {
- return this.resolveFilesWithGitCommand([
- "diff",
- "--cached",
- "--name-only"
- ]);
- }
- getUnstagedFiles() {
- return this.resolveFilesWithGitCommand([
- "ls-files",
- "--other",
- "--modified",
- "--exclude-standard"
- ]);
- }
- async getRoot(cwd) {
- const args = ["rev-parse", "--show-cdup"];
- try {
- return resolve(cwd, (await x("git", args, { nodeOptions: { cwd } })).stdout.trim());
- } catch {
- return null;
- }
- }
-}
-
-export { VitestGit };
diff --git a/vanilla/node_modules/vitest/dist/chunks/global.d.B15mdLcR.d.ts b/vanilla/node_modules/vitest/dist/chunks/global.d.B15mdLcR.d.ts
deleted file mode 100644
index 17d0167..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/global.d.B15mdLcR.d.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-import { PromisifyAssertion, Tester, ExpectStatic } from '@vitest/expect';
-import { Plugin } from '@vitest/pretty-format';
-import { SnapshotState } from '@vitest/snapshot';
-import { B as BenchmarkResult } from './benchmark.d.DAaHLpsq.js';
-import { U as UserConsoleLog } from './rpc.d.RH3apGEf.js';
-
-interface SnapshotMatcher<T> {
- <U extends { [P in keyof T] : any }>(snapshot: Partial<U>, hint?: string): void;
- (hint?: string): void;
-}
-interface InlineSnapshotMatcher<T> {
- <U extends { [P in keyof T] : any }>(properties: Partial<U>, snapshot?: string, hint?: string): void;
- (hint?: string): void;
-}
-declare module "@vitest/expect" {
- interface MatcherState {
- environment: string;
- snapshotState: SnapshotState;
- }
- interface ExpectPollOptions {
- interval?: number;
- timeout?: number;
- message?: string;
- }
- interface ExpectStatic {
- assert: Chai.AssertStatic;
- unreachable: (message?: string) => never;
- soft: <T>(actual: T, message?: string) => Assertion<T>;
- poll: <T>(actual: () => T, options?: ExpectPollOptions) => PromisifyAssertion<Awaited<T>>;
- addEqualityTesters: (testers: Array<Tester>) => void;
- assertions: (expected: number) => void;
- hasAssertions: () => void;
- addSnapshotSerializer: (plugin: Plugin) => void;
- }
- interface Assertion<T> {
- matchSnapshot: SnapshotMatcher<T>;
- toMatchSnapshot: SnapshotMatcher<T>;
- toMatchInlineSnapshot: InlineSnapshotMatcher<T>;
- /**
- * Checks that an error thrown by a function matches a previously recorded snapshot.
- *
- * @param hint - Optional custom error message.
- *
- * @example
- * expect(functionWithError).toThrowErrorMatchingSnapshot();
- */
- toThrowErrorMatchingSnapshot: (hint?: string) => void;
- /**
- * Checks that an error thrown by a function matches an inline snapshot within the test file.
- * Useful for keeping snapshots close to the test code.
- *
- * @param snapshot - Optional inline snapshot string to match.
- * @param hint - Optional custom error message.
- *
- * @example
- * const throwError = () => { throw new Error('Error occurred') };
- * expect(throwError).toThrowErrorMatchingInlineSnapshot(`"Error occurred"`);
- */
- toThrowErrorMatchingInlineSnapshot: (snapshot?: string, hint?: string) => void;
- /**
- * Compares the received value to a snapshot saved in a specified file.
- * Useful for cases where snapshot content is large or needs to be shared across tests.
- *
- * @param filepath - Path to the snapshot file.
- * @param hint - Optional custom error message.
- *
- * @example
- * await expect(largeData).toMatchFileSnapshot('path/to/snapshot.json');
- */
- toMatchFileSnapshot: (filepath: string, hint?: string) => Promise<void>;
- }
-}
-declare module "@vitest/runner" {
- interface TestContext {
- /**
- * `expect` instance bound to the current test.
- *
- * This API is useful for running snapshot tests concurrently because global expect cannot track them.
- */
- readonly expect: ExpectStatic;
- /** @internal */
- _local: boolean;
- }
- interface TaskMeta {
- typecheck?: boolean;
- benchmark?: boolean;
- failScreenshotPath?: string;
- }
- interface File {
- prepareDuration?: number;
- environmentLoad?: number;
- }
- interface TaskBase {
- logs?: UserConsoleLog[];
- }
- interface TaskResult {
- benchmark?: BenchmarkResult;
- }
-}
diff --git a/vanilla/node_modules/vitest/dist/chunks/globals.DOayXfHP.js b/vanilla/node_modules/vitest/dist/chunks/globals.DOayXfHP.js
deleted file mode 100644
index a92fa3f..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/globals.DOayXfHP.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import { g as globalApis } from './constants.D_Q9UYh-.js';
-import { i as index } from './index.Z5E_ObnR.js';
-import './vi.2VT5v0um.js';
-import '@vitest/expect';
-import '@vitest/runner';
-import './utils.DvEY5TfP.js';
-import '@vitest/utils/timers';
-import '@vitest/runner/utils';
-import '@vitest/snapshot';
-import '@vitest/utils/error';
-import '@vitest/utils/helpers';
-import '@vitest/spy';
-import '@vitest/utils/offset';
-import '@vitest/utils/source-map';
-import './_commonjsHelpers.D26ty3Ew.js';
-import './date.Bq6ZW5rf.js';
-import './benchmark.B3N2zMcH.js';
-import './evaluatedModules.Dg1zASAC.js';
-import 'pathe';
-import 'vite/module-runner';
-import 'expect-type';
-
-function registerApiGlobally() {
- globalApis.forEach((api) => {
- // @ts-expect-error I know what I am doing :P
- globalThis[api] = index[api];
- });
-}
-
-export { registerApiGlobally };
diff --git a/vanilla/node_modules/vitest/dist/chunks/index.6Qv1eEA6.js b/vanilla/node_modules/vitest/dist/chunks/index.6Qv1eEA6.js
deleted file mode 100644
index efc0785..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/index.6Qv1eEA6.js
+++ /dev/null
@@ -1,109 +0,0 @@
-import { chai } from '@vitest/expect';
-import { l as loadDiffConfig, b as loadSnapshotSerializers, t as takeCoverageInsideWorker } from './setup-common.Cm-kSBVi.js';
-import { r as rpc } from './rpc.BoxB0q7B.js';
-import { g as getWorkerState } from './utils.DvEY5TfP.js';
-import { V as VitestTestRunner, N as NodeBenchmarkRunner } from './test.B8ej_ZHS.js';
-
-function setupChaiConfig(config) {
- Object.assign(chai.config, config);
-}
-
-async function resolveSnapshotEnvironment(config, executor) {
- if (!config.snapshotEnvironment) {
- const { VitestNodeSnapshotEnvironment } = await import('./node.Ce0vMQM7.js');
- return new VitestNodeSnapshotEnvironment();
- }
- const mod = await executor.import(config.snapshotEnvironment);
- if (typeof mod.default !== "object" || !mod.default) throw new Error("Snapshot environment module must have a default export object with a shape of `SnapshotEnvironment`");
- return mod.default;
-}
-
-async function getTestRunnerConstructor(config, moduleRunner) {
- if (!config.runner) return config.mode === "test" ? VitestTestRunner : NodeBenchmarkRunner;
- const mod = await moduleRunner.import(config.runner);
- if (!mod.default && typeof mod.default !== "function") throw new Error(`Runner must export a default function, but got ${typeof mod.default} imported from ${config.runner}`);
- return mod.default;
-}
-async function resolveTestRunner(config, moduleRunner, traces) {
- const testRunner = new (await (getTestRunnerConstructor(config, moduleRunner)))(config);
- // inject private executor to every runner
- Object.defineProperty(testRunner, "moduleRunner", {
- value: moduleRunner,
- enumerable: false,
- configurable: false
- });
- if (!testRunner.config) testRunner.config = config;
- if (!testRunner.importFile) throw new Error("Runner must implement \"importFile\" method.");
- if ("__setTraces" in testRunner) testRunner.__setTraces(traces);
- const [diffOptions] = await Promise.all([loadDiffConfig(config, moduleRunner), loadSnapshotSerializers(config, moduleRunner)]);
- testRunner.config.diffOptions = diffOptions;
- // patch some methods, so custom runners don't need to call RPC
- const originalOnTaskUpdate = testRunner.onTaskUpdate;
- testRunner.onTaskUpdate = async (task, events) => {
- const p = rpc().onTaskUpdate(task, events);
- await originalOnTaskUpdate?.call(testRunner, task, events);
- return p;
- };
- // patch some methods, so custom runners don't need to call RPC
- const originalOnTestAnnotate = testRunner.onTestAnnotate;
- testRunner.onTestAnnotate = async (test, annotation) => {
- const p = rpc().onTaskArtifactRecord(test.id, {
- type: "internal:annotation",
- location: annotation.location,
- annotation
- });
- const overriddenResult = await originalOnTestAnnotate?.call(testRunner, test, annotation);
- const vitestResult = await p;
- return overriddenResult || vitestResult.annotation;
- };
- const originalOnTestArtifactRecord = testRunner.onTestArtifactRecord;
- testRunner.onTestArtifactRecord = async (test, artifact) => {
- const p = rpc().onTaskArtifactRecord(test.id, artifact);
- const overriddenResult = await originalOnTestArtifactRecord?.call(testRunner, test, artifact);
- const vitestResult = await p;
- return overriddenResult || vitestResult;
- };
- const originalOnCollectStart = testRunner.onCollectStart;
- testRunner.onCollectStart = async (file) => {
- await rpc().onQueued(file);
- await originalOnCollectStart?.call(testRunner, file);
- };
- const originalOnCollected = testRunner.onCollected;
- testRunner.onCollected = async (files) => {
- const state = getWorkerState();
- files.forEach((file) => {
- file.prepareDuration = state.durations.prepare;
- file.environmentLoad = state.durations.environment;
- // should be collected only for a single test file in a batch
- state.durations.prepare = 0;
- state.durations.environment = 0;
- });
- rpc().onCollected(files);
- await originalOnCollected?.call(testRunner, files);
- };
- const originalOnAfterRun = testRunner.onAfterRunFiles;
- testRunner.onAfterRunFiles = async (files) => {
- const state = getWorkerState();
- const coverage = await takeCoverageInsideWorker(config.coverage, moduleRunner);
- if (coverage) rpc().onAfterSuiteRun({
- coverage,
- testFiles: files.map((file) => file.name).sort(),
- environment: state.environment.viteEnvironment || state.environment.name,
- projectName: state.ctx.projectName
- });
- await originalOnAfterRun?.call(testRunner, files);
- };
- const originalOnAfterRunTask = testRunner.onAfterRunTask;
- testRunner.onAfterRunTask = async (test) => {
- if (config.bail && test.result?.state === "fail") {
- if (1 + await rpc().getCountOfFailedTests() >= config.bail) {
- rpc().onCancel("test-failure");
- testRunner.cancel?.("test-failure");
- }
- }
- await originalOnAfterRunTask?.call(testRunner, test);
- };
- return testRunner;
-}
-
-export { resolveSnapshotEnvironment as a, resolveTestRunner as r, setupChaiConfig as s };
diff --git a/vanilla/node_modules/vitest/dist/chunks/index.C5r1PdPD.js b/vanilla/node_modules/vitest/dist/chunks/index.C5r1PdPD.js
deleted file mode 100644
index 77cbe3b..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/index.C5r1PdPD.js
+++ /dev/null
@@ -1,231 +0,0 @@
-import fs from 'node:fs';
-import { getTasks, getFullName, getTests } from '@vitest/runner/utils';
-import * as pathe from 'pathe';
-import c from 'tinyrainbow';
-import { g as getStateSymbol, t as truncateString, F as F_RIGHT, D as DefaultReporter, f as formatProjectName, s as separator } from './index.M8mOzt4Y.js';
-import { stripVTControlCharacters } from 'node:util';
-import { notNullish } from '@vitest/utils/helpers';
-
-function createBenchmarkJsonReport(files) {
- const report = { files: [] };
- for (const file of files) {
- const groups = [];
- for (const task of getTasks(file)) if (task?.type === "suite") {
- const benchmarks = [];
- for (const t of task.tasks) {
- const benchmark = t.meta.benchmark && t.result?.benchmark;
- if (benchmark) benchmarks.push({
- id: t.id,
- ...benchmark,
- samples: []
- });
- }
- if (benchmarks.length) groups.push({
- fullName: getFullName(task, " > "),
- benchmarks
- });
- }
- report.files.push({
- filepath: file.filepath,
- groups
- });
- }
- return report;
-}
-function flattenFormattedBenchmarkReport(report) {
- const flat = {};
- for (const file of report.files) for (const group of file.groups) for (const t of group.benchmarks) flat[t.id] = t;
- return flat;
-}
-
-const outputMap = /* @__PURE__ */ new WeakMap();
-function formatNumber(number) {
- const res = String(number.toFixed(number < 100 ? 4 : 2)).split(".");
- return res[0].replace(/(?=(?:\d{3})+$)\B/g, ",") + (res[1] ? `.${res[1]}` : "");
-}
-const tableHead = [
- "name",
- "hz",
- "min",
- "max",
- "mean",
- "p75",
- "p99",
- "p995",
- "p999",
- "rme",
- "samples"
-];
-function renderBenchmarkItems(result) {
- return [
- result.name,
- formatNumber(result.hz || 0),
- formatNumber(result.min || 0),
- formatNumber(result.max || 0),
- formatNumber(result.mean || 0),
- formatNumber(result.p75 || 0),
- formatNumber(result.p99 || 0),
- formatNumber(result.p995 || 0),
- formatNumber(result.p999 || 0),
- `±${(result.rme || 0).toFixed(2)}%`,
- (result.sampleCount || 0).toString()
- ];
-}
-function computeColumnWidths(results) {
- const rows = [tableHead, ...results.map((v) => renderBenchmarkItems(v))];
- return Array.from(tableHead, (_, i) => Math.max(...rows.map((row) => stripVTControlCharacters(row[i]).length)));
-}
-function padRow(row, widths) {
- return row.map((v, i) => i ? v.padStart(widths[i], " ") : v.padEnd(widths[i], " "));
-}
-function renderTableHead(widths) {
- return " ".repeat(3) + padRow(tableHead, widths).map(c.bold).join(" ");
-}
-function renderBenchmark(result, widths) {
- const padded = padRow(renderBenchmarkItems(result), widths);
- return [
- padded[0],
- c.blue(padded[1]),
- c.cyan(padded[2]),
- c.cyan(padded[3]),
- c.cyan(padded[4]),
- c.cyan(padded[5]),
- c.cyan(padded[6]),
- c.cyan(padded[7]),
- c.cyan(padded[8]),
- c.dim(padded[9]),
- c.dim(padded[10])
- ].join(" ");
-}
-function renderTable(options) {
- const output = [];
- const benchMap = {};
- for (const task of options.tasks) if (task.meta.benchmark && task.result?.benchmark) benchMap[task.id] = {
- current: task.result.benchmark,
- baseline: options.compare?.[task.id]
- };
- const benchCount = Object.entries(benchMap).length;
- const columnWidths = computeColumnWidths(Object.values(benchMap).flatMap((v) => [v.current, v.baseline]).filter(notNullish));
- let idx = 0;
- const padding = " ".repeat(1 );
- for (const task of options.tasks) {
- const duration = task.result?.duration;
- const bench = benchMap[task.id];
- let prefix = "";
- if (idx === 0 && task.meta?.benchmark) prefix += `${renderTableHead(columnWidths)}\n${padding}`;
- prefix += ` ${getStateSymbol(task)} `;
- let suffix = "";
- if (task.type === "suite") suffix += c.dim(` (${getTests(task).length})`);
- if (task.mode === "skip" || task.mode === "todo") suffix += c.dim(c.gray(" [skipped]"));
- if (duration != null) {
- const color = duration > options.slowTestThreshold ? c.yellow : c.green;
- suffix += color(` ${Math.round(duration)}${c.dim("ms")}`);
- }
- if (options.showHeap && task.result?.heap != null) suffix += c.magenta(` ${Math.floor(task.result.heap / 1024 / 1024)} MB heap used`);
- if (bench) {
- let body = renderBenchmark(bench.current, columnWidths);
- if (options.compare && bench.baseline) {
- if (bench.current.hz) {
- const diff = bench.current.hz / bench.baseline.hz;
- const diffFixed = diff.toFixed(2);
- if (diffFixed === "1.0.0") body += c.gray(` [${diffFixed}x]`);
- if (diff > 1) body += c.blue(` [${diffFixed}x] ⇑`);
- else body += c.red(` [${diffFixed}x] ⇓`);
- }
- output.push(padding + prefix + body + suffix);
- const bodyBaseline = renderBenchmark(bench.baseline, columnWidths);
- output.push(`${padding} ${bodyBaseline} ${c.dim("(baseline)")}`);
- } else {
- if (bench.current.rank === 1 && benchCount > 1) body += c.bold(c.green(" fastest"));
- if (bench.current.rank === benchCount && benchCount > 2) body += c.bold(c.gray(" slowest"));
- output.push(padding + prefix + body + suffix);
- }
- } else output.push(padding + prefix + task.name + suffix);
- if (task.result?.state !== "pass" && outputMap.get(task) != null) {
- let data = outputMap.get(task);
- if (typeof data === "string") {
- data = stripVTControlCharacters(data.trim().split("\n").filter(Boolean).pop());
- if (data === "") data = void 0;
- }
- if (data != null) {
- const out = ` ${" ".repeat(options.level)}${F_RIGHT} ${data}`;
- output.push(c.gray(truncateString(out, options.columns)));
- }
- }
- idx++;
- }
- return output.filter(Boolean).join("\n");
-}
-
-class BenchmarkReporter extends DefaultReporter {
- compare;
- async onInit(ctx) {
- super.onInit(ctx);
- if (this.ctx.config.benchmark?.compare) {
- const compareFile = pathe.resolve(this.ctx.config.root, this.ctx.config.benchmark?.compare);
- try {
- this.compare = flattenFormattedBenchmarkReport(JSON.parse(await fs.promises.readFile(compareFile, "utf-8")));
- } catch (e) {
- this.error(`Failed to read '${compareFile}'`, e);
- }
- }
- }
- onTaskUpdate(packs) {
- for (const pack of packs) {
- const task = this.ctx.state.idMap.get(pack[0]);
- if (task?.type === "suite" && task.result?.state !== "run") task.tasks.filter((task) => task.result?.benchmark).sort((benchA, benchB) => benchA.result.benchmark.mean - benchB.result.benchmark.mean).forEach((bench, idx) => {
- bench.result.benchmark.rank = Number(idx) + 1;
- });
- }
- }
- onTestSuiteResult(testSuite) {
- super.onTestSuiteResult(testSuite);
- this.printSuiteTable(testSuite);
- }
- printTestModule(testModule) {
- this.printSuiteTable(testModule);
- }
- printSuiteTable(testTask) {
- const state = testTask.state();
- if (state === "pending" || state === "queued") return;
- const benches = testTask.task.tasks.filter((t) => t.meta.benchmark);
- const duration = testTask.task.result?.duration || 0;
- if (benches.length > 0 && benches.every((t) => t.result?.state !== "run" && t.result?.state !== "queued")) {
- let title = `\n ${getStateSymbol(testTask.task)} ${formatProjectName(testTask.project)}${getFullName(testTask.task, separator)}`;
- if (duration != null && duration > this.ctx.config.slowTestThreshold) title += c.yellow(` ${Math.round(duration)}${c.dim("ms")}`);
- this.log(title);
- this.log(renderTable({
- tasks: benches,
- level: 1,
- columns: this.ctx.logger.getColumns(),
- compare: this.compare,
- showHeap: this.ctx.config.logHeapUsage,
- slowTestThreshold: this.ctx.config.slowTestThreshold
- }));
- }
- }
- async onTestRunEnd(testModules, unhandledErrors, reason) {
- super.onTestRunEnd(testModules, unhandledErrors, reason);
- // write output for future comparison
- let outputFile = this.ctx.config.benchmark?.outputJson;
- if (outputFile) {
- outputFile = pathe.resolve(this.ctx.config.root, outputFile);
- const outputDirectory = pathe.dirname(outputFile);
- if (!fs.existsSync(outputDirectory)) await fs.promises.mkdir(outputDirectory, { recursive: true });
- const output = createBenchmarkJsonReport(testModules.map((t) => t.task.file));
- await fs.promises.writeFile(outputFile, JSON.stringify(output, null, 2));
- this.log(`Benchmark report written to ${outputFile}`);
- }
- }
-}
-
-class VerboseBenchmarkReporter extends BenchmarkReporter {
- verbose = true;
-}
-
-const BenchmarkReportsMap = {
- default: BenchmarkReporter,
- verbose: VerboseBenchmarkReporter
-};
-
-export { BenchmarkReporter as B, VerboseBenchmarkReporter as V, BenchmarkReportsMap as a };
diff --git a/vanilla/node_modules/vitest/dist/chunks/index.Chj8NDwU.js b/vanilla/node_modules/vitest/dist/chunks/index.Chj8NDwU.js
deleted file mode 100644
index 5943b9b..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/index.Chj8NDwU.js
+++ /dev/null
@@ -1,206 +0,0 @@
-//#region src/messages.ts
-const TYPE_REQUEST = "q";
-const TYPE_RESPONSE = "s";
-
-//#endregion
-//#region src/utils.ts
-function createPromiseWithResolvers() {
- let resolve;
- let reject;
- return {
- promise: new Promise((res, rej) => {
- resolve = res;
- reject = rej;
- }),
- resolve,
- reject
- };
-}
-const random = Math.random.bind(Math);
-const urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
-function nanoid(size = 21) {
- let id = "";
- let i = size;
- while (i--) id += urlAlphabet[random() * 64 | 0];
- return id;
-}
-
-//#endregion
-//#region src/main.ts
-const DEFAULT_TIMEOUT = 6e4;
-const defaultSerialize = (i) => i;
-const defaultDeserialize = defaultSerialize;
-const { clearTimeout, setTimeout } = globalThis;
-function createBirpc($functions, options) {
- const { post, on, off = () => {}, eventNames = [], serialize = defaultSerialize, deserialize = defaultDeserialize, resolver, bind = "rpc", timeout = DEFAULT_TIMEOUT, proxify = true } = options;
- let $closed = false;
- const _rpcPromiseMap = /* @__PURE__ */ new Map();
- let _promiseInit;
- let rpc;
- async function _call(method, args, event, optional) {
- if ($closed) throw new Error(`[birpc] rpc is closed, cannot call "${method}"`);
- const req = {
- m: method,
- a: args,
- t: TYPE_REQUEST
- };
- if (optional) req.o = true;
- const send = async (_req) => post(serialize(_req));
- if (event) {
- await send(req);
- return;
- }
- if (_promiseInit) try {
- await _promiseInit;
- } finally {
- _promiseInit = void 0;
- }
- let { promise, resolve, reject } = createPromiseWithResolvers();
- const id = nanoid();
- req.i = id;
- let timeoutId;
- async function handler(newReq = req) {
- if (timeout >= 0) {
- timeoutId = setTimeout(() => {
- try {
- if (options.onTimeoutError?.call(rpc, method, args) !== true) throw new Error(`[birpc] timeout on calling "${method}"`);
- } catch (e) {
- reject(e);
- }
- _rpcPromiseMap.delete(id);
- }, timeout);
- if (typeof timeoutId === "object") timeoutId = timeoutId.unref?.();
- }
- _rpcPromiseMap.set(id, {
- resolve,
- reject,
- timeoutId,
- method
- });
- await send(newReq);
- return promise;
- }
- try {
- if (options.onRequest) await options.onRequest.call(rpc, req, handler, resolve);
- else await handler();
- } catch (e) {
- if (options.onGeneralError?.call(rpc, e) !== true) throw e;
- return;
- } finally {
- clearTimeout(timeoutId);
- _rpcPromiseMap.delete(id);
- }
- return promise;
- }
- const builtinMethods = {
- $call: (method, ...args) => _call(method, args, false),
- $callOptional: (method, ...args) => _call(method, args, false, true),
- $callEvent: (method, ...args) => _call(method, args, true),
- $callRaw: (options$1) => _call(options$1.method, options$1.args, options$1.event, options$1.optional),
- $rejectPendingCalls,
- get $closed() {
- return $closed;
- },
- get $meta() {
- return options.meta;
- },
- $close,
- $functions
- };
- if (proxify) rpc = new Proxy({}, { get(_, method) {
- if (Object.prototype.hasOwnProperty.call(builtinMethods, method)) return builtinMethods[method];
- if (method === "then" && !eventNames.includes("then") && !("then" in $functions)) return void 0;
- const sendEvent = (...args) => _call(method, args, true);
- if (eventNames.includes(method)) {
- sendEvent.asEvent = sendEvent;
- return sendEvent;
- }
- const sendCall = (...args) => _call(method, args, false);
- sendCall.asEvent = sendEvent;
- return sendCall;
- } });
- else rpc = builtinMethods;
- function $close(customError) {
- $closed = true;
- _rpcPromiseMap.forEach(({ reject, method }) => {
- const error = /* @__PURE__ */ new Error(`[birpc] rpc is closed, cannot call "${method}"`);
- if (customError) {
- customError.cause ??= error;
- return reject(customError);
- }
- reject(error);
- });
- _rpcPromiseMap.clear();
- off(onMessage);
- }
- function $rejectPendingCalls(handler) {
- const handlerResults = Array.from(_rpcPromiseMap.values()).map(({ method, reject }) => {
- if (!handler) return reject(/* @__PURE__ */ new Error(`[birpc]: rejected pending call "${method}".`));
- return handler({
- method,
- reject
- });
- });
- _rpcPromiseMap.clear();
- return handlerResults;
- }
- async function onMessage(data, ...extra) {
- let msg;
- try {
- msg = deserialize(data);
- } catch (e) {
- if (options.onGeneralError?.call(rpc, e) !== true) throw e;
- return;
- }
- if (msg.t === TYPE_REQUEST) {
- const { m: method, a: args, o: optional } = msg;
- let result, error;
- let fn = await (resolver ? resolver.call(rpc, method, $functions[method]) : $functions[method]);
- if (optional) fn ||= () => void 0;
- if (!fn) error = /* @__PURE__ */ new Error(`[birpc] function "${method}" not found`);
- else try {
- result = await fn.apply(bind === "rpc" ? rpc : $functions, args);
- } catch (e) {
- error = e;
- }
- if (msg.i) {
- if (error && options.onFunctionError) {
- if (options.onFunctionError.call(rpc, error, method, args) === true) return;
- }
- if (!error) try {
- await post(serialize({
- t: TYPE_RESPONSE,
- i: msg.i,
- r: result
- }), ...extra);
- return;
- } catch (e) {
- error = e;
- if (options.onGeneralError?.call(rpc, e, method, args) !== true) throw e;
- }
- try {
- await post(serialize({
- t: TYPE_RESPONSE,
- i: msg.i,
- e: error
- }), ...extra);
- } catch (e) {
- if (options.onGeneralError?.call(rpc, e, method, args) !== true) throw e;
- }
- }
- } else {
- const { i: ack, r: result, e: error } = msg;
- const promise = _rpcPromiseMap.get(ack);
- if (promise) {
- clearTimeout(promise.timeoutId);
- if (error) promise.reject(error);
- else promise.resolve(result);
- }
- _rpcPromiseMap.delete(ack);
- }
- }
- _promiseInit = on(onMessage);
- return rpc;
-}
-
-export { createBirpc as c };
diff --git a/vanilla/node_modules/vitest/dist/chunks/index.CyBMJtT7.js b/vanilla/node_modules/vitest/dist/chunks/index.CyBMJtT7.js
deleted file mode 100644
index 6123ed4..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/index.CyBMJtT7.js
+++ /dev/null
@@ -1,727 +0,0 @@
-import { URL } from 'node:url';
-import { Console } from 'node:console';
-
-// SEE https://github.com/jsdom/jsdom/blob/master/lib/jsdom/living/interfaces.js
-const LIVING_KEYS = [
- "DOMException",
- "EventTarget",
- "NamedNodeMap",
- "Node",
- "Attr",
- "Element",
- "DocumentFragment",
- "DOMImplementation",
- "Document",
- "XMLDocument",
- "CharacterData",
- "Text",
- "CDATASection",
- "ProcessingInstruction",
- "Comment",
- "DocumentType",
- "NodeList",
- "RadioNodeList",
- "HTMLCollection",
- "HTMLOptionsCollection",
- "DOMStringMap",
- "DOMTokenList",
- "StyleSheetList",
- "HTMLElement",
- "HTMLHeadElement",
- "HTMLTitleElement",
- "HTMLBaseElement",
- "HTMLLinkElement",
- "HTMLMetaElement",
- "HTMLStyleElement",
- "HTMLBodyElement",
- "HTMLHeadingElement",
- "HTMLParagraphElement",
- "HTMLHRElement",
- "HTMLPreElement",
- "HTMLUListElement",
- "HTMLOListElement",
- "HTMLLIElement",
- "HTMLMenuElement",
- "HTMLDListElement",
- "HTMLDivElement",
- "HTMLAnchorElement",
- "HTMLAreaElement",
- "HTMLBRElement",
- "HTMLButtonElement",
- "HTMLCanvasElement",
- "HTMLDataElement",
- "HTMLDataListElement",
- "HTMLDetailsElement",
- "HTMLDialogElement",
- "HTMLDirectoryElement",
- "HTMLFieldSetElement",
- "HTMLFontElement",
- "HTMLFormElement",
- "HTMLHtmlElement",
- "HTMLImageElement",
- "HTMLInputElement",
- "HTMLLabelElement",
- "HTMLLegendElement",
- "HTMLMapElement",
- "HTMLMarqueeElement",
- "HTMLMediaElement",
- "HTMLMeterElement",
- "HTMLModElement",
- "HTMLOptGroupElement",
- "HTMLOptionElement",
- "HTMLOutputElement",
- "HTMLPictureElement",
- "HTMLProgressElement",
- "HTMLQuoteElement",
- "HTMLScriptElement",
- "HTMLSelectElement",
- "HTMLSlotElement",
- "HTMLSourceElement",
- "HTMLSpanElement",
- "HTMLTableCaptionElement",
- "HTMLTableCellElement",
- "HTMLTableColElement",
- "HTMLTableElement",
- "HTMLTimeElement",
- "HTMLTableRowElement",
- "HTMLTableSectionElement",
- "HTMLTemplateElement",
- "HTMLTextAreaElement",
- "HTMLUnknownElement",
- "HTMLFrameElement",
- "HTMLFrameSetElement",
- "HTMLIFrameElement",
- "HTMLEmbedElement",
- "HTMLObjectElement",
- "HTMLParamElement",
- "HTMLVideoElement",
- "HTMLAudioElement",
- "HTMLTrackElement",
- "HTMLFormControlsCollection",
- "SVGElement",
- "SVGGraphicsElement",
- "SVGSVGElement",
- "SVGTitleElement",
- "SVGAnimatedString",
- "SVGNumber",
- "SVGStringList",
- "Event",
- "CloseEvent",
- "CustomEvent",
- "MessageEvent",
- "ErrorEvent",
- "HashChangeEvent",
- "PopStateEvent",
- "StorageEvent",
- "ProgressEvent",
- "PageTransitionEvent",
- "SubmitEvent",
- "UIEvent",
- "FocusEvent",
- "InputEvent",
- "MouseEvent",
- "KeyboardEvent",
- "TouchEvent",
- "CompositionEvent",
- "WheelEvent",
- "BarProp",
- "External",
- "Location",
- "History",
- "Screen",
- "Crypto",
- "Performance",
- "Navigator",
- "PluginArray",
- "MimeTypeArray",
- "Plugin",
- "MimeType",
- "FileReader",
- "FormData",
- "Blob",
- "File",
- "FileList",
- "ValidityState",
- "DOMParser",
- "XMLSerializer",
- "XMLHttpRequestEventTarget",
- "XMLHttpRequestUpload",
- "XMLHttpRequest",
- "WebSocket",
- "NodeFilter",
- "NodeIterator",
- "TreeWalker",
- "AbstractRange",
- "Range",
- "StaticRange",
- "Selection",
- "Storage",
- "CustomElementRegistry",
- "ShadowRoot",
- "MutationObserver",
- "MutationRecord",
- "Uint8Array",
- "Uint16Array",
- "Uint32Array",
- "Uint8ClampedArray",
- "Int8Array",
- "Int16Array",
- "Int32Array",
- "Float32Array",
- "Float64Array",
- "ArrayBuffer",
- "DOMRectReadOnly",
- "DOMRect",
- "Image",
- "Audio",
- "Option",
- "CSS"
-];
-const OTHER_KEYS = [
- "addEventListener",
- "alert",
- "blur",
- "cancelAnimationFrame",
- "close",
- "confirm",
- "createPopup",
- "dispatchEvent",
- "document",
- "focus",
- "frames",
- "getComputedStyle",
- "history",
- "innerHeight",
- "innerWidth",
- "length",
- "location",
- "matchMedia",
- "moveBy",
- "moveTo",
- "name",
- "navigator",
- "open",
- "outerHeight",
- "outerWidth",
- "pageXOffset",
- "pageYOffset",
- "parent",
- "postMessage",
- "print",
- "prompt",
- "removeEventListener",
- "requestAnimationFrame",
- "resizeBy",
- "resizeTo",
- "screen",
- "screenLeft",
- "screenTop",
- "screenX",
- "screenY",
- "scroll",
- "scrollBy",
- "scrollLeft",
- "scrollTo",
- "scrollTop",
- "scrollX",
- "scrollY",
- "self",
- "stop",
- "top",
- "Window",
- "window"
-];
-const KEYS = LIVING_KEYS.concat(OTHER_KEYS);
-
-const skipKeys = [
- "window",
- "self",
- "top",
- "parent"
-];
-function getWindowKeys(global, win, additionalKeys = []) {
- const keysArray = [...additionalKeys, ...KEYS];
- return new Set(keysArray.concat(Object.getOwnPropertyNames(win)).filter((k) => {
- if (skipKeys.includes(k)) return false;
- if (k in global) return keysArray.includes(k);
- return true;
- }));
-}
-function isClassLikeName(name) {
- return name[0] === name[0].toUpperCase();
-}
-function populateGlobal(global, win, options = {}) {
- const { bindFunctions = false } = options;
- const keys = getWindowKeys(global, win, options.additionalKeys);
- const originals = /* @__PURE__ */ new Map();
- const overridenKeys = new Set([...KEYS, ...options.additionalKeys || []]);
- const overrideObject = /* @__PURE__ */ new Map();
- for (const key of keys) {
- const boundFunction = bindFunctions && typeof win[key] === "function" && !isClassLikeName(key) && win[key].bind(win);
- if (overridenKeys.has(key) && key in global) originals.set(key, global[key]);
- Object.defineProperty(global, key, {
- get() {
- if (overrideObject.has(key)) return overrideObject.get(key);
- if (boundFunction) return boundFunction;
- return win[key];
- },
- set(v) {
- overrideObject.set(key, v);
- },
- configurable: true
- });
- }
- global.window = global;
- global.self = global;
- global.top = global;
- global.parent = global;
- if (global.global) global.global = global;
- // rewrite defaultView to reference the same global context
- if (global.document && global.document.defaultView) Object.defineProperty(global.document, "defaultView", {
- get: () => global,
- enumerable: true,
- configurable: true
- });
- skipKeys.forEach((k) => keys.add(k));
- return {
- keys,
- skipKeys,
- originals
- };
-}
-
-var edge = {
- name: "edge-runtime",
- viteEnvironment: "ssr",
- async setupVM() {
- const { EdgeVM } = await import('@edge-runtime/vm');
- const vm = new EdgeVM({ extend: (context) => {
- context.global = context;
- context.Buffer = Buffer;
- return context;
- } });
- return {
- getVmContext() {
- return vm.context;
- },
- teardown() {
- // nothing to teardown
- }
- };
- },
- async setup(global) {
- const { EdgeVM } = await import('@edge-runtime/vm');
- const { keys, originals } = populateGlobal(global, new EdgeVM({ extend: (context) => {
- context.global = context;
- context.Buffer = Buffer;
- KEYS.forEach((key) => {
- if (key in global) context[key] = global[key];
- });
- return context;
- } }).context, { bindFunctions: true });
- return { teardown(global) {
- keys.forEach((key) => delete global[key]);
- originals.forEach((v, k) => global[k] = v);
- } };
- }
-};
-
-async function teardownWindow(win) {
- if (win.close && win.happyDOM.abort) {
- await win.happyDOM.abort();
- win.close();
- } else win.happyDOM.cancelAsync();
-}
-var happy = {
- name: "happy-dom",
- viteEnvironment: "client",
- async setupVM({ happyDOM = {} }) {
- const { Window } = await import('happy-dom');
- let win = new Window({
- ...happyDOM,
- console: console && globalThis.console ? globalThis.console : void 0,
- url: happyDOM.url || "http://localhost:3000",
- settings: {
- ...happyDOM.settings,
- disableErrorCapturing: true
- }
- });
- // TODO: browser doesn't expose Buffer, but a lot of dependencies use it
- win.Buffer = Buffer;
- // inject structuredClone if it exists
- if (typeof structuredClone !== "undefined" && !win.structuredClone) win.structuredClone = structuredClone;
- return {
- getVmContext() {
- return win;
- },
- async teardown() {
- await teardownWindow(win);
- win = void 0;
- }
- };
- },
- async setup(global, { happyDOM = {} }) {
- // happy-dom v3 introduced a breaking change to Window, but
- // provides GlobalWindow as a way to use previous behaviour
- const { Window, GlobalWindow } = await import('happy-dom');
- const win = new (GlobalWindow || Window)({
- ...happyDOM,
- console: console && global.console ? global.console : void 0,
- url: happyDOM.url || "http://localhost:3000",
- settings: {
- ...happyDOM.settings,
- disableErrorCapturing: true
- }
- });
- const { keys, originals } = populateGlobal(global, win, {
- bindFunctions: true,
- additionalKeys: [
- "Request",
- "Response",
- "MessagePort",
- "fetch",
- "Headers",
- "AbortController",
- "AbortSignal",
- "URL",
- "URLSearchParams",
- "FormData"
- ]
- });
- return { async teardown(global) {
- await teardownWindow(win);
- keys.forEach((key) => delete global[key]);
- originals.forEach((v, k) => global[k] = v);
- } };
- }
-};
-
-function catchWindowErrors(window) {
- let userErrorListenerCount = 0;
- function throwUnhandlerError(e) {
- if (userErrorListenerCount === 0 && e.error != null) {
- e.preventDefault();
- process.emit("uncaughtException", e.error);
- }
- }
- const addEventListener = window.addEventListener.bind(window);
- const removeEventListener = window.removeEventListener.bind(window);
- window.addEventListener("error", throwUnhandlerError);
- window.addEventListener = function(...args) {
- if (args[0] === "error") userErrorListenerCount++;
- return addEventListener.apply(this, args);
- };
- window.removeEventListener = function(...args) {
- if (args[0] === "error" && userErrorListenerCount) userErrorListenerCount--;
- return removeEventListener.apply(this, args);
- };
- return function clearErrorHandlers() {
- window.removeEventListener("error", throwUnhandlerError);
- };
-}
-let NodeFormData_;
-let NodeBlob_;
-let NodeRequest_;
-var jsdom = {
- name: "jsdom",
- viteEnvironment: "client",
- async setupVM({ jsdom = {} }) {
- // delay initialization because it takes ~1s
- NodeFormData_ = globalThis.FormData;
- NodeBlob_ = globalThis.Blob;
- NodeRequest_ = globalThis.Request;
- const { CookieJar, JSDOM, ResourceLoader, VirtualConsole } = await import('jsdom');
- const { html = "<!DOCTYPE html>", userAgent, url = "http://localhost:3000", contentType = "text/html", pretendToBeVisual = true, includeNodeLocations = false, runScripts = "dangerously", resources, console = false, cookieJar = false, ...restOptions } = jsdom;
- let virtualConsole;
- if (console && globalThis.console) {
- virtualConsole = new VirtualConsole();
- // jsdom <27
- if ("sendTo" in virtualConsole) virtualConsole.sendTo(globalThis.console);
- else virtualConsole.forwardTo(globalThis.console);
- }
- let dom = new JSDOM(html, {
- pretendToBeVisual,
- resources: resources ?? (userAgent ? new ResourceLoader({ userAgent }) : void 0),
- runScripts,
- url,
- virtualConsole,
- cookieJar: cookieJar ? new CookieJar() : void 0,
- includeNodeLocations,
- contentType,
- userAgent,
- ...restOptions
- });
- const clearAddEventListenerPatch = patchAddEventListener(dom.window);
- const clearWindowErrors = catchWindowErrors(dom.window);
- const utils = createCompatUtils(dom.window);
- // TODO: browser doesn't expose Buffer, but a lot of dependencies use it
- dom.window.Buffer = Buffer;
- dom.window.jsdom = dom;
- dom.window.Request = createCompatRequest(utils);
- dom.window.URL = createJSDOMCompatURL(utils);
- for (const name of [
- "structuredClone",
- "BroadcastChannel",
- "MessageChannel",
- "MessagePort",
- "TextEncoder",
- "TextDecoder"
- ]) {
- const value = globalThis[name];
- if (typeof value !== "undefined" && typeof dom.window[name] === "undefined") dom.window[name] = value;
- }
- for (const name of [
- "fetch",
- "Response",
- "Headers",
- "AbortController",
- "AbortSignal",
- "URLSearchParams"
- ]) {
- const value = globalThis[name];
- if (typeof value !== "undefined") dom.window[name] = value;
- }
- return {
- getVmContext() {
- return dom.getInternalVMContext();
- },
- teardown() {
- clearAddEventListenerPatch();
- clearWindowErrors();
- dom.window.close();
- dom = void 0;
- }
- };
- },
- async setup(global, { jsdom = {} }) {
- // delay initialization because it takes ~1s
- NodeFormData_ = globalThis.FormData;
- NodeBlob_ = globalThis.Blob;
- NodeRequest_ = globalThis.Request;
- const { CookieJar, JSDOM, ResourceLoader, VirtualConsole } = await import('jsdom');
- const { html = "<!DOCTYPE html>", userAgent, url = "http://localhost:3000", contentType = "text/html", pretendToBeVisual = true, includeNodeLocations = false, runScripts = "dangerously", resources, console = false, cookieJar = false, ...restOptions } = jsdom;
- let virtualConsole;
- if (console && globalThis.console) {
- virtualConsole = new VirtualConsole();
- // jsdom <27
- if ("sendTo" in virtualConsole) virtualConsole.sendTo(globalThis.console);
- else virtualConsole.forwardTo(globalThis.console);
- }
- const dom = new JSDOM(html, {
- pretendToBeVisual,
- resources: resources ?? (userAgent ? new ResourceLoader({ userAgent }) : void 0),
- runScripts,
- url,
- virtualConsole,
- cookieJar: cookieJar ? new CookieJar() : void 0,
- includeNodeLocations,
- contentType,
- userAgent,
- ...restOptions
- });
- const clearAddEventListenerPatch = patchAddEventListener(dom.window);
- const { keys, originals } = populateGlobal(global, dom.window, { bindFunctions: true });
- const clearWindowErrors = catchWindowErrors(global);
- const utils = createCompatUtils(dom.window);
- global.jsdom = dom;
- global.Request = createCompatRequest(utils);
- global.URL = createJSDOMCompatURL(utils);
- return { teardown(global) {
- clearAddEventListenerPatch();
- clearWindowErrors();
- dom.window.close();
- delete global.jsdom;
- keys.forEach((key) => delete global[key]);
- originals.forEach((v, k) => global[k] = v);
- } };
- }
-};
-function createCompatRequest(utils) {
- return class Request extends NodeRequest_ {
- constructor(...args) {
- const [input, init] = args;
- if (init?.body != null) {
- const compatInit = { ...init };
- if (init.body instanceof utils.window.Blob) compatInit.body = utils.makeCompatBlob(init.body);
- if (init.body instanceof utils.window.FormData) compatInit.body = utils.makeCompatFormData(init.body);
- super(input, compatInit);
- } else super(...args);
- }
- static [Symbol.hasInstance](instance) {
- return instance instanceof NodeRequest_;
- }
- };
-}
-function createJSDOMCompatURL(utils) {
- return class URL$1 extends URL {
- static createObjectURL(blob) {
- if (blob instanceof utils.window.Blob) {
- const compatBlob = utils.makeCompatBlob(blob);
- return URL.createObjectURL(compatBlob);
- }
- return URL.createObjectURL(blob);
- }
- static [Symbol.hasInstance](instance) {
- return instance instanceof URL;
- }
- };
-}
-function createCompatUtils(window) {
- // this returns a hidden Symbol(impl)
- // this is cursed, and jsdom should just implement fetch API itself
- const implSymbol = Object.getOwnPropertySymbols(Object.getOwnPropertyDescriptors(new window.Blob()))[0];
- const utils = {
- window,
- makeCompatFormData(formData) {
- const nodeFormData = new NodeFormData_();
- formData.forEach((value, key) => {
- if (value instanceof window.Blob) nodeFormData.append(key, utils.makeCompatBlob(value));
- else nodeFormData.append(key, value);
- });
- return nodeFormData;
- },
- makeCompatBlob(blob) {
- const buffer = blob[implSymbol]._buffer;
- return new NodeBlob_([buffer], { type: blob.type });
- }
- };
- return utils;
-}
-function patchAddEventListener(window) {
- const abortControllers = /* @__PURE__ */ new WeakMap();
- const JSDOMAbortSignal = window.AbortSignal;
- const JSDOMAbortController = window.AbortController;
- const originalAddEventListener = window.EventTarget.prototype.addEventListener;
- function getJsdomAbortController(signal) {
- if (!abortControllers.has(signal)) {
- const jsdomAbortController = new JSDOMAbortController();
- signal.addEventListener("abort", () => {
- jsdomAbortController.abort(signal.reason);
- });
- abortControllers.set(signal, jsdomAbortController);
- }
- return abortControllers.get(signal);
- }
- window.EventTarget.prototype.addEventListener = function addEventListener(type, callback, options) {
- if (typeof options === "object" && options?.signal != null) {
- const { signal, ...otherOptions } = options;
- // - this happens because AbortSignal is provided by Node.js,
- // but jsdom APIs require jsdom's AbortSignal, while Node APIs
- // (like fetch and Request) require a Node.js AbortSignal
- // - disable narrow typing with "as any" because we need it later
- if (!(signal instanceof JSDOMAbortSignal)) {
- const jsdomCompatOptions = Object.create(null);
- Object.assign(jsdomCompatOptions, otherOptions);
- jsdomCompatOptions.signal = getJsdomAbortController(signal).signal;
- return originalAddEventListener.call(this, type, callback, jsdomCompatOptions);
- }
- }
- return originalAddEventListener.call(this, type, callback, options);
- };
- return () => {
- window.EventTarget.prototype.addEventListener = originalAddEventListener;
- };
-}
-
-// some globals we do not want, either because deprecated or we set it ourselves
-const denyList = new Set([
- "GLOBAL",
- "root",
- "global",
- "Buffer",
- "ArrayBuffer",
- "Uint8Array"
-]);
-const nodeGlobals = /* @__PURE__ */ new Map();
-function populateNodeGlobals() {
- if (nodeGlobals.size !== 0) return;
- const names = Object.getOwnPropertyNames(globalThis);
- const length = names.length;
- for (let i = 0; i < length; i++) {
- const globalName = names[i];
- if (!denyList.has(globalName)) {
- const descriptor = Object.getOwnPropertyDescriptor(globalThis, globalName);
- if (!descriptor) throw new Error(`No property descriptor for ${globalName}, this is a bug in Vitest.`);
- nodeGlobals.set(globalName, descriptor);
- }
- }
-}
-var node = {
- name: "node",
- viteEnvironment: "ssr",
- async setupVM() {
- populateNodeGlobals();
- const vm = await import('node:vm');
- let context = vm.createContext();
- let global = vm.runInContext("this", context);
- const contextGlobals = new Set(Object.getOwnPropertyNames(global));
- for (const [nodeGlobalsKey, descriptor] of nodeGlobals) if (!contextGlobals.has(nodeGlobalsKey)) if (descriptor.configurable) Object.defineProperty(global, nodeGlobalsKey, {
- configurable: true,
- enumerable: descriptor.enumerable,
- get() {
- // @ts-expect-error: no index signature
- const val = globalThis[nodeGlobalsKey];
- // override lazy getter
- Object.defineProperty(global, nodeGlobalsKey, {
- configurable: true,
- enumerable: descriptor.enumerable,
- value: val,
- writable: descriptor.writable === true || nodeGlobalsKey === "performance"
- });
- return val;
- },
- set(val) {
- // override lazy getter
- Object.defineProperty(global, nodeGlobalsKey, {
- configurable: true,
- enumerable: descriptor.enumerable,
- value: val,
- writable: true
- });
- }
- });
- else if ("value" in descriptor) Object.defineProperty(global, nodeGlobalsKey, {
- configurable: false,
- enumerable: descriptor.enumerable,
- value: descriptor.value,
- writable: descriptor.writable
- });
- else Object.defineProperty(global, nodeGlobalsKey, {
- configurable: false,
- enumerable: descriptor.enumerable,
- get: descriptor.get,
- set: descriptor.set
- });
- global.global = global;
- global.Buffer = Buffer;
- global.ArrayBuffer = ArrayBuffer;
- // TextEncoder (global or via 'util') references a Uint8Array constructor
- // different than the global one used by users in tests. This makes sure the
- // same constructor is referenced by both.
- global.Uint8Array = Uint8Array;
- return {
- getVmContext() {
- return context;
- },
- teardown() {
- context = void 0;
- global = void 0;
- }
- };
- },
- async setup(global) {
- global.console.Console = Console;
- return { teardown(global) {
- delete global.console.Console;
- } };
- }
-};
-
-const environments = {
- node,
- jsdom,
- "happy-dom": happy,
- "edge-runtime": edge
-};
-
-export { environments as e, populateGlobal as p };
diff --git a/vanilla/node_modules/vitest/dist/chunks/index.D3XRDfWc.js b/vanilla/node_modules/vitest/dist/chunks/index.D3XRDfWc.js
deleted file mode 100644
index 5a69ef7..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/index.D3XRDfWc.js
+++ /dev/null
@@ -1,213 +0,0 @@
-import process from 'node:process';
-import fs from 'node:fs/promises';
-import path, { resolve } from 'node:path';
-import { existsSync } from 'node:fs';
-import { x } from 'tinyexec';
-
-const AGENTS = [
- "npm",
- "yarn",
- "yarn@berry",
- "pnpm",
- "pnpm@6",
- "bun",
- "deno"
-];
-const LOCKS = {
- "bun.lock": "bun",
- "bun.lockb": "bun",
- "deno.lock": "deno",
- "pnpm-lock.yaml": "pnpm",
- "pnpm-workspace.yaml": "pnpm",
- "yarn.lock": "yarn",
- "package-lock.json": "npm",
- "npm-shrinkwrap.json": "npm"
-};
-const INSTALL_METADATA = {
- "node_modules/.deno/": "deno",
- "node_modules/.pnpm/": "pnpm",
- "node_modules/.yarn-state.yml": "yarn",
- // yarn v2+ (node-modules)
- "node_modules/.yarn_integrity": "yarn",
- // yarn v1
- "node_modules/.package-lock.json": "npm",
- ".pnp.cjs": "yarn",
- // yarn v3+ (pnp)
- ".pnp.js": "yarn",
- // yarn v2 (pnp)
- "bun.lock": "bun",
- "bun.lockb": "bun"
-};
-
-async function pathExists(path2, type) {
- try {
- const stat = await fs.stat(path2);
- return type === "file" ? stat.isFile() : stat.isDirectory();
- } catch {
- return false;
- }
-}
-function* lookup(cwd = process.cwd()) {
- let directory = path.resolve(cwd);
- const { root } = path.parse(directory);
- while (directory && directory !== root) {
- yield directory;
- directory = path.dirname(directory);
- }
-}
-async function parsePackageJson(filepath, onUnknown) {
- return !filepath || !pathExists(filepath, "file") ? null : await handlePackageManager(filepath, onUnknown);
-}
-async function detect(options = {}) {
- const {
- cwd,
- strategies = ["lockfile", "packageManager-field", "devEngines-field"],
- onUnknown
- } = options;
- let stopDir;
- if (typeof options.stopDir === "string") {
- const resolved = path.resolve(options.stopDir);
- stopDir = (dir) => dir === resolved;
- } else {
- stopDir = options.stopDir;
- }
- for (const directory of lookup(cwd)) {
- for (const strategy of strategies) {
- switch (strategy) {
- case "lockfile": {
- for (const lock of Object.keys(LOCKS)) {
- if (await pathExists(path.join(directory, lock), "file")) {
- const name = LOCKS[lock];
- const result = await parsePackageJson(path.join(directory, "package.json"), onUnknown);
- if (result)
- return result;
- else
- return { name, agent: name };
- }
- }
- break;
- }
- case "packageManager-field":
- case "devEngines-field": {
- const result = await parsePackageJson(path.join(directory, "package.json"), onUnknown);
- if (result)
- return result;
- break;
- }
- case "install-metadata": {
- for (const metadata of Object.keys(INSTALL_METADATA)) {
- const fileOrDir = metadata.endsWith("/") ? "dir" : "file";
- if (await pathExists(path.join(directory, metadata), fileOrDir)) {
- const name = INSTALL_METADATA[metadata];
- const agent = name === "yarn" ? isMetadataYarnClassic(metadata) ? "yarn" : "yarn@berry" : name;
- return { name, agent };
- }
- }
- break;
- }
- }
- }
- if (stopDir?.(directory))
- break;
- }
- return null;
-}
-function getNameAndVer(pkg) {
- const handelVer = (version) => version?.match(/\d+(\.\d+){0,2}/)?.[0] ?? version;
- if (typeof pkg.packageManager === "string") {
- const [name, ver] = pkg.packageManager.replace(/^\^/, "").split("@");
- return { name, ver: handelVer(ver) };
- }
- if (typeof pkg.devEngines?.packageManager?.name === "string") {
- return {
- name: pkg.devEngines.packageManager.name,
- ver: handelVer(pkg.devEngines.packageManager.version)
- };
- }
- return void 0;
-}
-async function handlePackageManager(filepath, onUnknown) {
- try {
- const pkg = JSON.parse(await fs.readFile(filepath, "utf8"));
- let agent;
- const nameAndVer = getNameAndVer(pkg);
- if (nameAndVer) {
- const name = nameAndVer.name;
- const ver = nameAndVer.ver;
- let version = ver;
- if (name === "yarn" && ver && Number.parseInt(ver) > 1) {
- agent = "yarn@berry";
- version = "berry";
- return { name, agent, version };
- } else if (name === "pnpm" && ver && Number.parseInt(ver) < 7) {
- agent = "pnpm@6";
- return { name, agent, version };
- } else if (AGENTS.includes(name)) {
- agent = name;
- return { name, agent, version };
- } else {
- return onUnknown?.(pkg.packageManager) ?? null;
- }
- }
- } catch {
- }
- return null;
-}
-function isMetadataYarnClassic(metadataPath) {
- return metadataPath.endsWith(".yarn_integrity");
-}
-
-// src/detect.ts
-async function detectPackageManager(cwd = process.cwd()) {
- const result = await detect({
- cwd,
- onUnknown(packageManager) {
- console.warn("[@antfu/install-pkg] Unknown packageManager:", packageManager);
- return void 0;
- }
- });
- return result?.agent || null;
-}
-async function installPackage(names, options = {}) {
- const detectedAgent = options.packageManager || await detectPackageManager(options.cwd) || "npm";
- const [agent] = detectedAgent.split("@");
- if (!Array.isArray(names))
- names = [names];
- const args = (typeof options.additionalArgs === "function" ? options.additionalArgs(agent, detectedAgent) : options.additionalArgs) || [];
- if (options.preferOffline) {
- if (detectedAgent === "yarn@berry")
- args.unshift("--cached");
- else
- args.unshift("--prefer-offline");
- }
- if (agent === "pnpm") {
- args.unshift(
- /**
- * Prevent pnpm from removing installed devDeps while `NODE_ENV` is `production`
- * @see https://pnpm.io/cli/install#--prod--p
- */
- "--prod=false"
- );
- if (existsSync(resolve(options.cwd ?? process.cwd(), "pnpm-workspace.yaml"))) {
- args.unshift("-w");
- }
- }
- return x(
- agent,
- [
- agent === "yarn" ? "add" : "install",
- options.dev ? "-D" : "",
- ...args,
- ...names
- ].filter(Boolean),
- {
- nodeOptions: {
- stdio: options.silent ? "ignore" : "inherit",
- cwd: options.cwd
- },
- throwOnError: true
- }
- );
-}
-
-export { detectPackageManager, installPackage };
diff --git a/vanilla/node_modules/vitest/dist/chunks/index.D4KonVSU.js b/vanilla/node_modules/vitest/dist/chunks/index.D4KonVSU.js
deleted file mode 100644
index c218e05..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/index.D4KonVSU.js
+++ /dev/null
@@ -1,6343 +0,0 @@
-import { resolve, isAbsolute, dirname, join } from 'node:path';
-import { existsSync } from 'node:fs';
-import 'node:module';
-import 'node:url';
-import { g as getDefaultExportFromCjs } from './_commonjsHelpers.D26ty3Ew.js';
-import require$$0 from 'readline';
-import require$$0$1 from 'events';
-
-/**
-* Resolve an absolute path from {@link root}, but only
-* if {@link input} isn't already absolute.
-*
-* @param input The path to resolve.
-* @param root The base path; default = process.cwd()
-* @returns The resolved absolute path.
-*/
-function absolute(input, root) {
- return isAbsolute(input) ? input : resolve(root || ".", input);
-}
-
-/**
-* Get all parent directories of {@link base}.
-* Stops after {@link Options['last']} is processed.
-*
-* @returns An array of absolute paths of all parent directories.
-*/
-function up(base, options) {
- let { last, cwd } = options || {};
- let tmp = absolute(base, cwd);
- let root = absolute(last || "/", cwd);
- let prev, arr = [];
- while (prev !== root) {
- arr.push(tmp);
- tmp = dirname(prev = tmp);
- if (tmp === prev) break;
- }
- return arr;
-}
-
-/**
-* Get the first path that matches any of the names provided.
-*
-* > [NOTE]
-* > The order of {@link names} is respected.
-*
-* @param names The item names to find.
-* @returns The absolute path of the first item found, if any.
-*/
-function any(names, options) {
- let dir, start = options && options.cwd || "";
- let j = 0, len = names.length, tmp;
- for (dir of up(start, options)) {
- for (j = 0; j < len; j++) {
- tmp = join(dir, names[j]);
- if (existsSync(tmp)) return tmp;
- }
- }
-}
-
-var prompts$2 = {};
-
-var kleur;
-var hasRequiredKleur;
-
-function requireKleur () {
- if (hasRequiredKleur) return kleur;
- hasRequiredKleur = 1;
-
- const { FORCE_COLOR, NODE_DISABLE_COLORS, TERM } = process.env;
-
- const $ = {
- enabled: !NODE_DISABLE_COLORS && TERM !== 'dumb' && FORCE_COLOR !== '0',
-
- // modifiers
- reset: init(0, 0),
- bold: init(1, 22),
- dim: init(2, 22),
- italic: init(3, 23),
- underline: init(4, 24),
- inverse: init(7, 27),
- hidden: init(8, 28),
- strikethrough: init(9, 29),
-
- // colors
- black: init(30, 39),
- red: init(31, 39),
- green: init(32, 39),
- yellow: init(33, 39),
- blue: init(34, 39),
- magenta: init(35, 39),
- cyan: init(36, 39),
- white: init(37, 39),
- gray: init(90, 39),
- grey: init(90, 39),
-
- // background colors
- bgBlack: init(40, 49),
- bgRed: init(41, 49),
- bgGreen: init(42, 49),
- bgYellow: init(43, 49),
- bgBlue: init(44, 49),
- bgMagenta: init(45, 49),
- bgCyan: init(46, 49),
- bgWhite: init(47, 49)
- };
-
- function run(arr, str) {
- let i=0, tmp, beg='', end='';
- for (; i < arr.length; i++) {
- tmp = arr[i];
- beg += tmp.open;
- end += tmp.close;
- if (str.includes(tmp.close)) {
- str = str.replace(tmp.rgx, tmp.close + tmp.open);
- }
- }
- return beg + str + end;
- }
-
- function chain(has, keys) {
- let ctx = { has, keys };
-
- ctx.reset = $.reset.bind(ctx);
- ctx.bold = $.bold.bind(ctx);
- ctx.dim = $.dim.bind(ctx);
- ctx.italic = $.italic.bind(ctx);
- ctx.underline = $.underline.bind(ctx);
- ctx.inverse = $.inverse.bind(ctx);
- ctx.hidden = $.hidden.bind(ctx);
- ctx.strikethrough = $.strikethrough.bind(ctx);
-
- ctx.black = $.black.bind(ctx);
- ctx.red = $.red.bind(ctx);
- ctx.green = $.green.bind(ctx);
- ctx.yellow = $.yellow.bind(ctx);
- ctx.blue = $.blue.bind(ctx);
- ctx.magenta = $.magenta.bind(ctx);
- ctx.cyan = $.cyan.bind(ctx);
- ctx.white = $.white.bind(ctx);
- ctx.gray = $.gray.bind(ctx);
- ctx.grey = $.grey.bind(ctx);
-
- ctx.bgBlack = $.bgBlack.bind(ctx);
- ctx.bgRed = $.bgRed.bind(ctx);
- ctx.bgGreen = $.bgGreen.bind(ctx);
- ctx.bgYellow = $.bgYellow.bind(ctx);
- ctx.bgBlue = $.bgBlue.bind(ctx);
- ctx.bgMagenta = $.bgMagenta.bind(ctx);
- ctx.bgCyan = $.bgCyan.bind(ctx);
- ctx.bgWhite = $.bgWhite.bind(ctx);
-
- return ctx;
- }
-
- function init(open, close) {
- let blk = {
- open: `\x1b[${open}m`,
- close: `\x1b[${close}m`,
- rgx: new RegExp(`\\x1b\\[${close}m`, 'g')
- };
- return function (txt) {
- if (this !== void 0 && this.has !== void 0) {
- this.has.includes(open) || (this.has.push(open),this.keys.push(blk));
- return txt === void 0 ? this : $.enabled ? run(this.keys, txt+'') : txt+'';
- }
- return txt === void 0 ? chain([open], [blk]) : $.enabled ? run([blk], txt+'') : txt+'';
- };
- }
-
- kleur = $;
- return kleur;
-}
-
-var action$1;
-var hasRequiredAction$1;
-
-function requireAction$1 () {
- if (hasRequiredAction$1) return action$1;
- hasRequiredAction$1 = 1;
-
- action$1 = (key, isSelect) => {
- if (key.meta && key.name !== 'escape') return;
-
- if (key.ctrl) {
- if (key.name === 'a') return 'first';
- if (key.name === 'c') return 'abort';
- if (key.name === 'd') return 'abort';
- if (key.name === 'e') return 'last';
- if (key.name === 'g') return 'reset';
- }
-
- if (isSelect) {
- if (key.name === 'j') return 'down';
- if (key.name === 'k') return 'up';
- }
-
- if (key.name === 'return') return 'submit';
- if (key.name === 'enter') return 'submit'; // ctrl + J
-
- if (key.name === 'backspace') return 'delete';
- if (key.name === 'delete') return 'deleteForward';
- if (key.name === 'abort') return 'abort';
- if (key.name === 'escape') return 'exit';
- if (key.name === 'tab') return 'next';
- if (key.name === 'pagedown') return 'nextPage';
- if (key.name === 'pageup') return 'prevPage'; // TODO create home() in prompt types (e.g. TextPrompt)
-
- if (key.name === 'home') return 'home'; // TODO create end() in prompt types (e.g. TextPrompt)
-
- if (key.name === 'end') return 'end';
- if (key.name === 'up') return 'up';
- if (key.name === 'down') return 'down';
- if (key.name === 'right') return 'right';
- if (key.name === 'left') return 'left';
- return false;
- };
- return action$1;
-}
-
-var strip$1;
-var hasRequiredStrip$1;
-
-function requireStrip$1 () {
- if (hasRequiredStrip$1) return strip$1;
- hasRequiredStrip$1 = 1;
-
- strip$1 = str => {
- const pattern = ['[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)', '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))'].join('|');
- const RGX = new RegExp(pattern, 'g');
- return typeof str === 'string' ? str.replace(RGX, '') : str;
- };
- return strip$1;
-}
-
-var src;
-var hasRequiredSrc;
-
-function requireSrc () {
- if (hasRequiredSrc) return src;
- hasRequiredSrc = 1;
-
- const ESC = '\x1B';
- const CSI = `${ESC}[`;
- const beep = '\u0007';
-
- const cursor = {
- to(x, y) {
- if (!y) return `${CSI}${x + 1}G`;
- return `${CSI}${y + 1};${x + 1}H`;
- },
- move(x, y) {
- let ret = '';
-
- if (x < 0) ret += `${CSI}${-x}D`;
- else if (x > 0) ret += `${CSI}${x}C`;
-
- if (y < 0) ret += `${CSI}${-y}A`;
- else if (y > 0) ret += `${CSI}${y}B`;
-
- return ret;
- },
- up: (count = 1) => `${CSI}${count}A`,
- down: (count = 1) => `${CSI}${count}B`,
- forward: (count = 1) => `${CSI}${count}C`,
- backward: (count = 1) => `${CSI}${count}D`,
- nextLine: (count = 1) => `${CSI}E`.repeat(count),
- prevLine: (count = 1) => `${CSI}F`.repeat(count),
- left: `${CSI}G`,
- hide: `${CSI}?25l`,
- show: `${CSI}?25h`,
- save: `${ESC}7`,
- restore: `${ESC}8`
- };
-
- const scroll = {
- up: (count = 1) => `${CSI}S`.repeat(count),
- down: (count = 1) => `${CSI}T`.repeat(count)
- };
-
- const erase = {
- screen: `${CSI}2J`,
- up: (count = 1) => `${CSI}1J`.repeat(count),
- down: (count = 1) => `${CSI}J`.repeat(count),
- line: `${CSI}2K`,
- lineEnd: `${CSI}K`,
- lineStart: `${CSI}1K`,
- lines(count) {
- let clear = '';
- for (let i = 0; i < count; i++)
- clear += this.line + (i < count - 1 ? cursor.up() : '');
- if (count)
- clear += cursor.left;
- return clear;
- }
- };
-
- src = { cursor, scroll, erase, beep };
- return src;
-}
-
-var clear$1;
-var hasRequiredClear$1;
-
-function requireClear$1 () {
- if (hasRequiredClear$1) return clear$1;
- hasRequiredClear$1 = 1;
-
- function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike) { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
-
- function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
-
- function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
-
- const strip = requireStrip$1();
-
- const _require = requireSrc(),
- erase = _require.erase,
- cursor = _require.cursor;
-
- const width = str => [...strip(str)].length;
- /**
- * @param {string} prompt
- * @param {number} perLine
- */
-
-
- clear$1 = function (prompt, perLine) {
- if (!perLine) return erase.line + cursor.to(0);
- let rows = 0;
- const lines = prompt.split(/\r?\n/);
-
- var _iterator = _createForOfIteratorHelper(lines),
- _step;
-
- try {
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
- let line = _step.value;
- rows += 1 + Math.floor(Math.max(width(line) - 1, 0) / perLine);
- }
- } catch (err) {
- _iterator.e(err);
- } finally {
- _iterator.f();
- }
-
- return erase.lines(rows);
- };
- return clear$1;
-}
-
-var figures_1$1;
-var hasRequiredFigures$1;
-
-function requireFigures$1 () {
- if (hasRequiredFigures$1) return figures_1$1;
- hasRequiredFigures$1 = 1;
-
- const main = {
- arrowUp: '↑',
- arrowDown: '↓',
- arrowLeft: '←',
- arrowRight: '→',
- radioOn: '◉',
- radioOff: '◯',
- tick: '✔',
- cross: '✖',
- ellipsis: '…',
- pointerSmall: '›',
- line: '─',
- pointer: '❯'
- };
- const win = {
- arrowUp: main.arrowUp,
- arrowDown: main.arrowDown,
- arrowLeft: main.arrowLeft,
- arrowRight: main.arrowRight,
- radioOn: '(*)',
- radioOff: '( )',
- tick: '√',
- cross: '×',
- ellipsis: '...',
- pointerSmall: '»',
- line: '─',
- pointer: '>'
- };
- const figures = process.platform === 'win32' ? win : main;
- figures_1$1 = figures;
- return figures_1$1;
-}
-
-var style$1;
-var hasRequiredStyle$1;
-
-function requireStyle$1 () {
- if (hasRequiredStyle$1) return style$1;
- hasRequiredStyle$1 = 1;
-
- const c = requireKleur();
-
- const figures = requireFigures$1(); // rendering user input.
-
-
- const styles = Object.freeze({
- password: {
- scale: 1,
- render: input => '*'.repeat(input.length)
- },
- emoji: {
- scale: 2,
- render: input => '😃'.repeat(input.length)
- },
- invisible: {
- scale: 0,
- render: input => ''
- },
- default: {
- scale: 1,
- render: input => `${input}`
- }
- });
-
- const render = type => styles[type] || styles.default; // icon to signalize a prompt.
-
-
- const symbols = Object.freeze({
- aborted: c.red(figures.cross),
- done: c.green(figures.tick),
- exited: c.yellow(figures.cross),
- default: c.cyan('?')
- });
-
- const symbol = (done, aborted, exited) => aborted ? symbols.aborted : exited ? symbols.exited : done ? symbols.done : symbols.default; // between the question and the user's input.
-
-
- const delimiter = completing => c.gray(completing ? figures.ellipsis : figures.pointerSmall);
-
- const item = (expandable, expanded) => c.gray(expandable ? expanded ? figures.pointerSmall : '+' : figures.line);
-
- style$1 = {
- styles,
- render,
- symbols,
- symbol,
- delimiter,
- item
- };
- return style$1;
-}
-
-var lines$1;
-var hasRequiredLines$1;
-
-function requireLines$1 () {
- if (hasRequiredLines$1) return lines$1;
- hasRequiredLines$1 = 1;
-
- const strip = requireStrip$1();
- /**
- * @param {string} msg
- * @param {number} perLine
- */
-
-
- lines$1 = function (msg, perLine) {
- let lines = String(strip(msg) || '').split(/\r?\n/);
- if (!perLine) return lines.length;
- return lines.map(l => Math.ceil(l.length / perLine)).reduce((a, b) => a + b);
- };
- return lines$1;
-}
-
-var wrap$1;
-var hasRequiredWrap$1;
-
-function requireWrap$1 () {
- if (hasRequiredWrap$1) return wrap$1;
- hasRequiredWrap$1 = 1;
- /**
- * @param {string} msg The message to wrap
- * @param {object} opts
- * @param {number|string} [opts.margin] Left margin
- * @param {number} opts.width Maximum characters per line including the margin
- */
-
- wrap$1 = (msg, opts = {}) => {
- const tab = Number.isSafeInteger(parseInt(opts.margin)) ? new Array(parseInt(opts.margin)).fill(' ').join('') : opts.margin || '';
- const width = opts.width;
- return (msg || '').split(/\r?\n/g).map(line => line.split(/\s+/g).reduce((arr, w) => {
- if (w.length + tab.length >= width || arr[arr.length - 1].length + w.length + 1 < width) arr[arr.length - 1] += ` ${w}`;else arr.push(`${tab}${w}`);
- return arr;
- }, [tab]).join('\n')).join('\n');
- };
- return wrap$1;
-}
-
-var entriesToDisplay$1;
-var hasRequiredEntriesToDisplay$1;
-
-function requireEntriesToDisplay$1 () {
- if (hasRequiredEntriesToDisplay$1) return entriesToDisplay$1;
- hasRequiredEntriesToDisplay$1 = 1;
- /**
- * Determine what entries should be displayed on the screen, based on the
- * currently selected index and the maximum visible. Used in list-based
- * prompts like `select` and `multiselect`.
- *
- * @param {number} cursor the currently selected entry
- * @param {number} total the total entries available to display
- * @param {number} [maxVisible] the number of entries that can be displayed
- */
-
- entriesToDisplay$1 = (cursor, total, maxVisible) => {
- maxVisible = maxVisible || total;
- let startIndex = Math.min(total - maxVisible, cursor - Math.floor(maxVisible / 2));
- if (startIndex < 0) startIndex = 0;
- let endIndex = Math.min(startIndex + maxVisible, total);
- return {
- startIndex,
- endIndex
- };
- };
- return entriesToDisplay$1;
-}
-
-var util$1;
-var hasRequiredUtil$1;
-
-function requireUtil$1 () {
- if (hasRequiredUtil$1) return util$1;
- hasRequiredUtil$1 = 1;
-
- util$1 = {
- action: requireAction$1(),
- clear: requireClear$1(),
- style: requireStyle$1(),
- strip: requireStrip$1(),
- figures: requireFigures$1(),
- lines: requireLines$1(),
- wrap: requireWrap$1(),
- entriesToDisplay: requireEntriesToDisplay$1()
- };
- return util$1;
-}
-
-var prompt$2;
-var hasRequiredPrompt$1;
-
-function requirePrompt$1 () {
- if (hasRequiredPrompt$1) return prompt$2;
- hasRequiredPrompt$1 = 1;
-
- const readline = require$$0;
-
- const _require = requireUtil$1(),
- action = _require.action;
-
- const EventEmitter = require$$0$1;
-
- const _require2 = requireSrc(),
- beep = _require2.beep,
- cursor = _require2.cursor;
-
- const color = requireKleur();
- /**
- * Base prompt skeleton
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- */
-
-
- class Prompt extends EventEmitter {
- constructor(opts = {}) {
- super();
- this.firstRender = true;
- this.in = opts.stdin || process.stdin;
- this.out = opts.stdout || process.stdout;
-
- this.onRender = (opts.onRender || (() => void 0)).bind(this);
-
- const rl = readline.createInterface({
- input: this.in,
- escapeCodeTimeout: 50
- });
- readline.emitKeypressEvents(this.in, rl);
- if (this.in.isTTY) this.in.setRawMode(true);
- const isSelect = ['SelectPrompt', 'MultiselectPrompt'].indexOf(this.constructor.name) > -1;
-
- const keypress = (str, key) => {
- let a = action(key, isSelect);
-
- if (a === false) {
- this._ && this._(str, key);
- } else if (typeof this[a] === 'function') {
- this[a](key);
- } else {
- this.bell();
- }
- };
-
- this.close = () => {
- this.out.write(cursor.show);
- this.in.removeListener('keypress', keypress);
- if (this.in.isTTY) this.in.setRawMode(false);
- rl.close();
- this.emit(this.aborted ? 'abort' : this.exited ? 'exit' : 'submit', this.value);
- this.closed = true;
- };
-
- this.in.on('keypress', keypress);
- }
-
- fire() {
- this.emit('state', {
- value: this.value,
- aborted: !!this.aborted,
- exited: !!this.exited
- });
- }
-
- bell() {
- this.out.write(beep);
- }
-
- render() {
- this.onRender(color);
- if (this.firstRender) this.firstRender = false;
- }
-
- }
-
- prompt$2 = Prompt;
- return prompt$2;
-}
-
-var text$1;
-var hasRequiredText$1;
-
-function requireText$1 () {
- if (hasRequiredText$1) return text$1;
- hasRequiredText$1 = 1;
-
- function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
-
- function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
-
- const color = requireKleur();
-
- const Prompt = requirePrompt$1();
-
- const _require = requireSrc(),
- erase = _require.erase,
- cursor = _require.cursor;
-
- const _require2 = requireUtil$1(),
- style = _require2.style,
- clear = _require2.clear,
- lines = _require2.lines,
- figures = _require2.figures;
- /**
- * TextPrompt Base Element
- * @param {Object} opts Options
- * @param {String} opts.message Message
- * @param {String} [opts.style='default'] Render style
- * @param {String} [opts.initial] Default value
- * @param {Function} [opts.validate] Validate function
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- * @param {String} [opts.error] The invalid error label
- */
-
-
- class TextPrompt extends Prompt {
- constructor(opts = {}) {
- super(opts);
- this.transform = style.render(opts.style);
- this.scale = this.transform.scale;
- this.msg = opts.message;
- this.initial = opts.initial || ``;
-
- this.validator = opts.validate || (() => true);
-
- this.value = ``;
- this.errorMsg = opts.error || `Please Enter A Valid Value`;
- this.cursor = Number(!!this.initial);
- this.cursorOffset = 0;
- this.clear = clear(``, this.out.columns);
- this.render();
- }
-
- set value(v) {
- if (!v && this.initial) {
- this.placeholder = true;
- this.rendered = color.gray(this.transform.render(this.initial));
- } else {
- this.placeholder = false;
- this.rendered = this.transform.render(v);
- }
-
- this._value = v;
- this.fire();
- }
-
- get value() {
- return this._value;
- }
-
- reset() {
- this.value = ``;
- this.cursor = Number(!!this.initial);
- this.cursorOffset = 0;
- this.fire();
- this.render();
- }
-
- exit() {
- this.abort();
- }
-
- abort() {
- this.value = this.value || this.initial;
- this.done = this.aborted = true;
- this.error = false;
- this.red = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- validate() {
- var _this = this;
-
- return _asyncToGenerator(function* () {
- let valid = yield _this.validator(_this.value);
-
- if (typeof valid === `string`) {
- _this.errorMsg = valid;
- valid = false;
- }
-
- _this.error = !valid;
- })();
- }
-
- submit() {
- var _this2 = this;
-
- return _asyncToGenerator(function* () {
- _this2.value = _this2.value || _this2.initial;
- _this2.cursorOffset = 0;
- _this2.cursor = _this2.rendered.length;
- yield _this2.validate();
-
- if (_this2.error) {
- _this2.red = true;
-
- _this2.fire();
-
- _this2.render();
-
- return;
- }
-
- _this2.done = true;
- _this2.aborted = false;
-
- _this2.fire();
-
- _this2.render();
-
- _this2.out.write('\n');
-
- _this2.close();
- })();
- }
-
- next() {
- if (!this.placeholder) return this.bell();
- this.value = this.initial;
- this.cursor = this.rendered.length;
- this.fire();
- this.render();
- }
-
- moveCursor(n) {
- if (this.placeholder) return;
- this.cursor = this.cursor + n;
- this.cursorOffset += n;
- }
-
- _(c, key) {
- let s1 = this.value.slice(0, this.cursor);
- let s2 = this.value.slice(this.cursor);
- this.value = `${s1}${c}${s2}`;
- this.red = false;
- this.cursor = this.placeholder ? 0 : s1.length + 1;
- this.render();
- }
-
- delete() {
- if (this.isCursorAtStart()) return this.bell();
- let s1 = this.value.slice(0, this.cursor - 1);
- let s2 = this.value.slice(this.cursor);
- this.value = `${s1}${s2}`;
- this.red = false;
-
- if (this.isCursorAtStart()) {
- this.cursorOffset = 0;
- } else {
- this.cursorOffset++;
- this.moveCursor(-1);
- }
-
- this.render();
- }
-
- deleteForward() {
- if (this.cursor * this.scale >= this.rendered.length || this.placeholder) return this.bell();
- let s1 = this.value.slice(0, this.cursor);
- let s2 = this.value.slice(this.cursor + 1);
- this.value = `${s1}${s2}`;
- this.red = false;
-
- if (this.isCursorAtEnd()) {
- this.cursorOffset = 0;
- } else {
- this.cursorOffset++;
- }
-
- this.render();
- }
-
- first() {
- this.cursor = 0;
- this.render();
- }
-
- last() {
- this.cursor = this.value.length;
- this.render();
- }
-
- left() {
- if (this.cursor <= 0 || this.placeholder) return this.bell();
- this.moveCursor(-1);
- this.render();
- }
-
- right() {
- if (this.cursor * this.scale >= this.rendered.length || this.placeholder) return this.bell();
- this.moveCursor(1);
- this.render();
- }
-
- isCursorAtStart() {
- return this.cursor === 0 || this.placeholder && this.cursor === 1;
- }
-
- isCursorAtEnd() {
- return this.cursor === this.rendered.length || this.placeholder && this.cursor === this.rendered.length + 1;
- }
-
- render() {
- if (this.closed) return;
-
- if (!this.firstRender) {
- if (this.outputError) this.out.write(cursor.down(lines(this.outputError, this.out.columns) - 1) + clear(this.outputError, this.out.columns));
- this.out.write(clear(this.outputText, this.out.columns));
- }
-
- super.render();
- this.outputError = '';
- this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(this.done), this.red ? color.red(this.rendered) : this.rendered].join(` `);
-
- if (this.error) {
- this.outputError += this.errorMsg.split(`\n`).reduce((a, l, i) => a + `\n${i ? ' ' : figures.pointerSmall} ${color.red().italic(l)}`, ``);
- }
-
- this.out.write(erase.line + cursor.to(0) + this.outputText + cursor.save + this.outputError + cursor.restore + cursor.move(this.cursorOffset, 0));
- }
-
- }
-
- text$1 = TextPrompt;
- return text$1;
-}
-
-var select$1;
-var hasRequiredSelect$1;
-
-function requireSelect$1 () {
- if (hasRequiredSelect$1) return select$1;
- hasRequiredSelect$1 = 1;
-
- const color = requireKleur();
-
- const Prompt = requirePrompt$1();
-
- const _require = requireUtil$1(),
- style = _require.style,
- clear = _require.clear,
- figures = _require.figures,
- wrap = _require.wrap,
- entriesToDisplay = _require.entriesToDisplay;
-
- const _require2 = requireSrc(),
- cursor = _require2.cursor;
- /**
- * SelectPrompt Base Element
- * @param {Object} opts Options
- * @param {String} opts.message Message
- * @param {Array} opts.choices Array of choice objects
- * @param {String} [opts.hint] Hint to display
- * @param {Number} [opts.initial] Index of default value
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- * @param {Number} [opts.optionsPerPage=10] Max options to display at once
- */
-
-
- class SelectPrompt extends Prompt {
- constructor(opts = {}) {
- super(opts);
- this.msg = opts.message;
- this.hint = opts.hint || '- Use arrow-keys. Return to submit.';
- this.warn = opts.warn || '- This option is disabled';
- this.cursor = opts.initial || 0;
- this.choices = opts.choices.map((ch, idx) => {
- if (typeof ch === 'string') ch = {
- title: ch,
- value: idx
- };
- return {
- title: ch && (ch.title || ch.value || ch),
- value: ch && (ch.value === undefined ? idx : ch.value),
- description: ch && ch.description,
- selected: ch && ch.selected,
- disabled: ch && ch.disabled
- };
- });
- this.optionsPerPage = opts.optionsPerPage || 10;
- this.value = (this.choices[this.cursor] || {}).value;
- this.clear = clear('', this.out.columns);
- this.render();
- }
-
- moveCursor(n) {
- this.cursor = n;
- this.value = this.choices[n].value;
- this.fire();
- }
-
- reset() {
- this.moveCursor(0);
- this.fire();
- this.render();
- }
-
- exit() {
- this.abort();
- }
-
- abort() {
- this.done = this.aborted = true;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- submit() {
- if (!this.selection.disabled) {
- this.done = true;
- this.aborted = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- } else this.bell();
- }
-
- first() {
- this.moveCursor(0);
- this.render();
- }
-
- last() {
- this.moveCursor(this.choices.length - 1);
- this.render();
- }
-
- up() {
- if (this.cursor === 0) {
- this.moveCursor(this.choices.length - 1);
- } else {
- this.moveCursor(this.cursor - 1);
- }
-
- this.render();
- }
-
- down() {
- if (this.cursor === this.choices.length - 1) {
- this.moveCursor(0);
- } else {
- this.moveCursor(this.cursor + 1);
- }
-
- this.render();
- }
-
- next() {
- this.moveCursor((this.cursor + 1) % this.choices.length);
- this.render();
- }
-
- _(c, key) {
- if (c === ' ') return this.submit();
- }
-
- get selection() {
- return this.choices[this.cursor];
- }
-
- render() {
- if (this.closed) return;
- if (this.firstRender) this.out.write(cursor.hide);else this.out.write(clear(this.outputText, this.out.columns));
- super.render();
-
- let _entriesToDisplay = entriesToDisplay(this.cursor, this.choices.length, this.optionsPerPage),
- startIndex = _entriesToDisplay.startIndex,
- endIndex = _entriesToDisplay.endIndex; // Print prompt
-
-
- this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(false), this.done ? this.selection.title : this.selection.disabled ? color.yellow(this.warn) : color.gray(this.hint)].join(' '); // Print choices
-
- if (!this.done) {
- this.outputText += '\n';
-
- for (let i = startIndex; i < endIndex; i++) {
- let title,
- prefix,
- desc = '',
- v = this.choices[i]; // Determine whether to display "more choices" indicators
-
- if (i === startIndex && startIndex > 0) {
- prefix = figures.arrowUp;
- } else if (i === endIndex - 1 && endIndex < this.choices.length) {
- prefix = figures.arrowDown;
- } else {
- prefix = ' ';
- }
-
- if (v.disabled) {
- title = this.cursor === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title);
- prefix = (this.cursor === i ? color.bold().gray(figures.pointer) + ' ' : ' ') + prefix;
- } else {
- title = this.cursor === i ? color.cyan().underline(v.title) : v.title;
- prefix = (this.cursor === i ? color.cyan(figures.pointer) + ' ' : ' ') + prefix;
-
- if (v.description && this.cursor === i) {
- desc = ` - ${v.description}`;
-
- if (prefix.length + title.length + desc.length >= this.out.columns || v.description.split(/\r?\n/).length > 1) {
- desc = '\n' + wrap(v.description, {
- margin: 3,
- width: this.out.columns
- });
- }
- }
- }
-
- this.outputText += `${prefix} ${title}${color.gray(desc)}\n`;
- }
- }
-
- this.out.write(this.outputText);
- }
-
- }
-
- select$1 = SelectPrompt;
- return select$1;
-}
-
-var toggle$1;
-var hasRequiredToggle$1;
-
-function requireToggle$1 () {
- if (hasRequiredToggle$1) return toggle$1;
- hasRequiredToggle$1 = 1;
-
- const color = requireKleur();
-
- const Prompt = requirePrompt$1();
-
- const _require = requireUtil$1(),
- style = _require.style,
- clear = _require.clear;
-
- const _require2 = requireSrc(),
- cursor = _require2.cursor,
- erase = _require2.erase;
- /**
- * TogglePrompt Base Element
- * @param {Object} opts Options
- * @param {String} opts.message Message
- * @param {Boolean} [opts.initial=false] Default value
- * @param {String} [opts.active='no'] Active label
- * @param {String} [opts.inactive='off'] Inactive label
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- */
-
-
- class TogglePrompt extends Prompt {
- constructor(opts = {}) {
- super(opts);
- this.msg = opts.message;
- this.value = !!opts.initial;
- this.active = opts.active || 'on';
- this.inactive = opts.inactive || 'off';
- this.initialValue = this.value;
- this.render();
- }
-
- reset() {
- this.value = this.initialValue;
- this.fire();
- this.render();
- }
-
- exit() {
- this.abort();
- }
-
- abort() {
- this.done = this.aborted = true;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- submit() {
- this.done = true;
- this.aborted = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- deactivate() {
- if (this.value === false) return this.bell();
- this.value = false;
- this.render();
- }
-
- activate() {
- if (this.value === true) return this.bell();
- this.value = true;
- this.render();
- }
-
- delete() {
- this.deactivate();
- }
-
- left() {
- this.deactivate();
- }
-
- right() {
- this.activate();
- }
-
- down() {
- this.deactivate();
- }
-
- up() {
- this.activate();
- }
-
- next() {
- this.value = !this.value;
- this.fire();
- this.render();
- }
-
- _(c, key) {
- if (c === ' ') {
- this.value = !this.value;
- } else if (c === '1') {
- this.value = true;
- } else if (c === '0') {
- this.value = false;
- } else return this.bell();
-
- this.render();
- }
-
- render() {
- if (this.closed) return;
- if (this.firstRender) this.out.write(cursor.hide);else this.out.write(clear(this.outputText, this.out.columns));
- super.render();
- this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(this.done), this.value ? this.inactive : color.cyan().underline(this.inactive), color.gray('/'), this.value ? color.cyan().underline(this.active) : this.active].join(' ');
- this.out.write(erase.line + cursor.to(0) + this.outputText);
- }
-
- }
-
- toggle$1 = TogglePrompt;
- return toggle$1;
-}
-
-var datepart$1;
-var hasRequiredDatepart$1;
-
-function requireDatepart$1 () {
- if (hasRequiredDatepart$1) return datepart$1;
- hasRequiredDatepart$1 = 1;
-
- class DatePart {
- constructor({
- token,
- date,
- parts,
- locales
- }) {
- this.token = token;
- this.date = date || new Date();
- this.parts = parts || [this];
- this.locales = locales || {};
- }
-
- up() {}
-
- down() {}
-
- next() {
- const currentIdx = this.parts.indexOf(this);
- return this.parts.find((part, idx) => idx > currentIdx && part instanceof DatePart);
- }
-
- setTo(val) {}
-
- prev() {
- let parts = [].concat(this.parts).reverse();
- const currentIdx = parts.indexOf(this);
- return parts.find((part, idx) => idx > currentIdx && part instanceof DatePart);
- }
-
- toString() {
- return String(this.date);
- }
-
- }
-
- datepart$1 = DatePart;
- return datepart$1;
-}
-
-var meridiem$1;
-var hasRequiredMeridiem$1;
-
-function requireMeridiem$1 () {
- if (hasRequiredMeridiem$1) return meridiem$1;
- hasRequiredMeridiem$1 = 1;
-
- const DatePart = requireDatepart$1();
-
- class Meridiem extends DatePart {
- constructor(opts = {}) {
- super(opts);
- }
-
- up() {
- this.date.setHours((this.date.getHours() + 12) % 24);
- }
-
- down() {
- this.up();
- }
-
- toString() {
- let meridiem = this.date.getHours() > 12 ? 'pm' : 'am';
- return /\A/.test(this.token) ? meridiem.toUpperCase() : meridiem;
- }
-
- }
-
- meridiem$1 = Meridiem;
- return meridiem$1;
-}
-
-var day$1;
-var hasRequiredDay$1;
-
-function requireDay$1 () {
- if (hasRequiredDay$1) return day$1;
- hasRequiredDay$1 = 1;
-
- const DatePart = requireDatepart$1();
-
- const pos = n => {
- n = n % 10;
- return n === 1 ? 'st' : n === 2 ? 'nd' : n === 3 ? 'rd' : 'th';
- };
-
- class Day extends DatePart {
- constructor(opts = {}) {
- super(opts);
- }
-
- up() {
- this.date.setDate(this.date.getDate() + 1);
- }
-
- down() {
- this.date.setDate(this.date.getDate() - 1);
- }
-
- setTo(val) {
- this.date.setDate(parseInt(val.substr(-2)));
- }
-
- toString() {
- let date = this.date.getDate();
- let day = this.date.getDay();
- return this.token === 'DD' ? String(date).padStart(2, '0') : this.token === 'Do' ? date + pos(date) : this.token === 'd' ? day + 1 : this.token === 'ddd' ? this.locales.weekdaysShort[day] : this.token === 'dddd' ? this.locales.weekdays[day] : date;
- }
-
- }
-
- day$1 = Day;
- return day$1;
-}
-
-var hours$1;
-var hasRequiredHours$1;
-
-function requireHours$1 () {
- if (hasRequiredHours$1) return hours$1;
- hasRequiredHours$1 = 1;
-
- const DatePart = requireDatepart$1();
-
- class Hours extends DatePart {
- constructor(opts = {}) {
- super(opts);
- }
-
- up() {
- this.date.setHours(this.date.getHours() + 1);
- }
-
- down() {
- this.date.setHours(this.date.getHours() - 1);
- }
-
- setTo(val) {
- this.date.setHours(parseInt(val.substr(-2)));
- }
-
- toString() {
- let hours = this.date.getHours();
- if (/h/.test(this.token)) hours = hours % 12 || 12;
- return this.token.length > 1 ? String(hours).padStart(2, '0') : hours;
- }
-
- }
-
- hours$1 = Hours;
- return hours$1;
-}
-
-var milliseconds$1;
-var hasRequiredMilliseconds$1;
-
-function requireMilliseconds$1 () {
- if (hasRequiredMilliseconds$1) return milliseconds$1;
- hasRequiredMilliseconds$1 = 1;
-
- const DatePart = requireDatepart$1();
-
- class Milliseconds extends DatePart {
- constructor(opts = {}) {
- super(opts);
- }
-
- up() {
- this.date.setMilliseconds(this.date.getMilliseconds() + 1);
- }
-
- down() {
- this.date.setMilliseconds(this.date.getMilliseconds() - 1);
- }
-
- setTo(val) {
- this.date.setMilliseconds(parseInt(val.substr(-this.token.length)));
- }
-
- toString() {
- return String(this.date.getMilliseconds()).padStart(4, '0').substr(0, this.token.length);
- }
-
- }
-
- milliseconds$1 = Milliseconds;
- return milliseconds$1;
-}
-
-var minutes$1;
-var hasRequiredMinutes$1;
-
-function requireMinutes$1 () {
- if (hasRequiredMinutes$1) return minutes$1;
- hasRequiredMinutes$1 = 1;
-
- const DatePart = requireDatepart$1();
-
- class Minutes extends DatePart {
- constructor(opts = {}) {
- super(opts);
- }
-
- up() {
- this.date.setMinutes(this.date.getMinutes() + 1);
- }
-
- down() {
- this.date.setMinutes(this.date.getMinutes() - 1);
- }
-
- setTo(val) {
- this.date.setMinutes(parseInt(val.substr(-2)));
- }
-
- toString() {
- let m = this.date.getMinutes();
- return this.token.length > 1 ? String(m).padStart(2, '0') : m;
- }
-
- }
-
- minutes$1 = Minutes;
- return minutes$1;
-}
-
-var month$1;
-var hasRequiredMonth$1;
-
-function requireMonth$1 () {
- if (hasRequiredMonth$1) return month$1;
- hasRequiredMonth$1 = 1;
-
- const DatePart = requireDatepart$1();
-
- class Month extends DatePart {
- constructor(opts = {}) {
- super(opts);
- }
-
- up() {
- this.date.setMonth(this.date.getMonth() + 1);
- }
-
- down() {
- this.date.setMonth(this.date.getMonth() - 1);
- }
-
- setTo(val) {
- val = parseInt(val.substr(-2)) - 1;
- this.date.setMonth(val < 0 ? 0 : val);
- }
-
- toString() {
- let month = this.date.getMonth();
- let tl = this.token.length;
- return tl === 2 ? String(month + 1).padStart(2, '0') : tl === 3 ? this.locales.monthsShort[month] : tl === 4 ? this.locales.months[month] : String(month + 1);
- }
-
- }
-
- month$1 = Month;
- return month$1;
-}
-
-var seconds$1;
-var hasRequiredSeconds$1;
-
-function requireSeconds$1 () {
- if (hasRequiredSeconds$1) return seconds$1;
- hasRequiredSeconds$1 = 1;
-
- const DatePart = requireDatepart$1();
-
- class Seconds extends DatePart {
- constructor(opts = {}) {
- super(opts);
- }
-
- up() {
- this.date.setSeconds(this.date.getSeconds() + 1);
- }
-
- down() {
- this.date.setSeconds(this.date.getSeconds() - 1);
- }
-
- setTo(val) {
- this.date.setSeconds(parseInt(val.substr(-2)));
- }
-
- toString() {
- let s = this.date.getSeconds();
- return this.token.length > 1 ? String(s).padStart(2, '0') : s;
- }
-
- }
-
- seconds$1 = Seconds;
- return seconds$1;
-}
-
-var year$1;
-var hasRequiredYear$1;
-
-function requireYear$1 () {
- if (hasRequiredYear$1) return year$1;
- hasRequiredYear$1 = 1;
-
- const DatePart = requireDatepart$1();
-
- class Year extends DatePart {
- constructor(opts = {}) {
- super(opts);
- }
-
- up() {
- this.date.setFullYear(this.date.getFullYear() + 1);
- }
-
- down() {
- this.date.setFullYear(this.date.getFullYear() - 1);
- }
-
- setTo(val) {
- this.date.setFullYear(val.substr(-4));
- }
-
- toString() {
- let year = String(this.date.getFullYear()).padStart(4, '0');
- return this.token.length === 2 ? year.substr(-2) : year;
- }
-
- }
-
- year$1 = Year;
- return year$1;
-}
-
-var dateparts$1;
-var hasRequiredDateparts$1;
-
-function requireDateparts$1 () {
- if (hasRequiredDateparts$1) return dateparts$1;
- hasRequiredDateparts$1 = 1;
-
- dateparts$1 = {
- DatePart: requireDatepart$1(),
- Meridiem: requireMeridiem$1(),
- Day: requireDay$1(),
- Hours: requireHours$1(),
- Milliseconds: requireMilliseconds$1(),
- Minutes: requireMinutes$1(),
- Month: requireMonth$1(),
- Seconds: requireSeconds$1(),
- Year: requireYear$1()
- };
- return dateparts$1;
-}
-
-var date$1;
-var hasRequiredDate$1;
-
-function requireDate$1 () {
- if (hasRequiredDate$1) return date$1;
- hasRequiredDate$1 = 1;
-
- function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
-
- function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
-
- const color = requireKleur();
-
- const Prompt = requirePrompt$1();
-
- const _require = requireUtil$1(),
- style = _require.style,
- clear = _require.clear,
- figures = _require.figures;
-
- const _require2 = requireSrc(),
- erase = _require2.erase,
- cursor = _require2.cursor;
-
- const _require3 = requireDateparts$1(),
- DatePart = _require3.DatePart,
- Meridiem = _require3.Meridiem,
- Day = _require3.Day,
- Hours = _require3.Hours,
- Milliseconds = _require3.Milliseconds,
- Minutes = _require3.Minutes,
- Month = _require3.Month,
- Seconds = _require3.Seconds,
- Year = _require3.Year;
-
- const regex = /\\(.)|"((?:\\["\\]|[^"])+)"|(D[Do]?|d{3,4}|d)|(M{1,4})|(YY(?:YY)?)|([aA])|([Hh]{1,2})|(m{1,2})|(s{1,2})|(S{1,4})|./g;
- const regexGroups = {
- 1: ({
- token
- }) => token.replace(/\\(.)/g, '$1'),
- 2: opts => new Day(opts),
- // Day // TODO
- 3: opts => new Month(opts),
- // Month
- 4: opts => new Year(opts),
- // Year
- 5: opts => new Meridiem(opts),
- // AM/PM // TODO (special)
- 6: opts => new Hours(opts),
- // Hours
- 7: opts => new Minutes(opts),
- // Minutes
- 8: opts => new Seconds(opts),
- // Seconds
- 9: opts => new Milliseconds(opts) // Fractional seconds
-
- };
- const dfltLocales = {
- months: 'January,February,March,April,May,June,July,August,September,October,November,December'.split(','),
- monthsShort: 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
- weekdays: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
- weekdaysShort: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(',')
- };
- /**
- * DatePrompt Base Element
- * @param {Object} opts Options
- * @param {String} opts.message Message
- * @param {Number} [opts.initial] Index of default value
- * @param {String} [opts.mask] The format mask
- * @param {object} [opts.locales] The date locales
- * @param {String} [opts.error] The error message shown on invalid value
- * @param {Function} [opts.validate] Function to validate the submitted value
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- */
-
- class DatePrompt extends Prompt {
- constructor(opts = {}) {
- super(opts);
- this.msg = opts.message;
- this.cursor = 0;
- this.typed = '';
- this.locales = Object.assign(dfltLocales, opts.locales);
- this._date = opts.initial || new Date();
- this.errorMsg = opts.error || 'Please Enter A Valid Value';
-
- this.validator = opts.validate || (() => true);
-
- this.mask = opts.mask || 'YYYY-MM-DD HH:mm:ss';
- this.clear = clear('', this.out.columns);
- this.render();
- }
-
- get value() {
- return this.date;
- }
-
- get date() {
- return this._date;
- }
-
- set date(date) {
- if (date) this._date.setTime(date.getTime());
- }
-
- set mask(mask) {
- let result;
- this.parts = [];
-
- while (result = regex.exec(mask)) {
- let match = result.shift();
- let idx = result.findIndex(gr => gr != null);
- this.parts.push(idx in regexGroups ? regexGroups[idx]({
- token: result[idx] || match,
- date: this.date,
- parts: this.parts,
- locales: this.locales
- }) : result[idx] || match);
- }
-
- let parts = this.parts.reduce((arr, i) => {
- if (typeof i === 'string' && typeof arr[arr.length - 1] === 'string') arr[arr.length - 1] += i;else arr.push(i);
- return arr;
- }, []);
- this.parts.splice(0);
- this.parts.push(...parts);
- this.reset();
- }
-
- moveCursor(n) {
- this.typed = '';
- this.cursor = n;
- this.fire();
- }
-
- reset() {
- this.moveCursor(this.parts.findIndex(p => p instanceof DatePart));
- this.fire();
- this.render();
- }
-
- exit() {
- this.abort();
- }
-
- abort() {
- this.done = this.aborted = true;
- this.error = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- validate() {
- var _this = this;
-
- return _asyncToGenerator(function* () {
- let valid = yield _this.validator(_this.value);
-
- if (typeof valid === 'string') {
- _this.errorMsg = valid;
- valid = false;
- }
-
- _this.error = !valid;
- })();
- }
-
- submit() {
- var _this2 = this;
-
- return _asyncToGenerator(function* () {
- yield _this2.validate();
-
- if (_this2.error) {
- _this2.color = 'red';
-
- _this2.fire();
-
- _this2.render();
-
- return;
- }
-
- _this2.done = true;
- _this2.aborted = false;
-
- _this2.fire();
-
- _this2.render();
-
- _this2.out.write('\n');
-
- _this2.close();
- })();
- }
-
- up() {
- this.typed = '';
- this.parts[this.cursor].up();
- this.render();
- }
-
- down() {
- this.typed = '';
- this.parts[this.cursor].down();
- this.render();
- }
-
- left() {
- let prev = this.parts[this.cursor].prev();
- if (prev == null) return this.bell();
- this.moveCursor(this.parts.indexOf(prev));
- this.render();
- }
-
- right() {
- let next = this.parts[this.cursor].next();
- if (next == null) return this.bell();
- this.moveCursor(this.parts.indexOf(next));
- this.render();
- }
-
- next() {
- let next = this.parts[this.cursor].next();
- this.moveCursor(next ? this.parts.indexOf(next) : this.parts.findIndex(part => part instanceof DatePart));
- this.render();
- }
-
- _(c) {
- if (/\d/.test(c)) {
- this.typed += c;
- this.parts[this.cursor].setTo(this.typed);
- this.render();
- }
- }
-
- render() {
- if (this.closed) return;
- if (this.firstRender) this.out.write(cursor.hide);else this.out.write(clear(this.outputText, this.out.columns));
- super.render(); // Print prompt
-
- this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(false), this.parts.reduce((arr, p, idx) => arr.concat(idx === this.cursor && !this.done ? color.cyan().underline(p.toString()) : p), []).join('')].join(' '); // Print error
-
- if (this.error) {
- this.outputText += this.errorMsg.split('\n').reduce((a, l, i) => a + `\n${i ? ` ` : figures.pointerSmall} ${color.red().italic(l)}`, ``);
- }
-
- this.out.write(erase.line + cursor.to(0) + this.outputText);
- }
-
- }
-
- date$1 = DatePrompt;
- return date$1;
-}
-
-var number$1;
-var hasRequiredNumber$1;
-
-function requireNumber$1 () {
- if (hasRequiredNumber$1) return number$1;
- hasRequiredNumber$1 = 1;
-
- function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
-
- function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
-
- const color = requireKleur();
-
- const Prompt = requirePrompt$1();
-
- const _require = requireSrc(),
- cursor = _require.cursor,
- erase = _require.erase;
-
- const _require2 = requireUtil$1(),
- style = _require2.style,
- figures = _require2.figures,
- clear = _require2.clear,
- lines = _require2.lines;
-
- const isNumber = /[0-9]/;
-
- const isDef = any => any !== undefined;
-
- const round = (number, precision) => {
- let factor = Math.pow(10, precision);
- return Math.round(number * factor) / factor;
- };
- /**
- * NumberPrompt Base Element
- * @param {Object} opts Options
- * @param {String} opts.message Message
- * @param {String} [opts.style='default'] Render style
- * @param {Number} [opts.initial] Default value
- * @param {Number} [opts.max=+Infinity] Max value
- * @param {Number} [opts.min=-Infinity] Min value
- * @param {Boolean} [opts.float=false] Parse input as floats
- * @param {Number} [opts.round=2] Round floats to x decimals
- * @param {Number} [opts.increment=1] Number to increment by when using arrow-keys
- * @param {Function} [opts.validate] Validate function
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- * @param {String} [opts.error] The invalid error label
- */
-
-
- class NumberPrompt extends Prompt {
- constructor(opts = {}) {
- super(opts);
- this.transform = style.render(opts.style);
- this.msg = opts.message;
- this.initial = isDef(opts.initial) ? opts.initial : '';
- this.float = !!opts.float;
- this.round = opts.round || 2;
- this.inc = opts.increment || 1;
- this.min = isDef(opts.min) ? opts.min : -Infinity;
- this.max = isDef(opts.max) ? opts.max : Infinity;
- this.errorMsg = opts.error || `Please Enter A Valid Value`;
-
- this.validator = opts.validate || (() => true);
-
- this.color = `cyan`;
- this.value = ``;
- this.typed = ``;
- this.lastHit = 0;
- this.render();
- }
-
- set value(v) {
- if (!v && v !== 0) {
- this.placeholder = true;
- this.rendered = color.gray(this.transform.render(`${this.initial}`));
- this._value = ``;
- } else {
- this.placeholder = false;
- this.rendered = this.transform.render(`${round(v, this.round)}`);
- this._value = round(v, this.round);
- }
-
- this.fire();
- }
-
- get value() {
- return this._value;
- }
-
- parse(x) {
- return this.float ? parseFloat(x) : parseInt(x);
- }
-
- valid(c) {
- return c === `-` || c === `.` && this.float || isNumber.test(c);
- }
-
- reset() {
- this.typed = ``;
- this.value = ``;
- this.fire();
- this.render();
- }
-
- exit() {
- this.abort();
- }
-
- abort() {
- let x = this.value;
- this.value = x !== `` ? x : this.initial;
- this.done = this.aborted = true;
- this.error = false;
- this.fire();
- this.render();
- this.out.write(`\n`);
- this.close();
- }
-
- validate() {
- var _this = this;
-
- return _asyncToGenerator(function* () {
- let valid = yield _this.validator(_this.value);
-
- if (typeof valid === `string`) {
- _this.errorMsg = valid;
- valid = false;
- }
-
- _this.error = !valid;
- })();
- }
-
- submit() {
- var _this2 = this;
-
- return _asyncToGenerator(function* () {
- yield _this2.validate();
-
- if (_this2.error) {
- _this2.color = `red`;
-
- _this2.fire();
-
- _this2.render();
-
- return;
- }
-
- let x = _this2.value;
- _this2.value = x !== `` ? x : _this2.initial;
- _this2.done = true;
- _this2.aborted = false;
- _this2.error = false;
-
- _this2.fire();
-
- _this2.render();
-
- _this2.out.write(`\n`);
-
- _this2.close();
- })();
- }
-
- up() {
- this.typed = ``;
-
- if (this.value === '') {
- this.value = this.min - this.inc;
- }
-
- if (this.value >= this.max) return this.bell();
- this.value += this.inc;
- this.color = `cyan`;
- this.fire();
- this.render();
- }
-
- down() {
- this.typed = ``;
-
- if (this.value === '') {
- this.value = this.min + this.inc;
- }
-
- if (this.value <= this.min) return this.bell();
- this.value -= this.inc;
- this.color = `cyan`;
- this.fire();
- this.render();
- }
-
- delete() {
- let val = this.value.toString();
- if (val.length === 0) return this.bell();
- this.value = this.parse(val = val.slice(0, -1)) || ``;
-
- if (this.value !== '' && this.value < this.min) {
- this.value = this.min;
- }
-
- this.color = `cyan`;
- this.fire();
- this.render();
- }
-
- next() {
- this.value = this.initial;
- this.fire();
- this.render();
- }
-
- _(c, key) {
- if (!this.valid(c)) return this.bell();
- const now = Date.now();
- if (now - this.lastHit > 1000) this.typed = ``; // 1s elapsed
-
- this.typed += c;
- this.lastHit = now;
- this.color = `cyan`;
- if (c === `.`) return this.fire();
- this.value = Math.min(this.parse(this.typed), this.max);
- if (this.value > this.max) this.value = this.max;
- if (this.value < this.min) this.value = this.min;
- this.fire();
- this.render();
- }
-
- render() {
- if (this.closed) return;
-
- if (!this.firstRender) {
- if (this.outputError) this.out.write(cursor.down(lines(this.outputError, this.out.columns) - 1) + clear(this.outputError, this.out.columns));
- this.out.write(clear(this.outputText, this.out.columns));
- }
-
- super.render();
- this.outputError = ''; // Print prompt
-
- this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(this.done), !this.done || !this.done && !this.placeholder ? color[this.color]().underline(this.rendered) : this.rendered].join(` `); // Print error
-
- if (this.error) {
- this.outputError += this.errorMsg.split(`\n`).reduce((a, l, i) => a + `\n${i ? ` ` : figures.pointerSmall} ${color.red().italic(l)}`, ``);
- }
-
- this.out.write(erase.line + cursor.to(0) + this.outputText + cursor.save + this.outputError + cursor.restore);
- }
-
- }
-
- number$1 = NumberPrompt;
- return number$1;
-}
-
-var multiselect$1;
-var hasRequiredMultiselect$1;
-
-function requireMultiselect$1 () {
- if (hasRequiredMultiselect$1) return multiselect$1;
- hasRequiredMultiselect$1 = 1;
-
- const color = requireKleur();
-
- const _require = requireSrc(),
- cursor = _require.cursor;
-
- const Prompt = requirePrompt$1();
-
- const _require2 = requireUtil$1(),
- clear = _require2.clear,
- figures = _require2.figures,
- style = _require2.style,
- wrap = _require2.wrap,
- entriesToDisplay = _require2.entriesToDisplay;
- /**
- * MultiselectPrompt Base Element
- * @param {Object} opts Options
- * @param {String} opts.message Message
- * @param {Array} opts.choices Array of choice objects
- * @param {String} [opts.hint] Hint to display
- * @param {String} [opts.warn] Hint shown for disabled choices
- * @param {Number} [opts.max] Max choices
- * @param {Number} [opts.cursor=0] Cursor start position
- * @param {Number} [opts.optionsPerPage=10] Max options to display at once
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- */
-
-
- class MultiselectPrompt extends Prompt {
- constructor(opts = {}) {
- super(opts);
- this.msg = opts.message;
- this.cursor = opts.cursor || 0;
- this.scrollIndex = opts.cursor || 0;
- this.hint = opts.hint || '';
- this.warn = opts.warn || '- This option is disabled -';
- this.minSelected = opts.min;
- this.showMinError = false;
- this.maxChoices = opts.max;
- this.instructions = opts.instructions;
- this.optionsPerPage = opts.optionsPerPage || 10;
- this.value = opts.choices.map((ch, idx) => {
- if (typeof ch === 'string') ch = {
- title: ch,
- value: idx
- };
- return {
- title: ch && (ch.title || ch.value || ch),
- description: ch && ch.description,
- value: ch && (ch.value === undefined ? idx : ch.value),
- selected: ch && ch.selected,
- disabled: ch && ch.disabled
- };
- });
- this.clear = clear('', this.out.columns);
-
- if (!opts.overrideRender) {
- this.render();
- }
- }
-
- reset() {
- this.value.map(v => !v.selected);
- this.cursor = 0;
- this.fire();
- this.render();
- }
-
- selected() {
- return this.value.filter(v => v.selected);
- }
-
- exit() {
- this.abort();
- }
-
- abort() {
- this.done = this.aborted = true;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- submit() {
- const selected = this.value.filter(e => e.selected);
-
- if (this.minSelected && selected.length < this.minSelected) {
- this.showMinError = true;
- this.render();
- } else {
- this.done = true;
- this.aborted = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
- }
-
- first() {
- this.cursor = 0;
- this.render();
- }
-
- last() {
- this.cursor = this.value.length - 1;
- this.render();
- }
-
- next() {
- this.cursor = (this.cursor + 1) % this.value.length;
- this.render();
- }
-
- up() {
- if (this.cursor === 0) {
- this.cursor = this.value.length - 1;
- } else {
- this.cursor--;
- }
-
- this.render();
- }
-
- down() {
- if (this.cursor === this.value.length - 1) {
- this.cursor = 0;
- } else {
- this.cursor++;
- }
-
- this.render();
- }
-
- left() {
- this.value[this.cursor].selected = false;
- this.render();
- }
-
- right() {
- if (this.value.filter(e => e.selected).length >= this.maxChoices) return this.bell();
- this.value[this.cursor].selected = true;
- this.render();
- }
-
- handleSpaceToggle() {
- const v = this.value[this.cursor];
-
- if (v.selected) {
- v.selected = false;
- this.render();
- } else if (v.disabled || this.value.filter(e => e.selected).length >= this.maxChoices) {
- return this.bell();
- } else {
- v.selected = true;
- this.render();
- }
- }
-
- toggleAll() {
- if (this.maxChoices !== undefined || this.value[this.cursor].disabled) {
- return this.bell();
- }
-
- const newSelected = !this.value[this.cursor].selected;
- this.value.filter(v => !v.disabled).forEach(v => v.selected = newSelected);
- this.render();
- }
-
- _(c, key) {
- if (c === ' ') {
- this.handleSpaceToggle();
- } else if (c === 'a') {
- this.toggleAll();
- } else {
- return this.bell();
- }
- }
-
- renderInstructions() {
- if (this.instructions === undefined || this.instructions) {
- if (typeof this.instructions === 'string') {
- return this.instructions;
- }
-
- return '\nInstructions:\n' + ` ${figures.arrowUp}/${figures.arrowDown}: Highlight option\n` + ` ${figures.arrowLeft}/${figures.arrowRight}/[space]: Toggle selection\n` + (this.maxChoices === undefined ? ` a: Toggle all\n` : '') + ` enter/return: Complete answer`;
- }
-
- return '';
- }
-
- renderOption(cursor, v, i, arrowIndicator) {
- const prefix = (v.selected ? color.green(figures.radioOn) : figures.radioOff) + ' ' + arrowIndicator + ' ';
- let title, desc;
-
- if (v.disabled) {
- title = cursor === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title);
- } else {
- title = cursor === i ? color.cyan().underline(v.title) : v.title;
-
- if (cursor === i && v.description) {
- desc = ` - ${v.description}`;
-
- if (prefix.length + title.length + desc.length >= this.out.columns || v.description.split(/\r?\n/).length > 1) {
- desc = '\n' + wrap(v.description, {
- margin: prefix.length,
- width: this.out.columns
- });
- }
- }
- }
-
- return prefix + title + color.gray(desc || '');
- } // shared with autocompleteMultiselect
-
-
- paginateOptions(options) {
- if (options.length === 0) {
- return color.red('No matches for this query.');
- }
-
- let _entriesToDisplay = entriesToDisplay(this.cursor, options.length, this.optionsPerPage),
- startIndex = _entriesToDisplay.startIndex,
- endIndex = _entriesToDisplay.endIndex;
-
- let prefix,
- styledOptions = [];
-
- for (let i = startIndex; i < endIndex; i++) {
- if (i === startIndex && startIndex > 0) {
- prefix = figures.arrowUp;
- } else if (i === endIndex - 1 && endIndex < options.length) {
- prefix = figures.arrowDown;
- } else {
- prefix = ' ';
- }
-
- styledOptions.push(this.renderOption(this.cursor, options[i], i, prefix));
- }
-
- return '\n' + styledOptions.join('\n');
- } // shared with autocomleteMultiselect
-
-
- renderOptions(options) {
- if (!this.done) {
- return this.paginateOptions(options);
- }
-
- return '';
- }
-
- renderDoneOrInstructions() {
- if (this.done) {
- return this.value.filter(e => e.selected).map(v => v.title).join(', ');
- }
-
- const output = [color.gray(this.hint), this.renderInstructions()];
-
- if (this.value[this.cursor].disabled) {
- output.push(color.yellow(this.warn));
- }
-
- return output.join(' ');
- }
-
- render() {
- if (this.closed) return;
- if (this.firstRender) this.out.write(cursor.hide);
- super.render(); // print prompt
-
- let prompt = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(false), this.renderDoneOrInstructions()].join(' ');
-
- if (this.showMinError) {
- prompt += color.red(`You must select a minimum of ${this.minSelected} choices.`);
- this.showMinError = false;
- }
-
- prompt += this.renderOptions(this.value);
- this.out.write(this.clear + prompt);
- this.clear = clear(prompt, this.out.columns);
- }
-
- }
-
- multiselect$1 = MultiselectPrompt;
- return multiselect$1;
-}
-
-var autocomplete$1;
-var hasRequiredAutocomplete$1;
-
-function requireAutocomplete$1 () {
- if (hasRequiredAutocomplete$1) return autocomplete$1;
- hasRequiredAutocomplete$1 = 1;
-
- function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
-
- function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
-
- const color = requireKleur();
-
- const Prompt = requirePrompt$1();
-
- const _require = requireSrc(),
- erase = _require.erase,
- cursor = _require.cursor;
-
- const _require2 = requireUtil$1(),
- style = _require2.style,
- clear = _require2.clear,
- figures = _require2.figures,
- wrap = _require2.wrap,
- entriesToDisplay = _require2.entriesToDisplay;
-
- const getVal = (arr, i) => arr[i] && (arr[i].value || arr[i].title || arr[i]);
-
- const getTitle = (arr, i) => arr[i] && (arr[i].title || arr[i].value || arr[i]);
-
- const getIndex = (arr, valOrTitle) => {
- const index = arr.findIndex(el => el.value === valOrTitle || el.title === valOrTitle);
- return index > -1 ? index : undefined;
- };
- /**
- * TextPrompt Base Element
- * @param {Object} opts Options
- * @param {String} opts.message Message
- * @param {Array} opts.choices Array of auto-complete choices objects
- * @param {Function} [opts.suggest] Filter function. Defaults to sort by title
- * @param {Number} [opts.limit=10] Max number of results to show
- * @param {Number} [opts.cursor=0] Cursor start position
- * @param {String} [opts.style='default'] Render style
- * @param {String} [opts.fallback] Fallback message - initial to default value
- * @param {String} [opts.initial] Index of the default value
- * @param {Boolean} [opts.clearFirst] The first ESCAPE keypress will clear the input
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- * @param {String} [opts.noMatches] The no matches found label
- */
-
-
- class AutocompletePrompt extends Prompt {
- constructor(opts = {}) {
- super(opts);
- this.msg = opts.message;
- this.suggest = opts.suggest;
- this.choices = opts.choices;
- this.initial = typeof opts.initial === 'number' ? opts.initial : getIndex(opts.choices, opts.initial);
- this.select = this.initial || opts.cursor || 0;
- this.i18n = {
- noMatches: opts.noMatches || 'no matches found'
- };
- this.fallback = opts.fallback || this.initial;
- this.clearFirst = opts.clearFirst || false;
- this.suggestions = [];
- this.input = '';
- this.limit = opts.limit || 10;
- this.cursor = 0;
- this.transform = style.render(opts.style);
- this.scale = this.transform.scale;
- this.render = this.render.bind(this);
- this.complete = this.complete.bind(this);
- this.clear = clear('', this.out.columns);
- this.complete(this.render);
- this.render();
- }
-
- set fallback(fb) {
- this._fb = Number.isSafeInteger(parseInt(fb)) ? parseInt(fb) : fb;
- }
-
- get fallback() {
- let choice;
- if (typeof this._fb === 'number') choice = this.choices[this._fb];else if (typeof this._fb === 'string') choice = {
- title: this._fb
- };
- return choice || this._fb || {
- title: this.i18n.noMatches
- };
- }
-
- moveSelect(i) {
- this.select = i;
- if (this.suggestions.length > 0) this.value = getVal(this.suggestions, i);else this.value = this.fallback.value;
- this.fire();
- }
-
- complete(cb) {
- var _this = this;
-
- return _asyncToGenerator(function* () {
- const p = _this.completing = _this.suggest(_this.input, _this.choices);
-
- const suggestions = yield p;
- if (_this.completing !== p) return;
- _this.suggestions = suggestions.map((s, i, arr) => ({
- title: getTitle(arr, i),
- value: getVal(arr, i),
- description: s.description
- }));
- _this.completing = false;
- const l = Math.max(suggestions.length - 1, 0);
-
- _this.moveSelect(Math.min(l, _this.select));
-
- cb && cb();
- })();
- }
-
- reset() {
- this.input = '';
- this.complete(() => {
- this.moveSelect(this.initial !== void 0 ? this.initial : 0);
- this.render();
- });
- this.render();
- }
-
- exit() {
- if (this.clearFirst && this.input.length > 0) {
- this.reset();
- } else {
- this.done = this.exited = true;
- this.aborted = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
- }
-
- abort() {
- this.done = this.aborted = true;
- this.exited = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- submit() {
- this.done = true;
- this.aborted = this.exited = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- _(c, key) {
- let s1 = this.input.slice(0, this.cursor);
- let s2 = this.input.slice(this.cursor);
- this.input = `${s1}${c}${s2}`;
- this.cursor = s1.length + 1;
- this.complete(this.render);
- this.render();
- }
-
- delete() {
- if (this.cursor === 0) return this.bell();
- let s1 = this.input.slice(0, this.cursor - 1);
- let s2 = this.input.slice(this.cursor);
- this.input = `${s1}${s2}`;
- this.complete(this.render);
- this.cursor = this.cursor - 1;
- this.render();
- }
-
- deleteForward() {
- if (this.cursor * this.scale >= this.rendered.length) return this.bell();
- let s1 = this.input.slice(0, this.cursor);
- let s2 = this.input.slice(this.cursor + 1);
- this.input = `${s1}${s2}`;
- this.complete(this.render);
- this.render();
- }
-
- first() {
- this.moveSelect(0);
- this.render();
- }
-
- last() {
- this.moveSelect(this.suggestions.length - 1);
- this.render();
- }
-
- up() {
- if (this.select === 0) {
- this.moveSelect(this.suggestions.length - 1);
- } else {
- this.moveSelect(this.select - 1);
- }
-
- this.render();
- }
-
- down() {
- if (this.select === this.suggestions.length - 1) {
- this.moveSelect(0);
- } else {
- this.moveSelect(this.select + 1);
- }
-
- this.render();
- }
-
- next() {
- if (this.select === this.suggestions.length - 1) {
- this.moveSelect(0);
- } else this.moveSelect(this.select + 1);
-
- this.render();
- }
-
- nextPage() {
- this.moveSelect(Math.min(this.select + this.limit, this.suggestions.length - 1));
- this.render();
- }
-
- prevPage() {
- this.moveSelect(Math.max(this.select - this.limit, 0));
- this.render();
- }
-
- left() {
- if (this.cursor <= 0) return this.bell();
- this.cursor = this.cursor - 1;
- this.render();
- }
-
- right() {
- if (this.cursor * this.scale >= this.rendered.length) return this.bell();
- this.cursor = this.cursor + 1;
- this.render();
- }
-
- renderOption(v, hovered, isStart, isEnd) {
- let desc;
- let prefix = isStart ? figures.arrowUp : isEnd ? figures.arrowDown : ' ';
- let title = hovered ? color.cyan().underline(v.title) : v.title;
- prefix = (hovered ? color.cyan(figures.pointer) + ' ' : ' ') + prefix;
-
- if (v.description) {
- desc = ` - ${v.description}`;
-
- if (prefix.length + title.length + desc.length >= this.out.columns || v.description.split(/\r?\n/).length > 1) {
- desc = '\n' + wrap(v.description, {
- margin: 3,
- width: this.out.columns
- });
- }
- }
-
- return prefix + ' ' + title + color.gray(desc || '');
- }
-
- render() {
- if (this.closed) return;
- if (this.firstRender) this.out.write(cursor.hide);else this.out.write(clear(this.outputText, this.out.columns));
- super.render();
-
- let _entriesToDisplay = entriesToDisplay(this.select, this.choices.length, this.limit),
- startIndex = _entriesToDisplay.startIndex,
- endIndex = _entriesToDisplay.endIndex;
-
- this.outputText = [style.symbol(this.done, this.aborted, this.exited), color.bold(this.msg), style.delimiter(this.completing), this.done && this.suggestions[this.select] ? this.suggestions[this.select].title : this.rendered = this.transform.render(this.input)].join(' ');
-
- if (!this.done) {
- const suggestions = this.suggestions.slice(startIndex, endIndex).map((item, i) => this.renderOption(item, this.select === i + startIndex, i === 0 && startIndex > 0, i + startIndex === endIndex - 1 && endIndex < this.choices.length)).join('\n');
- this.outputText += `\n` + (suggestions || color.gray(this.fallback.title));
- }
-
- this.out.write(erase.line + cursor.to(0) + this.outputText);
- }
-
- }
-
- autocomplete$1 = AutocompletePrompt;
- return autocomplete$1;
-}
-
-var autocompleteMultiselect$1;
-var hasRequiredAutocompleteMultiselect$1;
-
-function requireAutocompleteMultiselect$1 () {
- if (hasRequiredAutocompleteMultiselect$1) return autocompleteMultiselect$1;
- hasRequiredAutocompleteMultiselect$1 = 1;
-
- const color = requireKleur();
-
- const _require = requireSrc(),
- cursor = _require.cursor;
-
- const MultiselectPrompt = requireMultiselect$1();
-
- const _require2 = requireUtil$1(),
- clear = _require2.clear,
- style = _require2.style,
- figures = _require2.figures;
- /**
- * MultiselectPrompt Base Element
- * @param {Object} opts Options
- * @param {String} opts.message Message
- * @param {Array} opts.choices Array of choice objects
- * @param {String} [opts.hint] Hint to display
- * @param {String} [opts.warn] Hint shown for disabled choices
- * @param {Number} [opts.max] Max choices
- * @param {Number} [opts.cursor=0] Cursor start position
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- */
-
-
- class AutocompleteMultiselectPrompt extends MultiselectPrompt {
- constructor(opts = {}) {
- opts.overrideRender = true;
- super(opts);
- this.inputValue = '';
- this.clear = clear('', this.out.columns);
- this.filteredOptions = this.value;
- this.render();
- }
-
- last() {
- this.cursor = this.filteredOptions.length - 1;
- this.render();
- }
-
- next() {
- this.cursor = (this.cursor + 1) % this.filteredOptions.length;
- this.render();
- }
-
- up() {
- if (this.cursor === 0) {
- this.cursor = this.filteredOptions.length - 1;
- } else {
- this.cursor--;
- }
-
- this.render();
- }
-
- down() {
- if (this.cursor === this.filteredOptions.length - 1) {
- this.cursor = 0;
- } else {
- this.cursor++;
- }
-
- this.render();
- }
-
- left() {
- this.filteredOptions[this.cursor].selected = false;
- this.render();
- }
-
- right() {
- if (this.value.filter(e => e.selected).length >= this.maxChoices) return this.bell();
- this.filteredOptions[this.cursor].selected = true;
- this.render();
- }
-
- delete() {
- if (this.inputValue.length) {
- this.inputValue = this.inputValue.substr(0, this.inputValue.length - 1);
- this.updateFilteredOptions();
- }
- }
-
- updateFilteredOptions() {
- const currentHighlight = this.filteredOptions[this.cursor];
- this.filteredOptions = this.value.filter(v => {
- if (this.inputValue) {
- if (typeof v.title === 'string') {
- if (v.title.toLowerCase().includes(this.inputValue.toLowerCase())) {
- return true;
- }
- }
-
- if (typeof v.value === 'string') {
- if (v.value.toLowerCase().includes(this.inputValue.toLowerCase())) {
- return true;
- }
- }
-
- return false;
- }
-
- return true;
- });
- const newHighlightIndex = this.filteredOptions.findIndex(v => v === currentHighlight);
- this.cursor = newHighlightIndex < 0 ? 0 : newHighlightIndex;
- this.render();
- }
-
- handleSpaceToggle() {
- const v = this.filteredOptions[this.cursor];
-
- if (v.selected) {
- v.selected = false;
- this.render();
- } else if (v.disabled || this.value.filter(e => e.selected).length >= this.maxChoices) {
- return this.bell();
- } else {
- v.selected = true;
- this.render();
- }
- }
-
- handleInputChange(c) {
- this.inputValue = this.inputValue + c;
- this.updateFilteredOptions();
- }
-
- _(c, key) {
- if (c === ' ') {
- this.handleSpaceToggle();
- } else {
- this.handleInputChange(c);
- }
- }
-
- renderInstructions() {
- if (this.instructions === undefined || this.instructions) {
- if (typeof this.instructions === 'string') {
- return this.instructions;
- }
-
- return `
-Instructions:
- ${figures.arrowUp}/${figures.arrowDown}: Highlight option
- ${figures.arrowLeft}/${figures.arrowRight}/[space]: Toggle selection
- [a,b,c]/delete: Filter choices
- enter/return: Complete answer
-`;
- }
-
- return '';
- }
-
- renderCurrentInput() {
- return `
-Filtered results for: ${this.inputValue ? this.inputValue : color.gray('Enter something to filter')}\n`;
- }
-
- renderOption(cursor, v, i) {
- let title;
- if (v.disabled) title = cursor === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title);else title = cursor === i ? color.cyan().underline(v.title) : v.title;
- return (v.selected ? color.green(figures.radioOn) : figures.radioOff) + ' ' + title;
- }
-
- renderDoneOrInstructions() {
- if (this.done) {
- return this.value.filter(e => e.selected).map(v => v.title).join(', ');
- }
-
- const output = [color.gray(this.hint), this.renderInstructions(), this.renderCurrentInput()];
-
- if (this.filteredOptions.length && this.filteredOptions[this.cursor].disabled) {
- output.push(color.yellow(this.warn));
- }
-
- return output.join(' ');
- }
-
- render() {
- if (this.closed) return;
- if (this.firstRender) this.out.write(cursor.hide);
- super.render(); // print prompt
-
- let prompt = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(false), this.renderDoneOrInstructions()].join(' ');
-
- if (this.showMinError) {
- prompt += color.red(`You must select a minimum of ${this.minSelected} choices.`);
- this.showMinError = false;
- }
-
- prompt += this.renderOptions(this.filteredOptions);
- this.out.write(this.clear + prompt);
- this.clear = clear(prompt, this.out.columns);
- }
-
- }
-
- autocompleteMultiselect$1 = AutocompleteMultiselectPrompt;
- return autocompleteMultiselect$1;
-}
-
-var confirm$1;
-var hasRequiredConfirm$1;
-
-function requireConfirm$1 () {
- if (hasRequiredConfirm$1) return confirm$1;
- hasRequiredConfirm$1 = 1;
-
- const color = requireKleur();
-
- const Prompt = requirePrompt$1();
-
- const _require = requireUtil$1(),
- style = _require.style,
- clear = _require.clear;
-
- const _require2 = requireSrc(),
- erase = _require2.erase,
- cursor = _require2.cursor;
- /**
- * ConfirmPrompt Base Element
- * @param {Object} opts Options
- * @param {String} opts.message Message
- * @param {Boolean} [opts.initial] Default value (true/false)
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- * @param {String} [opts.yes] The "Yes" label
- * @param {String} [opts.yesOption] The "Yes" option when choosing between yes/no
- * @param {String} [opts.no] The "No" label
- * @param {String} [opts.noOption] The "No" option when choosing between yes/no
- */
-
-
- class ConfirmPrompt extends Prompt {
- constructor(opts = {}) {
- super(opts);
- this.msg = opts.message;
- this.value = opts.initial;
- this.initialValue = !!opts.initial;
- this.yesMsg = opts.yes || 'yes';
- this.yesOption = opts.yesOption || '(Y/n)';
- this.noMsg = opts.no || 'no';
- this.noOption = opts.noOption || '(y/N)';
- this.render();
- }
-
- reset() {
- this.value = this.initialValue;
- this.fire();
- this.render();
- }
-
- exit() {
- this.abort();
- }
-
- abort() {
- this.done = this.aborted = true;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- submit() {
- this.value = this.value || false;
- this.done = true;
- this.aborted = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- _(c, key) {
- if (c.toLowerCase() === 'y') {
- this.value = true;
- return this.submit();
- }
-
- if (c.toLowerCase() === 'n') {
- this.value = false;
- return this.submit();
- }
-
- return this.bell();
- }
-
- render() {
- if (this.closed) return;
- if (this.firstRender) this.out.write(cursor.hide);else this.out.write(clear(this.outputText, this.out.columns));
- super.render();
- this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(this.done), this.done ? this.value ? this.yesMsg : this.noMsg : color.gray(this.initialValue ? this.yesOption : this.noOption)].join(' ');
- this.out.write(erase.line + cursor.to(0) + this.outputText);
- }
-
- }
-
- confirm$1 = ConfirmPrompt;
- return confirm$1;
-}
-
-var elements$1;
-var hasRequiredElements$1;
-
-function requireElements$1 () {
- if (hasRequiredElements$1) return elements$1;
- hasRequiredElements$1 = 1;
-
- elements$1 = {
- TextPrompt: requireText$1(),
- SelectPrompt: requireSelect$1(),
- TogglePrompt: requireToggle$1(),
- DatePrompt: requireDate$1(),
- NumberPrompt: requireNumber$1(),
- MultiselectPrompt: requireMultiselect$1(),
- AutocompletePrompt: requireAutocomplete$1(),
- AutocompleteMultiselectPrompt: requireAutocompleteMultiselect$1(),
- ConfirmPrompt: requireConfirm$1()
- };
- return elements$1;
-}
-
-var hasRequiredPrompts$2;
-
-function requirePrompts$2 () {
- if (hasRequiredPrompts$2) return prompts$2;
- hasRequiredPrompts$2 = 1;
- (function (exports$1) {
-
- const $ = exports$1;
-
- const el = requireElements$1();
-
- const noop = v => v;
-
- function toPrompt(type, args, opts = {}) {
- return new Promise((res, rej) => {
- const p = new el[type](args);
- const onAbort = opts.onAbort || noop;
- const onSubmit = opts.onSubmit || noop;
- const onExit = opts.onExit || noop;
- p.on('state', args.onState || noop);
- p.on('submit', x => res(onSubmit(x)));
- p.on('exit', x => res(onExit(x)));
- p.on('abort', x => rej(onAbort(x)));
- });
- }
- /**
- * Text prompt
- * @param {string} args.message Prompt message to display
- * @param {string} [args.initial] Default string value
- * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
- * @param {function} [args.onState] On state change callback
- * @param {function} [args.validate] Function to validate user input
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
-
-
- $.text = args => toPrompt('TextPrompt', args);
- /**
- * Password prompt with masked input
- * @param {string} args.message Prompt message to display
- * @param {string} [args.initial] Default string value
- * @param {function} [args.onState] On state change callback
- * @param {function} [args.validate] Function to validate user input
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
-
-
- $.password = args => {
- args.style = 'password';
- return $.text(args);
- };
- /**
- * Prompt where input is invisible, like sudo
- * @param {string} args.message Prompt message to display
- * @param {string} [args.initial] Default string value
- * @param {function} [args.onState] On state change callback
- * @param {function} [args.validate] Function to validate user input
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
-
-
- $.invisible = args => {
- args.style = 'invisible';
- return $.text(args);
- };
- /**
- * Number prompt
- * @param {string} args.message Prompt message to display
- * @param {number} args.initial Default number value
- * @param {function} [args.onState] On state change callback
- * @param {number} [args.max] Max value
- * @param {number} [args.min] Min value
- * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
- * @param {Boolean} [opts.float=false] Parse input as floats
- * @param {Number} [opts.round=2] Round floats to x decimals
- * @param {Number} [opts.increment=1] Number to increment by when using arrow-keys
- * @param {function} [args.validate] Function to validate user input
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
-
-
- $.number = args => toPrompt('NumberPrompt', args);
- /**
- * Date prompt
- * @param {string} args.message Prompt message to display
- * @param {number} args.initial Default number value
- * @param {function} [args.onState] On state change callback
- * @param {number} [args.max] Max value
- * @param {number} [args.min] Min value
- * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
- * @param {Boolean} [opts.float=false] Parse input as floats
- * @param {Number} [opts.round=2] Round floats to x decimals
- * @param {Number} [opts.increment=1] Number to increment by when using arrow-keys
- * @param {function} [args.validate] Function to validate user input
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
-
-
- $.date = args => toPrompt('DatePrompt', args);
- /**
- * Classic yes/no prompt
- * @param {string} args.message Prompt message to display
- * @param {boolean} [args.initial=false] Default value
- * @param {function} [args.onState] On state change callback
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
-
-
- $.confirm = args => toPrompt('ConfirmPrompt', args);
- /**
- * List prompt, split intput string by `seperator`
- * @param {string} args.message Prompt message to display
- * @param {string} [args.initial] Default string value
- * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
- * @param {string} [args.separator] String separator
- * @param {function} [args.onState] On state change callback
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input, in form of an `Array`
- */
-
-
- $.list = args => {
- const sep = args.separator || ',';
- return toPrompt('TextPrompt', args, {
- onSubmit: str => str.split(sep).map(s => s.trim())
- });
- };
- /**
- * Toggle/switch prompt
- * @param {string} args.message Prompt message to display
- * @param {boolean} [args.initial=false] Default value
- * @param {string} [args.active="on"] Text for `active` state
- * @param {string} [args.inactive="off"] Text for `inactive` state
- * @param {function} [args.onState] On state change callback
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
-
-
- $.toggle = args => toPrompt('TogglePrompt', args);
- /**
- * Interactive select prompt
- * @param {string} args.message Prompt message to display
- * @param {Array} args.choices Array of choices objects `[{ title, value }, ...]`
- * @param {number} [args.initial] Index of default value
- * @param {String} [args.hint] Hint to display
- * @param {function} [args.onState] On state change callback
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
-
-
- $.select = args => toPrompt('SelectPrompt', args);
- /**
- * Interactive multi-select / autocompleteMultiselect prompt
- * @param {string} args.message Prompt message to display
- * @param {Array} args.choices Array of choices objects `[{ title, value, [selected] }, ...]`
- * @param {number} [args.max] Max select
- * @param {string} [args.hint] Hint to display user
- * @param {Number} [args.cursor=0] Cursor start position
- * @param {function} [args.onState] On state change callback
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
-
-
- $.multiselect = args => {
- args.choices = [].concat(args.choices || []);
-
- const toSelected = items => items.filter(item => item.selected).map(item => item.value);
-
- return toPrompt('MultiselectPrompt', args, {
- onAbort: toSelected,
- onSubmit: toSelected
- });
- };
-
- $.autocompleteMultiselect = args => {
- args.choices = [].concat(args.choices || []);
-
- const toSelected = items => items.filter(item => item.selected).map(item => item.value);
-
- return toPrompt('AutocompleteMultiselectPrompt', args, {
- onAbort: toSelected,
- onSubmit: toSelected
- });
- };
-
- const byTitle = (input, choices) => Promise.resolve(choices.filter(item => item.title.slice(0, input.length).toLowerCase() === input.toLowerCase()));
- /**
- * Interactive auto-complete prompt
- * @param {string} args.message Prompt message to display
- * @param {Array} args.choices Array of auto-complete choices objects `[{ title, value }, ...]`
- * @param {Function} [args.suggest] Function to filter results based on user input. Defaults to sort by `title`
- * @param {number} [args.limit=10] Max number of results to show
- * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
- * @param {String} [args.initial] Index of the default value
- * @param {boolean} [opts.clearFirst] The first ESCAPE keypress will clear the input
- * @param {String} [args.fallback] Fallback message - defaults to initial value
- * @param {function} [args.onState] On state change callback
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
-
-
- $.autocomplete = args => {
- args.suggest = args.suggest || byTitle;
- args.choices = [].concat(args.choices || []);
- return toPrompt('AutocompletePrompt', args);
- };
- } (prompts$2));
- return prompts$2;
-}
-
-var dist;
-var hasRequiredDist;
-
-function requireDist () {
- if (hasRequiredDist) return dist;
- hasRequiredDist = 1;
-
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
-
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
-
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
-
- function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike) { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
-
- function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
-
- function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
-
- function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
-
- function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
-
- const prompts = requirePrompts$2();
-
- const passOn = ['suggest', 'format', 'onState', 'validate', 'onRender', 'type'];
-
- const noop = () => {};
- /**
- * Prompt for a series of questions
- * @param {Array|Object} questions Single question object or Array of question objects
- * @param {Function} [onSubmit] Callback function called on prompt submit
- * @param {Function} [onCancel] Callback function called on cancel/abort
- * @returns {Object} Object with values from user input
- */
-
-
- function prompt() {
- return _prompt.apply(this, arguments);
- }
-
- function _prompt() {
- _prompt = _asyncToGenerator(function* (questions = [], {
- onSubmit = noop,
- onCancel = noop
- } = {}) {
- const answers = {};
- const override = prompt._override || {};
- questions = [].concat(questions);
- let answer, question, quit, name, type, lastPrompt;
-
- const getFormattedAnswer = /*#__PURE__*/function () {
- var _ref = _asyncToGenerator(function* (question, answer, skipValidation = false) {
- if (!skipValidation && question.validate && question.validate(answer) !== true) {
- return;
- }
-
- return question.format ? yield question.format(answer, answers) : answer;
- });
-
- return function getFormattedAnswer(_x, _x2) {
- return _ref.apply(this, arguments);
- };
- }();
-
- var _iterator = _createForOfIteratorHelper(questions),
- _step;
-
- try {
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
- question = _step.value;
- var _question = question;
- name = _question.name;
- type = _question.type;
-
- // evaluate type first and skip if type is a falsy value
- if (typeof type === 'function') {
- type = yield type(answer, _objectSpread({}, answers), question);
- question['type'] = type;
- }
-
- if (!type) continue; // if property is a function, invoke it unless it's a special function
-
- for (let key in question) {
- if (passOn.includes(key)) continue;
- let value = question[key];
- question[key] = typeof value === 'function' ? yield value(answer, _objectSpread({}, answers), lastPrompt) : value;
- }
-
- lastPrompt = question;
-
- if (typeof question.message !== 'string') {
- throw new Error('prompt message is required');
- } // update vars in case they changed
-
-
- var _question2 = question;
- name = _question2.name;
- type = _question2.type;
-
- if (prompts[type] === void 0) {
- throw new Error(`prompt type (${type}) is not defined`);
- }
-
- if (override[question.name] !== undefined) {
- answer = yield getFormattedAnswer(question, override[question.name]);
-
- if (answer !== undefined) {
- answers[name] = answer;
- continue;
- }
- }
-
- try {
- // Get the injected answer if there is one or prompt the user
- answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : yield prompts[type](question);
- answers[name] = answer = yield getFormattedAnswer(question, answer, true);
- quit = yield onSubmit(question, answer, answers);
- } catch (err) {
- quit = !(yield onCancel(question, answers));
- }
-
- if (quit) return answers;
- }
- } catch (err) {
- _iterator.e(err);
- } finally {
- _iterator.f();
- }
-
- return answers;
- });
- return _prompt.apply(this, arguments);
- }
-
- function getInjectedAnswer(injected, deafultValue) {
- const answer = injected.shift();
-
- if (answer instanceof Error) {
- throw answer;
- }
-
- return answer === undefined ? deafultValue : answer;
- }
-
- function inject(answers) {
- prompt._injected = (prompt._injected || []).concat(answers);
- }
-
- function override(answers) {
- prompt._override = Object.assign({}, answers);
- }
-
- dist = Object.assign(prompt, {
- prompt,
- prompts,
- inject,
- override
- });
- return dist;
-}
-
-var prompts$1 = {};
-
-var action;
-var hasRequiredAction;
-
-function requireAction () {
- if (hasRequiredAction) return action;
- hasRequiredAction = 1;
-
- action = (key, isSelect) => {
- if (key.meta && key.name !== 'escape') return;
-
- if (key.ctrl) {
- if (key.name === 'a') return 'first';
- if (key.name === 'c') return 'abort';
- if (key.name === 'd') return 'abort';
- if (key.name === 'e') return 'last';
- if (key.name === 'g') return 'reset';
- }
-
- if (isSelect) {
- if (key.name === 'j') return 'down';
- if (key.name === 'k') return 'up';
- }
-
- if (key.name === 'return') return 'submit';
- if (key.name === 'enter') return 'submit'; // ctrl + J
- if (key.name === 'backspace') return 'delete';
- if (key.name === 'delete') return 'deleteForward';
- if (key.name === 'abort') return 'abort';
- if (key.name === 'escape') return 'exit';
- if (key.name === 'tab') return 'next';
- if (key.name === 'pagedown') return 'nextPage';
- if (key.name === 'pageup') return 'prevPage';
- // TODO create home() in prompt types (e.g. TextPrompt)
- if (key.name === 'home') return 'home';
- // TODO create end() in prompt types (e.g. TextPrompt)
- if (key.name === 'end') return 'end';
-
- if (key.name === 'up') return 'up';
- if (key.name === 'down') return 'down';
- if (key.name === 'right') return 'right';
- if (key.name === 'left') return 'left';
-
- return false;
- };
- return action;
-}
-
-var strip;
-var hasRequiredStrip;
-
-function requireStrip () {
- if (hasRequiredStrip) return strip;
- hasRequiredStrip = 1;
-
- strip = str => {
- const pattern = [
- '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
- '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))'
- ].join('|');
-
- const RGX = new RegExp(pattern, 'g');
- return typeof str === 'string' ? str.replace(RGX, '') : str;
- };
- return strip;
-}
-
-var clear;
-var hasRequiredClear;
-
-function requireClear () {
- if (hasRequiredClear) return clear;
- hasRequiredClear = 1;
-
- const strip = requireStrip();
- const { erase, cursor } = requireSrc();
-
- const width = str => [...strip(str)].length;
-
- /**
- * @param {string} prompt
- * @param {number} perLine
- */
- clear = function(prompt, perLine) {
- if (!perLine) return erase.line + cursor.to(0);
-
- let rows = 0;
- const lines = prompt.split(/\r?\n/);
- for (let line of lines) {
- rows += 1 + Math.floor(Math.max(width(line) - 1, 0) / perLine);
- }
-
- return erase.lines(rows);
- };
- return clear;
-}
-
-var figures_1;
-var hasRequiredFigures;
-
-function requireFigures () {
- if (hasRequiredFigures) return figures_1;
- hasRequiredFigures = 1;
-
- const main = {
- arrowUp: '↑',
- arrowDown: '↓',
- arrowLeft: '←',
- arrowRight: '→',
- radioOn: '◉',
- radioOff: '◯',
- tick: '✔',
- cross: '✖',
- ellipsis: '…',
- pointerSmall: '›',
- line: '─',
- pointer: '❯'
- };
- const win = {
- arrowUp: main.arrowUp,
- arrowDown: main.arrowDown,
- arrowLeft: main.arrowLeft,
- arrowRight: main.arrowRight,
- radioOn: '(*)',
- radioOff: '( )',
- tick: '√',
- cross: '×',
- ellipsis: '...',
- pointerSmall: '»',
- line: '─',
- pointer: '>'
- };
- const figures = process.platform === 'win32' ? win : main;
-
- figures_1 = figures;
- return figures_1;
-}
-
-var style;
-var hasRequiredStyle;
-
-function requireStyle () {
- if (hasRequiredStyle) return style;
- hasRequiredStyle = 1;
-
- const c = requireKleur();
- const figures = requireFigures();
-
- // rendering user input.
- const styles = Object.freeze({
- password: { scale: 1, render: input => '*'.repeat(input.length) },
- emoji: { scale: 2, render: input => '😃'.repeat(input.length) },
- invisible: { scale: 0, render: input => '' },
- default: { scale: 1, render: input => `${input}` }
- });
- const render = type => styles[type] || styles.default;
-
- // icon to signalize a prompt.
- const symbols = Object.freeze({
- aborted: c.red(figures.cross),
- done: c.green(figures.tick),
- exited: c.yellow(figures.cross),
- default: c.cyan('?')
- });
-
- const symbol = (done, aborted, exited) =>
- aborted ? symbols.aborted : exited ? symbols.exited : done ? symbols.done : symbols.default;
-
- // between the question and the user's input.
- const delimiter = completing =>
- c.gray(completing ? figures.ellipsis : figures.pointerSmall);
-
- const item = (expandable, expanded) =>
- c.gray(expandable ? (expanded ? figures.pointerSmall : '+') : figures.line);
-
- style = {
- styles,
- render,
- symbols,
- symbol,
- delimiter,
- item
- };
- return style;
-}
-
-var lines;
-var hasRequiredLines;
-
-function requireLines () {
- if (hasRequiredLines) return lines;
- hasRequiredLines = 1;
-
- const strip = requireStrip();
-
- /**
- * @param {string} msg
- * @param {number} perLine
- */
- lines = function (msg, perLine) {
- let lines = String(strip(msg) || '').split(/\r?\n/);
-
- if (!perLine) return lines.length;
- return lines.map(l => Math.ceil(l.length / perLine))
- .reduce((a, b) => a + b);
- };
- return lines;
-}
-
-var wrap;
-var hasRequiredWrap;
-
-function requireWrap () {
- if (hasRequiredWrap) return wrap;
- hasRequiredWrap = 1;
-
- /**
- * @param {string} msg The message to wrap
- * @param {object} opts
- * @param {number|string} [opts.margin] Left margin
- * @param {number} opts.width Maximum characters per line including the margin
- */
- wrap = (msg, opts = {}) => {
- const tab = Number.isSafeInteger(parseInt(opts.margin))
- ? new Array(parseInt(opts.margin)).fill(' ').join('')
- : (opts.margin || '');
-
- const width = opts.width;
-
- return (msg || '').split(/\r?\n/g)
- .map(line => line
- .split(/\s+/g)
- .reduce((arr, w) => {
- if (w.length + tab.length >= width || arr[arr.length - 1].length + w.length + 1 < width)
- arr[arr.length - 1] += ` ${w}`;
- else arr.push(`${tab}${w}`);
- return arr;
- }, [ tab ])
- .join('\n'))
- .join('\n');
- };
- return wrap;
-}
-
-var entriesToDisplay;
-var hasRequiredEntriesToDisplay;
-
-function requireEntriesToDisplay () {
- if (hasRequiredEntriesToDisplay) return entriesToDisplay;
- hasRequiredEntriesToDisplay = 1;
-
- /**
- * Determine what entries should be displayed on the screen, based on the
- * currently selected index and the maximum visible. Used in list-based
- * prompts like `select` and `multiselect`.
- *
- * @param {number} cursor the currently selected entry
- * @param {number} total the total entries available to display
- * @param {number} [maxVisible] the number of entries that can be displayed
- */
- entriesToDisplay = (cursor, total, maxVisible) => {
- maxVisible = maxVisible || total;
-
- let startIndex = Math.min(total- maxVisible, cursor - Math.floor(maxVisible / 2));
- if (startIndex < 0) startIndex = 0;
-
- let endIndex = Math.min(startIndex + maxVisible, total);
-
- return { startIndex, endIndex };
- };
- return entriesToDisplay;
-}
-
-var util;
-var hasRequiredUtil;
-
-function requireUtil () {
- if (hasRequiredUtil) return util;
- hasRequiredUtil = 1;
-
- util = {
- action: requireAction(),
- clear: requireClear(),
- style: requireStyle(),
- strip: requireStrip(),
- figures: requireFigures(),
- lines: requireLines(),
- wrap: requireWrap(),
- entriesToDisplay: requireEntriesToDisplay()
- };
- return util;
-}
-
-var prompt$1;
-var hasRequiredPrompt;
-
-function requirePrompt () {
- if (hasRequiredPrompt) return prompt$1;
- hasRequiredPrompt = 1;
-
- const readline = require$$0;
- const { action } = requireUtil();
- const EventEmitter = require$$0$1;
- const { beep, cursor } = requireSrc();
- const color = requireKleur();
-
- /**
- * Base prompt skeleton
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- */
- class Prompt extends EventEmitter {
- constructor(opts={}) {
- super();
-
- this.firstRender = true;
- this.in = opts.stdin || process.stdin;
- this.out = opts.stdout || process.stdout;
- this.onRender = (opts.onRender || (() => void 0)).bind(this);
- const rl = readline.createInterface({ input:this.in, escapeCodeTimeout:50 });
- readline.emitKeypressEvents(this.in, rl);
-
- if (this.in.isTTY) this.in.setRawMode(true);
- const isSelect = [ 'SelectPrompt', 'MultiselectPrompt' ].indexOf(this.constructor.name) > -1;
- const keypress = (str, key) => {
- let a = action(key, isSelect);
- if (a === false) {
- this._ && this._(str, key);
- } else if (typeof this[a] === 'function') {
- this[a](key);
- } else {
- this.bell();
- }
- };
-
- this.close = () => {
- this.out.write(cursor.show);
- this.in.removeListener('keypress', keypress);
- if (this.in.isTTY) this.in.setRawMode(false);
- rl.close();
- this.emit(this.aborted ? 'abort' : this.exited ? 'exit' : 'submit', this.value);
- this.closed = true;
- };
-
- this.in.on('keypress', keypress);
- }
-
- fire() {
- this.emit('state', {
- value: this.value,
- aborted: !!this.aborted,
- exited: !!this.exited
- });
- }
-
- bell() {
- this.out.write(beep);
- }
-
- render() {
- this.onRender(color);
- if (this.firstRender) this.firstRender = false;
- }
- }
-
- prompt$1 = Prompt;
- return prompt$1;
-}
-
-var text;
-var hasRequiredText;
-
-function requireText () {
- if (hasRequiredText) return text;
- hasRequiredText = 1;
- const color = requireKleur();
- const Prompt = requirePrompt();
- const { erase, cursor } = requireSrc();
- const { style, clear, lines, figures } = requireUtil();
-
- /**
- * TextPrompt Base Element
- * @param {Object} opts Options
- * @param {String} opts.message Message
- * @param {String} [opts.style='default'] Render style
- * @param {String} [opts.initial] Default value
- * @param {Function} [opts.validate] Validate function
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- * @param {String} [opts.error] The invalid error label
- */
- class TextPrompt extends Prompt {
- constructor(opts={}) {
- super(opts);
- this.transform = style.render(opts.style);
- this.scale = this.transform.scale;
- this.msg = opts.message;
- this.initial = opts.initial || ``;
- this.validator = opts.validate || (() => true);
- this.value = ``;
- this.errorMsg = opts.error || `Please Enter A Valid Value`;
- this.cursor = Number(!!this.initial);
- this.cursorOffset = 0;
- this.clear = clear(``, this.out.columns);
- this.render();
- }
-
- set value(v) {
- if (!v && this.initial) {
- this.placeholder = true;
- this.rendered = color.gray(this.transform.render(this.initial));
- } else {
- this.placeholder = false;
- this.rendered = this.transform.render(v);
- }
- this._value = v;
- this.fire();
- }
-
- get value() {
- return this._value;
- }
-
- reset() {
- this.value = ``;
- this.cursor = Number(!!this.initial);
- this.cursorOffset = 0;
- this.fire();
- this.render();
- }
-
- exit() {
- this.abort();
- }
-
- abort() {
- this.value = this.value || this.initial;
- this.done = this.aborted = true;
- this.error = false;
- this.red = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- async validate() {
- let valid = await this.validator(this.value);
- if (typeof valid === `string`) {
- this.errorMsg = valid;
- valid = false;
- }
- this.error = !valid;
- }
-
- async submit() {
- this.value = this.value || this.initial;
- this.cursorOffset = 0;
- this.cursor = this.rendered.length;
- await this.validate();
- if (this.error) {
- this.red = true;
- this.fire();
- this.render();
- return;
- }
- this.done = true;
- this.aborted = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- next() {
- if (!this.placeholder) return this.bell();
- this.value = this.initial;
- this.cursor = this.rendered.length;
- this.fire();
- this.render();
- }
-
- moveCursor(n) {
- if (this.placeholder) return;
- this.cursor = this.cursor+n;
- this.cursorOffset += n;
- }
-
- _(c, key) {
- let s1 = this.value.slice(0, this.cursor);
- let s2 = this.value.slice(this.cursor);
- this.value = `${s1}${c}${s2}`;
- this.red = false;
- this.cursor = this.placeholder ? 0 : s1.length+1;
- this.render();
- }
-
- delete() {
- if (this.isCursorAtStart()) return this.bell();
- let s1 = this.value.slice(0, this.cursor-1);
- let s2 = this.value.slice(this.cursor);
- this.value = `${s1}${s2}`;
- this.red = false;
- if (this.isCursorAtStart()) {
- this.cursorOffset = 0;
- } else {
- this.cursorOffset++;
- this.moveCursor(-1);
- }
- this.render();
- }
-
- deleteForward() {
- if(this.cursor*this.scale >= this.rendered.length || this.placeholder) return this.bell();
- let s1 = this.value.slice(0, this.cursor);
- let s2 = this.value.slice(this.cursor+1);
- this.value = `${s1}${s2}`;
- this.red = false;
- if (this.isCursorAtEnd()) {
- this.cursorOffset = 0;
- } else {
- this.cursorOffset++;
- }
- this.render();
- }
-
- first() {
- this.cursor = 0;
- this.render();
- }
-
- last() {
- this.cursor = this.value.length;
- this.render();
- }
-
- left() {
- if (this.cursor <= 0 || this.placeholder) return this.bell();
- this.moveCursor(-1);
- this.render();
- }
-
- right() {
- if (this.cursor*this.scale >= this.rendered.length || this.placeholder) return this.bell();
- this.moveCursor(1);
- this.render();
- }
-
- isCursorAtStart() {
- return this.cursor === 0 || (this.placeholder && this.cursor === 1);
- }
-
- isCursorAtEnd() {
- return this.cursor === this.rendered.length || (this.placeholder && this.cursor === this.rendered.length + 1)
- }
-
- render() {
- if (this.closed) return;
- if (!this.firstRender) {
- if (this.outputError)
- this.out.write(cursor.down(lines(this.outputError, this.out.columns) - 1) + clear(this.outputError, this.out.columns));
- this.out.write(clear(this.outputText, this.out.columns));
- }
- super.render();
- this.outputError = '';
-
- this.outputText = [
- style.symbol(this.done, this.aborted),
- color.bold(this.msg),
- style.delimiter(this.done),
- this.red ? color.red(this.rendered) : this.rendered
- ].join(` `);
-
- if (this.error) {
- this.outputError += this.errorMsg.split(`\n`)
- .reduce((a, l, i) => a + `\n${i ? ' ' : figures.pointerSmall} ${color.red().italic(l)}`, ``);
- }
-
- this.out.write(erase.line + cursor.to(0) + this.outputText + cursor.save + this.outputError + cursor.restore + cursor.move(this.cursorOffset, 0));
- }
- }
-
- text = TextPrompt;
- return text;
-}
-
-var select;
-var hasRequiredSelect;
-
-function requireSelect () {
- if (hasRequiredSelect) return select;
- hasRequiredSelect = 1;
-
- const color = requireKleur();
- const Prompt = requirePrompt();
- const { style, clear, figures, wrap, entriesToDisplay } = requireUtil();
- const { cursor } = requireSrc();
-
- /**
- * SelectPrompt Base Element
- * @param {Object} opts Options
- * @param {String} opts.message Message
- * @param {Array} opts.choices Array of choice objects
- * @param {String} [opts.hint] Hint to display
- * @param {Number} [opts.initial] Index of default value
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- * @param {Number} [opts.optionsPerPage=10] Max options to display at once
- */
- class SelectPrompt extends Prompt {
- constructor(opts={}) {
- super(opts);
- this.msg = opts.message;
- this.hint = opts.hint || '- Use arrow-keys. Return to submit.';
- this.warn = opts.warn || '- This option is disabled';
- this.cursor = opts.initial || 0;
- this.choices = opts.choices.map((ch, idx) => {
- if (typeof ch === 'string')
- ch = {title: ch, value: idx};
- return {
- title: ch && (ch.title || ch.value || ch),
- value: ch && (ch.value === undefined ? idx : ch.value),
- description: ch && ch.description,
- selected: ch && ch.selected,
- disabled: ch && ch.disabled
- };
- });
- this.optionsPerPage = opts.optionsPerPage || 10;
- this.value = (this.choices[this.cursor] || {}).value;
- this.clear = clear('', this.out.columns);
- this.render();
- }
-
- moveCursor(n) {
- this.cursor = n;
- this.value = this.choices[n].value;
- this.fire();
- }
-
- reset() {
- this.moveCursor(0);
- this.fire();
- this.render();
- }
-
- exit() {
- this.abort();
- }
-
- abort() {
- this.done = this.aborted = true;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- submit() {
- if (!this.selection.disabled) {
- this.done = true;
- this.aborted = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- } else
- this.bell();
- }
-
- first() {
- this.moveCursor(0);
- this.render();
- }
-
- last() {
- this.moveCursor(this.choices.length - 1);
- this.render();
- }
-
- up() {
- if (this.cursor === 0) {
- this.moveCursor(this.choices.length - 1);
- } else {
- this.moveCursor(this.cursor - 1);
- }
- this.render();
- }
-
- down() {
- if (this.cursor === this.choices.length - 1) {
- this.moveCursor(0);
- } else {
- this.moveCursor(this.cursor + 1);
- }
- this.render();
- }
-
- next() {
- this.moveCursor((this.cursor + 1) % this.choices.length);
- this.render();
- }
-
- _(c, key) {
- if (c === ' ') return this.submit();
- }
-
- get selection() {
- return this.choices[this.cursor];
- }
-
- render() {
- if (this.closed) return;
- if (this.firstRender) this.out.write(cursor.hide);
- else this.out.write(clear(this.outputText, this.out.columns));
- super.render();
-
- let { startIndex, endIndex } = entriesToDisplay(this.cursor, this.choices.length, this.optionsPerPage);
-
- // Print prompt
- this.outputText = [
- style.symbol(this.done, this.aborted),
- color.bold(this.msg),
- style.delimiter(false),
- this.done ? this.selection.title : this.selection.disabled
- ? color.yellow(this.warn) : color.gray(this.hint)
- ].join(' ');
-
- // Print choices
- if (!this.done) {
- this.outputText += '\n';
- for (let i = startIndex; i < endIndex; i++) {
- let title, prefix, desc = '', v = this.choices[i];
-
- // Determine whether to display "more choices" indicators
- if (i === startIndex && startIndex > 0) {
- prefix = figures.arrowUp;
- } else if (i === endIndex - 1 && endIndex < this.choices.length) {
- prefix = figures.arrowDown;
- } else {
- prefix = ' ';
- }
-
- if (v.disabled) {
- title = this.cursor === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title);
- prefix = (this.cursor === i ? color.bold().gray(figures.pointer) + ' ' : ' ') + prefix;
- } else {
- title = this.cursor === i ? color.cyan().underline(v.title) : v.title;
- prefix = (this.cursor === i ? color.cyan(figures.pointer) + ' ' : ' ') + prefix;
- if (v.description && this.cursor === i) {
- desc = ` - ${v.description}`;
- if (prefix.length + title.length + desc.length >= this.out.columns
- || v.description.split(/\r?\n/).length > 1) {
- desc = '\n' + wrap(v.description, { margin: 3, width: this.out.columns });
- }
- }
- }
-
- this.outputText += `${prefix} ${title}${color.gray(desc)}\n`;
- }
- }
-
- this.out.write(this.outputText);
- }
- }
-
- select = SelectPrompt;
- return select;
-}
-
-var toggle;
-var hasRequiredToggle;
-
-function requireToggle () {
- if (hasRequiredToggle) return toggle;
- hasRequiredToggle = 1;
- const color = requireKleur();
- const Prompt = requirePrompt();
- const { style, clear } = requireUtil();
- const { cursor, erase } = requireSrc();
-
- /**
- * TogglePrompt Base Element
- * @param {Object} opts Options
- * @param {String} opts.message Message
- * @param {Boolean} [opts.initial=false] Default value
- * @param {String} [opts.active='no'] Active label
- * @param {String} [opts.inactive='off'] Inactive label
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- */
- class TogglePrompt extends Prompt {
- constructor(opts={}) {
- super(opts);
- this.msg = opts.message;
- this.value = !!opts.initial;
- this.active = opts.active || 'on';
- this.inactive = opts.inactive || 'off';
- this.initialValue = this.value;
- this.render();
- }
-
- reset() {
- this.value = this.initialValue;
- this.fire();
- this.render();
- }
-
- exit() {
- this.abort();
- }
-
- abort() {
- this.done = this.aborted = true;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- submit() {
- this.done = true;
- this.aborted = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- deactivate() {
- if (this.value === false) return this.bell();
- this.value = false;
- this.render();
- }
-
- activate() {
- if (this.value === true) return this.bell();
- this.value = true;
- this.render();
- }
-
- delete() {
- this.deactivate();
- }
- left() {
- this.deactivate();
- }
- right() {
- this.activate();
- }
- down() {
- this.deactivate();
- }
- up() {
- this.activate();
- }
-
- next() {
- this.value = !this.value;
- this.fire();
- this.render();
- }
-
- _(c, key) {
- if (c === ' ') {
- this.value = !this.value;
- } else if (c === '1') {
- this.value = true;
- } else if (c === '0') {
- this.value = false;
- } else return this.bell();
- this.render();
- }
-
- render() {
- if (this.closed) return;
- if (this.firstRender) this.out.write(cursor.hide);
- else this.out.write(clear(this.outputText, this.out.columns));
- super.render();
-
- this.outputText = [
- style.symbol(this.done, this.aborted),
- color.bold(this.msg),
- style.delimiter(this.done),
- this.value ? this.inactive : color.cyan().underline(this.inactive),
- color.gray('/'),
- this.value ? color.cyan().underline(this.active) : this.active
- ].join(' ');
-
- this.out.write(erase.line + cursor.to(0) + this.outputText);
- }
- }
-
- toggle = TogglePrompt;
- return toggle;
-}
-
-var datepart;
-var hasRequiredDatepart;
-
-function requireDatepart () {
- if (hasRequiredDatepart) return datepart;
- hasRequiredDatepart = 1;
-
- class DatePart {
- constructor({token, date, parts, locales}) {
- this.token = token;
- this.date = date || new Date();
- this.parts = parts || [this];
- this.locales = locales || {};
- }
-
- up() {}
-
- down() {}
-
- next() {
- const currentIdx = this.parts.indexOf(this);
- return this.parts.find((part, idx) => idx > currentIdx && part instanceof DatePart);
- }
-
- setTo(val) {}
-
- prev() {
- let parts = [].concat(this.parts).reverse();
- const currentIdx = parts.indexOf(this);
- return parts.find((part, idx) => idx > currentIdx && part instanceof DatePart);
- }
-
- toString() {
- return String(this.date);
- }
- }
-
- datepart = DatePart;
- return datepart;
-}
-
-var meridiem;
-var hasRequiredMeridiem;
-
-function requireMeridiem () {
- if (hasRequiredMeridiem) return meridiem;
- hasRequiredMeridiem = 1;
-
- const DatePart = requireDatepart();
-
- class Meridiem extends DatePart {
- constructor(opts={}) {
- super(opts);
- }
-
- up() {
- this.date.setHours((this.date.getHours() + 12) % 24);
- }
-
- down() {
- this.up();
- }
-
- toString() {
- let meridiem = this.date.getHours() > 12 ? 'pm' : 'am';
- return /\A/.test(this.token) ? meridiem.toUpperCase() : meridiem;
- }
- }
-
- meridiem = Meridiem;
- return meridiem;
-}
-
-var day;
-var hasRequiredDay;
-
-function requireDay () {
- if (hasRequiredDay) return day;
- hasRequiredDay = 1;
-
- const DatePart = requireDatepart();
-
- const pos = n => {
- n = n % 10;
- return n === 1 ? 'st'
- : n === 2 ? 'nd'
- : n === 3 ? 'rd'
- : 'th';
- };
-
- class Day extends DatePart {
- constructor(opts={}) {
- super(opts);
- }
-
- up() {
- this.date.setDate(this.date.getDate() + 1);
- }
-
- down() {
- this.date.setDate(this.date.getDate() - 1);
- }
-
- setTo(val) {
- this.date.setDate(parseInt(val.substr(-2)));
- }
-
- toString() {
- let date = this.date.getDate();
- let day = this.date.getDay();
- return this.token === 'DD' ? String(date).padStart(2, '0')
- : this.token === 'Do' ? date + pos(date)
- : this.token === 'd' ? day + 1
- : this.token === 'ddd' ? this.locales.weekdaysShort[day]
- : this.token === 'dddd' ? this.locales.weekdays[day]
- : date;
- }
- }
-
- day = Day;
- return day;
-}
-
-var hours;
-var hasRequiredHours;
-
-function requireHours () {
- if (hasRequiredHours) return hours;
- hasRequiredHours = 1;
-
- const DatePart = requireDatepart();
-
- class Hours extends DatePart {
- constructor(opts={}) {
- super(opts);
- }
-
- up() {
- this.date.setHours(this.date.getHours() + 1);
- }
-
- down() {
- this.date.setHours(this.date.getHours() - 1);
- }
-
- setTo(val) {
- this.date.setHours(parseInt(val.substr(-2)));
- }
-
- toString() {
- let hours = this.date.getHours();
- if (/h/.test(this.token))
- hours = (hours % 12) || 12;
- return this.token.length > 1 ? String(hours).padStart(2, '0') : hours;
- }
- }
-
- hours = Hours;
- return hours;
-}
-
-var milliseconds;
-var hasRequiredMilliseconds;
-
-function requireMilliseconds () {
- if (hasRequiredMilliseconds) return milliseconds;
- hasRequiredMilliseconds = 1;
-
- const DatePart = requireDatepart();
-
- class Milliseconds extends DatePart {
- constructor(opts={}) {
- super(opts);
- }
-
- up() {
- this.date.setMilliseconds(this.date.getMilliseconds() + 1);
- }
-
- down() {
- this.date.setMilliseconds(this.date.getMilliseconds() - 1);
- }
-
- setTo(val) {
- this.date.setMilliseconds(parseInt(val.substr(-(this.token.length))));
- }
-
- toString() {
- return String(this.date.getMilliseconds()).padStart(4, '0')
- .substr(0, this.token.length);
- }
- }
-
- milliseconds = Milliseconds;
- return milliseconds;
-}
-
-var minutes;
-var hasRequiredMinutes;
-
-function requireMinutes () {
- if (hasRequiredMinutes) return minutes;
- hasRequiredMinutes = 1;
-
- const DatePart = requireDatepart();
-
- class Minutes extends DatePart {
- constructor(opts={}) {
- super(opts);
- }
-
- up() {
- this.date.setMinutes(this.date.getMinutes() + 1);
- }
-
- down() {
- this.date.setMinutes(this.date.getMinutes() - 1);
- }
-
- setTo(val) {
- this.date.setMinutes(parseInt(val.substr(-2)));
- }
-
- toString() {
- let m = this.date.getMinutes();
- return this.token.length > 1 ? String(m).padStart(2, '0') : m;
- }
- }
-
- minutes = Minutes;
- return minutes;
-}
-
-var month;
-var hasRequiredMonth;
-
-function requireMonth () {
- if (hasRequiredMonth) return month;
- hasRequiredMonth = 1;
-
- const DatePart = requireDatepart();
-
- class Month extends DatePart {
- constructor(opts={}) {
- super(opts);
- }
-
- up() {
- this.date.setMonth(this.date.getMonth() + 1);
- }
-
- down() {
- this.date.setMonth(this.date.getMonth() - 1);
- }
-
- setTo(val) {
- val = parseInt(val.substr(-2)) - 1;
- this.date.setMonth(val < 0 ? 0 : val);
- }
-
- toString() {
- let month = this.date.getMonth();
- let tl = this.token.length;
- return tl === 2 ? String(month + 1).padStart(2, '0')
- : tl === 3 ? this.locales.monthsShort[month]
- : tl === 4 ? this.locales.months[month]
- : String(month + 1);
- }
- }
-
- month = Month;
- return month;
-}
-
-var seconds;
-var hasRequiredSeconds;
-
-function requireSeconds () {
- if (hasRequiredSeconds) return seconds;
- hasRequiredSeconds = 1;
-
- const DatePart = requireDatepart();
-
- class Seconds extends DatePart {
- constructor(opts={}) {
- super(opts);
- }
-
- up() {
- this.date.setSeconds(this.date.getSeconds() + 1);
- }
-
- down() {
- this.date.setSeconds(this.date.getSeconds() - 1);
- }
-
- setTo(val) {
- this.date.setSeconds(parseInt(val.substr(-2)));
- }
-
- toString() {
- let s = this.date.getSeconds();
- return this.token.length > 1 ? String(s).padStart(2, '0') : s;
- }
- }
-
- seconds = Seconds;
- return seconds;
-}
-
-var year;
-var hasRequiredYear;
-
-function requireYear () {
- if (hasRequiredYear) return year;
- hasRequiredYear = 1;
-
- const DatePart = requireDatepart();
-
- class Year extends DatePart {
- constructor(opts={}) {
- super(opts);
- }
-
- up() {
- this.date.setFullYear(this.date.getFullYear() + 1);
- }
-
- down() {
- this.date.setFullYear(this.date.getFullYear() - 1);
- }
-
- setTo(val) {
- this.date.setFullYear(val.substr(-4));
- }
-
- toString() {
- let year = String(this.date.getFullYear()).padStart(4, '0');
- return this.token.length === 2 ? year.substr(-2) : year;
- }
- }
-
- year = Year;
- return year;
-}
-
-var dateparts;
-var hasRequiredDateparts;
-
-function requireDateparts () {
- if (hasRequiredDateparts) return dateparts;
- hasRequiredDateparts = 1;
-
- dateparts = {
- DatePart: requireDatepart(),
- Meridiem: requireMeridiem(),
- Day: requireDay(),
- Hours: requireHours(),
- Milliseconds: requireMilliseconds(),
- Minutes: requireMinutes(),
- Month: requireMonth(),
- Seconds: requireSeconds(),
- Year: requireYear(),
- };
- return dateparts;
-}
-
-var date;
-var hasRequiredDate;
-
-function requireDate () {
- if (hasRequiredDate) return date;
- hasRequiredDate = 1;
-
- const color = requireKleur();
- const Prompt = requirePrompt();
- const { style, clear, figures } = requireUtil();
- const { erase, cursor } = requireSrc();
- const { DatePart, Meridiem, Day, Hours, Milliseconds, Minutes, Month, Seconds, Year } = requireDateparts();
-
- const regex = /\\(.)|"((?:\\["\\]|[^"])+)"|(D[Do]?|d{3,4}|d)|(M{1,4})|(YY(?:YY)?)|([aA])|([Hh]{1,2})|(m{1,2})|(s{1,2})|(S{1,4})|./g;
- const regexGroups = {
- 1: ({token}) => token.replace(/\\(.)/g, '$1'),
- 2: (opts) => new Day(opts), // Day // TODO
- 3: (opts) => new Month(opts), // Month
- 4: (opts) => new Year(opts), // Year
- 5: (opts) => new Meridiem(opts), // AM/PM // TODO (special)
- 6: (opts) => new Hours(opts), // Hours
- 7: (opts) => new Minutes(opts), // Minutes
- 8: (opts) => new Seconds(opts), // Seconds
- 9: (opts) => new Milliseconds(opts), // Fractional seconds
- };
-
- const dfltLocales = {
- months: 'January,February,March,April,May,June,July,August,September,October,November,December'.split(','),
- monthsShort: 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
- weekdays: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
- weekdaysShort: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(',')
- };
-
-
- /**
- * DatePrompt Base Element
- * @param {Object} opts Options
- * @param {String} opts.message Message
- * @param {Number} [opts.initial] Index of default value
- * @param {String} [opts.mask] The format mask
- * @param {object} [opts.locales] The date locales
- * @param {String} [opts.error] The error message shown on invalid value
- * @param {Function} [opts.validate] Function to validate the submitted value
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- */
- class DatePrompt extends Prompt {
- constructor(opts={}) {
- super(opts);
- this.msg = opts.message;
- this.cursor = 0;
- this.typed = '';
- this.locales = Object.assign(dfltLocales, opts.locales);
- this._date = opts.initial || new Date();
- this.errorMsg = opts.error || 'Please Enter A Valid Value';
- this.validator = opts.validate || (() => true);
- this.mask = opts.mask || 'YYYY-MM-DD HH:mm:ss';
- this.clear = clear('', this.out.columns);
- this.render();
- }
-
- get value() {
- return this.date
- }
-
- get date() {
- return this._date;
- }
-
- set date(date) {
- if (date) this._date.setTime(date.getTime());
- }
-
- set mask(mask) {
- let result;
- this.parts = [];
- while(result = regex.exec(mask)) {
- let match = result.shift();
- let idx = result.findIndex(gr => gr != null);
- this.parts.push(idx in regexGroups
- ? regexGroups[idx]({ token: result[idx] || match, date: this.date, parts: this.parts, locales: this.locales })
- : result[idx] || match);
- }
-
- let parts = this.parts.reduce((arr, i) => {
- if (typeof i === 'string' && typeof arr[arr.length - 1] === 'string')
- arr[arr.length - 1] += i;
- else arr.push(i);
- return arr;
- }, []);
-
- this.parts.splice(0);
- this.parts.push(...parts);
- this.reset();
- }
-
- moveCursor(n) {
- this.typed = '';
- this.cursor = n;
- this.fire();
- }
-
- reset() {
- this.moveCursor(this.parts.findIndex(p => p instanceof DatePart));
- this.fire();
- this.render();
- }
-
- exit() {
- this.abort();
- }
-
- abort() {
- this.done = this.aborted = true;
- this.error = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- async validate() {
- let valid = await this.validator(this.value);
- if (typeof valid === 'string') {
- this.errorMsg = valid;
- valid = false;
- }
- this.error = !valid;
- }
-
- async submit() {
- await this.validate();
- if (this.error) {
- this.color = 'red';
- this.fire();
- this.render();
- return;
- }
- this.done = true;
- this.aborted = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- up() {
- this.typed = '';
- this.parts[this.cursor].up();
- this.render();
- }
-
- down() {
- this.typed = '';
- this.parts[this.cursor].down();
- this.render();
- }
-
- left() {
- let prev = this.parts[this.cursor].prev();
- if (prev == null) return this.bell();
- this.moveCursor(this.parts.indexOf(prev));
- this.render();
- }
-
- right() {
- let next = this.parts[this.cursor].next();
- if (next == null) return this.bell();
- this.moveCursor(this.parts.indexOf(next));
- this.render();
- }
-
- next() {
- let next = this.parts[this.cursor].next();
- this.moveCursor(next
- ? this.parts.indexOf(next)
- : this.parts.findIndex((part) => part instanceof DatePart));
- this.render();
- }
-
- _(c) {
- if (/\d/.test(c)) {
- this.typed += c;
- this.parts[this.cursor].setTo(this.typed);
- this.render();
- }
- }
-
- render() {
- if (this.closed) return;
- if (this.firstRender) this.out.write(cursor.hide);
- else this.out.write(clear(this.outputText, this.out.columns));
- super.render();
-
- // Print prompt
- this.outputText = [
- style.symbol(this.done, this.aborted),
- color.bold(this.msg),
- style.delimiter(false),
- this.parts.reduce((arr, p, idx) => arr.concat(idx === this.cursor && !this.done ? color.cyan().underline(p.toString()) : p), [])
- .join('')
- ].join(' ');
-
- // Print error
- if (this.error) {
- this.outputText += this.errorMsg.split('\n').reduce(
- (a, l, i) => a + `\n${i ? ` ` : figures.pointerSmall} ${color.red().italic(l)}`, ``);
- }
-
- this.out.write(erase.line + cursor.to(0) + this.outputText);
- }
- }
-
- date = DatePrompt;
- return date;
-}
-
-var number;
-var hasRequiredNumber;
-
-function requireNumber () {
- if (hasRequiredNumber) return number;
- hasRequiredNumber = 1;
- const color = requireKleur();
- const Prompt = requirePrompt();
- const { cursor, erase } = requireSrc();
- const { style, figures, clear, lines } = requireUtil();
-
- const isNumber = /[0-9]/;
- const isDef = any => any !== undefined;
- const round = (number, precision) => {
- let factor = Math.pow(10, precision);
- return Math.round(number * factor) / factor;
- };
-
- /**
- * NumberPrompt Base Element
- * @param {Object} opts Options
- * @param {String} opts.message Message
- * @param {String} [opts.style='default'] Render style
- * @param {Number} [opts.initial] Default value
- * @param {Number} [opts.max=+Infinity] Max value
- * @param {Number} [opts.min=-Infinity] Min value
- * @param {Boolean} [opts.float=false] Parse input as floats
- * @param {Number} [opts.round=2] Round floats to x decimals
- * @param {Number} [opts.increment=1] Number to increment by when using arrow-keys
- * @param {Function} [opts.validate] Validate function
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- * @param {String} [opts.error] The invalid error label
- */
- class NumberPrompt extends Prompt {
- constructor(opts={}) {
- super(opts);
- this.transform = style.render(opts.style);
- this.msg = opts.message;
- this.initial = isDef(opts.initial) ? opts.initial : '';
- this.float = !!opts.float;
- this.round = opts.round || 2;
- this.inc = opts.increment || 1;
- this.min = isDef(opts.min) ? opts.min : -Infinity;
- this.max = isDef(opts.max) ? opts.max : Infinity;
- this.errorMsg = opts.error || `Please Enter A Valid Value`;
- this.validator = opts.validate || (() => true);
- this.color = `cyan`;
- this.value = ``;
- this.typed = ``;
- this.lastHit = 0;
- this.render();
- }
-
- set value(v) {
- if (!v && v !== 0) {
- this.placeholder = true;
- this.rendered = color.gray(this.transform.render(`${this.initial}`));
- this._value = ``;
- } else {
- this.placeholder = false;
- this.rendered = this.transform.render(`${round(v, this.round)}`);
- this._value = round(v, this.round);
- }
- this.fire();
- }
-
- get value() {
- return this._value;
- }
-
- parse(x) {
- return this.float ? parseFloat(x) : parseInt(x);
- }
-
- valid(c) {
- return c === `-` || c === `.` && this.float || isNumber.test(c)
- }
-
- reset() {
- this.typed = ``;
- this.value = ``;
- this.fire();
- this.render();
- }
-
- exit() {
- this.abort();
- }
-
- abort() {
- let x = this.value;
- this.value = x !== `` ? x : this.initial;
- this.done = this.aborted = true;
- this.error = false;
- this.fire();
- this.render();
- this.out.write(`\n`);
- this.close();
- }
-
- async validate() {
- let valid = await this.validator(this.value);
- if (typeof valid === `string`) {
- this.errorMsg = valid;
- valid = false;
- }
- this.error = !valid;
- }
-
- async submit() {
- await this.validate();
- if (this.error) {
- this.color = `red`;
- this.fire();
- this.render();
- return;
- }
- let x = this.value;
- this.value = x !== `` ? x : this.initial;
- this.done = true;
- this.aborted = false;
- this.error = false;
- this.fire();
- this.render();
- this.out.write(`\n`);
- this.close();
- }
-
- up() {
- this.typed = ``;
- if(this.value === '') {
- this.value = this.min - this.inc;
- }
- if (this.value >= this.max) return this.bell();
- this.value += this.inc;
- this.color = `cyan`;
- this.fire();
- this.render();
- }
-
- down() {
- this.typed = ``;
- if(this.value === '') {
- this.value = this.min + this.inc;
- }
- if (this.value <= this.min) return this.bell();
- this.value -= this.inc;
- this.color = `cyan`;
- this.fire();
- this.render();
- }
-
- delete() {
- let val = this.value.toString();
- if (val.length === 0) return this.bell();
- this.value = this.parse((val = val.slice(0, -1))) || ``;
- if (this.value !== '' && this.value < this.min) {
- this.value = this.min;
- }
- this.color = `cyan`;
- this.fire();
- this.render();
- }
-
- next() {
- this.value = this.initial;
- this.fire();
- this.render();
- }
-
- _(c, key) {
- if (!this.valid(c)) return this.bell();
-
- const now = Date.now();
- if (now - this.lastHit > 1000) this.typed = ``; // 1s elapsed
- this.typed += c;
- this.lastHit = now;
- this.color = `cyan`;
-
- if (c === `.`) return this.fire();
-
- this.value = Math.min(this.parse(this.typed), this.max);
- if (this.value > this.max) this.value = this.max;
- if (this.value < this.min) this.value = this.min;
- this.fire();
- this.render();
- }
-
- render() {
- if (this.closed) return;
- if (!this.firstRender) {
- if (this.outputError)
- this.out.write(cursor.down(lines(this.outputError, this.out.columns) - 1) + clear(this.outputError, this.out.columns));
- this.out.write(clear(this.outputText, this.out.columns));
- }
- super.render();
- this.outputError = '';
-
- // Print prompt
- this.outputText = [
- style.symbol(this.done, this.aborted),
- color.bold(this.msg),
- style.delimiter(this.done),
- !this.done || (!this.done && !this.placeholder)
- ? color[this.color]().underline(this.rendered) : this.rendered
- ].join(` `);
-
- // Print error
- if (this.error) {
- this.outputError += this.errorMsg.split(`\n`)
- .reduce((a, l, i) => a + `\n${i ? ` ` : figures.pointerSmall} ${color.red().italic(l)}`, ``);
- }
-
- this.out.write(erase.line + cursor.to(0) + this.outputText + cursor.save + this.outputError + cursor.restore);
- }
- }
-
- number = NumberPrompt;
- return number;
-}
-
-var multiselect;
-var hasRequiredMultiselect;
-
-function requireMultiselect () {
- if (hasRequiredMultiselect) return multiselect;
- hasRequiredMultiselect = 1;
-
- const color = requireKleur();
- const { cursor } = requireSrc();
- const Prompt = requirePrompt();
- const { clear, figures, style, wrap, entriesToDisplay } = requireUtil();
-
- /**
- * MultiselectPrompt Base Element
- * @param {Object} opts Options
- * @param {String} opts.message Message
- * @param {Array} opts.choices Array of choice objects
- * @param {String} [opts.hint] Hint to display
- * @param {String} [opts.warn] Hint shown for disabled choices
- * @param {Number} [opts.max] Max choices
- * @param {Number} [opts.cursor=0] Cursor start position
- * @param {Number} [opts.optionsPerPage=10] Max options to display at once
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- */
- class MultiselectPrompt extends Prompt {
- constructor(opts={}) {
- super(opts);
- this.msg = opts.message;
- this.cursor = opts.cursor || 0;
- this.scrollIndex = opts.cursor || 0;
- this.hint = opts.hint || '';
- this.warn = opts.warn || '- This option is disabled -';
- this.minSelected = opts.min;
- this.showMinError = false;
- this.maxChoices = opts.max;
- this.instructions = opts.instructions;
- this.optionsPerPage = opts.optionsPerPage || 10;
- this.value = opts.choices.map((ch, idx) => {
- if (typeof ch === 'string')
- ch = {title: ch, value: idx};
- return {
- title: ch && (ch.title || ch.value || ch),
- description: ch && ch.description,
- value: ch && (ch.value === undefined ? idx : ch.value),
- selected: ch && ch.selected,
- disabled: ch && ch.disabled
- };
- });
- this.clear = clear('', this.out.columns);
- if (!opts.overrideRender) {
- this.render();
- }
- }
-
- reset() {
- this.value.map(v => !v.selected);
- this.cursor = 0;
- this.fire();
- this.render();
- }
-
- selected() {
- return this.value.filter(v => v.selected);
- }
-
- exit() {
- this.abort();
- }
-
- abort() {
- this.done = this.aborted = true;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- submit() {
- const selected = this.value
- .filter(e => e.selected);
- if (this.minSelected && selected.length < this.minSelected) {
- this.showMinError = true;
- this.render();
- } else {
- this.done = true;
- this.aborted = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
- }
-
- first() {
- this.cursor = 0;
- this.render();
- }
-
- last() {
- this.cursor = this.value.length - 1;
- this.render();
- }
- next() {
- this.cursor = (this.cursor + 1) % this.value.length;
- this.render();
- }
-
- up() {
- if (this.cursor === 0) {
- this.cursor = this.value.length - 1;
- } else {
- this.cursor--;
- }
- this.render();
- }
-
- down() {
- if (this.cursor === this.value.length - 1) {
- this.cursor = 0;
- } else {
- this.cursor++;
- }
- this.render();
- }
-
- left() {
- this.value[this.cursor].selected = false;
- this.render();
- }
-
- right() {
- if (this.value.filter(e => e.selected).length >= this.maxChoices) return this.bell();
- this.value[this.cursor].selected = true;
- this.render();
- }
-
- handleSpaceToggle() {
- const v = this.value[this.cursor];
-
- if (v.selected) {
- v.selected = false;
- this.render();
- } else if (v.disabled || this.value.filter(e => e.selected).length >= this.maxChoices) {
- return this.bell();
- } else {
- v.selected = true;
- this.render();
- }
- }
-
- toggleAll() {
- if (this.maxChoices !== undefined || this.value[this.cursor].disabled) {
- return this.bell();
- }
-
- const newSelected = !this.value[this.cursor].selected;
- this.value.filter(v => !v.disabled).forEach(v => v.selected = newSelected);
- this.render();
- }
-
- _(c, key) {
- if (c === ' ') {
- this.handleSpaceToggle();
- } else if (c === 'a') {
- this.toggleAll();
- } else {
- return this.bell();
- }
- }
-
- renderInstructions() {
- if (this.instructions === undefined || this.instructions) {
- if (typeof this.instructions === 'string') {
- return this.instructions;
- }
- return '\nInstructions:\n'
- + ` ${figures.arrowUp}/${figures.arrowDown}: Highlight option\n`
- + ` ${figures.arrowLeft}/${figures.arrowRight}/[space]: Toggle selection\n`
- + (this.maxChoices === undefined ? ` a: Toggle all\n` : '')
- + ` enter/return: Complete answer`;
- }
- return '';
- }
-
- renderOption(cursor, v, i, arrowIndicator) {
- const prefix = (v.selected ? color.green(figures.radioOn) : figures.radioOff) + ' ' + arrowIndicator + ' ';
- let title, desc;
-
- if (v.disabled) {
- title = cursor === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title);
- } else {
- title = cursor === i ? color.cyan().underline(v.title) : v.title;
- if (cursor === i && v.description) {
- desc = ` - ${v.description}`;
- if (prefix.length + title.length + desc.length >= this.out.columns
- || v.description.split(/\r?\n/).length > 1) {
- desc = '\n' + wrap(v.description, { margin: prefix.length, width: this.out.columns });
- }
- }
- }
-
- return prefix + title + color.gray(desc || '');
- }
-
- // shared with autocompleteMultiselect
- paginateOptions(options) {
- if (options.length === 0) {
- return color.red('No matches for this query.');
- }
-
- let { startIndex, endIndex } = entriesToDisplay(this.cursor, options.length, this.optionsPerPage);
- let prefix, styledOptions = [];
-
- for (let i = startIndex; i < endIndex; i++) {
- if (i === startIndex && startIndex > 0) {
- prefix = figures.arrowUp;
- } else if (i === endIndex - 1 && endIndex < options.length) {
- prefix = figures.arrowDown;
- } else {
- prefix = ' ';
- }
- styledOptions.push(this.renderOption(this.cursor, options[i], i, prefix));
- }
-
- return '\n' + styledOptions.join('\n');
- }
-
- // shared with autocomleteMultiselect
- renderOptions(options) {
- if (!this.done) {
- return this.paginateOptions(options);
- }
- return '';
- }
-
- renderDoneOrInstructions() {
- if (this.done) {
- return this.value
- .filter(e => e.selected)
- .map(v => v.title)
- .join(', ');
- }
-
- const output = [color.gray(this.hint), this.renderInstructions()];
-
- if (this.value[this.cursor].disabled) {
- output.push(color.yellow(this.warn));
- }
- return output.join(' ');
- }
-
- render() {
- if (this.closed) return;
- if (this.firstRender) this.out.write(cursor.hide);
- super.render();
-
- // print prompt
- let prompt = [
- style.symbol(this.done, this.aborted),
- color.bold(this.msg),
- style.delimiter(false),
- this.renderDoneOrInstructions()
- ].join(' ');
- if (this.showMinError) {
- prompt += color.red(`You must select a minimum of ${this.minSelected} choices.`);
- this.showMinError = false;
- }
- prompt += this.renderOptions(this.value);
-
- this.out.write(this.clear + prompt);
- this.clear = clear(prompt, this.out.columns);
- }
- }
-
- multiselect = MultiselectPrompt;
- return multiselect;
-}
-
-var autocomplete;
-var hasRequiredAutocomplete;
-
-function requireAutocomplete () {
- if (hasRequiredAutocomplete) return autocomplete;
- hasRequiredAutocomplete = 1;
-
- const color = requireKleur();
- const Prompt = requirePrompt();
- const { erase, cursor } = requireSrc();
- const { style, clear, figures, wrap, entriesToDisplay } = requireUtil();
-
- const getVal = (arr, i) => arr[i] && (arr[i].value || arr[i].title || arr[i]);
- const getTitle = (arr, i) => arr[i] && (arr[i].title || arr[i].value || arr[i]);
- const getIndex = (arr, valOrTitle) => {
- const index = arr.findIndex(el => el.value === valOrTitle || el.title === valOrTitle);
- return index > -1 ? index : undefined;
- };
-
- /**
- * TextPrompt Base Element
- * @param {Object} opts Options
- * @param {String} opts.message Message
- * @param {Array} opts.choices Array of auto-complete choices objects
- * @param {Function} [opts.suggest] Filter function. Defaults to sort by title
- * @param {Number} [opts.limit=10] Max number of results to show
- * @param {Number} [opts.cursor=0] Cursor start position
- * @param {String} [opts.style='default'] Render style
- * @param {String} [opts.fallback] Fallback message - initial to default value
- * @param {String} [opts.initial] Index of the default value
- * @param {Boolean} [opts.clearFirst] The first ESCAPE keypress will clear the input
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- * @param {String} [opts.noMatches] The no matches found label
- */
- class AutocompletePrompt extends Prompt {
- constructor(opts={}) {
- super(opts);
- this.msg = opts.message;
- this.suggest = opts.suggest;
- this.choices = opts.choices;
- this.initial = typeof opts.initial === 'number'
- ? opts.initial
- : getIndex(opts.choices, opts.initial);
- this.select = this.initial || opts.cursor || 0;
- this.i18n = { noMatches: opts.noMatches || 'no matches found' };
- this.fallback = opts.fallback || this.initial;
- this.clearFirst = opts.clearFirst || false;
- this.suggestions = [];
- this.input = '';
- this.limit = opts.limit || 10;
- this.cursor = 0;
- this.transform = style.render(opts.style);
- this.scale = this.transform.scale;
- this.render = this.render.bind(this);
- this.complete = this.complete.bind(this);
- this.clear = clear('', this.out.columns);
- this.complete(this.render);
- this.render();
- }
-
- set fallback(fb) {
- this._fb = Number.isSafeInteger(parseInt(fb)) ? parseInt(fb) : fb;
- }
-
- get fallback() {
- let choice;
- if (typeof this._fb === 'number')
- choice = this.choices[this._fb];
- else if (typeof this._fb === 'string')
- choice = { title: this._fb };
- return choice || this._fb || { title: this.i18n.noMatches };
- }
-
- moveSelect(i) {
- this.select = i;
- if (this.suggestions.length > 0)
- this.value = getVal(this.suggestions, i);
- else this.value = this.fallback.value;
- this.fire();
- }
-
- async complete(cb) {
- const p = (this.completing = this.suggest(this.input, this.choices));
- const suggestions = await p;
-
- if (this.completing !== p) return;
- this.suggestions = suggestions
- .map((s, i, arr) => ({ title: getTitle(arr, i), value: getVal(arr, i), description: s.description }));
- this.completing = false;
- const l = Math.max(suggestions.length - 1, 0);
- this.moveSelect(Math.min(l, this.select));
-
- cb && cb();
- }
-
- reset() {
- this.input = '';
- this.complete(() => {
- this.moveSelect(this.initial !== void 0 ? this.initial : 0);
- this.render();
- });
- this.render();
- }
-
- exit() {
- if (this.clearFirst && this.input.length > 0) {
- this.reset();
- } else {
- this.done = this.exited = true;
- this.aborted = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
- }
-
- abort() {
- this.done = this.aborted = true;
- this.exited = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- submit() {
- this.done = true;
- this.aborted = this.exited = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- _(c, key) {
- let s1 = this.input.slice(0, this.cursor);
- let s2 = this.input.slice(this.cursor);
- this.input = `${s1}${c}${s2}`;
- this.cursor = s1.length+1;
- this.complete(this.render);
- this.render();
- }
-
- delete() {
- if (this.cursor === 0) return this.bell();
- let s1 = this.input.slice(0, this.cursor-1);
- let s2 = this.input.slice(this.cursor);
- this.input = `${s1}${s2}`;
- this.complete(this.render);
- this.cursor = this.cursor-1;
- this.render();
- }
-
- deleteForward() {
- if(this.cursor*this.scale >= this.rendered.length) return this.bell();
- let s1 = this.input.slice(0, this.cursor);
- let s2 = this.input.slice(this.cursor+1);
- this.input = `${s1}${s2}`;
- this.complete(this.render);
- this.render();
- }
-
- first() {
- this.moveSelect(0);
- this.render();
- }
-
- last() {
- this.moveSelect(this.suggestions.length - 1);
- this.render();
- }
-
- up() {
- if (this.select === 0) {
- this.moveSelect(this.suggestions.length - 1);
- } else {
- this.moveSelect(this.select - 1);
- }
- this.render();
- }
-
- down() {
- if (this.select === this.suggestions.length - 1) {
- this.moveSelect(0);
- } else {
- this.moveSelect(this.select + 1);
- }
- this.render();
- }
-
- next() {
- if (this.select === this.suggestions.length - 1) {
- this.moveSelect(0);
- } else this.moveSelect(this.select + 1);
- this.render();
- }
-
- nextPage() {
- this.moveSelect(Math.min(this.select + this.limit, this.suggestions.length - 1));
- this.render();
- }
-
- prevPage() {
- this.moveSelect(Math.max(this.select - this.limit, 0));
- this.render();
- }
-
- left() {
- if (this.cursor <= 0) return this.bell();
- this.cursor = this.cursor-1;
- this.render();
- }
-
- right() {
- if (this.cursor*this.scale >= this.rendered.length) return this.bell();
- this.cursor = this.cursor+1;
- this.render();
- }
-
- renderOption(v, hovered, isStart, isEnd) {
- let desc;
- let prefix = isStart ? figures.arrowUp : isEnd ? figures.arrowDown : ' ';
- let title = hovered ? color.cyan().underline(v.title) : v.title;
- prefix = (hovered ? color.cyan(figures.pointer) + ' ' : ' ') + prefix;
- if (v.description) {
- desc = ` - ${v.description}`;
- if (prefix.length + title.length + desc.length >= this.out.columns
- || v.description.split(/\r?\n/).length > 1) {
- desc = '\n' + wrap(v.description, { margin: 3, width: this.out.columns });
- }
- }
- return prefix + ' ' + title + color.gray(desc || '');
- }
-
- render() {
- if (this.closed) return;
- if (this.firstRender) this.out.write(cursor.hide);
- else this.out.write(clear(this.outputText, this.out.columns));
- super.render();
-
- let { startIndex, endIndex } = entriesToDisplay(this.select, this.choices.length, this.limit);
-
- this.outputText = [
- style.symbol(this.done, this.aborted, this.exited),
- color.bold(this.msg),
- style.delimiter(this.completing),
- this.done && this.suggestions[this.select]
- ? this.suggestions[this.select].title
- : this.rendered = this.transform.render(this.input)
- ].join(' ');
-
- if (!this.done) {
- const suggestions = this.suggestions
- .slice(startIndex, endIndex)
- .map((item, i) => this.renderOption(item,
- this.select === i + startIndex,
- i === 0 && startIndex > 0,
- i + startIndex === endIndex - 1 && endIndex < this.choices.length))
- .join('\n');
- this.outputText += `\n` + (suggestions || color.gray(this.fallback.title));
- }
-
- this.out.write(erase.line + cursor.to(0) + this.outputText);
- }
- }
-
- autocomplete = AutocompletePrompt;
- return autocomplete;
-}
-
-var autocompleteMultiselect;
-var hasRequiredAutocompleteMultiselect;
-
-function requireAutocompleteMultiselect () {
- if (hasRequiredAutocompleteMultiselect) return autocompleteMultiselect;
- hasRequiredAutocompleteMultiselect = 1;
-
- const color = requireKleur();
- const { cursor } = requireSrc();
- const MultiselectPrompt = requireMultiselect();
- const { clear, style, figures } = requireUtil();
- /**
- * MultiselectPrompt Base Element
- * @param {Object} opts Options
- * @param {String} opts.message Message
- * @param {Array} opts.choices Array of choice objects
- * @param {String} [opts.hint] Hint to display
- * @param {String} [opts.warn] Hint shown for disabled choices
- * @param {Number} [opts.max] Max choices
- * @param {Number} [opts.cursor=0] Cursor start position
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- */
- class AutocompleteMultiselectPrompt extends MultiselectPrompt {
- constructor(opts={}) {
- opts.overrideRender = true;
- super(opts);
- this.inputValue = '';
- this.clear = clear('', this.out.columns);
- this.filteredOptions = this.value;
- this.render();
- }
-
- last() {
- this.cursor = this.filteredOptions.length - 1;
- this.render();
- }
- next() {
- this.cursor = (this.cursor + 1) % this.filteredOptions.length;
- this.render();
- }
-
- up() {
- if (this.cursor === 0) {
- this.cursor = this.filteredOptions.length - 1;
- } else {
- this.cursor--;
- }
- this.render();
- }
-
- down() {
- if (this.cursor === this.filteredOptions.length - 1) {
- this.cursor = 0;
- } else {
- this.cursor++;
- }
- this.render();
- }
-
- left() {
- this.filteredOptions[this.cursor].selected = false;
- this.render();
- }
-
- right() {
- if (this.value.filter(e => e.selected).length >= this.maxChoices) return this.bell();
- this.filteredOptions[this.cursor].selected = true;
- this.render();
- }
-
- delete() {
- if (this.inputValue.length) {
- this.inputValue = this.inputValue.substr(0, this.inputValue.length - 1);
- this.updateFilteredOptions();
- }
- }
-
- updateFilteredOptions() {
- const currentHighlight = this.filteredOptions[this.cursor];
- this.filteredOptions = this.value
- .filter(v => {
- if (this.inputValue) {
- if (typeof v.title === 'string') {
- if (v.title.toLowerCase().includes(this.inputValue.toLowerCase())) {
- return true;
- }
- }
- if (typeof v.value === 'string') {
- if (v.value.toLowerCase().includes(this.inputValue.toLowerCase())) {
- return true;
- }
- }
- return false;
- }
- return true;
- });
- const newHighlightIndex = this.filteredOptions.findIndex(v => v === currentHighlight);
- this.cursor = newHighlightIndex < 0 ? 0 : newHighlightIndex;
- this.render();
- }
-
- handleSpaceToggle() {
- const v = this.filteredOptions[this.cursor];
-
- if (v.selected) {
- v.selected = false;
- this.render();
- } else if (v.disabled || this.value.filter(e => e.selected).length >= this.maxChoices) {
- return this.bell();
- } else {
- v.selected = true;
- this.render();
- }
- }
-
- handleInputChange(c) {
- this.inputValue = this.inputValue + c;
- this.updateFilteredOptions();
- }
-
- _(c, key) {
- if (c === ' ') {
- this.handleSpaceToggle();
- } else {
- this.handleInputChange(c);
- }
- }
-
- renderInstructions() {
- if (this.instructions === undefined || this.instructions) {
- if (typeof this.instructions === 'string') {
- return this.instructions;
- }
- return `
-Instructions:
- ${figures.arrowUp}/${figures.arrowDown}: Highlight option
- ${figures.arrowLeft}/${figures.arrowRight}/[space]: Toggle selection
- [a,b,c]/delete: Filter choices
- enter/return: Complete answer
-`;
- }
- return '';
- }
-
- renderCurrentInput() {
- return `
-Filtered results for: ${this.inputValue ? this.inputValue : color.gray('Enter something to filter')}\n`;
- }
-
- renderOption(cursor, v, i) {
- let title;
- if (v.disabled) title = cursor === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title);
- else title = cursor === i ? color.cyan().underline(v.title) : v.title;
- return (v.selected ? color.green(figures.radioOn) : figures.radioOff) + ' ' + title
- }
-
- renderDoneOrInstructions() {
- if (this.done) {
- return this.value
- .filter(e => e.selected)
- .map(v => v.title)
- .join(', ');
- }
-
- const output = [color.gray(this.hint), this.renderInstructions(), this.renderCurrentInput()];
-
- if (this.filteredOptions.length && this.filteredOptions[this.cursor].disabled) {
- output.push(color.yellow(this.warn));
- }
- return output.join(' ');
- }
-
- render() {
- if (this.closed) return;
- if (this.firstRender) this.out.write(cursor.hide);
- super.render();
-
- // print prompt
-
- let prompt = [
- style.symbol(this.done, this.aborted),
- color.bold(this.msg),
- style.delimiter(false),
- this.renderDoneOrInstructions()
- ].join(' ');
-
- if (this.showMinError) {
- prompt += color.red(`You must select a minimum of ${this.minSelected} choices.`);
- this.showMinError = false;
- }
- prompt += this.renderOptions(this.filteredOptions);
-
- this.out.write(this.clear + prompt);
- this.clear = clear(prompt, this.out.columns);
- }
- }
-
- autocompleteMultiselect = AutocompleteMultiselectPrompt;
- return autocompleteMultiselect;
-}
-
-var confirm;
-var hasRequiredConfirm;
-
-function requireConfirm () {
- if (hasRequiredConfirm) return confirm;
- hasRequiredConfirm = 1;
- const color = requireKleur();
- const Prompt = requirePrompt();
- const { style, clear } = requireUtil();
- const { erase, cursor } = requireSrc();
-
- /**
- * ConfirmPrompt Base Element
- * @param {Object} opts Options
- * @param {String} opts.message Message
- * @param {Boolean} [opts.initial] Default value (true/false)
- * @param {Stream} [opts.stdin] The Readable stream to listen to
- * @param {Stream} [opts.stdout] The Writable stream to write readline data to
- * @param {String} [opts.yes] The "Yes" label
- * @param {String} [opts.yesOption] The "Yes" option when choosing between yes/no
- * @param {String} [opts.no] The "No" label
- * @param {String} [opts.noOption] The "No" option when choosing between yes/no
- */
- class ConfirmPrompt extends Prompt {
- constructor(opts={}) {
- super(opts);
- this.msg = opts.message;
- this.value = opts.initial;
- this.initialValue = !!opts.initial;
- this.yesMsg = opts.yes || 'yes';
- this.yesOption = opts.yesOption || '(Y/n)';
- this.noMsg = opts.no || 'no';
- this.noOption = opts.noOption || '(y/N)';
- this.render();
- }
-
- reset() {
- this.value = this.initialValue;
- this.fire();
- this.render();
- }
-
- exit() {
- this.abort();
- }
-
- abort() {
- this.done = this.aborted = true;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- submit() {
- this.value = this.value || false;
- this.done = true;
- this.aborted = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
-
- _(c, key) {
- if (c.toLowerCase() === 'y') {
- this.value = true;
- return this.submit();
- }
- if (c.toLowerCase() === 'n') {
- this.value = false;
- return this.submit();
- }
- return this.bell();
- }
-
- render() {
- if (this.closed) return;
- if (this.firstRender) this.out.write(cursor.hide);
- else this.out.write(clear(this.outputText, this.out.columns));
- super.render();
-
- this.outputText = [
- style.symbol(this.done, this.aborted),
- color.bold(this.msg),
- style.delimiter(this.done),
- this.done ? (this.value ? this.yesMsg : this.noMsg)
- : color.gray(this.initialValue ? this.yesOption : this.noOption)
- ].join(' ');
-
- this.out.write(erase.line + cursor.to(0) + this.outputText);
- }
- }
-
- confirm = ConfirmPrompt;
- return confirm;
-}
-
-var elements;
-var hasRequiredElements;
-
-function requireElements () {
- if (hasRequiredElements) return elements;
- hasRequiredElements = 1;
-
- elements = {
- TextPrompt: requireText(),
- SelectPrompt: requireSelect(),
- TogglePrompt: requireToggle(),
- DatePrompt: requireDate(),
- NumberPrompt: requireNumber(),
- MultiselectPrompt: requireMultiselect(),
- AutocompletePrompt: requireAutocomplete(),
- AutocompleteMultiselectPrompt: requireAutocompleteMultiselect(),
- ConfirmPrompt: requireConfirm()
- };
- return elements;
-}
-
-var hasRequiredPrompts$1;
-
-function requirePrompts$1 () {
- if (hasRequiredPrompts$1) return prompts$1;
- hasRequiredPrompts$1 = 1;
- (function (exports$1) {
- const $ = exports$1;
- const el = requireElements();
- const noop = v => v;
-
- function toPrompt(type, args, opts={}) {
- return new Promise((res, rej) => {
- const p = new el[type](args);
- const onAbort = opts.onAbort || noop;
- const onSubmit = opts.onSubmit || noop;
- const onExit = opts.onExit || noop;
- p.on('state', args.onState || noop);
- p.on('submit', x => res(onSubmit(x)));
- p.on('exit', x => res(onExit(x)));
- p.on('abort', x => rej(onAbort(x)));
- });
- }
-
- /**
- * Text prompt
- * @param {string} args.message Prompt message to display
- * @param {string} [args.initial] Default string value
- * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
- * @param {function} [args.onState] On state change callback
- * @param {function} [args.validate] Function to validate user input
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
- $.text = args => toPrompt('TextPrompt', args);
-
- /**
- * Password prompt with masked input
- * @param {string} args.message Prompt message to display
- * @param {string} [args.initial] Default string value
- * @param {function} [args.onState] On state change callback
- * @param {function} [args.validate] Function to validate user input
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
- $.password = args => {
- args.style = 'password';
- return $.text(args);
- };
-
- /**
- * Prompt where input is invisible, like sudo
- * @param {string} args.message Prompt message to display
- * @param {string} [args.initial] Default string value
- * @param {function} [args.onState] On state change callback
- * @param {function} [args.validate] Function to validate user input
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
- $.invisible = args => {
- args.style = 'invisible';
- return $.text(args);
- };
-
- /**
- * Number prompt
- * @param {string} args.message Prompt message to display
- * @param {number} args.initial Default number value
- * @param {function} [args.onState] On state change callback
- * @param {number} [args.max] Max value
- * @param {number} [args.min] Min value
- * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
- * @param {Boolean} [opts.float=false] Parse input as floats
- * @param {Number} [opts.round=2] Round floats to x decimals
- * @param {Number} [opts.increment=1] Number to increment by when using arrow-keys
- * @param {function} [args.validate] Function to validate user input
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
- $.number = args => toPrompt('NumberPrompt', args);
-
- /**
- * Date prompt
- * @param {string} args.message Prompt message to display
- * @param {number} args.initial Default number value
- * @param {function} [args.onState] On state change callback
- * @param {number} [args.max] Max value
- * @param {number} [args.min] Min value
- * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
- * @param {Boolean} [opts.float=false] Parse input as floats
- * @param {Number} [opts.round=2] Round floats to x decimals
- * @param {Number} [opts.increment=1] Number to increment by when using arrow-keys
- * @param {function} [args.validate] Function to validate user input
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
- $.date = args => toPrompt('DatePrompt', args);
-
- /**
- * Classic yes/no prompt
- * @param {string} args.message Prompt message to display
- * @param {boolean} [args.initial=false] Default value
- * @param {function} [args.onState] On state change callback
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
- $.confirm = args => toPrompt('ConfirmPrompt', args);
-
- /**
- * List prompt, split intput string by `seperator`
- * @param {string} args.message Prompt message to display
- * @param {string} [args.initial] Default string value
- * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
- * @param {string} [args.separator] String separator
- * @param {function} [args.onState] On state change callback
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input, in form of an `Array`
- */
- $.list = args => {
- const sep = args.separator || ',';
- return toPrompt('TextPrompt', args, {
- onSubmit: str => str.split(sep).map(s => s.trim())
- });
- };
-
- /**
- * Toggle/switch prompt
- * @param {string} args.message Prompt message to display
- * @param {boolean} [args.initial=false] Default value
- * @param {string} [args.active="on"] Text for `active` state
- * @param {string} [args.inactive="off"] Text for `inactive` state
- * @param {function} [args.onState] On state change callback
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
- $.toggle = args => toPrompt('TogglePrompt', args);
-
- /**
- * Interactive select prompt
- * @param {string} args.message Prompt message to display
- * @param {Array} args.choices Array of choices objects `[{ title, value }, ...]`
- * @param {number} [args.initial] Index of default value
- * @param {String} [args.hint] Hint to display
- * @param {function} [args.onState] On state change callback
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
- $.select = args => toPrompt('SelectPrompt', args);
-
- /**
- * Interactive multi-select / autocompleteMultiselect prompt
- * @param {string} args.message Prompt message to display
- * @param {Array} args.choices Array of choices objects `[{ title, value, [selected] }, ...]`
- * @param {number} [args.max] Max select
- * @param {string} [args.hint] Hint to display user
- * @param {Number} [args.cursor=0] Cursor start position
- * @param {function} [args.onState] On state change callback
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
- $.multiselect = args => {
- args.choices = [].concat(args.choices || []);
- const toSelected = items => items.filter(item => item.selected).map(item => item.value);
- return toPrompt('MultiselectPrompt', args, {
- onAbort: toSelected,
- onSubmit: toSelected
- });
- };
-
- $.autocompleteMultiselect = args => {
- args.choices = [].concat(args.choices || []);
- const toSelected = items => items.filter(item => item.selected).map(item => item.value);
- return toPrompt('AutocompleteMultiselectPrompt', args, {
- onAbort: toSelected,
- onSubmit: toSelected
- });
- };
-
- const byTitle = (input, choices) => Promise.resolve(
- choices.filter(item => item.title.slice(0, input.length).toLowerCase() === input.toLowerCase())
- );
-
- /**
- * Interactive auto-complete prompt
- * @param {string} args.message Prompt message to display
- * @param {Array} args.choices Array of auto-complete choices objects `[{ title, value }, ...]`
- * @param {Function} [args.suggest] Function to filter results based on user input. Defaults to sort by `title`
- * @param {number} [args.limit=10] Max number of results to show
- * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
- * @param {String} [args.initial] Index of the default value
- * @param {boolean} [opts.clearFirst] The first ESCAPE keypress will clear the input
- * @param {String} [args.fallback] Fallback message - defaults to initial value
- * @param {function} [args.onState] On state change callback
- * @param {Stream} [args.stdin] The Readable stream to listen to
- * @param {Stream} [args.stdout] The Writable stream to write readline data to
- * @returns {Promise} Promise with user input
- */
- $.autocomplete = args => {
- args.suggest = args.suggest || byTitle;
- args.choices = [].concat(args.choices || []);
- return toPrompt('AutocompletePrompt', args);
- };
- } (prompts$1));
- return prompts$1;
-}
-
-var lib;
-var hasRequiredLib;
-
-function requireLib () {
- if (hasRequiredLib) return lib;
- hasRequiredLib = 1;
-
- const prompts = requirePrompts$1();
-
- const passOn = ['suggest', 'format', 'onState', 'validate', 'onRender', 'type'];
- const noop = () => {};
-
- /**
- * Prompt for a series of questions
- * @param {Array|Object} questions Single question object or Array of question objects
- * @param {Function} [onSubmit] Callback function called on prompt submit
- * @param {Function} [onCancel] Callback function called on cancel/abort
- * @returns {Object} Object with values from user input
- */
- async function prompt(questions=[], { onSubmit=noop, onCancel=noop }={}) {
- const answers = {};
- const override = prompt._override || {};
- questions = [].concat(questions);
- let answer, question, quit, name, type, lastPrompt;
-
- const getFormattedAnswer = async (question, answer, skipValidation = false) => {
- if (!skipValidation && question.validate && question.validate(answer) !== true) {
- return;
- }
- return question.format ? await question.format(answer, answers) : answer
- };
-
- for (question of questions) {
- ({ name, type } = question);
-
- // evaluate type first and skip if type is a falsy value
- if (typeof type === 'function') {
- type = await type(answer, { ...answers }, question);
- question['type'] = type;
- }
- if (!type) continue;
-
- // if property is a function, invoke it unless it's a special function
- for (let key in question) {
- if (passOn.includes(key)) continue;
- let value = question[key];
- question[key] = typeof value === 'function' ? await value(answer, { ...answers }, lastPrompt) : value;
- }
-
- lastPrompt = question;
-
- if (typeof question.message !== 'string') {
- throw new Error('prompt message is required');
- }
-
- // update vars in case they changed
- ({ name, type } = question);
-
- if (prompts[type] === void 0) {
- throw new Error(`prompt type (${type}) is not defined`);
- }
-
- if (override[question.name] !== undefined) {
- answer = await getFormattedAnswer(question, override[question.name]);
- if (answer !== undefined) {
- answers[name] = answer;
- continue;
- }
- }
-
- try {
- // Get the injected answer if there is one or prompt the user
- answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : await prompts[type](question);
- answers[name] = answer = await getFormattedAnswer(question, answer, true);
- quit = await onSubmit(question, answer, answers);
- } catch (err) {
- quit = !(await onCancel(question, answers));
- }
-
- if (quit) return answers;
- }
-
- return answers;
- }
-
- function getInjectedAnswer(injected, deafultValue) {
- const answer = injected.shift();
- if (answer instanceof Error) {
- throw answer;
- }
-
- return (answer === undefined) ? deafultValue : answer;
- }
-
- function inject(answers) {
- prompt._injected = (prompt._injected || []).concat(answers);
- }
-
- function override(answers) {
- prompt._override = Object.assign({}, answers);
- }
-
- lib = Object.assign(prompt, { prompt, prompts, inject, override });
- return lib;
-}
-
-var prompts;
-var hasRequiredPrompts;
-
-function requirePrompts () {
- if (hasRequiredPrompts) return prompts;
- hasRequiredPrompts = 1;
- function isNodeLT(tar) {
- tar = (Array.isArray(tar) ? tar : tar.split('.')).map(Number);
- let i=0, src=process.versions.node.split('.').map(Number);
- for (; i < tar.length; i++) {
- if (src[i] > tar[i]) return false;
- if (tar[i] > src[i]) return true;
- }
- return false;
- }
-
- prompts =
- isNodeLT('8.6.0')
- ? requireDist()
- : requireLib();
- return prompts;
-}
-
-var promptsExports = requirePrompts();
-var prompt = /*@__PURE__*/getDefaultExportFromCjs(promptsExports);
-
-var index = /*#__PURE__*/Object.freeze({
- __proto__: null,
- default: prompt
-});
-
-export { any as a, index as i, prompt as p };
diff --git a/vanilla/node_modules/vitest/dist/chunks/index.M8mOzt4Y.js b/vanilla/node_modules/vitest/dist/chunks/index.M8mOzt4Y.js
deleted file mode 100644
index bd2608b..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/index.M8mOzt4Y.js
+++ /dev/null
@@ -1,3839 +0,0 @@
-import { existsSync, readFileSync, promises } from 'node:fs';
-import { mkdir, writeFile, readdir, stat, readFile } from 'node:fs/promises';
-import { resolve as resolve$1, dirname, isAbsolute, relative, basename, join, normalize } from 'pathe';
-import { performance as performance$1 } from 'node:perf_hooks';
-import { getTests, getTestName, hasFailed, getSuites, generateHash, createTaskName, calculateSuiteHash, someTasksAreOnly, interpretTaskModes, getTasks, getFullName } from '@vitest/runner/utils';
-import { slash, toArray, isPrimitive } from '@vitest/utils/helpers';
-import { parseStacktrace, defaultStackIgnorePatterns, parseErrorStacktrace } from '@vitest/utils/source-map';
-import c from 'tinyrainbow';
-import { i as isTTY } from './env.D4Lgay0q.js';
-import { stripVTControlCharacters } from 'node:util';
-import { Console } from 'node:console';
-import { Writable } from 'node:stream';
-import { inspect } from '@vitest/utils/display';
-import nodeos__default, { hostname } from 'node:os';
-import { x } from 'tinyexec';
-import { distDir } from '../path.js';
-import { parseAstAsync } from 'vite';
-import { positionToOffset, lineSplitRE } from '@vitest/utils/offset';
-import { createRequire } from 'node:module';
-
-/// <reference types="../types/index.d.ts" />
-
-// (c) 2020-present Andrea Giammarchi
-
-const {parse: $parse, stringify: $stringify} = JSON;
-const {keys} = Object;
-
-const Primitive = String; // it could be Number
-const primitive = 'string'; // it could be 'number'
-
-const ignore$1 = {};
-const object = 'object';
-
-const noop = (_, value) => value;
-
-const primitives = value => (
- value instanceof Primitive ? Primitive(value) : value
-);
-
-const Primitives = (_, value) => (
- typeof value === primitive ? new Primitive(value) : value
-);
-
-const revive = (input, parsed, output, $) => {
- const lazy = [];
- for (let ke = keys(output), {length} = ke, y = 0; y < length; y++) {
- const k = ke[y];
- const value = output[k];
- if (value instanceof Primitive) {
- const tmp = input[value];
- if (typeof tmp === object && !parsed.has(tmp)) {
- parsed.add(tmp);
- output[k] = ignore$1;
- lazy.push({k, a: [input, parsed, tmp, $]});
- }
- else
- output[k] = $.call(output, k, tmp);
- }
- else if (output[k] !== ignore$1)
- output[k] = $.call(output, k, value);
- }
- for (let {length} = lazy, i = 0; i < length; i++) {
- const {k, a} = lazy[i];
- output[k] = $.call(output, k, revive.apply(null, a));
- }
- return output;
-};
-
-const set = (known, input, value) => {
- const index = Primitive(input.push(value) - 1);
- known.set(value, index);
- return index;
-};
-
-/**
- * Converts a specialized flatted string into a JS value.
- * @param {string} text
- * @param {(this: any, key: string, value: any) => any} [reviver]
- * @returns {any}
- */
-const parse$1 = (text, reviver) => {
- const input = $parse(text, Primitives).map(primitives);
- const value = input[0];
- const $ = reviver || noop;
- const tmp = typeof value === object && value ?
- revive(input, new Set, value, $) :
- value;
- return $.call({'': tmp}, '', tmp);
-};
-
-/**
- * Converts a JS value into a specialized flatted string.
- * @param {any} value
- * @param {((this: any, key: string, value: any) => any) | (string | number)[] | null | undefined} [replacer]
- * @param {string | number | undefined} [space]
- * @returns {string}
- */
-const stringify = (value, replacer, space) => {
- const $ = replacer && typeof replacer === object ?
- (k, v) => (k === '' || -1 < replacer.indexOf(k) ? v : void 0) :
- (replacer || noop);
- const known = new Map;
- const input = [];
- const output = [];
- let i = +set(known, input, $.call({'': value}, '', value));
- let firstRun = !i;
- while (i < input.length) {
- firstRun = true;
- output[i] = $stringify(input[i++], replace, space);
- }
- return '[' + output.join(',') + ']';
- function replace(key, value) {
- if (firstRun) {
- firstRun = !firstRun;
- return value;
- }
- const after = $.call(this, key, value);
- switch (typeof after) {
- case object:
- if (after === null) return after;
- case primitive:
- return known.get(after) || set(known, input, after);
- }
- return after;
- }
-};
-
-function getOutputFile(config, reporter) {
- if (!config?.outputFile) return;
- if (typeof config.outputFile === "string") return config.outputFile;
- return config.outputFile[reporter];
-}
-function createDefinesScript(define) {
- if (!define) return "";
- if (serializeDefine(define) === "{}") return "";
- return `
-const defines = ${serializeDefine(define)}
-Object.keys(defines).forEach((key) => {
- const segments = key.split('.')
- let target = globalThis
- for (let i = 0; i < segments.length; i++) {
- const segment = segments[i]
- if (i === segments.length - 1) {
- target[segment] = defines[key]
- } else {
- target = target[segment] || (target[segment] = {})
- }
- }
-})
- `;
-}
-/**
-* Like `JSON.stringify` but keeps raw string values as a literal
-* in the generated code. For example: `"window"` would refer to
-* the global `window` object directly.
-*/
-function serializeDefine(define) {
- const userDefine = {};
- for (const key in define) {
- // vitest sets this to avoid vite:client-inject plugin
- if (key === "process.env.NODE_ENV" && define[key] === "process.env.NODE_ENV") continue;
- // import.meta.env.* is handled in `importAnalysis` plugin
- if (!key.startsWith("import.meta.env.")) userDefine[key] = define[key];
- }
- let res = `{`;
- const keys = Object.keys(userDefine).sort();
- for (let i = 0; i < keys.length; i++) {
- const key = keys[i];
- const val = userDefine[key];
- res += `${JSON.stringify(key)}: ${handleDefineValue(val)}`;
- if (i !== keys.length - 1) res += `, `;
- }
- return `${res}}`;
-}
-function handleDefineValue(value) {
- if (typeof value === "undefined") return "undefined";
- if (typeof value === "string") return value;
- return JSON.stringify(value);
-}
-
-class BlobReporter {
- start = 0;
- ctx;
- options;
- coverage;
- constructor(options) {
- this.options = options;
- }
- onInit(ctx) {
- if (ctx.config.watch) throw new Error("Blob reporter is not supported in watch mode");
- this.ctx = ctx;
- this.start = performance.now();
- this.coverage = void 0;
- }
- onCoverage(coverage) {
- this.coverage = coverage;
- }
- async onTestRunEnd(testModules, unhandledErrors) {
- const executionTime = performance.now() - this.start;
- const files = testModules.map((testModule) => testModule.task);
- const errors = [...unhandledErrors];
- const coverage = this.coverage;
- let outputFile = this.options.outputFile ?? getOutputFile(this.ctx.config, "blob");
- if (!outputFile) {
- const shard = this.ctx.config.shard;
- outputFile = shard ? `.vitest-reports/blob-${shard.index}-${shard.count}.json` : ".vitest-reports/blob.json";
- }
- const modules = this.ctx.projects.map((project) => {
- return [project.name, [...project.vite.moduleGraph.idToModuleMap.entries()].map((mod) => {
- if (!mod[1].file) return null;
- return [
- mod[0],
- mod[1].file,
- mod[1].url
- ];
- }).filter((x) => x != null)];
- });
- const report = [
- this.ctx.version,
- files,
- errors,
- modules,
- coverage,
- executionTime
- ];
- const reportFile = resolve$1(this.ctx.config.root, outputFile);
- await writeBlob(report, reportFile);
- this.ctx.logger.log("blob report written to", reportFile);
- }
-}
-async function writeBlob(content, filename) {
- const report = stringify(content);
- const dir = dirname(filename);
- if (!existsSync(dir)) await mkdir(dir, { recursive: true });
- await writeFile(filename, report, "utf-8");
-}
-async function readBlobs(currentVersion, blobsDirectory, projectsArray) {
- // using process.cwd() because --merge-reports can only be used in CLI
- const resolvedDir = resolve$1(process.cwd(), blobsDirectory);
- const promises = (await readdir(resolvedDir)).map(async (filename) => {
- const fullPath = resolve$1(resolvedDir, filename);
- if (!(await stat(fullPath)).isFile()) throw new TypeError(`vitest.mergeReports() expects all paths in "${blobsDirectory}" to be files generated by the blob reporter, but "${filename}" is not a file`);
- const [version, files, errors, moduleKeys, coverage, executionTime] = parse$1(await readFile(fullPath, "utf-8"));
- if (!version) throw new TypeError(`vitest.mergeReports() expects all paths in "${blobsDirectory}" to be files generated by the blob reporter, but "${filename}" is not a valid blob file`);
- return {
- version,
- files,
- errors,
- moduleKeys,
- coverage,
- file: filename,
- executionTime
- };
- });
- const blobs = await Promise.all(promises);
- if (!blobs.length) throw new Error(`vitest.mergeReports() requires at least one blob file in "${blobsDirectory}" directory, but none were found`);
- const versions = new Set(blobs.map((blob) => blob.version));
- if (versions.size > 1) throw new Error(`vitest.mergeReports() requires all blob files to be generated by the same Vitest version, received\n\n${blobs.map((b) => `- "${b.file}" uses v${b.version}`).join("\n")}`);
- if (!versions.has(currentVersion)) throw new Error(`the blobs in "${blobsDirectory}" were generated by a different version of Vitest. Expected v${currentVersion}, but received v${blobs[0].version}`);
- // fake module graph - it is used to check if module is imported, but we don't use values inside
- const projects = Object.fromEntries(projectsArray.map((p) => [p.name, p]));
- blobs.forEach((blob) => {
- blob.moduleKeys.forEach(([projectName, moduleIds]) => {
- const project = projects[projectName];
- if (!project) return;
- moduleIds.forEach(([moduleId, file, url]) => {
- const moduleNode = project.vite.moduleGraph.createFileOnlyEntry(file);
- moduleNode.url = url;
- moduleNode.id = moduleId;
- moduleNode.transformResult = {
- code: " ",
- map: null
- };
- project.vite.moduleGraph.idToModuleMap.set(moduleId, moduleNode);
- });
- });
- });
- return {
- files: blobs.flatMap((blob) => blob.files).sort((f1, f2) => {
- return (f1.result?.startTime || 0) - (f2.result?.startTime || 0);
- }),
- errors: blobs.flatMap((blob) => blob.errors),
- coverages: blobs.map((blob) => blob.coverage),
- executionTimes: blobs.map((blob) => blob.executionTime)
- };
-}
-
-function groupBy(collection, iteratee) {
- return collection.reduce((acc, item) => {
- const key = iteratee(item);
- acc[key] ||= [];
- acc[key].push(item);
- return acc;
- }, {});
-}
-function stdout() {
- // @ts-expect-error Node.js maps process.stdout to console._stdout
- // eslint-disable-next-line no-console
- return console._stdout || process.stdout;
-}
-function escapeRegExp(s) {
- // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
- return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
-}
-function wildcardPatternToRegExp(pattern) {
- const negated = pattern[0] === "!";
- if (negated) pattern = pattern.slice(1);
- let regexp = `${pattern.split("*").map(escapeRegExp).join(".*")}$`;
- if (negated) regexp = `(?!${regexp})`;
- return new RegExp(`^${regexp}`, "i");
-}
-function createIndexLocationsMap(source) {
- const map = /* @__PURE__ */ new Map();
- let index = 0;
- let line = 1;
- let column = 1;
- for (const char of source) {
- map.set(index++, {
- line,
- column
- });
- if (char === "\n" || char === "\r\n") {
- line++;
- column = 0;
- } else column++;
- }
- return map;
-}
-function createLocationsIndexMap(source) {
- const map = /* @__PURE__ */ new Map();
- let index = 0;
- let line = 1;
- let column = 1;
- for (const char of source) {
- map.set(`${line}:${column}`, index++);
- if (char === "\n" || char === "\r\n") {
- line++;
- column = 0;
- } else column++;
- }
- return map;
-}
-
-function hasFailedSnapshot(suite) {
- return getTests(suite).some((s) => {
- return s.result?.errors?.some((e) => typeof e?.message === "string" && e.message.match(/Snapshot .* mismatched/));
- });
-}
-function convertTasksToEvents(file, onTask) {
- const packs = [];
- const events = [];
- function visit(suite) {
- onTask?.(suite);
- packs.push([
- suite.id,
- suite.result,
- suite.meta
- ]);
- events.push([
- suite.id,
- "suite-prepare",
- void 0
- ]);
- suite.tasks.forEach((task) => {
- if (task.type === "suite") visit(task);
- else {
- onTask?.(task);
- if (suite.mode !== "skip" && suite.mode !== "todo") {
- packs.push([
- task.id,
- task.result,
- task.meta
- ]);
- events.push([
- task.id,
- "test-prepare",
- void 0
- ]);
- task.annotations.forEach((annotation) => {
- events.push([
- task.id,
- "test-annotation",
- { annotation }
- ]);
- });
- task.artifacts.forEach((artifact) => {
- events.push([
- task.id,
- "test-artifact",
- { artifact }
- ]);
- });
- events.push([
- task.id,
- "test-finished",
- void 0
- ]);
- }
- }
- });
- events.push([
- suite.id,
- "suite-finished",
- void 0
- ]);
- }
- visit(file);
- return {
- packs,
- events
- };
-}
-
-const F_RIGHT = "→";
-const F_DOWN = "↓";
-const F_DOWN_RIGHT = "↳";
-const F_POINTER = "❯";
-const F_DOT = "·";
-const F_CHECK = "✓";
-const F_CROSS = "×";
-const F_LONG_DASH = "⎯";
-const F_TREE_NODE_MIDDLE = "├──";
-const F_TREE_NODE_END = "└──";
-
-const pointer = c.yellow(F_POINTER);
-const skipped = c.dim(c.gray(F_DOWN));
-const benchmarkPass = c.green(F_DOT);
-const testPass = c.green(F_CHECK);
-const taskFail = c.red(F_CROSS);
-const suiteFail = c.red(F_POINTER);
-const pending$1 = c.gray("·");
-const separator = c.dim(" > ");
-const labelDefaultColors = [
- c.bgYellow,
- c.bgCyan,
- c.bgGreen,
- c.bgMagenta
-];
-function getCols(delta = 0) {
- let length = process.stdout?.columns;
- if (!length || Number.isNaN(length)) length = 30;
- return Math.max(length + delta, 0);
-}
-function errorBanner(message) {
- return divider(c.bold(c.bgRed(` ${message} `)), null, null, c.red);
-}
-function divider(text, left, right, color) {
- const cols = getCols();
- const c = color || ((text) => text);
- if (text) {
- const textLength = stripVTControlCharacters(text).length;
- if (left == null && right != null) left = cols - textLength - right;
- else {
- left = left ?? Math.floor((cols - textLength) / 2);
- right = cols - textLength - left;
- }
- left = Math.max(0, left);
- right = Math.max(0, right);
- return `${c(F_LONG_DASH.repeat(left))}${text}${c(F_LONG_DASH.repeat(right))}`;
- }
- return F_LONG_DASH.repeat(cols);
-}
-function formatTestPath(root, path) {
- if (isAbsolute(path)) path = relative(root, path);
- const dir = dirname(path);
- const ext = path.match(/(\.(spec|test)\.[cm]?[tj]sx?)$/)?.[0] || "";
- const base = basename(path, ext);
- return slash(c.dim(`${dir}/`) + c.bold(base)) + c.dim(ext);
-}
-function renderSnapshotSummary(rootDir, snapshots) {
- const summary = [];
- if (snapshots.added) summary.push(c.bold(c.green(`${snapshots.added} written`)));
- if (snapshots.unmatched) summary.push(c.bold(c.red(`${snapshots.unmatched} failed`)));
- if (snapshots.updated) summary.push(c.bold(c.green(`${snapshots.updated} updated `)));
- if (snapshots.filesRemoved) if (snapshots.didUpdate) summary.push(c.bold(c.green(`${snapshots.filesRemoved} files removed `)));
- else summary.push(c.bold(c.yellow(`${snapshots.filesRemoved} files obsolete `)));
- if (snapshots.filesRemovedList && snapshots.filesRemovedList.length) {
- const [head, ...tail] = snapshots.filesRemovedList;
- summary.push(`${c.gray(F_DOWN_RIGHT)} ${formatTestPath(rootDir, head)}`);
- tail.forEach((key) => {
- summary.push(` ${c.gray(F_DOT)} ${formatTestPath(rootDir, key)}`);
- });
- }
- if (snapshots.unchecked) {
- if (snapshots.didUpdate) summary.push(c.bold(c.green(`${snapshots.unchecked} removed`)));
- else summary.push(c.bold(c.yellow(`${snapshots.unchecked} obsolete`)));
- snapshots.uncheckedKeysByFile.forEach((uncheckedFile) => {
- summary.push(`${c.gray(F_DOWN_RIGHT)} ${formatTestPath(rootDir, uncheckedFile.filePath)}`);
- uncheckedFile.keys.forEach((key) => summary.push(` ${c.gray(F_DOT)} ${key}`));
- });
- }
- return summary;
-}
-function countTestErrors(tasks) {
- return tasks.reduce((c, i) => c + (i.result?.errors?.length || 0), 0);
-}
-function getStateString$1(tasks, name = "tests", showTotal = true) {
- if (tasks.length === 0) return c.dim(`no ${name}`);
- const passed = tasks.reduce((acc, i) => i.result?.state === "pass" ? acc + 1 : acc, 0);
- const failed = tasks.reduce((acc, i) => i.result?.state === "fail" ? acc + 1 : acc, 0);
- const skipped = tasks.reduce((acc, i) => i.mode === "skip" ? acc + 1 : acc, 0);
- const todo = tasks.reduce((acc, i) => i.mode === "todo" ? acc + 1 : acc, 0);
- return [
- failed ? c.bold(c.red(`${failed} failed`)) : null,
- passed ? c.bold(c.green(`${passed} passed`)) : null,
- skipped ? c.yellow(`${skipped} skipped`) : null,
- todo ? c.gray(`${todo} todo`) : null
- ].filter(Boolean).join(c.dim(" | ")) + (showTotal ? c.gray(` (${tasks.length})`) : "");
-}
-function getStateSymbol(task) {
- if (task.mode === "skip" || task.mode === "todo") return skipped;
- if (!task.result) return pending$1;
- if (task.result.state === "run" || task.result.state === "queued") {
- if (task.type === "suite") return pointer;
- }
- if (task.result.state === "pass") return task.meta?.benchmark ? benchmarkPass : testPass;
- if (task.result.state === "fail") return task.type === "suite" ? suiteFail : taskFail;
- return " ";
-}
-function formatTimeString(date) {
- return date.toTimeString().split(" ")[0];
-}
-function formatTime(time) {
- if (time > 1e3) return `${(time / 1e3).toFixed(2)}s`;
- return `${Math.round(time)}ms`;
-}
-function formatProjectName(project, suffix = " ") {
- if (!project?.name) return "";
- if (!c.isColorSupported) return `|${project.name}|${suffix}`;
- let background = project.color && c[`bg${capitalize(project.color)}`];
- if (!background) background = labelDefaultColors[project.name.split("").reduce((acc, v, idx) => acc + v.charCodeAt(0) + idx, 0) % labelDefaultColors.length];
- return c.black(background(` ${project.name} `)) + suffix;
-}
-function withLabel(color, label, message) {
- const bgColor = `bg${color.charAt(0).toUpperCase()}${color.slice(1)}`;
- return `${c.bold(c[bgColor](` ${label} `))} ${message ? c[color](message) : ""}`;
-}
-function padSummaryTitle(str) {
- return c.dim(`${str.padStart(11)} `);
-}
-function truncateString(text, maxLength) {
- const plainText = stripVTControlCharacters(text);
- if (plainText.length <= maxLength) return text;
- return `${plainText.slice(0, maxLength - 1)}…`;
-}
-function capitalize(text) {
- return `${text[0].toUpperCase()}${text.slice(1)}`;
-}
-
-var utils = /*#__PURE__*/Object.freeze({
- __proto__: null,
- benchmarkPass: benchmarkPass,
- countTestErrors: countTestErrors,
- divider: divider,
- errorBanner: errorBanner,
- formatProjectName: formatProjectName,
- formatTestPath: formatTestPath,
- formatTime: formatTime,
- formatTimeString: formatTimeString,
- getStateString: getStateString$1,
- getStateSymbol: getStateSymbol,
- padSummaryTitle: padSummaryTitle,
- pending: pending$1,
- pointer: pointer,
- renderSnapshotSummary: renderSnapshotSummary,
- separator: separator,
- skipped: skipped,
- suiteFail: suiteFail,
- taskFail: taskFail,
- testPass: testPass,
- truncateString: truncateString,
- withLabel: withLabel
-});
-
-const BADGE_PADDING = " ";
-class BaseReporter {
- start = 0;
- end = 0;
- watchFilters;
- failedUnwatchedFiles = [];
- isTTY;
- ctx = void 0;
- renderSucceed = false;
- verbose = false;
- _filesInWatchMode = /* @__PURE__ */ new Map();
- _timeStart = formatTimeString(/* @__PURE__ */ new Date());
- constructor(options = {}) {
- this.isTTY = options.isTTY ?? isTTY;
- }
- onInit(ctx) {
- this.ctx = ctx;
- this.ctx.logger.printBanner();
- }
- log(...messages) {
- this.ctx.logger.log(...messages);
- }
- error(...messages) {
- this.ctx.logger.error(...messages);
- }
- relative(path) {
- return relative(this.ctx.config.root, path);
- }
- onTestRunStart(_specifications) {
- this.start = performance$1.now();
- this._timeStart = formatTimeString(/* @__PURE__ */ new Date());
- }
- onTestRunEnd(testModules, unhandledErrors, _reason) {
- const files = testModules.map((testModule) => testModule.task);
- const errors = [...unhandledErrors];
- this.end = performance$1.now();
- if (!files.length && !errors.length) this.ctx.logger.printNoTestFound(this.ctx.filenamePattern);
- else this.reportSummary(files, errors);
- }
- onTestCaseResult(testCase) {
- if (testCase.result().state === "failed") this.logFailedTask(testCase.task);
- }
- onTestSuiteResult(testSuite) {
- if (testSuite.state() === "failed") this.logFailedTask(testSuite.task);
- }
- onTestModuleEnd(testModule) {
- if (testModule.state() === "failed") this.logFailedTask(testModule.task);
- this.printTestModule(testModule);
- }
- logFailedTask(task) {
- if (this.ctx.config.silent === "passed-only") for (const log of task.logs || []) this.onUserConsoleLog(log, "failed");
- }
- printTestModule(testModule) {
- const moduleState = testModule.state();
- if (moduleState === "queued" || moduleState === "pending") return;
- let testsCount = 0;
- let failedCount = 0;
- let skippedCount = 0;
- // delaying logs to calculate the test stats first
- // which minimizes the amount of for loops
- const logs = [];
- const originalLog = this.log.bind(this);
- this.log = (msg) => logs.push(msg);
- const visit = (suiteState, children) => {
- for (const child of children) if (child.type === "suite") {
- const suiteState = child.state();
- // Skipped suites are hidden when --hideSkippedTests, print otherwise
- if (!this.ctx.config.hideSkippedTests || suiteState !== "skipped") this.printTestSuite(child);
- visit(suiteState, child.children);
- } else {
- const testResult = child.result();
- testsCount++;
- if (testResult.state === "failed") failedCount++;
- else if (testResult.state === "skipped") skippedCount++;
- if (this.ctx.config.hideSkippedTests && suiteState === "skipped")
- // Skipped suites are hidden when --hideSkippedTests
- continue;
- this.printTestCase(moduleState, child);
- }
- };
- try {
- visit(moduleState, testModule.children);
- } finally {
- this.log = originalLog;
- }
- this.log(this.getModuleLog(testModule, {
- tests: testsCount,
- failed: failedCount,
- skipped: skippedCount
- }));
- logs.forEach((log) => this.log(log));
- }
- printTestCase(moduleState, test) {
- const testResult = test.result();
- const { duration = 0 } = test.diagnostic() || {};
- const padding = this.getTestIndentation(test.task);
- const suffix = this.getTestCaseSuffix(test);
- if (testResult.state === "failed") this.log(c.red(` ${padding}${taskFail} ${this.getTestName(test.task, separator)}`) + suffix);
- else if (duration > this.ctx.config.slowTestThreshold) this.log(` ${padding}${c.yellow(c.dim(F_CHECK))} ${this.getTestName(test.task, separator)} ${suffix}`);
- else if (this.ctx.config.hideSkippedTests && testResult.state === "skipped") ; else if (this.renderSucceed || moduleState === "failed") this.log(` ${padding}${this.getStateSymbol(test)} ${this.getTestName(test.task, separator)}${suffix}`);
- }
- getModuleLog(testModule, counts) {
- let state = c.dim(`${counts.tests} test${counts.tests > 1 ? "s" : ""}`);
- if (counts.failed) state += c.dim(" | ") + c.red(`${counts.failed} failed`);
- if (counts.skipped) state += c.dim(" | ") + c.yellow(`${counts.skipped} skipped`);
- let suffix = c.dim("(") + state + c.dim(")") + this.getDurationPrefix(testModule.task);
- const diagnostic = testModule.diagnostic();
- if (diagnostic.heap != null) suffix += c.magenta(` ${Math.floor(diagnostic.heap / 1024 / 1024)} MB heap used`);
- return ` ${this.getEntityPrefix(testModule)} ${testModule.task.name} ${suffix}`;
- }
- printTestSuite(testSuite) {
- if (!this.renderSucceed) return;
- const indentation = " ".repeat(getIndentation(testSuite.task));
- const tests = Array.from(testSuite.children.allTests());
- const state = this.getStateSymbol(testSuite);
- this.log(` ${indentation}${state} ${testSuite.name} ${c.dim(`(${tests.length})`)}`);
- }
- getTestName(test, _separator) {
- return test.name;
- }
- getFullName(test, separator) {
- if (test === test.file) return test.name;
- let name = test.file.name;
- if (test.location) name += c.dim(`:${test.location.line}:${test.location.column}`);
- name += separator;
- name += getTestName(test, separator);
- return name;
- }
- getTestIndentation(test) {
- return " ".repeat(getIndentation(test));
- }
- printAnnotations(test, console, padding = 0) {
- const annotations = test.annotations();
- if (!annotations.length) return;
- const PADDING = " ".repeat(padding);
- const groupedAnnotations = {};
- annotations.forEach((annotation) => {
- const { location, type } = annotation;
- let group;
- if (location) {
- const file = relative(test.project.config.root, location.file);
- group = `${c.gray(`${file}:${location.line}:${location.column}`)} ${c.bold(type)}`;
- } else group = c.bold(type);
- groupedAnnotations[group] ??= [];
- groupedAnnotations[group].push(annotation);
- });
- for (const group in groupedAnnotations) {
- this[console](`${PADDING}${c.blue(F_POINTER)} ${group}`);
- groupedAnnotations[group].forEach(({ message }) => {
- this[console](`${PADDING} ${c.blue(F_DOWN_RIGHT)} ${message}`);
- });
- }
- }
- getEntityPrefix(entity) {
- let title = this.getStateSymbol(entity);
- if (entity.project.name) title += ` ${formatProjectName(entity.project, "")}`;
- if (entity.meta().typecheck) title += ` ${c.bgBlue(c.bold(" TS "))}`;
- return title;
- }
- getTestCaseSuffix(testCase) {
- const { heap, retryCount, repeatCount } = testCase.diagnostic() || {};
- const testResult = testCase.result();
- let suffix = this.getDurationPrefix(testCase.task);
- if (retryCount != null && retryCount > 0) suffix += c.yellow(` (retry x${retryCount})`);
- if (repeatCount != null && repeatCount > 0) suffix += c.yellow(` (repeat x${repeatCount})`);
- if (heap != null) suffix += c.magenta(` ${Math.floor(heap / 1024 / 1024)} MB heap used`);
- if (testResult.state === "skipped" && testResult.note) suffix += c.dim(c.gray(` [${testResult.note}]`));
- return suffix;
- }
- getStateSymbol(test) {
- return getStateSymbol(test.task);
- }
- getDurationPrefix(task) {
- const duration = task.result?.duration && Math.round(task.result?.duration);
- if (duration == null) return "";
- return (duration > this.ctx.config.slowTestThreshold ? c.yellow : c.green)(` ${duration}${c.dim("ms")}`);
- }
- onWatcherStart(files = this.ctx.state.getFiles(), errors = this.ctx.state.getUnhandledErrors()) {
- if (errors.length > 0 || hasFailed(files)) this.log(withLabel("red", "FAIL", "Tests failed. Watching for file changes..."));
- else if (this.ctx.isCancelling) this.log(withLabel("red", "CANCELLED", "Test run cancelled. Watching for file changes..."));
- else this.log(withLabel("green", "PASS", "Waiting for file changes..."));
- const hints = [c.dim("press ") + c.bold("h") + c.dim(" to show help")];
- if (hasFailedSnapshot(files)) hints.unshift(c.dim("press ") + c.bold(c.yellow("u")) + c.dim(" to update snapshot"));
- else hints.push(c.dim("press ") + c.bold("q") + c.dim(" to quit"));
- this.log(BADGE_PADDING + hints.join(c.dim(", ")));
- }
- onWatcherRerun(files, trigger) {
- this.watchFilters = files;
- this.failedUnwatchedFiles = this.ctx.state.getTestModules().filter((testModule) => !files.includes(testModule.task.filepath) && testModule.state() === "failed");
- // Update re-run count for each file
- files.forEach((filepath) => {
- let reruns = this._filesInWatchMode.get(filepath) ?? 0;
- this._filesInWatchMode.set(filepath, ++reruns);
- });
- let banner = trigger ? c.dim(`${this.relative(trigger)} `) : "";
- if (files.length === 1) {
- const rerun = this._filesInWatchMode.get(files[0]) ?? 1;
- banner += c.blue(`x${rerun} `);
- }
- this.ctx.logger.clearFullScreen();
- this.log(withLabel("blue", "RERUN", banner));
- if (this.ctx.configOverride.project) this.log(BADGE_PADDING + c.dim(" Project name: ") + c.blue(toArray(this.ctx.configOverride.project).join(", ")));
- if (this.ctx.filenamePattern) this.log(BADGE_PADDING + c.dim(" Filename pattern: ") + c.blue(this.ctx.filenamePattern.join(", ")));
- if (this.ctx.configOverride.testNamePattern) this.log(BADGE_PADDING + c.dim(" Test name pattern: ") + c.blue(String(this.ctx.configOverride.testNamePattern)));
- this.log("");
- for (const testModule of this.failedUnwatchedFiles) this.printTestModule(testModule);
- }
- onUserConsoleLog(log, taskState) {
- if (!this.shouldLog(log, taskState)) return;
- const output = log.type === "stdout" ? this.ctx.logger.outputStream : this.ctx.logger.errorStream;
- const write = (msg) => output.write(msg);
- let headerText = "unknown test";
- const task = log.taskId ? this.ctx.state.idMap.get(log.taskId) : void 0;
- if (task) headerText = this.getFullName(task, separator);
- else if (log.taskId && log.taskId !== "__vitest__unknown_test__") headerText = log.taskId;
- write(c.gray(log.type + c.dim(` | ${headerText}\n`)) + log.content);
- if (log.origin) {
- // browser logs don't have an extra end of line at the end like Node.js does
- if (log.browser) write("\n");
- const project = task ? this.ctx.getProjectByName(task.file.projectName || "") : this.ctx.getRootProject();
- const stack = log.browser ? project.browser?.parseStacktrace(log.origin) || [] : parseStacktrace(log.origin);
- const highlight = task && stack.find((i) => i.file === task.file.filepath);
- for (const frame of stack) {
- const color = frame === highlight ? c.cyan : c.gray;
- const path = relative(project.config.root, frame.file);
- const positions = [frame.method, `${path}:${c.dim(`${frame.line}:${frame.column}`)}`].filter(Boolean).join(" ");
- write(color(` ${c.dim(F_POINTER)} ${positions}\n`));
- }
- }
- write("\n");
- }
- onTestRemoved(trigger) {
- this.log(c.yellow("Test removed...") + (trigger ? c.dim(` [ ${this.relative(trigger)} ]\n`) : ""));
- }
- shouldLog(log, taskState) {
- if (this.ctx.config.silent === true) return false;
- if (this.ctx.config.silent === "passed-only" && taskState !== "failed") return false;
- if (this.ctx.config.onConsoleLog) {
- const task = log.taskId ? this.ctx.state.idMap.get(log.taskId) : void 0;
- const entity = task && this.ctx.state.getReportedEntity(task);
- if (this.ctx.config.onConsoleLog(log.content, log.type, entity) === false) return false;
- }
- return true;
- }
- onServerRestart(reason) {
- this.log(c.bold(c.magenta(reason === "config" ? "\nRestarting due to config changes..." : "\nRestarting Vitest...")));
- }
- reportSummary(files, errors) {
- this.printErrorsSummary(files, errors);
- if (this.ctx.config.mode === "benchmark") this.reportBenchmarkSummary(files);
- else this.reportTestSummary(files, errors);
- }
- reportTestSummary(files, errors) {
- this.log();
- const affectedFiles = [...this.failedUnwatchedFiles.map((m) => m.task), ...files];
- const tests = getTests(affectedFiles);
- const snapshotOutput = renderSnapshotSummary(this.ctx.config.root, this.ctx.snapshot.summary);
- for (const [index, snapshot] of snapshotOutput.entries()) {
- const title = index === 0 ? "Snapshots" : "";
- this.log(`${padSummaryTitle(title)} ${snapshot}`);
- }
- if (snapshotOutput.length > 1) this.log();
- this.log(padSummaryTitle("Test Files"), getStateString$1(affectedFiles));
- this.log(padSummaryTitle("Tests"), getStateString$1(tests));
- if (this.ctx.projects.some((c) => c.config.typecheck.enabled)) {
- const failed = tests.filter((t) => t.meta?.typecheck && t.result?.errors?.length);
- this.log(padSummaryTitle("Type Errors"), failed.length ? c.bold(c.red(`${failed.length} failed`)) : c.dim("no errors"));
- }
- if (errors.length) this.log(padSummaryTitle("Errors"), c.bold(c.red(`${errors.length} error${errors.length > 1 ? "s" : ""}`)));
- this.log(padSummaryTitle("Start at"), this._timeStart);
- const collectTime = sum(files, (file) => file.collectDuration);
- const testsTime = sum(files, (file) => file.result?.duration);
- const setupTime = sum(files, (file) => file.setupDuration);
- if (this.watchFilters) this.log(padSummaryTitle("Duration"), formatTime(collectTime + testsTime + setupTime));
- else {
- const blobs = this.ctx.state.blobs;
- // Execution time is either sum of all runs of `--merge-reports` or the current run's time
- const executionTime = blobs?.executionTimes ? sum(blobs.executionTimes, (time) => time) : this.end - this.start;
- const environmentTime = sum(files, (file) => file.environmentLoad);
- const transformTime = this.ctx.state.transformTime;
- const typecheck = sum(this.ctx.projects, (project) => project.typechecker?.getResult().time);
- const timers = [
- `transform ${formatTime(transformTime)}`,
- `setup ${formatTime(setupTime)}`,
- `import ${formatTime(collectTime)}`,
- `tests ${formatTime(testsTime)}`,
- `environment ${formatTime(environmentTime)}`,
- typecheck && `typecheck ${formatTime(typecheck)}`
- ].filter(Boolean).join(", ");
- this.log(padSummaryTitle("Duration"), formatTime(executionTime) + c.dim(` (${timers})`));
- if (blobs?.executionTimes) this.log(padSummaryTitle("Per blob") + blobs.executionTimes.map((time) => ` ${formatTime(time)}`).join(""));
- }
- if (this.ctx.config.experimental.printImportBreakdown) this.printImportsBreakdown();
- this.log();
- }
- printImportsBreakdown() {
- const testModules = this.ctx.state.getTestModules();
- const allImports = [];
- for (const testModule of testModules) {
- const importDurations = testModule.diagnostic().importDurations;
- for (const filePath in importDurations) {
- const duration = importDurations[filePath];
- allImports.push({
- importedModuleId: filePath,
- testModule,
- selfTime: duration.selfTime,
- totalTime: duration.totalTime,
- external: duration.external
- });
- }
- }
- if (allImports.length === 0) return;
- const sortedImports = allImports.sort((a, b) => b.totalTime - a.totalTime);
- const maxTotalTime = sortedImports[0].totalTime;
- const topImports = sortedImports.slice(0, 10);
- const totalSelfTime = allImports.reduce((sum, imp) => sum + imp.selfTime, 0);
- const totalTotalTime = allImports.reduce((sum, imp) => sum + imp.totalTime, 0);
- const slowestImport = sortedImports[0];
- this.log();
- this.log(c.bold("Import Duration Breakdown") + c.dim(" (ordered by Total Time) (Top 10)"));
- // if there are multiple files, it's highly possible that some of them will import the same large file
- // we group them to show the distinction between those files more easily
- // Import Duration Breakdown (ordered by Total Time) (Top 10)
- // .../fields/FieldFile/__tests__/FieldFile.spec.ts self: 7ms total: 1.01s ████████████████████
- // ↳ tests/support/components/index.ts self: 0ms total: 861ms █████████████████░░░
- // ↳ tests/support/components/renderComponent.ts self: 59ms total: 861ms █████████████████░░░
- // ...s__/apps/desktop/form-updater.desktop.spec.ts self: 8ms total: 991ms ████████████████████
- // ...sts__/apps/mobile/form-updater.mobile.spec.ts self: 11ms total: 990ms ████████████████████
- // shared/components/Form/__tests__/Form.spec.ts self: 5ms total: 988ms ████████████████████
- // ↳ tests/support/components/index.ts self: 0ms total: 935ms ███████████████████░
- // ↳ tests/support/components/renderComponent.ts self: 61ms total: 935ms ███████████████████░
- // ...ditor/features/link/__test__/LinkForm.spec.ts self: 7ms total: 972ms ███████████████████░
- // ↳ tests/support/components/renderComponent.ts self: 56ms total: 936ms ███████████████████░
- const groupedImports = Object.entries(
- groupBy(topImports, (i) => i.testModule.id)
- // the first one is always the highest because the modules are already sorted
- ).sort(([, imps1], [, imps2]) => imps2[0].totalTime - imps1[0].totalTime);
- for (const [_, group] of groupedImports) group.forEach((imp, index) => {
- const barWidth = 20;
- const filledWidth = Math.round(imp.totalTime / maxTotalTime * barWidth);
- const bar = c.cyan("█".repeat(filledWidth)) + c.dim("░".repeat(barWidth - filledWidth));
- // only show the arrow if there is more than 1 group
- const pathDisplay = this.ellipsisPath(imp.importedModuleId, imp.external, groupedImports.length > 1 && index > 0);
- this.log(`${pathDisplay} ${c.dim("self:")} ${this.importDurationTime(imp.selfTime)} ${c.dim("total:")} ${this.importDurationTime(imp.totalTime)} ${bar}`);
- });
- this.log();
- this.log(c.dim("Total imports: ") + allImports.length);
- this.log(c.dim("Slowest import (total-time): ") + formatTime(slowestImport.totalTime));
- this.log(c.dim("Total import time (self/total): ") + formatTime(totalSelfTime) + c.dim(" / ") + formatTime(totalTotalTime));
- }
- importDurationTime(duration) {
- return (duration >= 500 ? c.red : duration >= 100 ? c.yellow : (c) => c)(formatTime(duration).padStart(6));
- }
- ellipsisPath(path, external, nested) {
- const pathDisplay = this.relative(path);
- const color = external ? c.magenta : (c) => c;
- const slicedPath = pathDisplay.slice(-44);
- let title = "";
- if (pathDisplay.length > slicedPath.length) title += "...";
- if (nested) title = ` ${F_DOWN_RIGHT} ${title}`;
- title += slicedPath;
- return color(title.padEnd(50));
- }
- printErrorsSummary(files, errors) {
- const suites = getSuites(files);
- const tests = getTests(files);
- const failedSuites = suites.filter((i) => i.result?.errors);
- const failedTests = tests.filter((i) => i.result?.state === "fail");
- const failedTotal = countTestErrors(failedSuites) + countTestErrors(failedTests);
- // TODO: error divider should take into account merged errors for counting
- let current = 1;
- const errorDivider = () => this.error(`${c.red(c.dim(divider(`[${current++}/${failedTotal}]`, void 0, 1)))}\n`);
- if (failedSuites.length) {
- this.error(`\n${errorBanner(`Failed Suites ${failedSuites.length}`)}\n`);
- this.printTaskErrors(failedSuites, errorDivider);
- }
- if (failedTests.length) {
- this.error(`\n${errorBanner(`Failed Tests ${failedTests.length}`)}\n`);
- this.printTaskErrors(failedTests, errorDivider);
- }
- if (errors.length) {
- this.ctx.logger.printUnhandledErrors(errors);
- this.error();
- }
- }
- reportBenchmarkSummary(files) {
- const topBenches = getTests(files).filter((i) => i.result?.benchmark?.rank === 1);
- this.log(`\n${withLabel("cyan", "BENCH", "Summary\n")}`);
- for (const bench of topBenches) {
- const group = bench.suite || bench.file;
- if (!group) continue;
- const groupName = this.getFullName(group, separator);
- const project = this.ctx.projects.find((p) => p.name === bench.file.projectName);
- this.log(` ${formatProjectName(project)}${bench.name}${c.dim(` - ${groupName}`)}`);
- const siblings = group.tasks.filter((i) => i.meta.benchmark && i.result?.benchmark && i !== bench).sort((a, b) => a.result.benchmark.rank - b.result.benchmark.rank);
- for (const sibling of siblings) {
- const number = (sibling.result.benchmark.mean / bench.result.benchmark.mean).toFixed(2);
- this.log(c.green(` ${number}x `) + c.gray("faster than ") + sibling.name);
- }
- this.log("");
- }
- }
- printTaskErrors(tasks, errorDivider) {
- const errorsQueue = [];
- for (const task of tasks)
- // Merge identical errors
- task.result?.errors?.forEach((error) => {
- let previous;
- if (error?.stack) previous = errorsQueue.find((i) => {
- if (i[0]?.stack !== error.stack || i[0]?.diff !== error.diff) return false;
- const currentProjectName = task?.projectName || task.file?.projectName || "";
- const projectName = i[1][0]?.projectName || i[1][0].file?.projectName || "";
- const currentAnnotations = task.type === "test" && task.annotations;
- const itemAnnotations = i[1][0].type === "test" && i[1][0].annotations;
- return projectName === currentProjectName && deepEqual(currentAnnotations, itemAnnotations);
- });
- if (previous) previous[1].push(task);
- else errorsQueue.push([error, [task]]);
- });
- for (const [error, tasks] of errorsQueue) {
- for (const task of tasks) {
- const filepath = task?.filepath || "";
- const projectName = task?.projectName || task.file?.projectName || "";
- const project = this.ctx.projects.find((p) => p.name === projectName);
- let name = this.getFullName(task, separator);
- if (filepath) name += c.dim(` [ ${this.relative(filepath)} ]`);
- this.ctx.logger.error(`${c.bgRed(c.bold(" FAIL "))} ${formatProjectName(project)}${name}`);
- }
- const screenshotPaths = tasks.map((t) => t.meta?.failScreenshotPath).filter((screenshot) => screenshot != null);
- this.ctx.logger.printError(error, {
- project: this.ctx.getProjectByName(tasks[0].file.projectName || ""),
- verbose: this.verbose,
- screenshotPaths,
- task: tasks[0]
- });
- if (tasks[0].type === "test" && tasks[0].annotations.length) {
- const test = this.ctx.state.getReportedEntity(tasks[0]);
- this.printAnnotations(test, "error", 1);
- this.error();
- }
- errorDivider();
- }
- }
-}
-function deepEqual(a, b) {
- if (a === b) return true;
- if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
- const keysA = Object.keys(a);
- const keysB = Object.keys(b);
- if (keysA.length !== keysB.length) return false;
- for (const key of keysA) if (!keysB.includes(key) || !deepEqual(a[key], b[key])) return false;
- return true;
-}
-function sum(items, cb) {
- return items.reduce((total, next) => {
- return total + Math.max(cb(next) || 0, 0);
- }, 0);
-}
-function getIndentation(suite, level = 1) {
- if (suite.suite && !("filepath" in suite.suite)) return getIndentation(suite.suite, level + 1);
- return level;
-}
-
-const DEFAULT_RENDER_INTERVAL_MS = 1e3;
-const ESC = "\x1B[";
-const CLEAR_LINE = `${ESC}K`;
-const MOVE_CURSOR_ONE_ROW_UP = `${ESC}1A`;
-const SYNC_START = `${ESC}?2026h`;
-const SYNC_END = `${ESC}?2026l`;
-/**
-* Renders content of `getWindow` at the bottom of the terminal and
-* forwards all other intercepted `stdout` and `stderr` logs above it.
-*/
-class WindowRenderer {
- options;
- streams;
- buffer = [];
- renderInterval = void 0;
- renderScheduled = false;
- windowHeight = 0;
- started = false;
- finished = false;
- cleanups = [];
- constructor(options) {
- this.options = {
- interval: DEFAULT_RENDER_INTERVAL_MS,
- ...options
- };
- this.streams = {
- output: options.logger.outputStream.write.bind(options.logger.outputStream),
- error: options.logger.errorStream.write.bind(options.logger.errorStream)
- };
- this.cleanups.push(this.interceptStream(process.stdout, "output"), this.interceptStream(process.stderr, "error"));
- // Write buffered content on unexpected exits, e.g. direct `process.exit()` calls
- this.options.logger.onTerminalCleanup(() => {
- this.flushBuffer();
- this.stop();
- });
- }
- start() {
- this.started = true;
- this.finished = false;
- this.renderInterval = setInterval(() => this.schedule(), this.options.interval).unref();
- }
- stop() {
- this.cleanups.splice(0).map((fn) => fn());
- clearInterval(this.renderInterval);
- }
- /**
- * Write all buffered output and stop buffering.
- * All intercepted writes are forwarded to actual write after this.
- */
- finish() {
- this.finished = true;
- this.flushBuffer();
- clearInterval(this.renderInterval);
- }
- /**
- * Queue new render update
- */
- schedule() {
- if (!this.renderScheduled) {
- this.renderScheduled = true;
- this.flushBuffer();
- setTimeout(() => {
- this.renderScheduled = false;
- }, 100).unref();
- }
- }
- flushBuffer() {
- if (this.buffer.length === 0) return this.render();
- let current;
- // Concatenate same types into a single render
- for (const next of this.buffer.splice(0)) {
- if (!current) {
- current = next;
- continue;
- }
- if (current.type !== next.type) {
- this.render(current.message, current.type);
- current = next;
- continue;
- }
- current.message += next.message;
- }
- if (current) this.render(current?.message, current?.type);
- }
- render(message, type = "output") {
- if (this.finished) {
- this.clearWindow();
- return this.write(message || "", type);
- }
- const windowContent = this.options.getWindow();
- const rowCount = getRenderedRowCount(windowContent, this.options.logger.getColumns());
- let padding = this.windowHeight - rowCount;
- if (padding > 0 && message) padding -= getRenderedRowCount([message], this.options.logger.getColumns());
- this.write(SYNC_START);
- this.clearWindow();
- if (message) this.write(message, type);
- if (padding > 0) this.write("\n".repeat(padding));
- this.write(windowContent.join("\n"));
- this.write(SYNC_END);
- this.windowHeight = rowCount + Math.max(0, padding);
- }
- clearWindow() {
- if (this.windowHeight === 0) return;
- this.write(CLEAR_LINE);
- for (let i = 1; i < this.windowHeight; i++) this.write(`${MOVE_CURSOR_ONE_ROW_UP}${CLEAR_LINE}`);
- this.windowHeight = 0;
- }
- interceptStream(stream, type) {
- const original = stream.write;
- // @ts-expect-error -- not sure how 2 overloads should be typed
- stream.write = (chunk, _, callback) => {
- if (chunk) if (this.finished || !this.started) this.write(chunk.toString(), type);
- else this.buffer.push({
- type,
- message: chunk.toString()
- });
- callback?.();
- };
- return function restore() {
- stream.write = original;
- };
- }
- write(message, type = "output") {
- this.streams[type](message);
- }
-}
-/** Calculate the actual row count needed to render `rows` into `stream` */
-function getRenderedRowCount(rows, columns) {
- let count = 0;
- for (const row of rows) {
- const text = stripVTControlCharacters(row);
- count += Math.max(1, Math.ceil(text.length / columns));
- }
- return count;
-}
-
-const DURATION_UPDATE_INTERVAL_MS = 100;
-const FINISHED_TEST_CLEANUP_TIME_MS = 1e3;
-/**
-* Reporter extension that renders summary and forwards all other logs above itself.
-* Intended to be used by other reporters, not as a standalone reporter.
-*/
-class SummaryReporter {
- ctx;
- options;
- renderer;
- modules = emptyCounters();
- tests = emptyCounters();
- maxParallelTests = 0;
- /** Currently running test modules, may include finished test modules too */
- runningModules = /* @__PURE__ */ new Map();
- /** ID of finished `this.runningModules` that are currently being shown */
- finishedModules = /* @__PURE__ */ new Map();
- startTime = "";
- currentTime = 0;
- duration = 0;
- durationInterval = void 0;
- onInit(ctx, options = {}) {
- this.ctx = ctx;
- this.options = {
- verbose: false,
- ...options
- };
- this.renderer = new WindowRenderer({
- logger: ctx.logger,
- getWindow: () => this.createSummary()
- });
- this.ctx.onClose(() => {
- clearInterval(this.durationInterval);
- this.renderer.stop();
- });
- }
- onTestRunStart(specifications) {
- this.runningModules.clear();
- this.finishedModules.clear();
- this.modules = emptyCounters();
- this.tests = emptyCounters();
- this.startTimers();
- this.renderer.start();
- this.modules.total = specifications.length;
- }
- onTestRunEnd() {
- this.runningModules.clear();
- this.finishedModules.clear();
- this.renderer.finish();
- clearInterval(this.durationInterval);
- }
- onTestModuleQueued(module) {
- // When new test module starts, take the place of previously finished test module, if any
- if (this.finishedModules.size) {
- const finished = this.finishedModules.keys().next().value;
- this.removeTestModule(finished);
- }
- this.runningModules.set(module.id, initializeStats(module));
- this.renderer.schedule();
- }
- onTestModuleCollected(module) {
- let stats = this.runningModules.get(module.id);
- if (!stats) {
- stats = initializeStats(module);
- this.runningModules.set(module.id, stats);
- }
- const total = Array.from(module.children.allTests()).length;
- this.tests.total += total;
- stats.total = total;
- this.maxParallelTests = Math.max(this.maxParallelTests, this.runningModules.size);
- this.renderer.schedule();
- }
- onHookStart(options) {
- const stats = this.getHookStats(options);
- if (!stats) return;
- const hook = {
- name: options.name,
- visible: false,
- startTime: performance.now(),
- onFinish: () => {}
- };
- stats.hook?.onFinish?.();
- stats.hook = hook;
- const timeout = setTimeout(() => {
- hook.visible = true;
- }, this.ctx.config.slowTestThreshold).unref();
- hook.onFinish = () => clearTimeout(timeout);
- }
- onHookEnd(options) {
- const stats = this.getHookStats(options);
- if (stats?.hook?.name !== options.name) return;
- stats.hook.onFinish();
- stats.hook.visible = false;
- }
- onTestCaseReady(test) {
- // Track slow running tests only on verbose mode
- if (!this.options.verbose) return;
- const stats = this.runningModules.get(test.module.id);
- if (!stats || stats.tests.has(test.id)) return;
- const slowTest = {
- name: test.name,
- visible: false,
- startTime: performance.now(),
- onFinish: () => {}
- };
- const timeout = setTimeout(() => {
- slowTest.visible = true;
- }, this.ctx.config.slowTestThreshold).unref();
- slowTest.onFinish = () => {
- slowTest.hook?.onFinish();
- clearTimeout(timeout);
- };
- stats.tests.set(test.id, slowTest);
- }
- onTestCaseResult(test) {
- const stats = this.runningModules.get(test.module.id);
- if (!stats) return;
- stats.tests.get(test.id)?.onFinish();
- stats.tests.delete(test.id);
- stats.completed++;
- const result = test.result();
- if (result?.state === "passed") this.tests.passed++;
- else if (result?.state === "failed") this.tests.failed++;
- else if (!result?.state || result?.state === "skipped") this.tests.skipped++;
- this.renderer.schedule();
- }
- onTestModuleEnd(module) {
- const state = module.state();
- this.modules.completed++;
- if (state === "passed") this.modules.passed++;
- else if (state === "failed") this.modules.failed++;
- else if (module.task.mode === "todo" && state === "skipped") this.modules.todo++;
- else if (state === "skipped") this.modules.skipped++;
- // Keep finished tests visible in summary for a while if there are more tests left.
- // When a new test starts in onTestModuleQueued it will take this ones place.
- // This reduces flickering by making summary more stable.
- if (this.modules.total - this.modules.completed > this.maxParallelTests) this.finishedModules.set(module.id, setTimeout(() => {
- this.removeTestModule(module.id);
- }, FINISHED_TEST_CLEANUP_TIME_MS).unref());
- else
- // Run is about to end as there are less tests left than whole run had parallel at max.
- // Remove finished test immediately.
- this.removeTestModule(module.id);
- this.renderer.schedule();
- }
- getHookStats({ entity }) {
- // Track slow running hooks only on verbose mode
- if (!this.options.verbose) return;
- const module = entity.type === "module" ? entity : entity.module;
- const stats = this.runningModules.get(module.id);
- if (!stats) return;
- return entity.type === "test" ? stats.tests.get(entity.id) : stats;
- }
- createSummary() {
- const summary = [""];
- for (const testFile of Array.from(this.runningModules.values()).sort(sortRunningModules)) {
- const typecheck = testFile.typecheck ? `${c.bgBlue(c.bold(" TS "))} ` : "";
- summary.push(c.bold(c.yellow(` ${F_POINTER} `)) + formatProjectName({
- name: testFile.projectName,
- color: testFile.projectColor
- }) + typecheck + testFile.filename + c.dim(!testFile.completed && !testFile.total ? " [queued]" : ` ${testFile.completed}/${testFile.total}`));
- const slowTasks = [testFile.hook, ...testFile.tests.values()].filter((t) => t != null && t.visible);
- for (const [index, task] of slowTasks.entries()) {
- const elapsed = this.currentTime - task.startTime;
- const icon = index === slowTasks.length - 1 ? F_TREE_NODE_END : F_TREE_NODE_MIDDLE;
- summary.push(c.bold(c.yellow(` ${icon} `)) + task.name + c.bold(c.yellow(` ${formatTime(Math.max(0, elapsed))}`)));
- if (task.hook?.visible) summary.push(c.bold(c.yellow(` ${F_TREE_NODE_END} `)) + task.hook.name);
- }
- }
- if (this.runningModules.size > 0) summary.push("");
- summary.push(padSummaryTitle("Test Files") + getStateString(this.modules));
- summary.push(padSummaryTitle("Tests") + getStateString(this.tests));
- summary.push(padSummaryTitle("Start at") + this.startTime);
- summary.push(padSummaryTitle("Duration") + formatTime(this.duration));
- summary.push("");
- return summary;
- }
- startTimers() {
- const start = performance.now();
- this.startTime = formatTimeString(/* @__PURE__ */ new Date());
- this.durationInterval = setInterval(() => {
- this.currentTime = performance.now();
- this.duration = this.currentTime - start;
- }, DURATION_UPDATE_INTERVAL_MS).unref();
- }
- removeTestModule(id) {
- if (!id) return;
- const testFile = this.runningModules.get(id);
- testFile?.hook?.onFinish();
- testFile?.tests?.forEach((test) => test.onFinish());
- this.runningModules.delete(id);
- clearTimeout(this.finishedModules.get(id));
- this.finishedModules.delete(id);
- }
-}
-function emptyCounters() {
- return {
- completed: 0,
- passed: 0,
- failed: 0,
- skipped: 0,
- todo: 0,
- total: 0
- };
-}
-function getStateString(entry) {
- return [
- entry.failed ? c.bold(c.red(`${entry.failed} failed`)) : null,
- c.bold(c.green(`${entry.passed} passed`)),
- entry.skipped ? c.yellow(`${entry.skipped} skipped`) : null,
- entry.todo ? c.gray(`${entry.todo} todo`) : null
- ].filter(Boolean).join(c.dim(" | ")) + c.gray(` (${entry.total})`);
-}
-function sortRunningModules(a, b) {
- if ((a.projectName || "") > (b.projectName || "")) return 1;
- if ((a.projectName || "") < (b.projectName || "")) return -1;
- return a.filename.localeCompare(b.filename);
-}
-function initializeStats(module) {
- return {
- total: 0,
- completed: 0,
- filename: module.task.name,
- projectName: module.project.name,
- projectColor: module.project.color,
- tests: /* @__PURE__ */ new Map(),
- typecheck: !!module.task.meta.typecheck
- };
-}
-
-class DefaultReporter extends BaseReporter {
- options;
- summary;
- constructor(options = {}) {
- super(options);
- this.options = {
- summary: true,
- ...options
- };
- if (!this.isTTY) this.options.summary = false;
- if (this.options.summary) this.summary = new SummaryReporter();
- }
- onTestRunStart(specifications) {
- if (this.isTTY) {
- if (this.renderSucceed === void 0) this.renderSucceed = !!this.renderSucceed;
- if (this.renderSucceed !== true) this.renderSucceed = specifications.length <= 1;
- }
- super.onTestRunStart(specifications);
- this.summary?.onTestRunStart(specifications);
- }
- onTestRunEnd(testModules, unhandledErrors, reason) {
- super.onTestRunEnd(testModules, unhandledErrors, reason);
- this.summary?.onTestRunEnd();
- }
- onTestModuleQueued(file) {
- this.summary?.onTestModuleQueued(file);
- }
- onTestModuleCollected(module) {
- this.summary?.onTestModuleCollected(module);
- }
- onTestModuleEnd(module) {
- super.onTestModuleEnd(module);
- this.summary?.onTestModuleEnd(module);
- }
- onTestCaseReady(test) {
- this.summary?.onTestCaseReady(test);
- }
- onTestCaseResult(test) {
- super.onTestCaseResult(test);
- this.summary?.onTestCaseResult(test);
- }
- onHookStart(hook) {
- this.summary?.onHookStart(hook);
- }
- onHookEnd(hook) {
- this.summary?.onHookEnd(hook);
- }
- onInit(ctx) {
- super.onInit(ctx);
- this.summary?.onInit(ctx, { verbose: this.verbose });
- }
-}
-
-class DotReporter extends BaseReporter {
- renderer;
- tests = /* @__PURE__ */ new Map();
- finishedTests = /* @__PURE__ */ new Set();
- onInit(ctx) {
- super.onInit(ctx);
- if (this.isTTY) {
- this.renderer = new WindowRenderer({
- logger: ctx.logger,
- getWindow: () => this.createSummary()
- });
- this.ctx.onClose(() => this.renderer?.stop());
- }
- }
- // Ignore default logging of base reporter
- printTestModule() {}
- onWatcherRerun(files, trigger) {
- this.tests.clear();
- this.renderer?.start();
- super.onWatcherRerun(files, trigger);
- }
- onTestRunEnd(testModules, unhandledErrors, reason) {
- if (this.isTTY) {
- const finalLog = formatTests(Array.from(this.tests.values()));
- this.ctx.logger.log(finalLog);
- } else this.ctx.logger.log();
- this.tests.clear();
- this.renderer?.finish();
- super.onTestRunEnd(testModules, unhandledErrors, reason);
- }
- onTestModuleCollected(module) {
- for (const test of module.children.allTests())
- // Dot reporter marks pending tests as running
- this.onTestCaseReady(test);
- }
- onTestCaseReady(test) {
- if (this.finishedTests.has(test.id)) return;
- this.tests.set(test.id, test.result().state || "run");
- this.renderer?.schedule();
- }
- onTestCaseResult(test) {
- const result = test.result().state;
- // On non-TTY the finished tests are printed immediately
- if (!this.isTTY && result !== "pending") this.ctx.logger.outputStream.write(formatTests([result]));
- super.onTestCaseResult(test);
- this.finishedTests.add(test.id);
- this.tests.set(test.id, result || "skipped");
- this.renderer?.schedule();
- }
- onTestModuleEnd(testModule) {
- super.onTestModuleEnd(testModule);
- if (!this.isTTY) return;
- const columns = this.ctx.logger.getColumns();
- if (this.tests.size < columns) return;
- const finishedTests = Array.from(this.tests).filter((entry) => entry[1] !== "pending");
- if (finishedTests.length < columns) return;
- // Remove finished tests from state and render them in static output
- const states = [];
- let count = 0;
- for (const [id, state] of finishedTests) {
- if (count++ >= columns) break;
- this.tests.delete(id);
- states.push(state);
- }
- this.ctx.logger.log(formatTests(states));
- this.renderer?.schedule();
- }
- createSummary() {
- return [formatTests(Array.from(this.tests.values())), ""];
- }
-}
-// These are compared with reference equality in formatTests
-const pass = {
- char: "·",
- color: c.green
-};
-const fail = {
- char: "x",
- color: c.red
-};
-const pending = {
- char: "*",
- color: c.yellow
-};
-const skip = {
- char: "-",
- color: (char) => c.dim(c.gray(char))
-};
-function getIcon(state) {
- switch (state) {
- case "passed": return pass;
- case "failed": return fail;
- case "skipped": return skip;
- default: return pending;
- }
-}
-/**
-* Format test states into string while keeping ANSI escapes at minimal.
-* Sibling icons with same color are merged into a single c.color() call.
-*/
-function formatTests(states) {
- let currentIcon = pending;
- let count = 0;
- let output = "";
- for (const state of states) {
- const icon = getIcon(state);
- if (currentIcon === icon) {
- count++;
- continue;
- }
- output += currentIcon.color(currentIcon.char.repeat(count));
- // Start tracking new group
- count = 1;
- currentIcon = icon;
- }
- output += currentIcon.color(currentIcon.char.repeat(count));
- return output;
-}
-
-// src/vlq.ts
-var comma = ",".charCodeAt(0);
-var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-var intToChar = new Uint8Array(64);
-var charToInt = new Uint8Array(128);
-for (let i = 0; i < chars.length; i++) {
- const c = chars.charCodeAt(i);
- intToChar[i] = c;
- charToInt[c] = i;
-}
-function decodeInteger(reader, relative) {
- let value = 0;
- let shift = 0;
- let integer = 0;
- do {
- const c = reader.next();
- integer = charToInt[c];
- value |= (integer & 31) << shift;
- shift += 5;
- } while (integer & 32);
- const shouldNegate = value & 1;
- value >>>= 1;
- if (shouldNegate) {
- value = -2147483648 | -value;
- }
- return relative + value;
-}
-function hasMoreVlq(reader, max) {
- if (reader.pos >= max) return false;
- return reader.peek() !== comma;
-}
-var StringReader = class {
- constructor(buffer) {
- this.pos = 0;
- this.buffer = buffer;
- }
- next() {
- return this.buffer.charCodeAt(this.pos++);
- }
- peek() {
- return this.buffer.charCodeAt(this.pos);
- }
- indexOf(char) {
- const { buffer, pos } = this;
- const idx = buffer.indexOf(char, pos);
- return idx === -1 ? buffer.length : idx;
- }
-};
-
-// src/sourcemap-codec.ts
-function decode(mappings) {
- const { length } = mappings;
- const reader = new StringReader(mappings);
- const decoded = [];
- let genColumn = 0;
- let sourcesIndex = 0;
- let sourceLine = 0;
- let sourceColumn = 0;
- let namesIndex = 0;
- do {
- const semi = reader.indexOf(";");
- const line = [];
- let sorted = true;
- let lastCol = 0;
- genColumn = 0;
- while (reader.pos < semi) {
- let seg;
- genColumn = decodeInteger(reader, genColumn);
- if (genColumn < lastCol) sorted = false;
- lastCol = genColumn;
- if (hasMoreVlq(reader, semi)) {
- sourcesIndex = decodeInteger(reader, sourcesIndex);
- sourceLine = decodeInteger(reader, sourceLine);
- sourceColumn = decodeInteger(reader, sourceColumn);
- if (hasMoreVlq(reader, semi)) {
- namesIndex = decodeInteger(reader, namesIndex);
- seg = [genColumn, sourcesIndex, sourceLine, sourceColumn, namesIndex];
- } else {
- seg = [genColumn, sourcesIndex, sourceLine, sourceColumn];
- }
- } else {
- seg = [genColumn];
- }
- line.push(seg);
- reader.pos++;
- }
- if (!sorted) sort(line);
- decoded.push(line);
- reader.pos = semi + 1;
- } while (reader.pos <= length);
- return decoded;
-}
-function sort(line) {
- line.sort(sortComparator$1);
-}
-function sortComparator$1(a, b) {
- return a[0] - b[0];
-}
-
-// Matches the scheme of a URL, eg "http://"
-const schemeRegex = /^[\w+.-]+:\/\//;
-/**
- * Matches the parts of a URL:
- * 1. Scheme, including ":", guaranteed.
- * 2. User/password, including "@", optional.
- * 3. Host, guaranteed.
- * 4. Port, including ":", optional.
- * 5. Path, including "/", optional.
- * 6. Query, including "?", optional.
- * 7. Hash, including "#", optional.
- */
-const urlRegex = /^([\w+.-]+:)\/\/([^@/#?]*@)?([^:/#?]*)(:\d+)?(\/[^#?]*)?(\?[^#]*)?(#.*)?/;
-/**
- * File URLs are weird. They dont' need the regular `//` in the scheme, they may or may not start
- * with a leading `/`, they can have a domain (but only if they don't start with a Windows drive).
- *
- * 1. Host, optional.
- * 2. Path, which may include "/", guaranteed.
- * 3. Query, including "?", optional.
- * 4. Hash, including "#", optional.
- */
-const fileRegex = /^file:(?:\/\/((?![a-z]:)[^/#?]*)?)?(\/?[^#?]*)(\?[^#]*)?(#.*)?/i;
-function isAbsoluteUrl(input) {
- return schemeRegex.test(input);
-}
-function isSchemeRelativeUrl(input) {
- return input.startsWith('//');
-}
-function isAbsolutePath(input) {
- return input.startsWith('/');
-}
-function isFileUrl(input) {
- return input.startsWith('file:');
-}
-function isRelative(input) {
- return /^[.?#]/.test(input);
-}
-function parseAbsoluteUrl(input) {
- const match = urlRegex.exec(input);
- return makeUrl(match[1], match[2] || '', match[3], match[4] || '', match[5] || '/', match[6] || '', match[7] || '');
-}
-function parseFileUrl(input) {
- const match = fileRegex.exec(input);
- const path = match[2];
- return makeUrl('file:', '', match[1] || '', '', isAbsolutePath(path) ? path : '/' + path, match[3] || '', match[4] || '');
-}
-function makeUrl(scheme, user, host, port, path, query, hash) {
- return {
- scheme,
- user,
- host,
- port,
- path,
- query,
- hash,
- type: 7 /* Absolute */,
- };
-}
-function parseUrl(input) {
- if (isSchemeRelativeUrl(input)) {
- const url = parseAbsoluteUrl('http:' + input);
- url.scheme = '';
- url.type = 6 /* SchemeRelative */;
- return url;
- }
- if (isAbsolutePath(input)) {
- const url = parseAbsoluteUrl('http://foo.com' + input);
- url.scheme = '';
- url.host = '';
- url.type = 5 /* AbsolutePath */;
- return url;
- }
- if (isFileUrl(input))
- return parseFileUrl(input);
- if (isAbsoluteUrl(input))
- return parseAbsoluteUrl(input);
- const url = parseAbsoluteUrl('http://foo.com/' + input);
- url.scheme = '';
- url.host = '';
- url.type = input
- ? input.startsWith('?')
- ? 3 /* Query */
- : input.startsWith('#')
- ? 2 /* Hash */
- : 4 /* RelativePath */
- : 1 /* Empty */;
- return url;
-}
-function stripPathFilename(path) {
- // If a path ends with a parent directory "..", then it's a relative path with excess parent
- // paths. It's not a file, so we can't strip it.
- if (path.endsWith('/..'))
- return path;
- const index = path.lastIndexOf('/');
- return path.slice(0, index + 1);
-}
-function mergePaths(url, base) {
- normalizePath(base, base.type);
- // If the path is just a "/", then it was an empty path to begin with (remember, we're a relative
- // path).
- if (url.path === '/') {
- url.path = base.path;
- }
- else {
- // Resolution happens relative to the base path's directory, not the file.
- url.path = stripPathFilename(base.path) + url.path;
- }
-}
-/**
- * The path can have empty directories "//", unneeded parents "foo/..", or current directory
- * "foo/.". We need to normalize to a standard representation.
- */
-function normalizePath(url, type) {
- const rel = type <= 4 /* RelativePath */;
- const pieces = url.path.split('/');
- // We need to preserve the first piece always, so that we output a leading slash. The item at
- // pieces[0] is an empty string.
- let pointer = 1;
- // Positive is the number of real directories we've output, used for popping a parent directory.
- // Eg, "foo/bar/.." will have a positive 2, and we can decrement to be left with just "foo".
- let positive = 0;
- // We need to keep a trailing slash if we encounter an empty directory (eg, splitting "foo/" will
- // generate `["foo", ""]` pieces). And, if we pop a parent directory. But once we encounter a
- // real directory, we won't need to append, unless the other conditions happen again.
- let addTrailingSlash = false;
- for (let i = 1; i < pieces.length; i++) {
- const piece = pieces[i];
- // An empty directory, could be a trailing slash, or just a double "//" in the path.
- if (!piece) {
- addTrailingSlash = true;
- continue;
- }
- // If we encounter a real directory, then we don't need to append anymore.
- addTrailingSlash = false;
- // A current directory, which we can always drop.
- if (piece === '.')
- continue;
- // A parent directory, we need to see if there are any real directories we can pop. Else, we
- // have an excess of parents, and we'll need to keep the "..".
- if (piece === '..') {
- if (positive) {
- addTrailingSlash = true;
- positive--;
- pointer--;
- }
- else if (rel) {
- // If we're in a relativePath, then we need to keep the excess parents. Else, in an absolute
- // URL, protocol relative URL, or an absolute path, we don't need to keep excess.
- pieces[pointer++] = piece;
- }
- continue;
- }
- // We've encountered a real directory. Move it to the next insertion pointer, which accounts for
- // any popped or dropped directories.
- pieces[pointer++] = piece;
- positive++;
- }
- let path = '';
- for (let i = 1; i < pointer; i++) {
- path += '/' + pieces[i];
- }
- if (!path || (addTrailingSlash && !path.endsWith('/..'))) {
- path += '/';
- }
- url.path = path;
-}
-/**
- * Attempts to resolve `input` URL/path relative to `base`.
- */
-function resolve(input, base) {
- if (!input && !base)
- return '';
- const url = parseUrl(input);
- let inputType = url.type;
- if (base && inputType !== 7 /* Absolute */) {
- const baseUrl = parseUrl(base);
- const baseType = baseUrl.type;
- switch (inputType) {
- case 1 /* Empty */:
- url.hash = baseUrl.hash;
- // fall through
- case 2 /* Hash */:
- url.query = baseUrl.query;
- // fall through
- case 3 /* Query */:
- case 4 /* RelativePath */:
- mergePaths(url, baseUrl);
- // fall through
- case 5 /* AbsolutePath */:
- // The host, user, and port are joined, you can't copy one without the others.
- url.user = baseUrl.user;
- url.host = baseUrl.host;
- url.port = baseUrl.port;
- // fall through
- case 6 /* SchemeRelative */:
- // The input doesn't have a schema at least, so we need to copy at least that over.
- url.scheme = baseUrl.scheme;
- }
- if (baseType > inputType)
- inputType = baseType;
- }
- normalizePath(url, inputType);
- const queryHash = url.query + url.hash;
- switch (inputType) {
- // This is impossible, because of the empty checks at the start of the function.
- // case UrlType.Empty:
- case 2 /* Hash */:
- case 3 /* Query */:
- return queryHash;
- case 4 /* RelativePath */: {
- // The first char is always a "/", and we need it to be relative.
- const path = url.path.slice(1);
- if (!path)
- return queryHash || '.';
- if (isRelative(base || input) && !isRelative(path)) {
- // If base started with a leading ".", or there is no base and input started with a ".",
- // then we need to ensure that the relative path starts with a ".". We don't know if
- // relative starts with a "..", though, so check before prepending.
- return './' + path + queryHash;
- }
- return path + queryHash;
- }
- case 5 /* AbsolutePath */:
- return url.path + queryHash;
- default:
- return url.scheme + '//' + url.user + url.host + url.port + url.path + queryHash;
- }
-}
-
-// src/trace-mapping.ts
-
-// src/strip-filename.ts
-function stripFilename(path) {
- if (!path) return "";
- const index = path.lastIndexOf("/");
- return path.slice(0, index + 1);
-}
-
-// src/resolve.ts
-function resolver(mapUrl, sourceRoot) {
- const from = stripFilename(mapUrl);
- const prefix = sourceRoot ? sourceRoot + "/" : "";
- return (source) => resolve(prefix + (source || ""), from);
-}
-
-// src/sourcemap-segment.ts
-var COLUMN = 0;
-var SOURCES_INDEX = 1;
-var SOURCE_LINE = 2;
-var SOURCE_COLUMN = 3;
-var NAMES_INDEX = 4;
-var REV_GENERATED_LINE = 1;
-var REV_GENERATED_COLUMN = 2;
-
-// src/sort.ts
-function maybeSort(mappings, owned) {
- const unsortedIndex = nextUnsortedSegmentLine(mappings, 0);
- if (unsortedIndex === mappings.length) return mappings;
- if (!owned) mappings = mappings.slice();
- for (let i = unsortedIndex; i < mappings.length; i = nextUnsortedSegmentLine(mappings, i + 1)) {
- mappings[i] = sortSegments(mappings[i], owned);
- }
- return mappings;
-}
-function nextUnsortedSegmentLine(mappings, start) {
- for (let i = start; i < mappings.length; i++) {
- if (!isSorted(mappings[i])) return i;
- }
- return mappings.length;
-}
-function isSorted(line) {
- for (let j = 1; j < line.length; j++) {
- if (line[j][COLUMN] < line[j - 1][COLUMN]) {
- return false;
- }
- }
- return true;
-}
-function sortSegments(line, owned) {
- if (!owned) line = line.slice();
- return line.sort(sortComparator);
-}
-function sortComparator(a, b) {
- return a[COLUMN] - b[COLUMN];
-}
-
-// src/by-source.ts
-function buildBySources(decoded, memos) {
- const sources = memos.map(() => []);
- for (let i = 0; i < decoded.length; i++) {
- const line = decoded[i];
- for (let j = 0; j < line.length; j++) {
- const seg = line[j];
- if (seg.length === 1) continue;
- const sourceIndex2 = seg[SOURCES_INDEX];
- const sourceLine = seg[SOURCE_LINE];
- const sourceColumn = seg[SOURCE_COLUMN];
- const source = sources[sourceIndex2];
- const segs = source[sourceLine] || (source[sourceLine] = []);
- segs.push([sourceColumn, i, seg[COLUMN]]);
- }
- }
- for (let i = 0; i < sources.length; i++) {
- const source = sources[i];
- for (let j = 0; j < source.length; j++) {
- const line = source[j];
- if (line) line.sort(sortComparator);
- }
- }
- return sources;
-}
-
-// src/binary-search.ts
-var found = false;
-function binarySearch(haystack, needle, low, high) {
- while (low <= high) {
- const mid = low + (high - low >> 1);
- const cmp = haystack[mid][COLUMN] - needle;
- if (cmp === 0) {
- found = true;
- return mid;
- }
- if (cmp < 0) {
- low = mid + 1;
- } else {
- high = mid - 1;
- }
- }
- found = false;
- return low - 1;
-}
-function upperBound(haystack, needle, index) {
- for (let i = index + 1; i < haystack.length; index = i++) {
- if (haystack[i][COLUMN] !== needle) break;
- }
- return index;
-}
-function lowerBound(haystack, needle, index) {
- for (let i = index - 1; i >= 0; index = i--) {
- if (haystack[i][COLUMN] !== needle) break;
- }
- return index;
-}
-function memoizedState() {
- return {
- lastKey: -1,
- lastNeedle: -1,
- lastIndex: -1
- };
-}
-function memoizedBinarySearch(haystack, needle, state, key) {
- const { lastKey, lastNeedle, lastIndex } = state;
- let low = 0;
- let high = haystack.length - 1;
- if (key === lastKey) {
- if (needle === lastNeedle) {
- found = lastIndex !== -1 && haystack[lastIndex][COLUMN] === needle;
- return lastIndex;
- }
- if (needle >= lastNeedle) {
- low = lastIndex === -1 ? 0 : lastIndex;
- } else {
- high = lastIndex;
- }
- }
- state.lastKey = key;
- state.lastNeedle = needle;
- return state.lastIndex = binarySearch(haystack, needle, low, high);
-}
-
-// src/types.ts
-function parse(map) {
- return typeof map === "string" ? JSON.parse(map) : map;
-}
-
-// src/trace-mapping.ts
-var LINE_GTR_ZERO = "`line` must be greater than 0 (lines start at line 1)";
-var COL_GTR_EQ_ZERO = "`column` must be greater than or equal to 0 (columns start at column 0)";
-var LEAST_UPPER_BOUND = -1;
-var GREATEST_LOWER_BOUND = 1;
-var TraceMap = class {
- constructor(map, mapUrl) {
- const isString = typeof map === "string";
- if (!isString && map._decodedMemo) return map;
- const parsed = parse(map);
- const { version, file, names, sourceRoot, sources, sourcesContent } = parsed;
- this.version = version;
- this.file = file;
- this.names = names || [];
- this.sourceRoot = sourceRoot;
- this.sources = sources;
- this.sourcesContent = sourcesContent;
- this.ignoreList = parsed.ignoreList || parsed.x_google_ignoreList || void 0;
- const resolve = resolver(mapUrl, sourceRoot);
- this.resolvedSources = sources.map(resolve);
- const { mappings } = parsed;
- if (typeof mappings === "string") {
- this._encoded = mappings;
- this._decoded = void 0;
- } else if (Array.isArray(mappings)) {
- this._encoded = void 0;
- this._decoded = maybeSort(mappings, isString);
- } else if (parsed.sections) {
- throw new Error(`TraceMap passed sectioned source map, please use FlattenMap export instead`);
- } else {
- throw new Error(`invalid source map: ${JSON.stringify(parsed)}`);
- }
- this._decodedMemo = memoizedState();
- this._bySources = void 0;
- this._bySourceMemos = void 0;
- }
-};
-function cast(map) {
- return map;
-}
-function decodedMappings(map) {
- var _a;
- return (_a = cast(map))._decoded || (_a._decoded = decode(cast(map)._encoded));
-}
-function originalPositionFor(map, needle) {
- let { line, column, bias } = needle;
- line--;
- if (line < 0) throw new Error(LINE_GTR_ZERO);
- if (column < 0) throw new Error(COL_GTR_EQ_ZERO);
- const decoded = decodedMappings(map);
- if (line >= decoded.length) return OMapping(null, null, null, null);
- const segments = decoded[line];
- const index = traceSegmentInternal(
- segments,
- cast(map)._decodedMemo,
- line,
- column,
- bias || GREATEST_LOWER_BOUND
- );
- if (index === -1) return OMapping(null, null, null, null);
- const segment = segments[index];
- if (segment.length === 1) return OMapping(null, null, null, null);
- const { names, resolvedSources } = map;
- return OMapping(
- resolvedSources[segment[SOURCES_INDEX]],
- segment[SOURCE_LINE] + 1,
- segment[SOURCE_COLUMN],
- segment.length === 5 ? names[segment[NAMES_INDEX]] : null
- );
-}
-function generatedPositionFor(map, needle) {
- const { source, line, column, bias } = needle;
- return generatedPosition(map, source, line, column, bias || GREATEST_LOWER_BOUND, false);
-}
-function eachMapping(map, cb) {
- const decoded = decodedMappings(map);
- const { names, resolvedSources } = map;
- for (let i = 0; i < decoded.length; i++) {
- const line = decoded[i];
- for (let j = 0; j < line.length; j++) {
- const seg = line[j];
- const generatedLine = i + 1;
- const generatedColumn = seg[0];
- let source = null;
- let originalLine = null;
- let originalColumn = null;
- let name = null;
- if (seg.length !== 1) {
- source = resolvedSources[seg[1]];
- originalLine = seg[2] + 1;
- originalColumn = seg[3];
- }
- if (seg.length === 5) name = names[seg[4]];
- cb({
- generatedLine,
- generatedColumn,
- source,
- originalLine,
- originalColumn,
- name
- });
- }
- }
-}
-function OMapping(source, line, column, name) {
- return { source, line, column, name };
-}
-function GMapping(line, column) {
- return { line, column };
-}
-function traceSegmentInternal(segments, memo, line, column, bias) {
- let index = memoizedBinarySearch(segments, column, memo, line);
- if (found) {
- index = (bias === LEAST_UPPER_BOUND ? upperBound : lowerBound)(segments, column, index);
- } else if (bias === LEAST_UPPER_BOUND) index++;
- if (index === -1 || index === segments.length) return -1;
- return index;
-}
-function generatedPosition(map, source, line, column, bias, all) {
- var _a, _b;
- line--;
- if (line < 0) throw new Error(LINE_GTR_ZERO);
- if (column < 0) throw new Error(COL_GTR_EQ_ZERO);
- const { sources, resolvedSources } = map;
- let sourceIndex2 = sources.indexOf(source);
- if (sourceIndex2 === -1) sourceIndex2 = resolvedSources.indexOf(source);
- if (sourceIndex2 === -1) return all ? [] : GMapping(null, null);
- const bySourceMemos = (_a = cast(map))._bySourceMemos || (_a._bySourceMemos = sources.map(memoizedState));
- const generated = (_b = cast(map))._bySources || (_b._bySources = buildBySources(decodedMappings(map), bySourceMemos));
- const segments = generated[sourceIndex2][line];
- if (segments == null) return all ? [] : GMapping(null, null);
- const memo = bySourceMemos[sourceIndex2];
- const index = traceSegmentInternal(segments, memo, line, column, bias);
- if (index === -1) return GMapping(null, null);
- const segment = segments[index];
- return GMapping(segment[REV_GENERATED_LINE] + 1, segment[REV_GENERATED_COLUMN]);
-}
-
-// AST walker module for ESTree compatible trees
-
-
-// An ancestor walk keeps an array of ancestor nodes (including the
-// current node) and passes them to the callback as third parameter
-// (and also as state parameter when no other state is present).
-function ancestor(node, visitors, baseVisitor, state, override) {
- var ancestors = [];
- if (!baseVisitor) { baseVisitor = base
- ; }(function c(node, st, override) {
- var type = override || node.type;
- var isNew = node !== ancestors[ancestors.length - 1];
- if (isNew) { ancestors.push(node); }
- baseVisitor[type](node, st, c);
- if (visitors[type]) { visitors[type](node, st || ancestors, ancestors); }
- if (isNew) { ancestors.pop(); }
- })(node, state, override);
-}
-
-function skipThrough(node, st, c) { c(node, st); }
-function ignore(_node, _st, _c) {}
-
-// Node walkers.
-
-var base = {};
-
-base.Program = base.BlockStatement = base.StaticBlock = function (node, st, c) {
- for (var i = 0, list = node.body; i < list.length; i += 1)
- {
- var stmt = list[i];
-
- c(stmt, st, "Statement");
- }
-};
-base.Statement = skipThrough;
-base.EmptyStatement = ignore;
-base.ExpressionStatement = base.ParenthesizedExpression = base.ChainExpression =
- function (node, st, c) { return c(node.expression, st, "Expression"); };
-base.IfStatement = function (node, st, c) {
- c(node.test, st, "Expression");
- c(node.consequent, st, "Statement");
- if (node.alternate) { c(node.alternate, st, "Statement"); }
-};
-base.LabeledStatement = function (node, st, c) { return c(node.body, st, "Statement"); };
-base.BreakStatement = base.ContinueStatement = ignore;
-base.WithStatement = function (node, st, c) {
- c(node.object, st, "Expression");
- c(node.body, st, "Statement");
-};
-base.SwitchStatement = function (node, st, c) {
- c(node.discriminant, st, "Expression");
- for (var i = 0, list = node.cases; i < list.length; i += 1) {
- var cs = list[i];
-
- c(cs, st);
- }
-};
-base.SwitchCase = function (node, st, c) {
- if (node.test) { c(node.test, st, "Expression"); }
- for (var i = 0, list = node.consequent; i < list.length; i += 1)
- {
- var cons = list[i];
-
- c(cons, st, "Statement");
- }
-};
-base.ReturnStatement = base.YieldExpression = base.AwaitExpression = function (node, st, c) {
- if (node.argument) { c(node.argument, st, "Expression"); }
-};
-base.ThrowStatement = base.SpreadElement =
- function (node, st, c) { return c(node.argument, st, "Expression"); };
-base.TryStatement = function (node, st, c) {
- c(node.block, st, "Statement");
- if (node.handler) { c(node.handler, st); }
- if (node.finalizer) { c(node.finalizer, st, "Statement"); }
-};
-base.CatchClause = function (node, st, c) {
- if (node.param) { c(node.param, st, "Pattern"); }
- c(node.body, st, "Statement");
-};
-base.WhileStatement = base.DoWhileStatement = function (node, st, c) {
- c(node.test, st, "Expression");
- c(node.body, st, "Statement");
-};
-base.ForStatement = function (node, st, c) {
- if (node.init) { c(node.init, st, "ForInit"); }
- if (node.test) { c(node.test, st, "Expression"); }
- if (node.update) { c(node.update, st, "Expression"); }
- c(node.body, st, "Statement");
-};
-base.ForInStatement = base.ForOfStatement = function (node, st, c) {
- c(node.left, st, "ForInit");
- c(node.right, st, "Expression");
- c(node.body, st, "Statement");
-};
-base.ForInit = function (node, st, c) {
- if (node.type === "VariableDeclaration") { c(node, st); }
- else { c(node, st, "Expression"); }
-};
-base.DebuggerStatement = ignore;
-
-base.FunctionDeclaration = function (node, st, c) { return c(node, st, "Function"); };
-base.VariableDeclaration = function (node, st, c) {
- for (var i = 0, list = node.declarations; i < list.length; i += 1)
- {
- var decl = list[i];
-
- c(decl, st);
- }
-};
-base.VariableDeclarator = function (node, st, c) {
- c(node.id, st, "Pattern");
- if (node.init) { c(node.init, st, "Expression"); }
-};
-
-base.Function = function (node, st, c) {
- if (node.id) { c(node.id, st, "Pattern"); }
- for (var i = 0, list = node.params; i < list.length; i += 1)
- {
- var param = list[i];
-
- c(param, st, "Pattern");
- }
- c(node.body, st, node.expression ? "Expression" : "Statement");
-};
-
-base.Pattern = function (node, st, c) {
- if (node.type === "Identifier")
- { c(node, st, "VariablePattern"); }
- else if (node.type === "MemberExpression")
- { c(node, st, "MemberPattern"); }
- else
- { c(node, st); }
-};
-base.VariablePattern = ignore;
-base.MemberPattern = skipThrough;
-base.RestElement = function (node, st, c) { return c(node.argument, st, "Pattern"); };
-base.ArrayPattern = function (node, st, c) {
- for (var i = 0, list = node.elements; i < list.length; i += 1) {
- var elt = list[i];
-
- if (elt) { c(elt, st, "Pattern"); }
- }
-};
-base.ObjectPattern = function (node, st, c) {
- for (var i = 0, list = node.properties; i < list.length; i += 1) {
- var prop = list[i];
-
- if (prop.type === "Property") {
- if (prop.computed) { c(prop.key, st, "Expression"); }
- c(prop.value, st, "Pattern");
- } else if (prop.type === "RestElement") {
- c(prop.argument, st, "Pattern");
- }
- }
-};
-
-base.Expression = skipThrough;
-base.ThisExpression = base.Super = base.MetaProperty = ignore;
-base.ArrayExpression = function (node, st, c) {
- for (var i = 0, list = node.elements; i < list.length; i += 1) {
- var elt = list[i];
-
- if (elt) { c(elt, st, "Expression"); }
- }
-};
-base.ObjectExpression = function (node, st, c) {
- for (var i = 0, list = node.properties; i < list.length; i += 1)
- {
- var prop = list[i];
-
- c(prop, st);
- }
-};
-base.FunctionExpression = base.ArrowFunctionExpression = base.FunctionDeclaration;
-base.SequenceExpression = function (node, st, c) {
- for (var i = 0, list = node.expressions; i < list.length; i += 1)
- {
- var expr = list[i];
-
- c(expr, st, "Expression");
- }
-};
-base.TemplateLiteral = function (node, st, c) {
- for (var i = 0, list = node.quasis; i < list.length; i += 1)
- {
- var quasi = list[i];
-
- c(quasi, st);
- }
-
- for (var i$1 = 0, list$1 = node.expressions; i$1 < list$1.length; i$1 += 1)
- {
- var expr = list$1[i$1];
-
- c(expr, st, "Expression");
- }
-};
-base.TemplateElement = ignore;
-base.UnaryExpression = base.UpdateExpression = function (node, st, c) {
- c(node.argument, st, "Expression");
-};
-base.BinaryExpression = base.LogicalExpression = function (node, st, c) {
- c(node.left, st, "Expression");
- c(node.right, st, "Expression");
-};
-base.AssignmentExpression = base.AssignmentPattern = function (node, st, c) {
- c(node.left, st, "Pattern");
- c(node.right, st, "Expression");
-};
-base.ConditionalExpression = function (node, st, c) {
- c(node.test, st, "Expression");
- c(node.consequent, st, "Expression");
- c(node.alternate, st, "Expression");
-};
-base.NewExpression = base.CallExpression = function (node, st, c) {
- c(node.callee, st, "Expression");
- if (node.arguments)
- { for (var i = 0, list = node.arguments; i < list.length; i += 1)
- {
- var arg = list[i];
-
- c(arg, st, "Expression");
- } }
-};
-base.MemberExpression = function (node, st, c) {
- c(node.object, st, "Expression");
- if (node.computed) { c(node.property, st, "Expression"); }
-};
-base.ExportNamedDeclaration = base.ExportDefaultDeclaration = function (node, st, c) {
- if (node.declaration)
- { c(node.declaration, st, node.type === "ExportNamedDeclaration" || node.declaration.id ? "Statement" : "Expression"); }
- if (node.source) { c(node.source, st, "Expression"); }
-};
-base.ExportAllDeclaration = function (node, st, c) {
- if (node.exported)
- { c(node.exported, st); }
- c(node.source, st, "Expression");
-};
-base.ImportDeclaration = function (node, st, c) {
- for (var i = 0, list = node.specifiers; i < list.length; i += 1)
- {
- var spec = list[i];
-
- c(spec, st);
- }
- c(node.source, st, "Expression");
-};
-base.ImportExpression = function (node, st, c) {
- c(node.source, st, "Expression");
-};
-base.ImportSpecifier = base.ImportDefaultSpecifier = base.ImportNamespaceSpecifier = base.Identifier = base.PrivateIdentifier = base.Literal = ignore;
-
-base.TaggedTemplateExpression = function (node, st, c) {
- c(node.tag, st, "Expression");
- c(node.quasi, st, "Expression");
-};
-base.ClassDeclaration = base.ClassExpression = function (node, st, c) { return c(node, st, "Class"); };
-base.Class = function (node, st, c) {
- if (node.id) { c(node.id, st, "Pattern"); }
- if (node.superClass) { c(node.superClass, st, "Expression"); }
- c(node.body, st);
-};
-base.ClassBody = function (node, st, c) {
- for (var i = 0, list = node.body; i < list.length; i += 1)
- {
- var elt = list[i];
-
- c(elt, st);
- }
-};
-base.MethodDefinition = base.PropertyDefinition = base.Property = function (node, st, c) {
- if (node.computed) { c(node.key, st, "Expression"); }
- if (node.value) { c(node.value, st, "Expression"); }
-};
-
-async function collectTests(ctx, filepath) {
- const request = await ctx.vite.environments.ssr.transformRequest(filepath);
- if (!request) return null;
- const ast = await parseAstAsync(request.code);
- const testFilepath = relative(ctx.config.root, filepath);
- const projectName = ctx.name;
- const file = {
- filepath,
- type: "suite",
- id: generateHash(`${testFilepath}${projectName ? `${projectName}:__typecheck__` : "__typecheck__"}`),
- name: testFilepath,
- fullName: testFilepath,
- mode: "run",
- tasks: [],
- start: ast.start,
- end: ast.end,
- projectName,
- meta: { typecheck: true },
- file: null
- };
- file.file = file;
- const definitions = [];
- const getName = (callee) => {
- if (!callee) return null;
- if (callee.type === "Identifier") return callee.name;
- if (callee.type === "CallExpression") return getName(callee.callee);
- if (callee.type === "TaggedTemplateExpression") return getName(callee.tag);
- if (callee.type === "MemberExpression") {
- if (callee.object?.type === "Identifier" && [
- "it",
- "test",
- "describe",
- "suite"
- ].includes(callee.object.name)) return callee.object?.name;
- // direct call as `__vite_ssr_exports_0__.test()`
- if (callee.object?.name?.startsWith("__vite_ssr_")) return getName(callee.property);
- // call as `__vite_ssr__.test.skip()`
- return getName(callee.object?.property);
- }
- // unwrap (0, ...)
- if (callee.type === "SequenceExpression" && callee.expressions.length === 2) {
- const [e0, e1] = callee.expressions;
- if (e0.type === "Literal" && e0.value === 0) return getName(e1);
- }
- return null;
- };
- ancestor(ast, { CallExpression(node) {
- const { callee } = node;
- const name = getName(callee);
- if (!name) return;
- if (![
- "it",
- "test",
- "describe",
- "suite"
- ].includes(name)) return;
- const property = callee?.property?.name;
- let mode = !property || property === name ? "run" : property;
- // they will be picked up in the next iteration
- if ([
- "each",
- "for",
- "skipIf",
- "runIf"
- ].includes(mode)) return;
- let start;
- const end = node.end;
- // .each
- if (callee.type === "CallExpression") start = callee.end;
- else if (callee.type === "TaggedTemplateExpression") start = callee.end + 1;
- else start = node.start;
- const { arguments: [messageNode] } = node;
- const message = messageNode?.type === "Literal" || messageNode?.type === "TemplateLiteral" ? request.code.slice(messageNode.start + 1, messageNode.end - 1) : request.code.slice(messageNode.start, messageNode.end);
- // cannot statically analyze, so we always skip it
- if (mode === "skipIf" || mode === "runIf") mode = "skip";
- definitions.push({
- start,
- end,
- name: message,
- type: name === "it" || name === "test" ? "test" : "suite",
- mode,
- task: null
- });
- } });
- let lastSuite = file;
- const updateLatestSuite = (index) => {
- while (lastSuite.suite && lastSuite.end < index) lastSuite = lastSuite.suite;
- return lastSuite;
- };
- definitions.sort((a, b) => a.start - b.start).forEach((definition) => {
- const latestSuite = updateLatestSuite(definition.start);
- let mode = definition.mode;
- if (latestSuite.mode !== "run")
- // inherit suite mode, if it's set
- mode = latestSuite.mode;
- if (definition.type === "suite") {
- const task = {
- type: definition.type,
- id: "",
- suite: latestSuite,
- file,
- tasks: [],
- mode,
- name: definition.name,
- fullName: createTaskName([lastSuite.fullName, definition.name]),
- fullTestName: createTaskName([lastSuite.fullTestName, definition.name]),
- end: definition.end,
- start: definition.start,
- meta: { typecheck: true }
- };
- definition.task = task;
- latestSuite.tasks.push(task);
- lastSuite = task;
- return;
- }
- const task = {
- type: definition.type,
- id: "",
- suite: latestSuite,
- file,
- mode,
- timeout: 0,
- context: {},
- name: definition.name,
- fullName: createTaskName([lastSuite.fullName, definition.name]),
- fullTestName: createTaskName([lastSuite.fullTestName, definition.name]),
- end: definition.end,
- start: definition.start,
- annotations: [],
- artifacts: [],
- meta: { typecheck: true }
- };
- definition.task = task;
- latestSuite.tasks.push(task);
- });
- calculateSuiteHash(file);
- const hasOnly = someTasksAreOnly(file);
- interpretTaskModes(file, ctx.config.testNamePattern, void 0, hasOnly, false, ctx.config.allowOnly);
- return {
- file,
- parsed: request.code,
- filepath,
- map: request.map,
- definitions
- };
-}
-
-const newLineRegExp = /\r?\n/;
-const errCodeRegExp = /error TS(?<errCode>\d+)/;
-async function makeTscErrorInfo(errInfo) {
- const [errFilePathPos = "", ...errMsgRawArr] = errInfo.split(":");
- if (!errFilePathPos || errMsgRawArr.length === 0 || errMsgRawArr.join("").length === 0) return ["unknown filepath", null];
- const errMsgRaw = errMsgRawArr.join("").trim();
- // get filePath, line, col
- const [errFilePath, errPos] = errFilePathPos.slice(0, -1).split("(");
- if (!errFilePath || !errPos) return ["unknown filepath", null];
- const [errLine, errCol] = errPos.split(",");
- if (!errLine || !errCol) return [errFilePath, null];
- // get errCode, errMsg
- const execArr = errCodeRegExp.exec(errMsgRaw);
- if (!execArr) return [errFilePath, null];
- const errCodeStr = execArr.groups?.errCode ?? "";
- if (!errCodeStr) return [errFilePath, null];
- const line = Number(errLine);
- const col = Number(errCol);
- const errCode = Number(errCodeStr);
- return [errFilePath, {
- filePath: errFilePath,
- errCode,
- line,
- column: col,
- errMsg: errMsgRaw.slice(`error TS${errCode} `.length)
- }];
-}
-async function getRawErrsMapFromTsCompile(tscErrorStdout) {
- const rawErrsMap = /* @__PURE__ */ new Map();
- (await Promise.all(tscErrorStdout.split(newLineRegExp).reduce((prev, next) => {
- if (!next) return prev;
- else if (next[0] !== " ") prev.push(next);
- else prev[prev.length - 1] += `\n${next}`;
- return prev;
- }, []).map((errInfoLine) => makeTscErrorInfo(errInfoLine)))).forEach(([errFilePath, errInfo]) => {
- if (!errInfo) return;
- if (!rawErrsMap.has(errFilePath)) rawErrsMap.set(errFilePath, [errInfo]);
- else rawErrsMap.get(errFilePath)?.push(errInfo);
- });
- return rawErrsMap;
-}
-
-class TypeCheckError extends Error {
- name = "TypeCheckError";
- constructor(message, stacks) {
- super(message);
- this.message = message;
- this.stacks = stacks;
- }
-}
-class Typechecker {
- _onParseStart;
- _onParseEnd;
- _onWatcherRerun;
- _result = {
- files: [],
- sourceErrors: [],
- time: 0
- };
- _startTime = 0;
- _output = "";
- _tests = {};
- process;
- files = [];
- constructor(project) {
- this.project = project;
- }
- setFiles(files) {
- this.files = files;
- }
- onParseStart(fn) {
- this._onParseStart = fn;
- }
- onParseEnd(fn) {
- this._onParseEnd = fn;
- }
- onWatcherRerun(fn) {
- this._onWatcherRerun = fn;
- }
- async collectFileTests(filepath) {
- return collectTests(this.project, filepath);
- }
- getFiles() {
- return this.files;
- }
- async collectTests() {
- const tests = (await Promise.all(this.getFiles().map((filepath) => this.collectFileTests(filepath)))).reduce((acc, data) => {
- if (!data) return acc;
- acc[data.filepath] = data;
- return acc;
- }, {});
- this._tests = tests;
- return tests;
- }
- markPassed(file) {
- if (!file.result?.state) file.result = { state: "pass" };
- const markTasks = (tasks) => {
- for (const task of tasks) {
- if ("tasks" in task) markTasks(task.tasks);
- if (!task.result?.state && (task.mode === "run" || task.mode === "queued")) task.result = { state: "pass" };
- }
- };
- markTasks(file.tasks);
- }
- async prepareResults(output) {
- // Detect if tsc output is help text instead of error output
- // This happens when tsconfig.json is missing and tsc can't find any config
- if (output.includes("The TypeScript Compiler - Version") || output.includes("COMMON COMMANDS")) {
- const { typecheck } = this.project.config;
- const msg = `TypeScript compiler returned help text instead of type checking results.
-This usually means the tsconfig file was not found.
-
-Possible solutions:
- 1. Ensure '${typecheck.tsconfig || "tsconfig.json"}' exists in your project root\n 2. If using a custom tsconfig, verify the path in your Vitest config:\n test: { typecheck: { tsconfig: 'path/to/tsconfig.json' } }\n 3. Check that the tsconfig file is valid JSON`;
- throw new Error(msg);
- }
- const typeErrors = await this.parseTscLikeOutput(output);
- const testFiles = new Set(this.getFiles());
- if (!this._tests) this._tests = await this.collectTests();
- const sourceErrors = [];
- const files = [];
- testFiles.forEach((path) => {
- const { file, definitions, map, parsed } = this._tests[path];
- const errors = typeErrors.get(path);
- files.push(file);
- if (!errors) {
- this.markPassed(file);
- return;
- }
- const sortedDefinitions = [...definitions.sort((a, b) => b.start - a.start)];
- // has no map for ".js" files that use // @ts-check
- const traceMap = map && new TraceMap(map);
- const indexMap = createLocationsIndexMap(parsed);
- const markState = (task, state) => {
- task.result = { state: task.mode === "run" || task.mode === "only" ? state : task.mode };
- if (task.suite) markState(task.suite, state);
- else if (task.file && task !== task.file) markState(task.file, state);
- };
- errors.forEach(({ error, originalError }) => {
- const processedPos = traceMap ? findGeneratedPosition(traceMap, {
- line: originalError.line,
- column: originalError.column,
- source: basename(path)
- }) : originalError;
- const line = processedPos.line ?? originalError.line;
- const column = processedPos.column ?? originalError.column;
- const index = indexMap.get(`${line}:${column}`);
- const definition = index != null && sortedDefinitions.find((def) => def.start <= index && def.end >= index);
- const suite = definition ? definition.task : file;
- const state = suite.mode === "run" || suite.mode === "only" ? "fail" : suite.mode;
- const errors = suite.result?.errors || [];
- suite.result = {
- state,
- errors
- };
- errors.push(error);
- if (state === "fail") {
- if (suite.suite) markState(suite.suite, "fail");
- else if (suite.file && suite !== suite.file) markState(suite.file, "fail");
- }
- });
- this.markPassed(file);
- });
- typeErrors.forEach((errors, path) => {
- if (!testFiles.has(path)) sourceErrors.push(...errors.map(({ error }) => error));
- });
- return {
- files,
- sourceErrors,
- time: performance$1.now() - this._startTime
- };
- }
- async parseTscLikeOutput(output) {
- const errorsMap = await getRawErrsMapFromTsCompile(output);
- const typesErrors = /* @__PURE__ */ new Map();
- errorsMap.forEach((errors, path) => {
- const filepath = resolve$1(this.project.config.root, path);
- const suiteErrors = errors.map((info) => {
- const limit = Error.stackTraceLimit;
- Error.stackTraceLimit = 0;
- // Some expect-type errors have the most useful information on the second line e.g. `This expression is not callable.\n Type 'ExpectString<number>' has no call signatures.`
- const errMsg = info.errMsg.replace(/\r?\n\s*(Type .* has no call signatures)/g, " $1");
- const error = new TypeCheckError(errMsg, [{
- file: filepath,
- line: info.line,
- column: info.column,
- method: ""
- }]);
- Error.stackTraceLimit = limit;
- return {
- originalError: info,
- error: {
- name: error.name,
- message: errMsg,
- stacks: error.stacks,
- stack: ""
- }
- };
- });
- typesErrors.set(filepath, suiteErrors);
- });
- return typesErrors;
- }
- async stop() {
- this.process?.kill();
- this.process = void 0;
- }
- async ensurePackageInstalled(ctx, checker) {
- if (checker !== "tsc" && checker !== "vue-tsc") return;
- const packageName = checker === "tsc" ? "typescript" : "vue-tsc";
- await ctx.packageInstaller.ensureInstalled(packageName, ctx.config.root);
- }
- getExitCode() {
- return this.process?.exitCode != null && this.process.exitCode;
- }
- getOutput() {
- return this._output;
- }
- async spawn() {
- const { root, watch, typecheck } = this.project.config;
- const args = [
- "--noEmit",
- "--pretty",
- "false",
- "--incremental",
- "--tsBuildInfoFile",
- join(process.versions.pnp ? join(nodeos__default.tmpdir(), this.project.hash) : distDir, "tsconfig.tmp.tsbuildinfo")
- ];
- // use builtin watcher because it's faster
- if (watch) args.push("--watch");
- if (typecheck.allowJs) args.push("--allowJs", "--checkJs");
- if (typecheck.tsconfig) args.push("-p", resolve$1(root, typecheck.tsconfig));
- this._output = "";
- this._startTime = performance$1.now();
- const child = x(typecheck.checker, args, {
- nodeOptions: {
- cwd: root,
- stdio: "pipe"
- },
- throwOnError: false
- });
- this.process = child.process;
- let rerunTriggered = false;
- let dataReceived = false;
- return new Promise((resolve, reject) => {
- if (!child.process || !child.process.stdout) {
- reject(/* @__PURE__ */ new Error(`Failed to initialize ${typecheck.checker}. This is a bug in Vitest - please, open an issue with reproduction.`));
- return;
- }
- let resolved = false;
- child.process.stdout.on("data", (chunk) => {
- dataReceived = true;
- this._output += chunk;
- if (!watch) return;
- if (this._output.includes("File change detected") && !rerunTriggered) {
- this._onWatcherRerun?.();
- this._startTime = performance$1.now();
- this._result.sourceErrors = [];
- this._result.files = [];
- this._tests = null;
- rerunTriggered = true;
- }
- if (/Found \w+ errors*. Watching for/.test(this._output)) {
- rerunTriggered = false;
- this.prepareResults(this._output).then((result) => {
- this._result = result;
- this._onParseEnd?.(result);
- });
- this._output = "";
- }
- });
- // Also capture stderr for configuration errors like missing tsconfig
- child.process.stderr?.on("data", (chunk) => {
- this._output += chunk;
- });
- const timeout = setTimeout(() => reject(/* @__PURE__ */ new Error(`${typecheck.checker} spawn timed out`)), this.project.config.typecheck.spawnTimeout);
- let winTimeout;
- function onError(cause) {
- if (resolved) return;
- clearTimeout(timeout);
- clearTimeout(winTimeout);
- resolved = true;
- reject(new Error("Spawning typechecker failed - is typescript installed?", { cause }));
- }
- child.process.once("spawn", () => {
- this._onParseStart?.();
- child.process?.off("error", onError);
- clearTimeout(timeout);
- if (process.platform === "win32")
- // on Windows, the process might be spawned but fail to start
- // we wait for a potential error here. if "close" event didn't trigger,
- // we resolve the promise
- winTimeout = setTimeout(() => {
- resolved = true;
- resolve({ result: child });
- }, 200);
- else {
- resolved = true;
- resolve({ result: child });
- }
- });
- if (process.platform === "win32") child.process.once("close", (code) => {
- if (code != null && code !== 0 && !dataReceived) onError(/* @__PURE__ */ new Error(`The ${typecheck.checker} command exited with code ${code}.`));
- });
- child.process.once("error", onError);
- });
- }
- async start() {
- if (this.process) return;
- const { watch } = this.project.config;
- const { result: child } = await this.spawn();
- if (!watch) {
- await child;
- this._result = await this.prepareResults(this._output);
- await this._onParseEnd?.(this._result);
- }
- }
- getResult() {
- return this._result;
- }
- getTestFiles() {
- return Object.values(this._tests || {}).map((i) => i.file);
- }
- getTestPacksAndEvents() {
- const packs = [];
- const events = [];
- for (const { file } of Object.values(this._tests || {})) {
- const result = convertTasksToEvents(file);
- packs.push(...result.packs);
- events.push(...result.events);
- }
- return {
- packs,
- events
- };
- }
-}
-function findGeneratedPosition(traceMap, { line, column, source }) {
- const found = generatedPositionFor(traceMap, {
- line,
- column,
- source
- });
- if (found.line !== null) return found;
- // find the next source token position when the exact error position doesn't exist in source map.
- // this can happen, for example, when the type error is in the comment "// @ts-expect-error"
- // and comments are stripped away in the generated code.
- const mappings = [];
- eachMapping(traceMap, (m) => {
- if (m.source === source && m.originalLine !== null && m.originalColumn !== null && (line === m.originalLine ? column < m.originalColumn : line < m.originalLine)) mappings.push(m);
- });
- const next = mappings.sort((a, b) => a.originalLine === b.originalLine ? a.originalColumn - b.originalColumn : a.originalLine - b.originalLine).at(0);
- if (next) return {
- line: next.generatedLine,
- column: next.generatedColumn
- };
- return {
- line: null,
- column: null
- };
-}
-
-// use Logger with custom Console to capture entire error printing
-function capturePrintError(error, ctx, options) {
- let output = "";
- const console = new Console(new Writable({ write(chunk, _encoding, callback) {
- output += String(chunk);
- callback();
- } }));
- return {
- nearest: printError(error, ctx, {
- error: console.error.bind(console),
- highlight: ctx.logger.highlight.bind(ctx.logger)
- }, {
- showCodeFrame: false,
- ...options
- })?.nearest,
- output
- };
-}
-function printError(error, ctx, logger, options) {
- const project = options.project ?? ctx.coreWorkspaceProject ?? ctx.projects[0];
- return printErrorInner(error, project, {
- logger,
- type: options.type,
- showCodeFrame: options.showCodeFrame,
- screenshotPaths: options.screenshotPaths,
- printProperties: options.verbose,
- parseErrorStacktrace(error) {
- if (error.stacks) if (options.fullStack) return error.stacks;
- else return error.stacks.filter((stack) => {
- return !defaultStackIgnorePatterns.some((p) => stack.file.match(p));
- });
- // browser stack trace needs to be processed differently,
- // so there is a separate method for that
- if (options.task?.file.pool === "browser" && project.browser) return project.browser.parseErrorStacktrace(error, {
- frameFilter: project.config.onStackTrace,
- ignoreStackEntries: options.fullStack ? [] : void 0
- });
- // node.js stack trace already has correct source map locations
- return parseErrorStacktrace(error, {
- frameFilter: project.config.onStackTrace,
- ignoreStackEntries: options.fullStack ? [] : void 0
- });
- }
- });
-}
-function printErrorInner(error, project, options) {
- const { showCodeFrame = true, type, printProperties = true } = options;
- const logger = options.logger;
- let e = error;
- if (isPrimitive(e)) e = {
- message: String(error).split(/\n/g)[0],
- stack: String(error)
- };
- if (!e) {
- const error = /* @__PURE__ */ new Error("unknown error");
- e = {
- message: e ?? error.message,
- stack: error.stack
- };
- }
- // Error may have occurred even before the configuration was resolved
- if (!project) {
- printErrorMessage(e, logger);
- return;
- }
- const stacks = options.parseErrorStacktrace(e);
- const nearest = error instanceof TypeCheckError ? error.stacks[0] : stacks.find((stack) => {
- // we are checking that this module was processed by us at one point
- try {
- return [...Object.values(project._vite?.environments || {}), ...Object.values(project.browser?.vite.environments || {})].some((environment) => {
- return [...environment.moduleGraph.getModulesByFile(stack.file)?.values() || []].some((module) => !!module.transformResult);
- }) && existsSync(stack.file);
- } catch {
- return false;
- }
- });
- if (type) printErrorType(type, project.vitest);
- printErrorMessage(e, logger);
- if (options.screenshotPaths?.length) {
- const uniqueScreenshots = Array.from(new Set(options.screenshotPaths));
- const length = uniqueScreenshots.length;
- logger.error(`\nFailure screenshot${length > 1 ? "s" : ""}:`);
- logger.error(uniqueScreenshots.map((p) => ` - ${c.dim(relative(process.cwd(), p))}`).join("\n"));
- if (!e.diff) logger.error();
- }
- if (e.codeFrame) logger.error(`${e.codeFrame}\n`);
- if ("__vitest_rollup_error__" in e) {
- // https://github.com/vitejs/vite/blob/95020ab49e12d143262859e095025cf02423c1d9/packages/vite/src/node/server/middlewares/error.ts#L25-L36
- const err = e.__vitest_rollup_error__;
- logger.error([
- err.plugin && ` Plugin: ${c.magenta(err.plugin)}`,
- err.id && ` File: ${c.cyan(err.id)}${err.loc ? `:${err.loc.line}:${err.loc.column}` : ""}`,
- err.frame && c.yellow(err.frame.split(/\r?\n/g).map((l) => ` `.repeat(2) + l).join(`\n`))
- ].filter(Boolean).join("\n"));
- }
- // E.g. AssertionError from assert does not set showDiff but has both actual and expected properties
- if (e.diff) logger.error(`\n${e.diff}\n`);
- // if the error provide the frame
- if (e.frame) logger.error(c.yellow(e.frame));
- else printStack(logger, project, stacks, nearest, printProperties ? getErrorProperties(e) : {}, (s) => {
- if (showCodeFrame && s === nearest && nearest) {
- const sourceCode = readFileSync(nearest.file, "utf-8");
- logger.error(generateCodeFrame(sourceCode.length > 1e5 ? sourceCode : logger.highlight(nearest.file, sourceCode), 4, s));
- }
- });
- const testPath = e.VITEST_TEST_PATH;
- const testName = e.VITEST_TEST_NAME;
- // testName has testPath inside
- if (testPath) logger.error(c.red(`This error originated in "${c.bold(relative(project.config.root, testPath))}" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.`));
- if (testName) logger.error(c.red(`The latest test that might've caused the error is "${c.bold(testName)}". It might mean one of the following:
-- The error was thrown, while Vitest was running this test.
-- If the error occurred after the test had been completed, this was the last documented test before it was thrown.`));
- if (typeof e.cause === "object" && e.cause && "name" in e.cause) {
- e.cause.name = `Caused by: ${e.cause.name}`;
- printErrorInner(e.cause, project, {
- showCodeFrame: false,
- logger: options.logger,
- parseErrorStacktrace: options.parseErrorStacktrace
- });
- }
- handleImportOutsideModuleError(e.stack || "", logger);
- return { nearest };
-}
-function printErrorType(type, ctx) {
- ctx.logger.error(`\n${errorBanner(type)}`);
-}
-const skipErrorProperties = new Set([
- "cause",
- "stacks",
- "type",
- "showDiff",
- "ok",
- "operator",
- "diff",
- "codeFrame",
- "actual",
- "expected",
- "diffOptions",
- "runnerError",
- "sourceURL",
- "column",
- "line",
- "fileName",
- "lineNumber",
- "columnNumber",
- "VITEST_TEST_NAME",
- "VITEST_TEST_PATH",
- "__vitest_rollup_error__",
- ...Object.getOwnPropertyNames(Error.prototype),
- ...Object.getOwnPropertyNames(Object.prototype)
-]);
-function getErrorProperties(e) {
- const errorObject = Object.create(null);
- if (e.name === "AssertionError") return errorObject;
- for (const key of Object.getOwnPropertyNames(e))
- // print the original stack if it was ever changed manually by the user
- if (key === "stack" && e[key] != null && typeof e[key] !== "string") errorObject[key] = e[key];
- else if (key !== "stack" && !skipErrorProperties.has(key)) errorObject[key] = e[key];
- return errorObject;
-}
-const esmErrors = ["Cannot use import statement outside a module", "Unexpected token 'export'"];
-function handleImportOutsideModuleError(stack, logger) {
- if (!esmErrors.some((e) => stack.includes(e))) return;
- const path = normalize(stack.split("\n")[0].trim());
- let name = path.split("/node_modules/").pop() || "";
- if (name[0] === "@") name = name.split("/").slice(0, 2).join("/");
- else name = name.split("/")[0];
- if (name) printModuleWarningForPackage(logger, path, name);
- else printModuleWarningForSourceCode(logger, path);
-}
-function printModuleWarningForPackage(logger, path, name) {
- logger.error(c.yellow(`Module ${path} seems to be an ES Module but shipped in a CommonJS package. You might want to create an issue to the package ${c.bold(`"${name}"`)} asking them to ship the file in .mjs extension or add "type": "module" in their package.json.
-
-As a temporary workaround you can try to inline the package by updating your config:
-
-` + c.gray(c.dim("// vitest.config.js")) + "\n" + c.green(`export default {
- test: {
- server: {
- deps: {
- inline: [
- ${c.yellow(c.bold(`"${name}"`))}
- ]
- }
- }
- }
-}\n`)));
-}
-function printModuleWarningForSourceCode(logger, path) {
- logger.error(c.yellow(`Module ${path} seems to be an ES Module but shipped in a CommonJS package. To fix this issue, change the file extension to .mjs or add "type": "module" in your package.json.`));
-}
-function printErrorMessage(error, logger) {
- const errorName = error.name || "Unknown Error";
- if (!error.message) {
- logger.error(error);
- return;
- }
- if (error.message.length > 5e3)
- // Protect against infinite stack trace in tinyrainbow
- logger.error(`${c.red(c.bold(errorName))}: ${error.message}`);
- else logger.error(c.red(`${c.bold(errorName)}: ${error.message}`));
-}
-function printStack(logger, project, stack, highlight, errorProperties, onStack) {
- for (const frame of stack) {
- const color = frame === highlight ? c.cyan : c.gray;
- const path = relative(project.config.root, frame.file);
- logger.error(color(` ${c.dim(F_POINTER)} ${[frame.method, `${path}:${c.dim(`${frame.line}:${frame.column}`)}`].filter(Boolean).join(" ")}`));
- onStack?.(frame);
- }
- if (stack.length) logger.error();
- if (hasProperties(errorProperties)) {
- logger.error(c.red(c.dim(divider())));
- const propertiesString = inspect(errorProperties);
- logger.error(c.red(c.bold("Serialized Error:")), c.gray(propertiesString));
- }
-}
-function hasProperties(obj) {
- // eslint-disable-next-line no-unreachable-loop
- for (const _key in obj) return true;
- return false;
-}
-function generateCodeFrame(source, indent = 0, loc, range = 2) {
- const start = typeof loc === "object" ? positionToOffset(source, loc.line, loc.column) : loc;
- const end = start;
- const lines = source.split(lineSplitRE);
- const nl = /\r\n/.test(source) ? 2 : 1;
- let count = 0;
- let res = [];
- const columns = process.stdout?.columns || 80;
- for (let i = 0; i < lines.length; i++) {
- count += lines[i].length + nl;
- if (count >= start) {
- for (let j = i - range; j <= i + range || end > count; j++) {
- if (j < 0 || j >= lines.length) continue;
- const lineLength = lines[j].length;
- const strippedContent = stripVTControlCharacters(lines[j]);
- if (strippedContent.startsWith("//# sourceMappingURL")) continue;
- // too long, maybe it's a minified file, skip for codeframe
- if (strippedContent.length > 200) return "";
- res.push(lineNo(j + 1) + truncateString(lines[j].replace(/\t/g, " "), columns - 5 - indent));
- if (j === i) {
- // push underline
- const pad = start - (count - lineLength) + (nl - 1);
- const length = Math.max(1, end > count ? lineLength - pad : end - start);
- res.push(lineNo() + " ".repeat(pad) + c.red("^".repeat(length)));
- } else if (j > i) {
- if (end > count) {
- const length = Math.max(1, Math.min(end - count, lineLength));
- res.push(lineNo() + c.red("^".repeat(length)));
- }
- count += lineLength + 1;
- }
- }
- break;
- }
- }
- if (indent) res = res.map((line) => " ".repeat(indent) + line);
- return res.join("\n");
-}
-function lineNo(no = "") {
- return c.gray(`${String(no).padStart(3, " ")}| `);
-}
-
-class GithubActionsReporter {
- ctx = void 0;
- options;
- constructor(options = {}) {
- this.options = options;
- }
- onInit(ctx) {
- this.ctx = ctx;
- }
- onTestCaseAnnotate(testCase, annotation) {
- if (!annotation.location || this.options.displayAnnotations === false) return;
- const type = getTitle(annotation.type);
- const formatted = formatMessage({
- command: getType(annotation.type),
- properties: {
- file: annotation.location.file,
- line: String(annotation.location.line),
- column: String(annotation.location.column),
- ...type && { title: type }
- },
- message: stripVTControlCharacters(annotation.message)
- });
- this.ctx.logger.log(`\n${formatted}`);
- }
- onTestRunEnd(testModules, unhandledErrors) {
- const files = testModules.map((testModule) => testModule.task);
- const errors = [...unhandledErrors];
- // collect all errors and associate them with projects
- const projectErrors = new Array();
- for (const error of errors) projectErrors.push({
- project: this.ctx.getRootProject(),
- title: "Unhandled error",
- error
- });
- for (const file of files) {
- const tasks = getTasks(file);
- const project = this.ctx.getProjectByName(file.projectName || "");
- for (const task of tasks) {
- if (task.result?.state !== "fail") continue;
- const title = getFullName(task, " > ");
- for (const error of task.result?.errors ?? []) projectErrors.push({
- project,
- title: project.name ? `[${project.name}] ${title}` : title,
- error,
- file
- });
- }
- }
- const onWritePath = this.options.onWritePath ?? defaultOnWritePath;
- // format errors via `printError`
- for (const { project, title, error, file } of projectErrors) {
- const result = capturePrintError(error, this.ctx, {
- project,
- task: file
- });
- const stack = result?.nearest;
- if (!stack) continue;
- const formatted = formatMessage({
- command: "error",
- properties: {
- file: onWritePath(stack.file),
- title,
- line: String(stack.line),
- column: String(stack.column)
- },
- message: stripVTControlCharacters(result.output)
- });
- this.ctx.logger.log(`\n${formatted}`);
- }
- }
-}
-const BUILT_IN_TYPES = [
- "notice",
- "error",
- "warning"
-];
-function getTitle(type) {
- if (BUILT_IN_TYPES.includes(type)) return;
- return type;
-}
-function getType(type) {
- if (BUILT_IN_TYPES.includes(type)) return type;
- return "notice";
-}
-function defaultOnWritePath(path) {
- return path;
-}
-// workflow command formatting based on
-// https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-error-message
-// https://github.com/actions/toolkit/blob/f1d9b4b985e6f0f728b4b766db73498403fd5ca3/packages/core/src/command.ts#L80-L85
-function formatMessage({ command, properties, message }) {
- let result = `::${command}`;
- Object.entries(properties).forEach(([k, v], i) => {
- result += i === 0 ? " " : ",";
- result += `${k}=${escapeProperty(v)}`;
- });
- result += `::${escapeData(message)}`;
- return result;
-}
-function escapeData(s) {
- return s.replace(/%/g, "%25").replace(/\r/g, "%0D").replace(/\n/g, "%0A");
-}
-function escapeProperty(s) {
- return s.replace(/%/g, "%25").replace(/\r/g, "%0D").replace(/\n/g, "%0A").replace(/:/g, "%3A").replace(/,/g, "%2C");
-}
-
-class HangingProcessReporter {
- whyRunning;
- onInit() {
- this.whyRunning = createRequire(import.meta.url)("why-is-node-running");
- }
- onProcessTimeout() {
- this.whyRunning?.();
- }
-}
-
-const StatusMap = {
- fail: "failed",
- only: "pending",
- pass: "passed",
- run: "pending",
- skip: "skipped",
- todo: "todo",
- queued: "pending"
-};
-class JsonReporter {
- start = 0;
- ctx;
- options;
- coverageMap;
- constructor(options) {
- this.options = options;
- }
- onInit(ctx) {
- this.ctx = ctx;
- this.start = Date.now();
- this.coverageMap = void 0;
- }
- onCoverage(coverageMap) {
- this.coverageMap = coverageMap;
- }
- async onTestRunEnd(testModules) {
- const files = testModules.map((testModule) => testModule.task);
- const suites = getSuites(files);
- const numTotalTestSuites = suites.length;
- const tests = getTests(files);
- const numTotalTests = tests.length;
- const numFailedTestSuites = suites.filter((s) => s.result?.state === "fail").length;
- const numPendingTestSuites = suites.filter((s) => s.result?.state === "run" || s.result?.state === "queued" || s.mode === "todo").length;
- const numPassedTestSuites = numTotalTestSuites - numFailedTestSuites - numPendingTestSuites;
- const numFailedTests = tests.filter((t) => t.result?.state === "fail").length;
- const numPassedTests = tests.filter((t) => t.result?.state === "pass").length;
- const numPendingTests = tests.filter((t) => t.result?.state === "run" || t.result?.state === "queued" || t.mode === "skip" || t.result?.state === "skip").length;
- const numTodoTests = tests.filter((t) => t.mode === "todo").length;
- const testResults = [];
- const success = !!(files.length > 0 || this.ctx.config.passWithNoTests) && numFailedTestSuites === 0 && numFailedTests === 0;
- for (const file of files) {
- const tests = getTests([file]);
- let startTime = tests.reduce((prev, next) => Math.min(prev, next.result?.startTime ?? Number.POSITIVE_INFINITY), Number.POSITIVE_INFINITY);
- if (startTime === Number.POSITIVE_INFINITY) startTime = this.start;
- const endTime = tests.reduce((prev, next) => Math.max(prev, (next.result?.startTime ?? 0) + (next.result?.duration ?? 0)), startTime);
- const assertionResults = tests.map((t) => {
- const ancestorTitles = [];
- let iter = t.suite;
- while (iter) {
- ancestorTitles.push(iter.name);
- iter = iter.suite;
- }
- ancestorTitles.reverse();
- return {
- ancestorTitles,
- fullName: t.name ? [...ancestorTitles, t.name].join(" ") : ancestorTitles.join(" "),
- status: StatusMap[t.result?.state || t.mode] || "skipped",
- title: t.name,
- duration: t.result?.duration,
- failureMessages: t.result?.errors?.map((e) => e.stack || e.message) || [],
- location: t.location,
- meta: t.meta
- };
- });
- if (tests.some((t) => t.result?.state === "run" || t.result?.state === "queued")) this.ctx.logger.warn("WARNING: Some tests are still running when generating the JSON report.This is likely an internal bug in Vitest.Please report it to https://github.com/vitest-dev/vitest/issues");
- const hasFailedTests = tests.some((t) => t.result?.state === "fail");
- testResults.push({
- assertionResults,
- startTime,
- endTime,
- status: file.result?.state === "fail" || hasFailedTests ? "failed" : "passed",
- message: file.result?.errors?.[0]?.message ?? "",
- name: file.filepath
- });
- }
- const result = {
- numTotalTestSuites,
- numPassedTestSuites,
- numFailedTestSuites,
- numPendingTestSuites,
- numTotalTests,
- numPassedTests,
- numFailedTests,
- numPendingTests,
- numTodoTests,
- snapshot: this.ctx.snapshot.summary,
- startTime: this.start,
- success,
- testResults,
- coverageMap: this.coverageMap
- };
- await this.writeReport(JSON.stringify(result));
- }
- /**
- * Writes the report to an output file if specified in the config,
- * or logs it to the console otherwise.
- * @param report
- */
- async writeReport(report) {
- const outputFile = this.options.outputFile ?? getOutputFile(this.ctx.config, "json");
- if (outputFile) {
- const reportFile = resolve$1(this.ctx.config.root, outputFile);
- const outputDirectory = dirname(reportFile);
- if (!existsSync(outputDirectory)) await promises.mkdir(outputDirectory, { recursive: true });
- await promises.writeFile(reportFile, report, "utf-8");
- this.ctx.logger.log(`JSON report written to ${reportFile}`);
- } else this.ctx.logger.log(report);
- }
-}
-
-class IndentedLogger {
- currentIndent = "";
- constructor(baseLog) {
- this.baseLog = baseLog;
- }
- indent() {
- this.currentIndent += " ";
- }
- unindent() {
- this.currentIndent = this.currentIndent.substring(0, this.currentIndent.length - 4);
- }
- log(text) {
- return this.baseLog(this.currentIndent + text);
- }
-}
-
-function flattenTasks$1(task, baseName = "") {
- const base = baseName ? `${baseName} > ` : "";
- if (task.type === "suite") return task.tasks.flatMap((child) => flattenTasks$1(child, `${base}${task.name}`));
- else return [{
- ...task,
- name: `${base}${task.name}`
- }];
-}
-// https://gist.github.com/john-doherty/b9195065884cdbfd2017a4756e6409cc
-function removeInvalidXMLCharacters(value, removeDiscouragedChars) {
- let regex = /([\0-\x08\v\f\x0E-\x1F\uFFFD\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g;
- value = String(value || "").replace(regex, "");
- {
- // remove everything discouraged by XML 1.0 specifications
- regex = new RegExp(
- /* eslint-disable regexp/prefer-character-class, regexp/no-obscure-range, regexp/no-useless-non-capturing-group */
- "([\\x7F-\\x84]|[\\x86-\\x9F]|[\\uFDD0-\\uFDEF]|\\uD83F[\\uDFFE\\uDFFF]|(?:\\uD87F[\\uDFFE\\uDFFF])|\\uD8BF[\\uDFFE\\uDFFF]|\\uD8FF[\\uDFFE\\uDFFF]|(?:\\uD93F[\\uDFFE\\uDFFF])|\\uD97F[\\uDFFE\\uDFFF]|\\uD9BF[\\uDFFE\\uDFFF]|\\uD9FF[\\uDFFE\\uDFFF]|\\uDA3F[\\uDFFE\\uDFFF]|\\uDA7F[\\uDFFE\\uDFFF]|\\uDABF[\\uDFFE\\uDFFF]|(?:\\uDAFF[\\uDFFE\\uDFFF])|\\uDB3F[\\uDFFE\\uDFFF]|\\uDB7F[\\uDFFE\\uDFFF]|(?:\\uDBBF[\\uDFFE\\uDFFF])|\\uDBFF[\\uDFFE\\uDFFF](?:[\\0-\\t\\v\\f\\x0E-\\u2027\\u202A-\\uD7FF\\uE000-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]))",
- "g"
- /* eslint-enable */
- );
- value = value.replace(regex, "");
- }
- return value;
-}
-function escapeXML(value) {
- return removeInvalidXMLCharacters(String(value).replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&apos;").replace(/</g, "&lt;").replace(/>/g, "&gt;"));
-}
-function executionTime(durationMS) {
- return (durationMS / 1e3).toLocaleString("en-US", {
- useGrouping: false,
- maximumFractionDigits: 10
- });
-}
-function getDuration(task) {
- return executionTime(task.result?.duration ?? 0);
-}
-class JUnitReporter {
- ctx;
- reportFile;
- baseLog;
- logger;
- _timeStart = /* @__PURE__ */ new Date();
- fileFd;
- options;
- constructor(options) {
- this.options = { ...options };
- this.options.includeConsoleOutput ??= true;
- }
- async onInit(ctx) {
- this.ctx = ctx;
- const outputFile = this.options.outputFile ?? getOutputFile(this.ctx.config, "junit");
- if (outputFile) {
- this.reportFile = resolve$1(this.ctx.config.root, outputFile);
- const outputDirectory = dirname(this.reportFile);
- if (!existsSync(outputDirectory)) await promises.mkdir(outputDirectory, { recursive: true });
- this.fileFd = await promises.open(this.reportFile, "w+");
- this.baseLog = async (text) => {
- if (!this.fileFd) this.fileFd = await promises.open(this.reportFile, "w+");
- await promises.writeFile(this.fileFd, `${text}\n`);
- };
- } else this.baseLog = async (text) => this.ctx.logger.log(text);
- this._timeStart = /* @__PURE__ */ new Date();
- this.logger = new IndentedLogger(this.baseLog);
- }
- async writeElement(name, attrs, children) {
- const pairs = [];
- for (const key in attrs) {
- const attr = attrs[key];
- if (attr === void 0) continue;
- pairs.push(`${key}="${escapeXML(attr)}"`);
- }
- await this.logger.log(`<${name}${pairs.length ? ` ${pairs.join(" ")}` : ""}>`);
- this.logger.indent();
- await children.call(this);
- this.logger.unindent();
- await this.logger.log(`</${name}>`);
- }
- async writeLogs(task, type) {
- if (task.logs == null || task.logs.length === 0) return;
- const logType = type === "err" ? "stderr" : "stdout";
- const logs = task.logs.filter((log) => log.type === logType);
- if (logs.length === 0) return;
- await this.writeElement(`system-${type}`, {}, async () => {
- for (const log of logs) await this.baseLog(escapeXML(log.content));
- });
- }
- async writeTasks(tasks, filename) {
- for (const task of tasks) {
- let classname = filename;
- const templateVars = {
- filename: task.file.name,
- filepath: task.file.filepath
- };
- if (typeof this.options.classnameTemplate === "function") classname = this.options.classnameTemplate(templateVars);
- else if (typeof this.options.classnameTemplate === "string") classname = this.options.classnameTemplate.replace(/\{filename\}/g, templateVars.filename).replace(/\{filepath\}/g, templateVars.filepath);
- await this.writeElement("testcase", {
- classname,
- file: this.options.addFileAttribute ? filename : void 0,
- name: task.name,
- time: getDuration(task)
- }, async () => {
- if (this.options.includeConsoleOutput) {
- await this.writeLogs(task, "out");
- await this.writeLogs(task, "err");
- }
- if (task.mode === "skip" || task.mode === "todo") await this.logger.log("<skipped/>");
- if (task.type === "test" && task.annotations.length) {
- await this.logger.log("<properties>");
- this.logger.indent();
- for (const annotation of task.annotations) {
- await this.logger.log(`<property name="${escapeXML(annotation.type)}" value="${escapeXML(annotation.message)}">`);
- await this.logger.log("</property>");
- }
- this.logger.unindent();
- await this.logger.log("</properties>");
- }
- if (task.result?.state === "fail") {
- const errors = task.result.errors || [];
- for (const error of errors) await this.writeElement("failure", {
- message: error?.message,
- type: error?.name
- }, async () => {
- if (!error) return;
- const result = capturePrintError(error, this.ctx, {
- project: this.ctx.getProjectByName(task.file.projectName || ""),
- task
- });
- await this.baseLog(escapeXML(stripVTControlCharacters(result.output.trim())));
- });
- }
- });
- }
- }
- async onTestRunEnd(testModules) {
- const files = testModules.map((testModule) => testModule.task);
- await this.logger.log("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
- const transformed = files.map((file) => {
- const tasks = file.tasks.flatMap((task) => flattenTasks$1(task));
- const stats = tasks.reduce((stats, task) => {
- return {
- passed: stats.passed + Number(task.result?.state === "pass"),
- failures: stats.failures + Number(task.result?.state === "fail"),
- skipped: stats.skipped + Number(task.mode === "skip" || task.mode === "todo")
- };
- }, {
- passed: 0,
- failures: 0,
- skipped: 0
- });
- // inject failed suites to surface errors during beforeAll/afterAll
- const suites = getSuites(file);
- for (const suite of suites) if (suite.result?.errors) {
- tasks.push(suite);
- stats.failures += 1;
- }
- // If there are no tests, but the file failed to load, we still want to report it as a failure
- if (tasks.length === 0 && file.result?.state === "fail") {
- stats.failures = 1;
- tasks.push({
- id: file.id,
- type: "test",
- name: file.name,
- fullName: file.name,
- fullTestName: file.name,
- mode: "run",
- result: file.result,
- meta: {},
- timeout: 0,
- context: null,
- suite: null,
- file: null,
- annotations: [],
- artifacts: []
- });
- }
- return {
- ...file,
- tasks,
- stats
- };
- });
- const stats = transformed.reduce((stats, file) => {
- stats.tests += file.tasks.length;
- stats.failures += file.stats.failures;
- stats.time += file.result?.duration || 0;
- return stats;
- }, {
- name: this.options.suiteName || "vitest tests",
- tests: 0,
- failures: 0,
- errors: 0,
- time: 0
- });
- await this.writeElement("testsuites", {
- ...stats,
- time: executionTime(stats.time)
- }, async () => {
- for (const file of transformed) {
- const filename = relative(this.ctx.config.root, file.filepath);
- await this.writeElement("testsuite", {
- name: filename,
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
- hostname: hostname(),
- tests: file.tasks.length,
- failures: file.stats.failures,
- errors: 0,
- skipped: file.stats.skipped,
- time: getDuration(file)
- }, async () => {
- await this.writeTasks(file.tasks, filename);
- });
- }
- });
- if (this.reportFile) this.ctx.logger.log(`JUNIT report written to ${this.reportFile}`);
- await this.fileFd?.close();
- this.fileFd = void 0;
- }
-}
-
-function yamlString(str) {
- if (!str) return "";
- return `"${str.replace(/"/g, "\\\"")}"`;
-}
-function tapString(str) {
- return str.replace(/\\/g, "\\\\").replace(/#/g, "\\#").replace(/\n/g, " ");
-}
-class TapReporter {
- ctx;
- logger;
- onInit(ctx) {
- this.ctx = ctx;
- this.logger = new IndentedLogger(ctx.logger.log.bind(ctx.logger));
- }
- static getComment(task) {
- if (task.mode === "skip") return " # SKIP";
- else if (task.mode === "todo") return " # TODO";
- else if (task.result?.duration != null) return ` # time=${task.result.duration.toFixed(2)}ms`;
- else return "";
- }
- logErrorDetails(error, stack) {
- const errorName = error.name || "Unknown Error";
- this.logger.log(`name: ${yamlString(String(errorName))}`);
- this.logger.log(`message: ${yamlString(String(error.message))}`);
- if (stack)
- // For compatibility with tap-mocha-reporter
- this.logger.log(`stack: ${yamlString(`${stack.file}:${stack.line}:${stack.column}`)}`);
- }
- logTasks(tasks) {
- this.logger.log(`1..${tasks.length}`);
- for (const [i, task] of tasks.entries()) {
- const id = i + 1;
- const ok = task.result?.state === "pass" || task.mode === "skip" || task.mode === "todo" ? "ok" : "not ok";
- const comment = TapReporter.getComment(task);
- if (task.type === "suite" && task.tasks.length > 0) {
- this.logger.log(`${ok} ${id} - ${tapString(task.name)}${comment} {`);
- this.logger.indent();
- this.logTasks(task.tasks);
- this.logger.unindent();
- this.logger.log("}");
- } else {
- this.logger.log(`${ok} ${id} - ${tapString(task.name)}${comment}`);
- const project = this.ctx.getProjectByName(task.file.projectName || "");
- if (task.type === "test" && task.annotations) {
- this.logger.indent();
- task.annotations.forEach(({ type, message }) => {
- this.logger.log(`# ${type}: ${message}`);
- });
- this.logger.unindent();
- }
- if (task.result?.state === "fail" && task.result.errors) {
- this.logger.indent();
- task.result.errors.forEach((error) => {
- const stack = (task.file.pool === "browser" ? project.browser?.parseErrorStacktrace(error) || [] : parseErrorStacktrace(error, { frameFilter: this.ctx.config.onStackTrace }))[0];
- this.logger.log("---");
- this.logger.log("error:");
- this.logger.indent();
- this.logErrorDetails(error);
- this.logger.unindent();
- if (stack) this.logger.log(`at: ${yamlString(`${stack.file}:${stack.line}:${stack.column}`)}`);
- if (error.showDiff) {
- this.logger.log(`actual: ${yamlString(error.actual)}`);
- this.logger.log(`expected: ${yamlString(error.expected)}`);
- }
- });
- this.logger.log("...");
- this.logger.unindent();
- }
- }
- }
- }
- onTestRunEnd(testModules) {
- const files = testModules.map((testModule) => testModule.task);
- this.logger.log("TAP version 13");
- this.logTasks(files);
- }
-}
-
-function flattenTasks(task, baseName = "") {
- const base = baseName ? `${baseName} > ` : "";
- if (task.type === "suite" && task.tasks.length > 0) return task.tasks.flatMap((child) => flattenTasks(child, `${base}${task.name}`));
- else return [{
- ...task,
- name: `${base}${task.name}`
- }];
-}
-class TapFlatReporter extends TapReporter {
- onInit(ctx) {
- super.onInit(ctx);
- }
- onTestRunEnd(testModules) {
- this.ctx.logger.log("TAP version 13");
- const flatTasks = testModules.flatMap((testModule) => flattenTasks(testModule.task));
- this.logTasks(flatTasks);
- }
-}
-
-class TreeReporter extends DefaultReporter {
- verbose = true;
- renderSucceed = true;
-}
-
-class VerboseReporter extends DefaultReporter {
- verbose = true;
- renderSucceed = true;
- printTestModule(_module) {
- // don't print test module, only print tests
- }
- onTestCaseResult(test) {
- super.onTestCaseResult(test);
- const testResult = test.result();
- if (this.ctx.config.hideSkippedTests && testResult.state === "skipped") return;
- let title = ` ${this.getEntityPrefix(test)} `;
- title += test.module.task.name;
- if (test.location) title += c.dim(`:${test.location.line}:${test.location.column}`);
- title += separator;
- title += getTestName(test.task, separator);
- title += this.getTestCaseSuffix(test);
- this.log(title);
- if (testResult.state === "failed") testResult.errors.forEach((error) => this.log(c.red(` ${F_RIGHT} ${error.message}`)));
- if (test.annotations().length) {
- this.log();
- this.printAnnotations(test, "log", 3);
- this.log();
- }
- }
-}
-
-const ReportersMap = {
- "default": DefaultReporter,
- "blob": BlobReporter,
- "verbose": VerboseReporter,
- "dot": DotReporter,
- "json": JsonReporter,
- "tap": TapReporter,
- "tap-flat": TapFlatReporter,
- "junit": JUnitReporter,
- "tree": TreeReporter,
- "hanging-process": HangingProcessReporter,
- "github-actions": GithubActionsReporter
-};
-
-export { utils as A, BlobReporter as B, DefaultReporter as D, F_RIGHT as F, GithubActionsReporter as G, HangingProcessReporter as H, JsonReporter as J, ReportersMap as R, TapFlatReporter as T, VerboseReporter as V, DotReporter as a, JUnitReporter as b, TapReporter as c, stringify as d, createIndexLocationsMap as e, formatProjectName as f, getStateSymbol as g, TraceMap as h, ancestor as i, printError as j, errorBanner as k, divider as l, Typechecker as m, generateCodeFrame as n, originalPositionFor as o, parse$1 as p, escapeRegExp as q, createDefinesScript as r, separator as s, truncateString as t, groupBy as u, readBlobs as v, withLabel as w, convertTasksToEvents as x, wildcardPatternToRegExp as y, stdout as z };
diff --git a/vanilla/node_modules/vitest/dist/chunks/index.Z5E_ObnR.js b/vanilla/node_modules/vitest/dist/chunks/index.Z5E_ObnR.js
deleted file mode 100644
index 97d126a..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/index.Z5E_ObnR.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import { b as assert, c as createExpect, g as globalExpect, i as inject, s as should, v as vi, d as vitest } from './vi.2VT5v0um.js';
-import { b as bench } from './benchmark.B3N2zMcH.js';
-import { V as VitestEvaluatedModules } from './evaluatedModules.Dg1zASAC.js';
-import { expectTypeOf } from 'expect-type';
-import { afterAll, afterEach, beforeAll, beforeEach, describe, it, onTestFailed, onTestFinished, recordArtifact, suite, test } from '@vitest/runner';
-import { chai } from '@vitest/expect';
-
-const assertType = function assertType() {};
-
-var index = /*#__PURE__*/Object.freeze({
- __proto__: null,
- EvaluatedModules: VitestEvaluatedModules,
- afterAll: afterAll,
- afterEach: afterEach,
- assert: assert,
- assertType: assertType,
- beforeAll: beforeAll,
- beforeEach: beforeEach,
- bench: bench,
- chai: chai,
- createExpect: createExpect,
- describe: describe,
- expect: globalExpect,
- expectTypeOf: expectTypeOf,
- inject: inject,
- it: it,
- onTestFailed: onTestFailed,
- onTestFinished: onTestFinished,
- recordArtifact: recordArtifact,
- should: should,
- suite: suite,
- test: test,
- vi: vi,
- vitest: vitest
-});
-
-export { assertType as a, index as i };
diff --git a/vanilla/node_modules/vitest/dist/chunks/init-forks._y3TW739.js b/vanilla/node_modules/vitest/dist/chunks/init-forks._y3TW739.js
deleted file mode 100644
index dd4c7ae..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/init-forks._y3TW739.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import { i as init } from './init.B6MLFIaN.js';
-
-if (!process.send) throw new Error("Expected worker to be run in node:child_process");
-// Store globals in case tests overwrite them
-const processExit = process.exit.bind(process);
-const processSend = process.send.bind(process);
-const processOn = process.on.bind(process);
-const processOff = process.off.bind(process);
-const processRemoveAllListeners = process.removeAllListeners.bind(process);
-// Work-around for nodejs/node#55094
-if (process.execArgv.some((execArg) => execArg.startsWith("--prof") || execArg.startsWith("--cpu-prof") || execArg.startsWith("--heap-prof") || execArg.startsWith("--diagnostic-dir"))) processOn("SIGTERM", () => processExit());
-processOn("error", onError);
-function workerInit(options) {
- const { runTests } = options;
- init({
- post: (v) => processSend(v),
- on: (cb) => processOn("message", cb),
- off: (cb) => processOff("message", cb),
- teardown: () => {
- processRemoveAllListeners("message");
- processOff("error", onError);
- },
- runTests: (state, traces) => executeTests("run", state, traces),
- collectTests: (state, traces) => executeTests("collect", state, traces),
- setup: options.setup
- });
- async function executeTests(method, state, traces) {
- try {
- await runTests(method, state, traces);
- } finally {
- process.exit = processExit;
- }
- }
-}
-// Prevent leaving worker in loops where it tries to send message to closed main
-// thread, errors, and tries to send the error.
-function onError(error) {
- if (error?.code === "ERR_IPC_CHANNEL_CLOSED" || error?.code === "EPIPE") processExit(1);
-}
-
-export { workerInit as w };
diff --git a/vanilla/node_modules/vitest/dist/chunks/init-threads.DBO2kn-p.js b/vanilla/node_modules/vitest/dist/chunks/init-threads.DBO2kn-p.js
deleted file mode 100644
index 8b7ccb8..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/init-threads.DBO2kn-p.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import { isMainThread, parentPort } from 'node:worker_threads';
-import { i as init } from './init.B6MLFIaN.js';
-
-if (isMainThread || !parentPort) throw new Error("Expected worker to be run in node:worker_threads");
-function workerInit(options) {
- const { runTests } = options;
- init({
- post: (response) => parentPort.postMessage(response),
- on: (callback) => parentPort.on("message", callback),
- off: (callback) => parentPort.off("message", callback),
- teardown: () => parentPort.removeAllListeners("message"),
- runTests: async (state, traces) => runTests("run", state, traces),
- collectTests: async (state, traces) => runTests("collect", state, traces),
- setup: options.setup
- });
-}
-
-export { workerInit as w };
diff --git a/vanilla/node_modules/vitest/dist/chunks/init.B6MLFIaN.js b/vanilla/node_modules/vitest/dist/chunks/init.B6MLFIaN.js
deleted file mode 100644
index bd404dc..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/init.B6MLFIaN.js
+++ /dev/null
@@ -1,334 +0,0 @@
-import { readFileSync } from 'node:fs';
-import { isBuiltin } from 'node:module';
-import { pathToFileURL } from 'node:url';
-import { resolve } from 'pathe';
-import { ModuleRunner } from 'vite/module-runner';
-import { b as VitestTransport } from './startModuleRunner.DEj0jb3e.js';
-import { e as environments } from './index.CyBMJtT7.js';
-import { serializeError } from '@vitest/utils/error';
-import { T as Traces } from './traces.CCmnQaNT.js';
-import { o as onCancel, a as rpcDone, c as createRuntimeRpc } from './rpc.BoxB0q7B.js';
-import { createStackString, parseStacktrace } from '@vitest/utils/source-map';
-import { s as setupInspect } from './inspector.CvyFGlXm.js';
-import { V as VitestEvaluatedModules } from './evaluatedModules.Dg1zASAC.js';
-
-function isBuiltinEnvironment(env) {
- return env in environments;
-}
-const isWindows = process.platform === "win32";
-const _loaders = /* @__PURE__ */ new Map();
-function createEnvironmentLoader(root, rpc) {
- const cachedLoader = _loaders.get(root);
- if (!cachedLoader || cachedLoader.isClosed()) {
- _loaders.delete(root);
- const moduleRunner = new ModuleRunner({
- hmr: false,
- sourcemapInterceptor: "prepareStackTrace",
- transport: new VitestTransport({
- async fetchModule(id, importer, options) {
- const result = await rpc.fetch(id, importer, "__vitest__", options);
- if ("cached" in result) return {
- code: readFileSync(result.tmp, "utf-8"),
- ...result
- };
- if (isWindows && "externalize" in result)
- // TODO: vitest returns paths for external modules, but Vite returns file://
- // https://github.com/vitejs/vite/pull/20449
- result.externalize = isBuiltin(id) || /^(?:node:|data:|http:|https:|file:)/.test(id) ? result.externalize : pathToFileURL(result.externalize).toString();
- return result;
- },
- async resolveId(id, importer) {
- return rpc.resolve(id, importer, "__vitest__");
- }
- })
- });
- _loaders.set(root, moduleRunner);
- }
- return _loaders.get(root);
-}
-async function loadEnvironment(name, root, rpc, traces) {
- if (isBuiltinEnvironment(name)) return { environment: environments[name] };
- const loader = createEnvironmentLoader(root, rpc);
- const packageId = name[0] === "." || name[0] === "/" ? resolve(root, name) : (await traces.$("vitest.runtime.environment.resolve", () => rpc.resolve(`vitest-environment-${name}`, void 0, "__vitest__")))?.id ?? resolve(root, name);
- const pkg = await traces.$("vitest.runtime.environment.import", () => loader.import(packageId));
- if (!pkg || !pkg.default || typeof pkg.default !== "object") throw new TypeError(`Environment "${name}" is not a valid environment. Path "${packageId}" should export default object with a "setup" or/and "setupVM" method.`);
- const environment = pkg.default;
- if (environment.transformMode != null && environment.transformMode !== "web" && environment.transformMode !== "ssr") throw new TypeError(`Environment "${name}" is not a valid environment. Path "${packageId}" should export default object with a "transformMode" method equal to "ssr" or "web", received "${environment.transformMode}".`);
- if (environment.transformMode) {
- console.warn(`The Vitest environment ${environment.name} defines the "transformMode". This options was deprecated in Vitest 4 and will be removed in the next major version. Please, use "viteEnvironment" instead.`);
- // keep for backwards compat
- environment.viteEnvironment ??= environment.transformMode === "ssr" ? "ssr" : "client";
- }
- return {
- environment,
- loader
- };
-}
-
-const cleanupListeners = /* @__PURE__ */ new Set();
-const moduleRunnerListeners = /* @__PURE__ */ new Set();
-function onCleanup(cb) {
- cleanupListeners.add(cb);
-}
-async function cleanup() {
- await Promise.all([...cleanupListeners].map((l) => l()));
-}
-function onModuleRunner(cb) {
- moduleRunnerListeners.add(cb);
-}
-function emitModuleRunner(moduleRunner) {
- moduleRunnerListeners.forEach((l) => l(moduleRunner));
-}
-
-const resolvingModules = /* @__PURE__ */ new Set();
-async function execute(method, ctx, worker, traces) {
- const prepareStart = performance.now();
- const cleanups = [setupInspect(ctx)];
- // RPC is used to communicate between worker (be it a thread worker or child process or a custom implementation) and the main thread
- const rpc = ctx.rpc;
- try {
- // do not close the RPC channel so that we can get the error messages sent to the main thread
- cleanups.push(async () => {
- await Promise.all(rpc.$rejectPendingCalls(({ method, reject }) => {
- reject(/* @__PURE__ */ new Error(`[vitest-worker]: Closing rpc while "${method}" was pending`));
- }));
- });
- const state = {
- ctx,
- evaluatedModules: new VitestEvaluatedModules(),
- resolvingModules,
- moduleExecutionInfo: /* @__PURE__ */ new Map(),
- config: ctx.config,
- environment: null,
- durations: {
- environment: 0,
- prepare: prepareStart
- },
- rpc,
- onCancel,
- onCleanup: onCleanup,
- providedContext: ctx.providedContext,
- onFilterStackTrace(stack) {
- return createStackString(parseStacktrace(stack));
- },
- metaEnv: createImportMetaEnvProxy()
- };
- const methodName = method === "collect" ? "collectTests" : "runTests";
- if (!worker[methodName] || typeof worker[methodName] !== "function") throw new TypeError(`Test worker should expose "runTests" method. Received "${typeof worker.runTests}".`);
- await worker[methodName](state, traces);
- } finally {
- await rpcDone().catch(() => {});
- await Promise.all(cleanups.map((fn) => fn())).catch(() => {});
- }
-}
-function run(ctx, worker, traces) {
- return execute("run", ctx, worker, traces);
-}
-function collect(ctx, worker, traces) {
- return execute("collect", ctx, worker, traces);
-}
-async function teardown() {
- await cleanup();
-}
-const env = process.env;
-function createImportMetaEnvProxy() {
- // packages/vitest/src/node/plugins/index.ts:146
- const booleanKeys = [
- "DEV",
- "PROD",
- "SSR"
- ];
- return new Proxy(env, {
- get(_, key) {
- if (typeof key !== "string") return;
- if (booleanKeys.includes(key)) return !!process.env[key];
- return process.env[key];
- },
- set(_, key, value) {
- if (typeof key !== "string") return true;
- if (booleanKeys.includes(key)) process.env[key] = value ? "1" : "";
- else process.env[key] = value;
- return true;
- }
- });
-}
-
-const __vitest_worker_response__ = true;
-const memoryUsage = process.memoryUsage.bind(process);
-let reportMemory = false;
-let traces;
-/** @experimental */
-function init(worker) {
- worker.on(onMessage);
- if (worker.onModuleRunner) onModuleRunner(worker.onModuleRunner);
- let runPromise;
- let isRunning = false;
- let workerTeardown;
- let setupContext;
- function send(response) {
- worker.post(worker.serialize ? worker.serialize(response) : response);
- }
- async function onMessage(rawMessage) {
- const message = worker.deserialize ? worker.deserialize(rawMessage) : rawMessage;
- if (message?.__vitest_worker_request__ !== true) return;
- switch (message.type) {
- case "start": {
- process.env.VITEST_POOL_ID = String(message.poolId);
- process.env.VITEST_WORKER_ID = String(message.workerId);
- reportMemory = message.options.reportMemory;
- traces ??= await new Traces({
- enabled: message.traces.enabled,
- sdkPath: message.traces.sdkPath
- }).waitInit();
- const { environment, config, pool } = message.context;
- const context = traces.getContextFromCarrier(message.traces.otelCarrier);
- // record telemetry as part of "start"
- traces.recordInitSpan(context);
- try {
- setupContext = {
- environment,
- config,
- pool,
- rpc: createRuntimeRpc(worker),
- projectName: config.name || "",
- traces
- };
- workerTeardown = await traces.$("vitest.runtime.setup", { context }, () => worker.setup?.(setupContext));
- send({
- type: "started",
- __vitest_worker_response__
- });
- } catch (error) {
- send({
- type: "started",
- __vitest_worker_response__,
- error: serializeError(error)
- });
- }
- break;
- }
- case "run":
- // Prevent concurrent execution if worker is already running
- if (isRunning) {
- send({
- type: "testfileFinished",
- __vitest_worker_response__,
- error: serializeError(/* @__PURE__ */ new Error("[vitest-worker]: Worker is already running tests"))
- });
- return;
- }
- try {
- process.env.VITEST_WORKER_ID = String(message.context.workerId);
- } catch (error) {
- return send({
- type: "testfileFinished",
- __vitest_worker_response__,
- error: serializeError(error),
- usedMemory: reportMemory ? memoryUsage().heapUsed : void 0
- });
- }
- isRunning = true;
- try {
- const tracesContext = traces.getContextFromCarrier(message.otelCarrier);
- runPromise = traces.$("vitest.runtime.run", {
- context: tracesContext,
- attributes: {
- "vitest.worker.specifications": traces.isEnabled() ? getFilesWithLocations(message.context.files) : [],
- "vitest.worker.id": message.context.workerId
- }
- }, () => run({
- ...setupContext,
- ...message.context
- }, worker, traces).catch((error) => serializeError(error)));
- send({
- type: "testfileFinished",
- __vitest_worker_response__,
- error: await runPromise,
- usedMemory: reportMemory ? memoryUsage().heapUsed : void 0
- });
- } finally {
- runPromise = void 0;
- isRunning = false;
- }
- break;
- case "collect":
- // Prevent concurrent execution if worker is already running
- if (isRunning) {
- send({
- type: "testfileFinished",
- __vitest_worker_response__,
- error: serializeError(/* @__PURE__ */ new Error("[vitest-worker]: Worker is already running tests"))
- });
- return;
- }
- try {
- process.env.VITEST_WORKER_ID = String(message.context.workerId);
- } catch (error) {
- return send({
- type: "testfileFinished",
- __vitest_worker_response__,
- error: serializeError(error),
- usedMemory: reportMemory ? memoryUsage().heapUsed : void 0
- });
- }
- isRunning = true;
- try {
- const tracesContext = traces.getContextFromCarrier(message.otelCarrier);
- runPromise = traces.$("vitest.runtime.collect", {
- context: tracesContext,
- attributes: {
- "vitest.worker.specifications": traces.isEnabled() ? getFilesWithLocations(message.context.files) : [],
- "vitest.worker.id": message.context.workerId
- }
- }, () => collect({
- ...setupContext,
- ...message.context
- }, worker, traces).catch((error) => serializeError(error)));
- send({
- type: "testfileFinished",
- __vitest_worker_response__,
- error: await runPromise,
- usedMemory: reportMemory ? memoryUsage().heapUsed : void 0
- });
- } finally {
- runPromise = void 0;
- isRunning = false;
- }
- break;
- case "stop":
- await runPromise;
- try {
- const context = traces.getContextFromCarrier(message.otelCarrier);
- const error = await traces.$("vitest.runtime.teardown", { context }, async () => {
- const error = await teardown().catch((error) => serializeError(error));
- await workerTeardown?.();
- return error;
- });
- await traces.finish();
- send({
- type: "stopped",
- error,
- __vitest_worker_response__
- });
- } catch (error) {
- send({
- type: "stopped",
- error: serializeError(error),
- __vitest_worker_response__
- });
- }
- worker.teardown?.();
- break;
- }
- }
-}
-function getFilesWithLocations(files) {
- return files.flatMap((file) => {
- if (!file.testLocations) return file.filepath;
- return file.testLocations.map((location) => {
- return `${file}:${location}`;
- });
- });
-}
-
-export { emitModuleRunner as e, init as i, loadEnvironment as l };
diff --git a/vanilla/node_modules/vitest/dist/chunks/inspector.CvyFGlXm.js b/vanilla/node_modules/vitest/dist/chunks/inspector.CvyFGlXm.js
deleted file mode 100644
index 99fb843..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/inspector.CvyFGlXm.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import { createRequire } from 'node:module';
-import { pathToFileURL } from 'node:url';
-
-const __require = createRequire(import.meta.url);
-let inspector;
-let session;
-/**
-* Enables debugging inside `worker_threads` and `child_process`.
-* Should be called as early as possible when worker/process has been set up.
-*/
-function setupInspect(ctx) {
- const config = ctx.config;
- const isEnabled = config.inspector.enabled;
- if (isEnabled) {
- inspector = __require("node:inspector");
- if (!(inspector.url() !== void 0)) {
- inspector.open(config.inspector.port, config.inspector.host, config.inspector.waitForDebugger);
- if (config.inspectBrk) {
- const firstTestFile = typeof ctx.files[0] === "string" ? ctx.files[0] : ctx.files[0].filepath;
- // Stop at first test file
- if (firstTestFile) {
- session = new inspector.Session();
- session.connect();
- session.post("Debugger.enable");
- session.post("Debugger.setBreakpointByUrl", {
- lineNumber: 0,
- url: pathToFileURL(firstTestFile)
- });
- }
- }
- }
- }
- const keepOpen = shouldKeepOpen(config);
- return function cleanup() {
- if (isEnabled && !keepOpen && inspector) {
- inspector.close();
- session?.disconnect();
- }
- };
-}
-function closeInspector(config) {
- const keepOpen = shouldKeepOpen(config);
- if (inspector && !keepOpen) {
- inspector.close();
- session?.disconnect();
- }
-}
-function shouldKeepOpen(config) {
- // In watch mode the inspector can persist re-runs if isolation is disabled and a single worker is used
- return config.watch && config.isolate === false && config.maxWorkers === 1;
-}
-
-export { closeInspector as c, setupInspect as s };
diff --git a/vanilla/node_modules/vitest/dist/chunks/modules.BJuCwlRJ.js b/vanilla/node_modules/vitest/dist/chunks/modules.BJuCwlRJ.js
deleted file mode 100644
index 3156848..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/modules.BJuCwlRJ.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import { builtinModules } from 'node:module';
-
-// copied from vite
-// https://github.com/vitejs/vite/blob/814120f2ad387ca3d1e16c7dd403b04ca4b97f75/packages/vite/src/node/utils.ts#L106
-// Supported by Node, Deno, Bun
-const NODE_BUILTIN_NAMESPACE = "node:";
-// Supported by Deno
-const NPM_BUILTIN_NAMESPACE = "npm:";
-// Supported by Bun
-const BUN_BUILTIN_NAMESPACE = "bun:";
-// Some runtimes like Bun injects namespaced modules here, which is not a node builtin
-const nodeBuiltins = builtinModules.filter((id) => !id.includes(":"));
-const { bun: isBun, deno: isDeno } = process.versions;
-// TODO: Use `isBuiltin` from `node:module`, but Deno doesn't support it
-function isBuiltin(id) {
- if (isDeno && id.startsWith(NPM_BUILTIN_NAMESPACE)) return true;
- if (isBun && id.startsWith(BUN_BUILTIN_NAMESPACE)) return true;
- return isNodeBuiltin(id);
-}
-function isNodeBuiltin(id) {
- if (id.startsWith(NODE_BUILTIN_NAMESPACE)) return true;
- return nodeBuiltins.includes(id);
-}
-const browserExternalId = "__vite-browser-external";
-const browserExternalLength = 24;
-function isBrowserExternal(id) {
- return id.startsWith(browserExternalId);
-}
-function toBuiltin(id) {
- if (id.startsWith(browserExternalId)) id = id.slice(browserExternalLength);
- if (id.startsWith(NPM_BUILTIN_NAMESPACE) || id.startsWith(BUN_BUILTIN_NAMESPACE) || id.startsWith(NODE_BUILTIN_NAMESPACE)) return id;
- if (isDeno || isBun) return id;
- return `node:${id}`;
-}
-
-export { isBrowserExternal as a, isBuiltin as i, toBuiltin as t };
diff --git a/vanilla/node_modules/vitest/dist/chunks/node.Ce0vMQM7.js b/vanilla/node_modules/vitest/dist/chunks/node.Ce0vMQM7.js
deleted file mode 100644
index 79dbbe2..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/node.Ce0vMQM7.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import { NodeSnapshotEnvironment } from '@vitest/snapshot/environment';
-import { g as getWorkerState } from './utils.DvEY5TfP.js';
-import '@vitest/utils/timers';
-
-class VitestNodeSnapshotEnvironment extends NodeSnapshotEnvironment {
- getHeader() {
- return `// Vitest Snapshot v${this.getVersion()}, https://vitest.dev/guide/snapshot.html`;
- }
- resolvePath(filepath) {
- return getWorkerState().rpc.resolveSnapshotPath(filepath);
- }
-}
-
-export { VitestNodeSnapshotEnvironment };
diff --git a/vanilla/node_modules/vitest/dist/chunks/plugin.d.CtqpEehP.d.ts b/vanilla/node_modules/vitest/dist/chunks/plugin.d.CtqpEehP.d.ts
deleted file mode 100644
index 4955bd8..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/plugin.d.CtqpEehP.d.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { DevEnvironment } from 'vite';
-import { V as Vitest, T as TestProject, b as TestProjectConfiguration } from './reporters.d.CWXNI2jG.js';
-
-/**
-* Generate a unique cache identifier.
-*
-* Return `false` to disable caching of the file.
-* @experimental
-*/
-interface CacheKeyIdGenerator {
- (context: CacheKeyIdGeneratorContext): string | undefined | null | false;
-}
-/**
-* @experimental
-*/
-interface CacheKeyIdGeneratorContext {
- environment: DevEnvironment;
- id: string;
- sourceCode: string;
-}
-
-interface VitestPluginContext {
- vitest: Vitest;
- project: TestProject;
- injectTestProjects: (config: TestProjectConfiguration | TestProjectConfiguration[]) => Promise<TestProject[]>;
- /**
- * Define a generator that will be applied before hashing the cache key.
- *
- * Use this to make sure Vitest generates correct hash. It is a good idea
- * to define this function if your plugin can be registered with different options.
- *
- * This is called only if `experimental.fsModuleCache` is defined.
- * @experimental
- */
- experimental_defineCacheKeyGenerator: (callback: CacheKeyIdGenerator) => void;
-}
-
-export type { CacheKeyIdGenerator as C, VitestPluginContext as V, CacheKeyIdGeneratorContext as a };
diff --git a/vanilla/node_modules/vitest/dist/chunks/reporters.d.CWXNI2jG.d.ts b/vanilla/node_modules/vitest/dist/chunks/reporters.d.CWXNI2jG.d.ts
deleted file mode 100644
index 3eee24b..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/reporters.d.CWXNI2jG.d.ts
+++ /dev/null
@@ -1,3271 +0,0 @@
-import { TaskMeta, Suite, File, TestAnnotation, TestArtifact, ImportDuration, Test, Task, TaskResultPack, FileSpecification, CancelReason, SequenceSetupFiles, SequenceHooks } from '@vitest/runner';
-import { TestError, SerializedError, Arrayable, ParsedStack, Awaitable } from '@vitest/utils';
-import { A as AfterSuiteRunMeta, U as UserConsoleLog, P as ProvidedContext, L as LabelColor } from './rpc.d.RH3apGEf.js';
-import { Writable } from 'node:stream';
-import { DevEnvironment, TransformResult as TransformResult$1, ViteDevServer, Plugin, UserConfig as UserConfig$1, DepOptimizationConfig, ServerOptions, ConfigEnv, AliasOptions } from 'vite';
-import { S as SerializedTestSpecification, c as SourceModuleDiagnostic, B as BrowserTesterOptions } from './browser.d.ChKACdzH.js';
-import { MockedModule } from '@vitest/mocker';
-import { StackTraceParserOptions } from '@vitest/utils/source-map';
-import { BrowserCommands } from 'vitest/browser';
-import { B as BrowserTraceViewMode, S as SerializedConfig, F as FakeTimerInstallOpts } from './config.d.Cy95HiCx.js';
-import { PrettyFormatOptions } from '@vitest/pretty-format';
-import { SnapshotSummary, SnapshotStateOptions } from '@vitest/snapshot';
-import { SerializedDiffOptions } from '@vitest/utils/diff';
-import { chai } from '@vitest/expect';
-import { happyDomTypes, jsdomTypes } from 'vitest/optional-types.js';
-import { c as ContextTestEnvironment, d as WorkerExecuteContext, e as WorkerTestEnvironment } from './worker.d.Dyxm8DEL.js';
-import { O as OTELCarrier } from './traces.d.402V_yFI.js';
-import { B as BenchmarkResult } from './benchmark.d.DAaHLpsq.js';
-import { a as RuntimeCoverageProviderModule } from './coverage.d.BZtK59WP.js';
-import { SnapshotManager } from '@vitest/snapshot/manager';
-import { Console } from 'node:console';
-import { Stats } from 'node:fs';
-
-type ChaiConfig = Omit<Partial<typeof chai.config>, "useProxy" | "proxyExcludedKeys">;
-
-type HappyDOMOptions = Omit<NonNullable<ConstructorParameters<typeof happyDomTypes.Window>[0]>, "console">;
-
-type JSDOMOptions = ConstructorOptionsOverride & Omit<jsdomTypes.ConstructorOptions, keyof ConstructorOptionsOverride>;
-interface ConstructorOptionsOverride {
- /**
- * The html content for the test.
- *
- * @default '<!DOCTYPE html>'
- */
- html?: string | ArrayBufferLike;
- /**
- * userAgent affects the value read from navigator.userAgent, as well as the User-Agent header sent while fetching subresources.
- *
- * @default `Mozilla/5.0 (${process.platform}) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/${jsdomVersion}`
- */
- userAgent?: string;
- /**
- * url sets the value returned by window.location, document.URL, and document.documentURI,
- * and affects things like resolution of relative URLs within the document
- * and the same-origin restrictions and referrer used while fetching subresources.
- *
- * @default 'http://localhost:3000'.
- */
- url?: string;
- /**
- * Enable console?
- *
- * @default false
- */
- console?: boolean;
- /**
- * jsdom does not have the capability to render visual content, and will act like a headless browser by default.
- * It provides hints to web pages through APIs such as document.hidden that their content is not visible.
- *
- * When the `pretendToBeVisual` option is set to `true`, jsdom will pretend that it is rendering and displaying
- * content.
- *
- * @default true
- */
- pretendToBeVisual?: boolean;
- /**
- * Enable CookieJar
- *
- * @default false
- */
- cookieJar?: boolean;
- resources?: "usable";
-}
-
-declare class ReportedTaskImplementation {
- /**
- * The project associated with the test or suite.
- */
- readonly project: TestProject;
- /**
- * Unique identifier.
- * This ID is deterministic and will be the same for the same test across multiple runs.
- * The ID is based on the project name, module url and test order.
- */
- readonly id: string;
- /**
- * Location in the module where the test or suite is defined.
- */
- readonly location: {
- line: number;
- column: number;
- } | undefined;
- /**
- * Checks if the test did not fail the suite.
- * If the test is not finished yet or was skipped, it will return `true`.
- */
- ok(): boolean;
- /**
- * Custom metadata that was attached to the test during its execution.
- */
- meta(): TaskMeta;
-}
-declare class TestCase extends ReportedTaskImplementation {
- #private;
- readonly type = "test";
- /**
- * Direct reference to the test module where the test or suite is defined.
- */
- readonly module: TestModule;
- /**
- * Name of the test.
- */
- readonly name: string;
- /**
- * Options that the test was initiated with.
- */
- readonly options: TaskOptions;
- /**
- * Parent suite. If the test was called directly inside the module, the parent will be the module itself.
- */
- readonly parent: TestSuite | TestModule;
- /**
- * Full name of the test including all parent suites separated with `>`.
- */
- get fullName(): string;
- /**
- * Test results.
- * - **pending**: Test was collected, but didn't finish running yet.
- * - **passed**: Test passed successfully
- * - **failed**: Test failed to execute
- * - **skipped**: Test was skipped during collection or dynamically with `ctx.skip()`.
- */
- result(): TestResult;
- /**
- * Test annotations added via the `task.annotate` API during the test execution.
- */
- annotations(): ReadonlyArray<TestAnnotation>;
- /**
- * @experimental
- *
- * Test artifacts recorded via the `recordArtifact` API during the test execution.
- */
- artifacts(): ReadonlyArray<TestArtifact>;
- /**
- * Useful information about the test like duration, memory usage, etc.
- * Diagnostic is only available after the test has finished.
- */
- diagnostic(): TestDiagnostic | undefined;
-}
-declare class TestCollection {
- #private;
- constructor(task: Suite | File, project: TestProject);
- /**
- * Returns the test or suite at a specific index.
- */
- at(index: number): TestCase | TestSuite | undefined;
- /**
- * The number of tests and suites in the collection.
- */
- get size(): number;
- /**
- * Returns the collection in array form for easier manipulation.
- */
- array(): (TestCase | TestSuite)[];
- /**
- * Filters all tests that are part of this collection and its children.
- */
- allTests(state?: TestState): Generator<TestCase, undefined, void>;
- /**
- * Filters only the tests that are part of this collection.
- */
- tests(state?: TestState): Generator<TestCase, undefined, void>;
- /**
- * Filters only the suites that are part of this collection.
- */
- suites(): Generator<TestSuite, undefined, void>;
- /**
- * Filters all suites that are part of this collection and its children.
- */
- allSuites(): Generator<TestSuite, undefined, void>;
- [Symbol.iterator](): Generator<TestSuite | TestCase, undefined, void>;
-}
-
-type ReportedHookContext = {
- readonly name: "beforeAll" | "afterAll";
- readonly entity: TestSuite | TestModule;
-} | {
- readonly name: "beforeEach" | "afterEach";
- readonly entity: TestCase;
-};
-declare abstract class SuiteImplementation extends ReportedTaskImplementation {
- /**
- * Collection of suites and tests that are part of this suite.
- */
- readonly children: TestCollection;
- /**
- * Errors that happened outside of the test run during collection, like syntax errors.
- */
- errors(): SerializedError[];
-}
-declare class TestSuite extends SuiteImplementation {
- #private;
- readonly type = "suite";
- /**
- * Name of the test or the suite.
- */
- readonly name: string;
- /**
- * Direct reference to the test module where the test or suite is defined.
- */
- readonly module: TestModule;
- /**
- * Parent suite. If suite was called directly inside the module, the parent will be the module itself.
- */
- readonly parent: TestSuite | TestModule;
- /**
- * Options that suite was initiated with.
- */
- readonly options: TaskOptions;
- /**
- * Checks if the suite has any failed tests.
- * This will also return `false` if suite failed during collection.
- */
- ok: () => boolean;
- /**
- * The meta information attached to the suite during its collection or execution.
- */
- meta: () => TaskMeta;
- /**
- * Checks the running state of the suite.
- */
- state(): TestSuiteState;
- /**
- * Full name of the suite including all parent suites separated with `>`.
- */
- get fullName(): string;
-}
-declare class TestModule extends SuiteImplementation {
- readonly location: undefined;
- readonly type = "module";
- /**
- * The Vite environment that processes files on the server.
- *
- * Can be empty if test module did not run yet.
- */
- readonly viteEnvironment: DevEnvironment | undefined;
- /**
- * This is usually an absolute UNIX file path.
- * It can be a virtual ID if the file is not on the disk.
- * This value corresponds to the ID in the Vite's module graph.
- */
- readonly moduleId: string;
- /**
- * Module id relative to the project. This is the same as `task.name`.
- */
- readonly relativeModuleId: string;
- /**
- * Checks the running state of the test file.
- */
- state(): TestModuleState;
- /**
- * Checks if the module has any failed tests.
- * This will also return `false` if module failed during collection.
- */
- ok: () => boolean;
- /**
- * The meta information attached to the module during its collection or execution.
- */
- meta: () => TaskMeta;
- /**
- * Useful information about the module like duration, memory usage, etc.
- * If the module was not executed yet, all diagnostic values will return `0`.
- */
- diagnostic(): ModuleDiagnostic;
-}
-interface TaskOptions {
- readonly each: boolean | undefined;
- readonly fails: boolean | undefined;
- readonly concurrent: boolean | undefined;
- readonly shuffle: boolean | undefined;
- readonly retry: number | undefined;
- readonly repeats: number | undefined;
- readonly mode: "run" | "only" | "skip" | "todo";
-}
-type TestSuiteState = "skipped" | "pending" | "failed" | "passed";
-type TestModuleState = TestSuiteState | "queued";
-type TestState = TestResult["state"];
-type TestResult = TestResultPassed | TestResultFailed | TestResultSkipped | TestResultPending;
-interface TestResultPending {
- /**
- * The test was collected, but didn't finish running yet.
- */
- readonly state: "pending";
- /**
- * Pending tests have no errors.
- */
- readonly errors: undefined;
-}
-interface TestResultPassed {
- /**
- * The test passed successfully.
- */
- readonly state: "passed";
- /**
- * Errors that were thrown during the test execution.
- *
- * **Note**: If test was retried successfully, errors will still be reported.
- */
- readonly errors: ReadonlyArray<TestError> | undefined;
-}
-interface TestResultFailed {
- /**
- * The test failed to execute.
- */
- readonly state: "failed";
- /**
- * Errors that were thrown during the test execution.
- */
- readonly errors: ReadonlyArray<TestError>;
-}
-interface TestResultSkipped {
- /**
- * The test was skipped with `only` (on another test), `skip` or `todo` flag.
- * You can see which one was used in the `options.mode` option.
- */
- readonly state: "skipped";
- /**
- * Skipped tests have no errors.
- */
- readonly errors: undefined;
- /**
- * A custom note passed down to `ctx.skip(note)`.
- */
- readonly note: string | undefined;
-}
-interface TestDiagnostic {
- /**
- * If the duration of the test is above `slowTestThreshold`.
- */
- readonly slow: boolean;
- /**
- * The amount of memory used by the test in bytes.
- * This value is only available if the test was executed with `logHeapUsage` flag.
- */
- readonly heap: number | undefined;
- /**
- * The time it takes to execute the test in ms.
- */
- readonly duration: number;
- /**
- * The time in ms when the test started.
- */
- readonly startTime: number;
- /**
- * The amount of times the test was retried.
- */
- readonly retryCount: number;
- /**
- * The amount of times the test was repeated as configured by `repeats` option.
- * This value can be lower if the test failed during the repeat and no `retry` is configured.
- */
- readonly repeatCount: number;
- /**
- * If test passed on a second retry.
- */
- readonly flaky: boolean;
-}
-interface ModuleDiagnostic {
- /**
- * The time it takes to import and initiate an environment.
- */
- readonly environmentSetupDuration: number;
- /**
- * The time it takes Vitest to setup test harness (runner, mocks, etc.).
- */
- readonly prepareDuration: number;
- /**
- * The time it takes to import the test module.
- * This includes importing everything in the module and executing suite callbacks.
- */
- readonly collectDuration: number;
- /**
- * The time it takes to import the setup module.
- */
- readonly setupDuration: number;
- /**
- * Accumulated duration of all tests and hooks in the module.
- */
- readonly duration: number;
- /**
- * The amount of memory used by the test module in bytes.
- * This value is only available if the test was executed with `logHeapUsage` flag.
- */
- readonly heap: number | undefined;
- /**
- * The time spent importing every non-externalized dependency that Vitest has processed.
- */
- readonly importDurations: Record<string, ImportDuration>;
-}
-declare function experimental_getRunnerTask(entity: TestCase): Test;
-declare function experimental_getRunnerTask(entity: TestSuite): Suite;
-declare function experimental_getRunnerTask(entity: TestModule): File;
-declare function experimental_getRunnerTask(entity: TestCase | TestSuite | TestModule): Suite | File | Test;
-
-declare class TestSpecification {
- /**
- * The task ID associated with the test module.
- */
- readonly taskId: string;
- /**
- * The test project that the module belongs to.
- */
- readonly project: TestProject;
- /**
- * The ID of the module in the Vite module graph. It is usually an absolute file path.
- */
- readonly moduleId: string;
- /**
- * The current test pool. It's possible to have multiple pools in a single test project with `poolMatchGlob` and `typecheck.enabled`.
- * @experimental In Vitest 4, the project will only support a single pool and this property will be removed.
- */
- readonly pool: Pool;
- /**
- * Line numbers of the test locations to run.
- */
- readonly testLines: number[] | undefined;
- constructor(project: TestProject, moduleId: string, pool: Pool, testLines?: number[] | undefined);
- /**
- * Test module associated with the specification.
- */
- get testModule(): TestModule | undefined;
- toJSON(): SerializedTestSpecification;
-}
-
-interface CoverageSummaryData {
- lines: Totals;
- statements: Totals;
- branches: Totals;
- functions: Totals;
-}
-
-declare class CoverageSummary {
- constructor(data: CoverageSummary | CoverageSummaryData);
- merge(obj: CoverageSummary): CoverageSummary;
- toJSON(): CoverageSummaryData;
- isEmpty(): boolean;
- data: CoverageSummaryData;
- lines: Totals;
- statements: Totals;
- branches: Totals;
- functions: Totals;
-}
-
-interface CoverageMapData {
- [key: string]: FileCoverage | FileCoverageData;
-}
-
-declare class CoverageMap {
- constructor(data: CoverageMapData | CoverageMap);
- addFileCoverage(pathOrObject: string | FileCoverage | FileCoverageData): void;
- files(): string[];
- fileCoverageFor(filename: string): FileCoverage;
- filter(callback: (key: string) => boolean): void;
- getCoverageSummary(): CoverageSummary;
- merge(data: CoverageMapData | CoverageMap): void;
- toJSON(): CoverageMapData;
- data: CoverageMapData;
-}
-
-interface Location {
- line: number;
- column: number;
-}
-
-interface Range {
- start: Location;
- end: Location;
-}
-
-interface BranchMapping {
- loc: Range;
- type: string;
- locations: Range[];
- line: number;
-}
-
-interface FunctionMapping {
- name: string;
- decl: Range;
- loc: Range;
- line: number;
-}
-
-interface FileCoverageData {
- path: string;
- statementMap: { [key: string]: Range };
- fnMap: { [key: string]: FunctionMapping };
- branchMap: { [key: string]: BranchMapping };
- s: { [key: string]: number };
- f: { [key: string]: number };
- b: { [key: string]: number[] };
-}
-
-interface Totals {
- total: number;
- covered: number;
- skipped: number;
- pct: number;
-}
-
-interface Coverage {
- covered: number;
- total: number;
- coverage: number;
-}
-
-declare class FileCoverage implements FileCoverageData {
- constructor(data: string | FileCoverage | FileCoverageData);
- merge(other: FileCoverageData): void;
- getBranchCoverageByLine(): { [line: number]: Coverage };
- getLineCoverage(): { [line: number]: number };
- getUncoveredLines(): number[];
- resetHits(): void;
- computeBranchTotals(): Totals;
- computeSimpleTotals(): Totals;
- toSummary(): CoverageSummary;
- toJSON(): object;
-
- data: FileCoverageData;
- path: string;
- statementMap: { [key: string]: Range };
- fnMap: { [key: string]: FunctionMapping };
- branchMap: { [key: string]: BranchMapping };
- s: { [key: string]: number };
- f: { [key: string]: number };
- b: { [key: string]: number[] };
-}
-
-interface Node {
- isRoot(): boolean;
- visit(visitor: Visitor, state: any): void;
-}
-
-interface Visitor<N extends Node = Node> {
- onStart(root: N, state: any): void;
- onSummary(root: N, state: any): void;
- onDetail(root: N, state: any): void;
- onSummaryEnd(root: N, state: any): void;
- onEnd(root: N, state: any): void;
-}
-
-interface FileOptions {
- file: string;
-}
-
-interface ProjectOptions {
- projectRoot: string;
-}
-
-interface ReportOptions {
- clover: CloverOptions;
- cobertura: CoberturaOptions;
- "html-spa": HtmlSpaOptions;
- html: HtmlOptions;
- json: JsonOptions$1;
- "json-summary": JsonSummaryOptions;
- lcov: LcovOptions;
- lcovonly: LcovOnlyOptions;
- none: never;
- teamcity: TeamcityOptions;
- text: TextOptions;
- "text-lcov": TextLcovOptions;
- "text-summary": TextSummaryOptions;
-}
-
-interface CloverOptions extends FileOptions, ProjectOptions {}
-
-interface CoberturaOptions extends FileOptions, ProjectOptions {}
-
-interface HtmlSpaOptions extends HtmlOptions {
- metricsToShow: Array<"lines" | "branches" | "functions" | "statements">;
-}
-interface HtmlOptions {
- verbose: boolean;
- skipEmpty: boolean;
- subdir: string;
- linkMapper: LinkMapper;
-}
-
-type JsonOptions$1 = FileOptions;
-type JsonSummaryOptions = FileOptions;
-
-interface LcovOptions extends FileOptions, ProjectOptions {}
-interface LcovOnlyOptions extends FileOptions, ProjectOptions {}
-
-interface TeamcityOptions extends FileOptions {
- blockName: string;
-}
-
-interface TextOptions extends FileOptions {
- maxCols: number;
- skipEmpty: boolean;
- skipFull: boolean;
-}
-type TextLcovOptions = ProjectOptions;
-type TextSummaryOptions = FileOptions;
-
-interface LinkMapper {
- getPath(node: string | Node): string;
- relativePath(source: string | Node, target: string | Node): string;
- assetPath(node: Node, name: string): string;
-}
-
-type TransformResult = string | Partial<TransformResult$1> | undefined | null | void;
-type CoverageResults = unknown;
-interface CoverageProvider {
- name: string;
- /** Called when provider is being initialized before tests run */
- initialize: (ctx: Vitest) => Promise<void> | void;
- /** Called when setting coverage options for Vitest context (`ctx.config.coverage`) */
- resolveOptions: () => ResolvedCoverageOptions;
- /** Callback to clean previous reports */
- clean: (clean?: boolean) => void | Promise<void>;
- /** Called with coverage results after a single test file has been run */
- onAfterSuiteRun: (meta: AfterSuiteRunMeta) => void | Promise<void>;
- /** Callback called when test run fails */
- onTestFailure?: () => void | Promise<void>;
- /** Callback to generate final coverage results */
- generateCoverage: (reportContext: ReportContext) => CoverageResults | Promise<CoverageResults>;
- /** Callback to convert coverage results to coverage reports. Called with results returned from `generateCoverage` */
- reportCoverage: (coverage: CoverageResults, reportContext: ReportContext) => void | Promise<void>;
- /** Callback for `--merge-reports` options. Called with multiple coverage results generated by `generateCoverage`. */
- mergeReports?: (coverages: CoverageResults[]) => void | Promise<void>;
- /** Callback called for instrumenting files with coverage counters. */
- onFileTransform?: (sourceCode: string, id: string, pluginCtx: any) => TransformResult | Promise<TransformResult>;
- /**
- * Return `true` if this file is transformed by the coverage provider.
- * This is used to generate the persistent file hash by `fsModuleCache`
- * @experimental
- */
- requiresTransform?: (id: string) => boolean;
- /** Callback that's called when the coverage is enabled via a programmatic `enableCoverage` API. */
- onEnabled?: () => void | Promise<void>;
-}
-interface ReportContext {
- /** Indicates whether all tests were run. False when only specific tests were run. */
- allTestsRun?: boolean;
-}
-interface CoverageProviderModule extends RuntimeCoverageProviderModule {
- /**
- * Factory for creating a new coverage provider
- */
- getProvider: () => CoverageProvider | Promise<CoverageProvider>;
-}
-type CoverageReporter = keyof ReportOptions | (string & {});
-type CoverageReporterWithOptions<ReporterName extends CoverageReporter = CoverageReporter> = ReporterName extends keyof ReportOptions ? ReportOptions[ReporterName] extends never ? [ReporterName, object] : [ReporterName, Partial<ReportOptions[ReporterName]>] : [ReporterName, Record<string, unknown>];
-type CoverageProviderName = "v8" | "istanbul" | "custom" | undefined;
-type CoverageOptions<T extends CoverageProviderName = CoverageProviderName> = T extends "istanbul" ? {
- provider: T;
-} & CoverageIstanbulOptions : T extends "v8" ? {
- /**
- * Provider to use for coverage collection.
- *
- * @default 'v8'
- */
- provider: T;
-} & CoverageV8Options : T extends "custom" ? {
- provider: T;
-} & CustomProviderOptions : {
- provider?: T;
-} & CoverageV8Options;
-/** Fields that have default values. Internally these will always be defined. */
-type FieldsWithDefaultValues = "enabled" | "clean" | "cleanOnRerun" | "reportsDirectory" | "exclude" | "reportOnFailure" | "allowExternal" | "processingConcurrency";
-type ResolvedCoverageOptions<T extends CoverageProviderName = CoverageProviderName> = CoverageOptions<T> & Required<Pick<CoverageOptions<T>, FieldsWithDefaultValues>> & {
- reporter: CoverageReporterWithOptions[];
-};
-interface BaseCoverageOptions {
- /**
- * Enables coverage collection. Can be overridden using `--coverage` CLI option.
- *
- * @default false
- */
- enabled?: boolean;
- /**
- * List of files included in coverage as glob patterns.
- * By default only files covered by tests are included.
- *
- * See [Including and excluding files from coverage report](https://vitest.dev/guide/coverage.html#including-and-excluding-files-from-coverage-report) for examples.
- */
- include?: string[];
- /**
- * List of files excluded from coverage as glob patterns.
- * Files are first checked against `coverage.include`.
- *
- * See [Including and excluding files from coverage report](https://vitest.dev/guide/coverage.html#including-and-excluding-files-from-coverage-report) for examples.
- */
- exclude?: string[];
- /**
- * Clean coverage results before running tests
- *
- * @default true
- */
- clean?: boolean;
- /**
- * Clean coverage report on watch rerun
- *
- * @default true
- */
- cleanOnRerun?: boolean;
- /**
- * Directory to write coverage report to
- *
- * @default './coverage'
- */
- reportsDirectory?: string;
- /**
- * Coverage reporters to use.
- * See [istanbul documentation](https://istanbul.js.org/docs/advanced/alternative-reporters/) for detailed list of all reporters.
- *
- * @default ['text', 'html', 'clover', 'json']
- */
- reporter?: Arrayable<CoverageReporter> | (CoverageReporter | [CoverageReporter] | CoverageReporterWithOptions)[];
- /**
- * Do not show files with 100% statement, branch, and function coverage
- *
- * @default false
- */
- skipFull?: boolean;
- /**
- * Configurations for thresholds
- *
- * @example
- *
- * ```ts
- * {
- * // Thresholds for all files
- * functions: 95,
- * branches: 70,
- * perFile: true,
- * autoUpdate: true,
- *
- * // Thresholds for utilities
- * 'src/utils/**.ts': {
- * lines: 100,
- * statements: 95,
- * }
- * }
- * ```
- */
- thresholds?: Thresholds | ({
- [glob: string]: Pick<Thresholds, 100 | "statements" | "functions" | "branches" | "lines">;
- } & Thresholds);
- /**
- * Watermarks for statements, lines, branches and functions.
- *
- * Default value is `[50,80]` for each property.
- */
- watermarks?: {
- statements?: [number, number];
- functions?: [number, number];
- branches?: [number, number];
- lines?: [number, number];
- };
- /**
- * Generate coverage report even when tests fail.
- *
- * @default false
- */
- reportOnFailure?: boolean;
- /**
- * Collect coverage of files outside the project `root`.
- *
- * @default false
- */
- allowExternal?: boolean;
- /**
- * Apply exclusions again after coverage has been remapped to original sources.
- * This is useful when your source files are transpiled and may contain source maps
- * of non-source files.
- *
- * Use this option when you are seeing files that show up in report even if they
- * match your `coverage.exclude` patterns.
- *
- * @default false
- */
- excludeAfterRemap?: boolean;
- /**
- * Concurrency limit used when processing the coverage results.
- * Defaults to `Math.min(20, os.availableParallelism?.() ?? os.cpus().length)`
- */
- processingConcurrency?: number;
- /**
- * Set to array of class method names to ignore for coverage
- *
- * @default []
- */
- ignoreClassMethods?: string[];
-}
-interface CoverageIstanbulOptions extends BaseCoverageOptions {}
-interface CoverageV8Options extends BaseCoverageOptions {}
-interface CustomProviderOptions extends Pick<BaseCoverageOptions, FieldsWithDefaultValues> {
- /** Name of the module or path to a file to load the custom provider from */
- customProviderModule: string;
-}
-interface Thresholds {
- /** Set global thresholds to `100` */
- 100?: boolean;
- /** Check thresholds per file. */
- perFile?: boolean;
- /**
- * Update threshold values automatically when current coverage is higher than earlier thresholds
- * Also can accept a function to format the new threshold values
- *
- * @default false
- */
- autoUpdate?: boolean | ((newThreshold: number) => number);
- /** Thresholds for statements */
- statements?: number;
- /** Thresholds for functions */
- functions?: number;
- /** Thresholds for branches */
- branches?: number;
- /** Thresholds for lines */
- lines?: number;
-}
-
-interface TestRunResult {
- testModules: TestModule[];
- unhandledErrors: unknown[];
-}
-
-declare class TypeCheckError extends Error {
- message: string;
- stacks: ParsedStack[];
- name: string;
- constructor(message: string, stacks: ParsedStack[]);
-}
-
-interface ErrorOptions {
- type?: string;
- fullStack?: boolean;
- project?: TestProject;
- verbose?: boolean;
- screenshotPaths?: string[];
- task?: Task;
- showCodeFrame?: boolean;
-}
-type Listener = () => void;
-declare class Logger {
- ctx: Vitest;
- outputStream: NodeJS.WriteStream | Writable;
- errorStream: NodeJS.WriteStream | Writable;
- private _clearScreenPending;
- private _highlights;
- private cleanupListeners;
- console: Console;
- constructor(ctx: Vitest, outputStream?: NodeJS.WriteStream | Writable, errorStream?: NodeJS.WriteStream | Writable);
- log(...args: any[]): void;
- error(...args: any[]): void;
- warn(...args: any[]): void;
- clearFullScreen(message?: string): void;
- clearScreen(message: string, force?: boolean): void;
- private _clearScreen;
- printError(err: unknown, options?: ErrorOptions): void;
- deprecate(message: string): void;
- clearHighlightCache(filename?: string): void;
- highlight(filename: string, source: string): string;
- printNoTestFound(filters?: string[]): void;
- printBanner(): void;
- printBrowserBanner(project: TestProject): void;
- printUnhandledErrors(errors: ReadonlyArray<unknown>): void;
- printSourceTypeErrors(errors: TypeCheckError[]): void;
- getColumns(): number;
- onTerminalCleanup(listener: Listener): void;
- private addCleanupListeners;
- private registerUnhandledRejection;
-}
-
-interface SuiteResultCache {
- failed: boolean;
- duration: number;
-}
-declare class ResultsCache {
- private logger;
- private cache;
- private workspacesKeyMap;
- private cachePath;
- private version;
- private root;
- constructor(logger: Logger);
- getCachePath(): string | null;
- setConfig(root: string, config: ResolvedConfig["cache"]): void;
- getResults(key: string): SuiteResultCache | undefined;
- clearCache(): Promise<void>;
- readFromCache(): Promise<void>;
- updateResults(files: File[]): void;
- removeFromCache(filepath: string): void;
- writeToCache(): Promise<void>;
-}
-
-type FileStatsCache = Pick<Stats, "size">;
-declare class FilesStatsCache {
- cache: Map<string, FileStatsCache>;
- getStats(key: string): FileStatsCache | undefined;
- populateStats(root: string, specs: TestSpecification[]): Promise<void>;
- updateStats(fsPath: string, key: string): Promise<void>;
- removeStats(fsPath: string): void;
-}
-
-declare class VitestCache {
- results: ResultsCache;
- stats: FilesStatsCache;
- constructor(logger: Logger);
- getFileTestResults(key: string): SuiteResultCache | undefined;
- getFileStats(key: string): {
- size: number;
- } | undefined;
- static resolveCacheDir(root: string, dir?: string, projectName?: string): string;
-}
-
-declare class VitestPackageInstaller {
- isPackageExists(name: string, options?: {
- paths?: string[];
- }): boolean;
- ensureInstalled(dependency: string, root: string, version?: string): Promise<boolean>;
-}
-
-type TestRunEndReason = "passed" | "interrupted" | "failed";
-interface Reporter {
- onInit?: (vitest: Vitest) => void;
- /**
- * Called when the project initiated the browser instance.
- * project.browser will always be defined.
- * @experimental
- */
- onBrowserInit?: (project: TestProject) => Awaitable<void>;
- onTestRemoved?: (trigger?: string) => Awaitable<void>;
- onWatcherStart?: (files?: File[], errors?: unknown[]) => Awaitable<void>;
- onWatcherRerun?: (files: string[], trigger?: string) => Awaitable<void>;
- onServerRestart?: (reason?: string) => Awaitable<void>;
- onUserConsoleLog?: (log: UserConsoleLog) => Awaitable<void>;
- onProcessTimeout?: () => Awaitable<void>;
- /**
- * Called when the new test run starts.
- */
- onTestRunStart?: (specifications: ReadonlyArray<TestSpecification>) => Awaitable<void>;
- /**
- * Called when the test run is finished.
- */
- onTestRunEnd?: (testModules: ReadonlyArray<TestModule>, unhandledErrors: ReadonlyArray<SerializedError>, reason: TestRunEndReason) => Awaitable<void>;
- /**
- * Called when the module is enqueued for testing. The file itself is not loaded yet.
- */
- onTestModuleQueued?: (testModule: TestModule) => Awaitable<void>;
- /**
- * Called when the test file is loaded and the module is ready to run tests.
- */
- onTestModuleCollected?: (testModule: TestModule) => Awaitable<void>;
- /**
- * Called when starting to run tests of the test file
- */
- onTestModuleStart?: (testModule: TestModule) => Awaitable<void>;
- /**
- * Called when all tests of the test file have finished running.
- */
- onTestModuleEnd?: (testModule: TestModule) => Awaitable<void>;
- /**
- * Called when test case is ready to run.
- * Called before the `beforeEach` hooks for the test are run.
- */
- onTestCaseReady?: (testCase: TestCase) => Awaitable<void>;
- /**
- * Called after the test and its hooks are finished running.
- * The `result()` cannot be `pending`.
- */
- onTestCaseResult?: (testCase: TestCase) => Awaitable<void>;
- /**
- * Called when annotation is added via the `task.annotate` API.
- */
- onTestCaseAnnotate?: (testCase: TestCase, annotation: TestAnnotation) => Awaitable<void>;
- /**
- * Called when artifacts are recorded on tests via the `recordArtifact` utility.
- */
- onTestCaseArtifactRecord?: (testCase: TestCase, artifact: TestArtifact) => Awaitable<void>;
- /**
- * Called when test suite is ready to run.
- * Called before the `beforeAll` hooks for the test are run.
- */
- onTestSuiteReady?: (testSuite: TestSuite) => Awaitable<void>;
- /**
- * Called after the test suite and its hooks are finished running.
- * The `state` cannot be `pending`.
- */
- onTestSuiteResult?: (testSuite: TestSuite) => Awaitable<void>;
- /**
- * Called before the hook starts to run.
- */
- onHookStart?: (hook: ReportedHookContext) => Awaitable<void>;
- /**
- * Called after the hook finished running.
- */
- onHookEnd?: (hook: ReportedHookContext) => Awaitable<void>;
- onCoverage?: (coverage: unknown) => Awaitable<void>;
-}
-
-interface BlobOptions {
- outputFile?: string;
-}
-declare class BlobReporter implements Reporter {
- start: number;
- ctx: Vitest;
- options: BlobOptions;
- coverage: unknown | undefined;
- constructor(options: BlobOptions);
- onInit(ctx: Vitest): void;
- onCoverage(coverage: unknown): void;
- onTestRunEnd(testModules: ReadonlyArray<TestModule>, unhandledErrors: ReadonlyArray<SerializedError>): Promise<void>;
-}
-interface MergedBlobs {
- files: File[];
- errors: unknown[];
- coverages: unknown[];
- executionTimes: number[];
-}
-
-declare class StateManager {
- filesMap: Map<string, File[]>;
- pathsSet: Set<string>;
- idMap: Map<string, Task>;
- taskFileMap: WeakMap<Task, File>;
- errorsSet: Set<unknown>;
- reportedTasksMap: WeakMap<Task, TestModule | TestCase | TestSuite>;
- blobs?: MergedBlobs;
- transformTime: number;
- metadata: Record<string, {
- externalized: Record<string, string>;
- duration: Record<string, number[]>;
- tmps: Record<string, string>;
- dumpDir?: string;
- outline?: {
- externalized: number;
- inlined: number;
- };
- }>;
- onUnhandledError?: OnUnhandledErrorCallback;
- constructor(options: {
- onUnhandledError?: OnUnhandledErrorCallback;
- });
- catchError(error: unknown, type: string): void;
- clearErrors(): void;
- getUnhandledErrors(): unknown[];
- getPaths(): string[];
- /**
- * Return files that were running or collected.
- */
- getFiles(keys?: string[]): File[];
- getTestModules(keys?: string[]): TestModule[];
- getFilepaths(): string[];
- getFailedFilepaths(): string[];
- collectPaths(paths?: string[]): void;
- collectFiles(project: TestProject, files?: File[]): void;
- clearFiles(project: TestProject, paths?: string[]): void;
- updateId(task: Task, project: TestProject): void;
- getReportedEntity(task: Task): TestModule | TestCase | TestSuite | undefined;
- getReportedEntityById(taskId: string): TestModule | TestCase | TestSuite | undefined;
- updateTasks(packs: TaskResultPack[]): void;
- updateUserLog(log: UserConsoleLog): void;
- getCountOfFailedTests(): number;
- cancelFiles(files: FileSpecification[], project: TestProject): void;
-}
-
-declare class VitestWatcher {
- private vitest;
- /**
- * Modules that will be invalidated on the next run.
- */
- readonly invalidates: Set<string>;
- /**
- * Test files that have changed and need to be rerun.
- */
- readonly changedTests: Set<string>;
- private readonly _onRerun;
- constructor(vitest: Vitest);
- unregisterWatcher: () => void;
- registerWatcher(): this;
- private scheduleRerun;
- private getTestFilesFromWatcherTrigger;
- onFileChange: (id: string) => void;
- onFileDelete: (id: string) => void;
- onFileCreate: (id: string) => void;
- private handleSetupFile;
- /**
- * @returns A value indicating whether rerun is needed (changedTests was mutated)
- */
- private handleFileChanged;
-}
-interface WatcherTriggerPattern {
- pattern: RegExp;
- testsToRun: (file: string, match: RegExpMatchArray) => string[] | string | null | undefined | void;
-}
-
-interface VitestOptions {
- packageInstaller?: VitestPackageInstaller;
- stdin?: NodeJS.ReadStream;
- stdout?: NodeJS.WriteStream | Writable;
- stderr?: NodeJS.WriteStream | Writable;
-}
-declare class Vitest {
- readonly mode: VitestRunMode;
- /**
- * Current Vitest version.
- * @example '2.0.0'
- */
- readonly version: string;
- static readonly version: string;
- /**
- * The logger instance used to log messages. It's recommended to use this logger instead of `console`.
- * It's possible to override stdout and stderr streams when initiating Vitest.
- * @example
- * new Vitest('test', {
- * stdout: new Writable(),
- * })
- */
- readonly logger: Logger;
- /**
- * The package installer instance used to install Vitest packages.
- * @example
- * await vitest.packageInstaller.ensureInstalled('@vitest/browser', process.cwd())
- */
- readonly packageInstaller: VitestPackageInstaller;
- /**
- * A path to the built Vitest directory. This is usually a folder in `node_modules`.
- */
- readonly distPath: string;
- /**
- * A list of projects that are currently running.
- * If projects were filtered with `--project` flag, they won't appear here.
- */
- projects: TestProject[];
- /**
- * A watcher handler. This is not the file system watcher. The handler only
- * exposes methods to handle changed files.
- *
- * If you have your own watcher, you can use these methods to replicate
- * Vitest behaviour.
- */
- readonly watcher: VitestWatcher;
- private isFirstRun;
- private restartsCount;
- private readonly specifications;
- private pool;
- private _config?;
- private _vite?;
- private _state?;
- private _cache?;
- private _snapshot?;
- private _coverageProvider?;
- constructor(mode: VitestRunMode, cliOptions: UserConfig, options?: VitestOptions);
- private _onRestartListeners;
- private _onClose;
- private _onSetServer;
- private _onCancelListeners;
- private _onUserTestsRerun;
- private _onFilterWatchedSpecification;
- /**
- * The global config.
- */
- get config(): ResolvedConfig;
- /**
- * Global Vite's dev server instance.
- */
- get vite(): ViteDevServer;
- /**
- * The global test state manager.
- * @experimental The State API is experimental and not subject to semver.
- */
- get state(): StateManager;
- /**
- * The global snapshot manager. You can access the current state on `snapshot.summary`.
- */
- get snapshot(): SnapshotManager;
- /**
- * Test results and test file stats cache. Primarily used by the sequencer to sort tests.
- */
- get cache(): VitestCache;
- enableCoverage(): Promise<void>;
- disableCoverage(): void;
- private clearAllCachePaths;
- private _coverageOverrideCache;
- /**
- * Inject new test projects into the workspace.
- * @param config Glob, config path or a custom config options.
- * @returns An array of new test projects. Can be empty if the name was filtered out.
- */
- private injectTestProject;
- /**
- * Provide a value to the test context. This value will be available to all tests with `inject`.
- */
- provide: <T extends keyof ProvidedContext & string>(key: T, value: ProvidedContext[T]) => void;
- /**
- * Get global provided context.
- */
- getProvidedContext(): ProvidedContext;
- /**
- * Return project that has the root (or "global") config.
- */
- getRootProject(): TestProject;
- getProjectByName(name: string): TestProject;
- /**
- * Import a file using Vite module runner. The file will be transformed by Vite and executed in a separate context.
- * @param moduleId The ID of the module in Vite module graph
- */
- import<T>(moduleId: string): Promise<T>;
- /**
- * Creates a coverage provider if `coverage` is enabled in the config.
- */
- createCoverageProvider(): Promise<CoverageProvider | null>;
- private resolveProjects;
- /**
- * Glob test files in every project and create a TestSpecification for each file and pool.
- * @param filters String filters to match the test files.
- */
- globTestSpecifications(filters?: string[]): Promise<TestSpecification[]>;
- private initCoverageProvider;
- /**
- * Deletes all Vitest caches, including `experimental.fsModuleCache`.
- * @experimental
- */
- experimental_clearCache(): Promise<void>;
- /**
- * Merge reports from multiple runs located in the specified directory (value from `--merge-reports` if not specified).
- */
- mergeReports(directory?: string): Promise<TestRunResult>;
- /**
- * Returns the seed, if tests are running in a random order.
- */
- getSeed(): number | null;
- collect(filters?: string[]): Promise<TestRunResult>;
- /**
- * Returns the list of test files that match the config and filters.
- * @param filters String filters to match the test files
- */
- getRelevantTestSpecifications(filters?: string[]): Promise<TestSpecification[]>;
- /**
- * Initialize reporters, the coverage provider, and run tests.
- * This method can throw an error:
- * - `FilesNotFoundError` if no tests are found
- * - `GitNotFoundError` if `--related` flag is used, but git repository is not initialized
- * - `Error` from the user reporters
- * @param filters String filters to match the test files
- */
- start(filters?: string[]): Promise<TestRunResult>;
- /**
- * Initialize reporters and the coverage provider. This method doesn't run any tests.
- * If the `--watch` flag is provided, Vitest will still run changed tests even if this method was not called.
- */
- init(): Promise<void>;
- /**
- * If there is a test run happening, returns a promise that will
- * resolve when the test run is finished.
- */
- waitForTestRunEnd(): Promise<void>;
- /**
- * Get test specifications associated with the given module. If module is not a test file, an empty array is returned.
- *
- * **Note:** this method relies on a cache generated by `globTestSpecifications`. If the file was not processed yet, use `project.matchesGlobPattern` instead.
- * @param moduleId The module ID to get test specifications for.
- */
- getModuleSpecifications(moduleId: string): TestSpecification[];
- /**
- * Vitest automatically caches test specifications for each file. This method clears the cache for the given file or the whole cache altogether.
- */
- clearSpecificationsCache(moduleId?: string): void;
- /**
- * Run tests for the given test specifications. This does not trigger `onWatcher*` events.
- * @param specifications A list of specifications to run.
- * @param allTestsRun Indicates whether all tests were run. This only matters for coverage.
- */
- runTestSpecifications(specifications: TestSpecification[], allTestsRun?: boolean): Promise<TestRunResult>;
- /**
- * Rerun files and trigger `onWatcherRerun`, `onWatcherStart` and `onTestsRerun` events.
- * @param specifications A list of specifications to run.
- * @param allTestsRun Indicates whether all tests were run. This only matters for coverage.
- */
- rerunTestSpecifications(specifications: TestSpecification[], allTestsRun?: boolean): Promise<TestRunResult>;
- private runFiles;
- /**
- * Returns module's diagnostic. If `testModule` is not provided, `selfTime` and `totalTime` will be aggregated across all tests.
- *
- * If the module was not transformed or executed, the diagnostic will be empty.
- * @experimental
- * @see {@link https://vitest.dev/api/advanced/vitest#getsourcemodulediagnostic}
- */
- experimental_getSourceModuleDiagnostic(moduleId: string, testModule?: TestModule): Promise<SourceModuleDiagnostic>;
- experimental_parseSpecifications(specifications: TestSpecification[], options?: {
- /** @default os.availableParallelism() */
- concurrency?: number;
- }): Promise<TestModule[]>;
- experimental_parseSpecification(specification: TestSpecification): Promise<TestModule>;
- /**
- * Collect tests in specified modules. Vitest will run the files to collect tests.
- * @param specifications A list of specifications to run.
- */
- collectTests(specifications: TestSpecification[]): Promise<TestRunResult>;
- /**
- * Gracefully cancel the current test run. Vitest will wait until all running tests are finished before cancelling.
- */
- cancelCurrentRun(reason: CancelReason): Promise<void>;
- private initializeGlobalSetup;
- /**
- * Update snapshots in specified files. If no files are provided, it will update files with failed tests and obsolete snapshots.
- * @param files The list of files on the file system
- */
- updateSnapshot(files?: string[]): Promise<TestRunResult>;
- /**
- * Enable the mode that allows updating snapshots when running tests.
- * This method doesn't run any tests.
- *
- * Every test that runs after this method is called will update snapshots.
- * To disable the mode, call `resetSnapshotUpdate`.
- */
- enableSnapshotUpdate(): void;
- /**
- * Disable the mode that allows updating snapshots when running tests.
- */
- resetSnapshotUpdate(): void;
- /**
- * Set the global test name pattern to a regexp.
- * This method doesn't run any tests.
- */
- setGlobalTestNamePattern(pattern: string | RegExp): void;
- /**
- * Returns the regexp used for the global test name pattern.
- */
- getGlobalTestNamePattern(): RegExp | undefined;
- /**
- * Resets the global test name pattern. This method doesn't run any tests.
- */
- resetGlobalTestNamePattern(): void;
- private _rerunTimer;
- private scheduleRerun;
- /**
- * Invalidate a file in all projects.
- */
- invalidateFile(filepath: string): void;
- private reportCoverage;
- /**
- * Closes all projects and their associated resources.
- * This can only be called once; the closing promise is cached until the server restarts.
- */
- close(): Promise<void>;
- /**
- * Closes all projects and exit the process
- * @param force If true, the process will exit immediately after closing the projects.
- */
- exit(force?: boolean): Promise<void>;
- /**
- * Should the server be kept running after the tests are done.
- */
- shouldKeepServer(): boolean;
- /**
- * Register a handler that will be called when the server is restarted due to a config change.
- */
- onServerRestart(fn: OnServerRestartHandler): void;
- /**
- * Register a handler that will be called when the test run is cancelled with `vitest.cancelCurrentRun`.
- */
- onCancel(fn: (reason: CancelReason) => Awaitable<void>): () => void;
- /**
- * Register a handler that will be called when the server is closed.
- */
- onClose(fn: () => Awaitable<void>): void;
- /**
- * Register a handler that will be called when the tests are rerunning.
- */
- onTestsRerun(fn: OnTestsRerunHandler): void;
- /**
- * Register a handler that will be called when a file is changed.
- * This callback should return `true` of `false` indicating whether the test file needs to be rerun.
- * @example
- * const testsToRun = [resolve('./test.spec.ts')]
- * vitest.onFilterWatchedSpecification(specification => testsToRun.includes(specification.moduleId))
- */
- onFilterWatchedSpecification(fn: (specification: TestSpecification) => boolean): void;
- /**
- * Check if the project with a given name should be included.
- */
- matchesProjectFilter(name: string): boolean;
-}
-type OnServerRestartHandler = (reason?: string) => Promise<void> | void;
-type OnTestsRerunHandler = (testFiles: TestSpecification[]) => Promise<void> | void;
-
-interface CDPSession {
- send: (method: string, params?: Record<string, unknown>) => Promise<unknown>;
- on: (event: string, listener: (...args: unknown[]) => void) => void;
- once: (event: string, listener: (...args: unknown[]) => void) => void;
- off: (event: string, listener: (...args: unknown[]) => void) => void;
-}
-interface BrowserModuleMocker {
- register: (sessionId: string, module: MockedModule) => Promise<void>;
- delete: (sessionId: string, url: string) => Promise<void>;
- clear: (sessionId: string) => Promise<void>;
-}
-interface BrowserProviderOption<Options extends object = object> {
- name: string;
- supportedBrowser?: ReadonlyArray<string>;
- options: Options;
- providerFactory: (project: TestProject) => BrowserProvider;
- serverFactory: BrowserServerFactory;
-}
-interface BrowserServerOptions {
- project: TestProject;
- coveragePlugin: () => Plugin;
- mocksPlugins: (options: {
- filter: (id: string) => boolean;
- }) => Plugin[];
- metaEnvReplacer: () => Plugin;
-}
-interface BrowserServerFactory {
- (options: BrowserServerOptions): Promise<ParentProjectBrowser>;
-}
-interface BrowserProvider {
- name: string;
- mocker?: BrowserModuleMocker;
- readonly initScripts?: string[];
- /**
- * @experimental opt-in into file parallelisation
- */
- supportsParallelism: boolean;
- getCommandsContext: (sessionId: string) => Record<string, unknown>;
- openPage: (sessionId: string, url: string) => Promise<void>;
- getCDPSession?: (sessionId: string) => Promise<CDPSession>;
- close: () => Awaitable<void>;
-}
-type BrowserBuiltinProvider = "webdriverio" | "playwright" | "preview";
-interface _BrowserNames {}
-type UnsupportedProperties = "browser" | "typecheck" | "alias" | "sequence" | "root" | "pool" | "runner" | "api" | "deps" | "environment" | "environmentOptions" | "server" | "benchmark" | "name";
-interface BrowserInstanceOption extends Omit<ProjectConfig, UnsupportedProperties>, Pick<BrowserConfigOptions, "headless" | "locators" | "viewport" | "testerHtmlPath" | "screenshotDirectory" | "screenshotFailures"> {
- /**
- * Name of the browser
- */
- browser: keyof _BrowserNames extends never ? string : _BrowserNames[keyof _BrowserNames];
- name?: string;
- provider?: BrowserProviderOption;
-}
-interface BrowserConfigOptions {
- /**
- * if running tests in the browser should be the default
- *
- * @default false
- */
- enabled?: boolean;
- /**
- * Configurations for different browser setups
- */
- instances?: BrowserInstanceOption[];
- /**
- * Browser provider
- * @example
- * ```ts
- * import { playwright } from '@vitest/browser-playwright'
- * export default defineConfig({
- * test: {
- * browser: {
- * provider: playwright(),
- * },
- * },
- * })
- * ```
- */
- provider?: BrowserProviderOption;
- /**
- * enable headless mode
- *
- * @default process.env.CI
- */
- headless?: boolean;
- /**
- * Serve API options.
- *
- * The default port is 63315.
- */
- api?: ApiConfig | number;
- /**
- * Isolate test environment after each test
- *
- * @default true
- * @deprecated use top-level `isolate` instead
- */
- isolate?: boolean;
- /**
- * Run test files in parallel if provider supports this option
- * This option only has effect in headless mode (enabled in CI by default)
- *
- * @default // Same as "test.fileParallelism"
- * @deprecated use top-level `fileParallelism` instead
- */
- fileParallelism?: boolean;
- /**
- * Show Vitest UI
- *
- * @default !process.env.CI
- */
- ui?: boolean;
- /**
- * Default viewport size
- */
- viewport?: {
- /**
- * Width of the viewport
- * @default 414
- */
- width: number;
- /**
- * Height of the viewport
- * @default 896
- */
- height: number;
- };
- /**
- * Locator options
- */
- locators?: {
- /**
- * Attribute used to locate elements by test id
- * @default 'data-testid'
- */
- testIdAttribute?: string;
- };
- /**
- * Generate traces that can be viewed on https://trace.playwright.dev/
- *
- * This option is supported only by **playwright** provider.
- */
- trace?: BrowserTraceViewMode | {
- mode: BrowserTraceViewMode;
- /**
- * The directory where all traces will be stored. By default, Vitest
- * stores all traces in `__traces__` folder close to the test file.
- */
- tracesDir?: string;
- /**
- * Whether to capture screenshots during tracing. Screenshots are used to build a timeline preview.
- * @default true
- */
- screenshots?: boolean;
- /**
- * If this option is true tracing will
- * - capture DOM snapshot on every action
- * - record network activity
- * @default true
- */
- snapshots?: boolean;
- };
- /**
- * Directory where screenshots will be saved when page.screenshot() is called
- * If not set, all screenshots are saved to __screenshots__ directory in the same folder as the test file.
- * If this is set, it will be resolved relative to the project root.
- * @default __screenshots__
- */
- screenshotDirectory?: string;
- /**
- * Should Vitest take screenshots if the test fails
- * @default !browser.ui
- */
- screenshotFailures?: boolean;
- /**
- * Path to the index.html file that will be used to run tests.
- */
- testerHtmlPath?: string;
- /**
- * Scripts injected into the main window.
- */
- orchestratorScripts?: BrowserScript[];
- /**
- * Commands that will be executed on the server
- * via the browser `import("vitest/browser").commands` API.
- * @see {@link https://vitest.dev/api/browser/commands}
- */
- commands?: Record<string, BrowserCommand<any>>;
- /**
- * Timeout for connecting to the browser
- * @default 30000
- */
- connectTimeout?: number;
- expect?: {
- toMatchScreenshot?: { [ComparatorName in keyof ToMatchScreenshotComparators] : {
- /**
- * The name of the comparator to use for visual diffing.
- *
- * @defaultValue `'pixelmatch'`
- */
- comparatorName?: ComparatorName;
- comparatorOptions?: ToMatchScreenshotComparators[ComparatorName];
- } }[keyof ToMatchScreenshotComparators] & ToMatchScreenshotOptions;
- };
- /**
- * Enables tracking uncaught errors and exceptions so they can be reported by Vitest.
- *
- * If you need to hide certain errors, it is recommended to use [`onUnhandledError`](https://vitest.dev/config/#onunhandlederror) option instead.
- *
- * Disabling this will completely remove all Vitest error handlers, which can help debugging with the "Pause on exceptions" checkbox turned on.
- * @default true
- */
- trackUnhandledErrors?: boolean;
-}
-interface BrowserCommandContext {
- testPath: string | undefined;
- provider: BrowserProvider;
- project: TestProject;
- sessionId: string;
- triggerCommand: <K extends keyof BrowserCommands>(name: K, ...args: Parameters<BrowserCommands[K]>) => ReturnType<BrowserCommands[K]>;
-}
-interface BrowserServerStateSession {
- project: TestProject;
- connected: () => void;
- fail: (v: Error) => void;
-}
-interface BrowserOrchestrator {
- cleanupTesters: () => Promise<void>;
- createTesters: (options: BrowserTesterOptions) => Promise<void>;
- onCancel: (reason: CancelReason) => Promise<void>;
- $close: () => void;
-}
-interface BrowserServerState {
- orchestrators: Map<string, BrowserOrchestrator>;
-}
-interface ParentProjectBrowser {
- spawn: (project: TestProject) => ProjectBrowser;
- vite: ViteDevServer;
-}
-interface ProjectBrowser {
- vite: ViteDevServer;
- state: BrowserServerState;
- provider: BrowserProvider;
- close: () => Promise<void>;
- initBrowserProvider: (project: TestProject) => Promise<void>;
- parseStacktrace: (stack: string) => ParsedStack[];
- parseErrorStacktrace: (error: TestError, options?: StackTraceParserOptions) => ParsedStack[];
- registerCommand: <K extends keyof BrowserCommands>(name: K, cb: BrowserCommand<Parameters<BrowserCommands[K]>, ReturnType<BrowserCommands[K]>>) => void;
- triggerCommand: <K extends keyof BrowserCommands>(name: K, context: BrowserCommandContext, ...args: Parameters<BrowserCommands[K]>) => ReturnType<BrowserCommands[K]>;
-}
-interface BrowserCommand<
- Payload extends unknown[] = [],
- ReturnValue = any
-> {
- (context: BrowserCommandContext, ...payload: Payload): Awaitable<ReturnValue>;
-}
-interface BrowserScript {
- /**
- * If "content" is provided and type is "module", this will be its identifier.
- *
- * If you are using TypeScript, you can add `.ts` extension here for example.
- * @default `injected-${index}.js`
- */
- id?: string;
- /**
- * JavaScript content to be injected. This string is processed by Vite plugins if type is "module".
- *
- * You can use `id` to give Vite a hint about the file extension.
- */
- content?: string;
- /**
- * Path to the script. This value is resolved by Vite so it can be a node module or a file path.
- */
- src?: string;
- /**
- * If the script should be loaded asynchronously.
- */
- async?: boolean;
- /**
- * Script type.
- * @default 'module'
- */
- type?: string;
-}
-interface ResolvedBrowserOptions extends BrowserConfigOptions {
- name: string;
- enabled: boolean;
- headless: boolean;
- isolate: boolean;
- fileParallelism: boolean;
- api: ApiConfig;
- ui: boolean;
- viewport: {
- width: number;
- height: number;
- };
- screenshotFailures: boolean;
- locators: {
- testIdAttribute: string;
- };
- trace: {
- mode: BrowserTraceViewMode;
- tracesDir?: string;
- screenshots?: boolean;
- snapshots?: boolean;
- };
-}
-type ToMatchScreenshotResolvePath = (data: {
- /**
- * Path **without** extension, sanitized and relative to the test file.
- *
- * This comes from the arguments passed to `toMatchScreenshot`; if called
- * without arguments this will be the auto-generated name.
- *
- * @example
- * test('calls `onClick`', () => {
- * expect(locator).toMatchScreenshot()
- * // arg = "calls-onclick-1"
- * })
- *
- * @example
- * expect(locator).toMatchScreenshot('foo/bar/baz.png')
- * // arg = "foo/bar/baz"
- *
- * @example
- * expect(locator).toMatchScreenshot('../foo/bar/baz.png')
- * // arg = "foo/bar/baz"
- */
- arg: string;
- /**
- * Screenshot extension, with leading dot.
- *
- * This can be set through the arguments passed to `toMatchScreenshot`, but
- * the value will fall back to `'.png'` if an unsupported extension is used.
- */
- ext: string;
- /**
- * The instance's browser name.
- */
- browserName: string;
- /**
- * The value of {@linkcode process.platform}.
- */
- platform: NodeJS.Platform;
- /**
- * The value provided to
- * {@linkcode https://vitest.dev/config/browser/screenshotdirectory|browser.screenshotDirectory},
- * if none is provided, its default value.
- */
- screenshotDirectory: string;
- /**
- * Absolute path to the project's
- * {@linkcode https://vitest.dev/config/#root|root}.
- */
- root: string;
- /**
- * Path to the test file, relative to the project's
- * {@linkcode https://vitest.dev/config/#root|root}.
- */
- testFileDirectory: string;
- /**
- * The test's filename.
- */
- testFileName: string;
- /**
- * The {@linkcode https://vitest.dev/api/#test|test}'s name, including
- * parent {@linkcode https://vitest.dev/api/#describe|describe}, sanitized.
- */
- testName: string;
- /**
- * The value provided to
- * {@linkcode https://vitest.dev/config/#attachmentsdir|attachmentsDir},
- * if none is provided, its default value.
- */
- attachmentsDir: string;
-}) => string;
-interface ToMatchScreenshotOptions {
- /**
- * Overrides default reference screenshot path.
- *
- * @default `${root}/${testFileDirectory}/${screenshotDirectory}/${testFileName}/${arg}-${browserName}-${platform}${ext}`
- */
- resolveScreenshotPath?: ToMatchScreenshotResolvePath;
- /**
- * Overrides default screenshot path used for diffs.
- *
- * @default `${root}/${attachmentsDir}/${testFileDirectory}/${testFileName}/${arg}-${browserName}-${platform}${ext}`
- */
- resolveDiffPath?: ToMatchScreenshotResolvePath;
-}
-interface ToMatchScreenshotComparators {}
-
-declare class TestProject {
- options?: InitializeProjectOptions | undefined;
- /**
- * The global Vitest instance.
- */
- readonly vitest: Vitest;
- /**
- * Resolved global configuration. If there are no workspace projects, this will be the same as `config`.
- */
- readonly globalConfig: ResolvedConfig;
- /**
- * Browser instance if the browser is enabled. This is initialized when the tests run for the first time.
- */
- browser?: ProjectBrowser;
- /**
- * Temporary directory for the project. This is unique for each project. Vitest stores transformed content here.
- */
- readonly tmpDir: string;
- /** @inetrnal */ testFilesList: string[] | null;
- private runner;
- private closingPromise;
- private typecheckFilesList;
- private _globalSetups?;
- private _provided;
- constructor(vitest: Vitest, options?: InitializeProjectOptions | undefined, tmpDir?: string);
- /**
- * The unique hash of this project. This value is consistent between the reruns.
- *
- * It is based on the root of the project (not consistent between OS) and its name.
- */
- get hash(): string;
- /**
- * Provide a value to the test context. This value will be available to all tests with `inject`.
- */
- provide: <T extends keyof ProvidedContext & string>(key: T, value: ProvidedContext[T]) => void;
- /**
- * Get the provided context. The project context is merged with the global context.
- */
- getProvidedContext(): ProvidedContext;
- /**
- * Creates a new test specification. Specifications describe how to run tests.
- * @param moduleId The file path
- */
- createSpecification(moduleId: string, locations?: number[] | undefined, pool?: string): TestSpecification;
- toJSON(): SerializedTestProject;
- /**
- * Vite's dev server instance. Every workspace project has its own server.
- */
- get vite(): ViteDevServer;
- /**
- * Resolved project configuration.
- */
- get config(): ResolvedConfig;
- /**
- * The name of the project or an empty string if not set.
- */
- get name(): string;
- /**
- * The color used when reporting tasks of this project.
- */
- get color(): ProjectName["color"];
- /**
- * Serialized project configuration. This is the config that tests receive.
- */
- get serializedConfig(): SerializedConfig;
- /**
- * Check if this is the root project. The root project is the one that has the root config.
- */
- isRootProject(): boolean;
- onTestsRerun(cb: OnTestsRerunHandler): void;
- /**
- * Get all files in the project that match the globs in the config and the filters.
- * @param filters String filters to match the test files.
- */
- globTestFiles(filters?: string[]): Promise<{
- /**
- * Test files that match the filters.
- */
- testFiles: string[];
- /**
- * Typecheck test files that match the filters. This will be empty unless `typecheck.enabled` is `true`.
- */
- typecheckTestFiles: string[];
- }>;
- private globAllTestFiles;
- isBrowserEnabled(): boolean;
- private markTestFile;
- /**
- * Test if a file matches the test globs. This does the actual glob matching if the test is not cached, unlike `isCachedTestFile`.
- */
- matchesTestGlob(moduleId: string, source?: () => string): boolean;
- private isInSourceTestCode;
- private filterFiles;
- private _parentBrowser?;
- /**
- * Closes the project and all associated resources. This can only be called once; the closing promise is cached until the server restarts.
- * If the resources are needed again, create a new project.
- */
- close(): Promise<void>;
- /**
- * Import a file using Vite module runner.
- * @param moduleId The ID of the module in Vite module graph
- */
- import<T>(moduleId: string): Promise<T>;
- private _setHash;
- private _serializeOverriddenConfig;
- private clearTmpDir;
-}
-interface SerializedTestProject {
- name: string;
- serializedConfig: SerializedConfig;
- context: ProvidedContext;
-}
-interface InitializeProjectOptions extends TestProjectInlineConfiguration {
- configFile: string | false;
-}
-
-interface PoolRunnerInitializer {
- readonly name: string;
- createPoolWorker: (options: PoolOptions) => PoolWorker;
-}
-interface PoolOptions {
- distPath: string;
- project: TestProject;
- method: "run" | "collect";
- cacheFs?: boolean;
- environment: ContextTestEnvironment;
- execArgv: string[];
- env: Partial<NodeJS.ProcessEnv>;
-}
-interface PoolWorker {
- readonly name: string;
- readonly reportMemory?: boolean;
- readonly cacheFs?: boolean;
- on: (event: string, callback: (arg: any) => void) => void;
- off: (event: string, callback: (arg: any) => void) => void;
- send: (message: WorkerRequest) => void;
- deserialize: (data: unknown) => unknown;
- start: () => Promise<void>;
- stop: () => Promise<void>;
- /**
- * This is called on workers that already satisfy certain constraints:
- * - The task has the same worker name
- * - The task has the same project
- */
- canReuse?: (task: PoolTask) => boolean;
-}
-interface PoolTask {
- worker: "forks" | "threads" | "vmForks" | "vmThreads" | (string & {});
- project: TestProject;
- isolate: boolean;
- /**
- * Custom `process.env`. All tasks in the same project will reference the same object,
- * so modifying it once will modify it for every task.
- */
- env: Partial<NodeJS.ProcessEnv>;
- /**
- * Custom `execArgv`. All tasks in the same project will reference the same array,
- * so modifying it once will modify it for every task.
- */
- execArgv: string[];
- context: WorkerExecuteContext;
- memoryLimit: number | null;
-}
-type WorkerRequest = {
- __vitest_worker_request__: true;
-} & ({
- type: "start";
- poolId: number;
- workerId: WorkerExecuteContext["workerId"];
- options: {
- reportMemory: boolean;
- };
- context: {
- environment: WorkerTestEnvironment;
- config: SerializedConfig;
- pool: string;
- };
- traces: {
- enabled: boolean;
- sdkPath?: string;
- otelCarrier?: OTELCarrier;
- };
-} | {
- type: "stop";
- otelCarrier?: OTELCarrier;
-} | {
- type: "run";
- context: WorkerExecuteContext;
- otelCarrier?: OTELCarrier;
-} | {
- type: "collect";
- context: WorkerExecuteContext;
- otelCarrier?: OTELCarrier;
-} | {
- type: "cancel";
-});
-type WorkerResponse = {
- __vitest_worker_response__: true;
-} & ({
- type: "started";
- error?: unknown;
-} | {
- type: "stopped";
- error?: unknown;
-} | {
- type: "testfileFinished";
- usedMemory?: number;
- error?: unknown;
-});
-
-interface BaseOptions {
- isTTY?: boolean;
-}
-declare abstract class BaseReporter implements Reporter {
- start: number;
- end: number;
- watchFilters?: string[];
- failedUnwatchedFiles: TestModule[];
- isTTY: boolean;
- ctx: Vitest;
- renderSucceed: boolean;
- protected verbose: boolean;
- private _filesInWatchMode;
- private _timeStart;
- constructor(options?: BaseOptions);
- onInit(ctx: Vitest): void;
- log(...messages: any): void;
- error(...messages: any): void;
- relative(path: string): string;
- onTestRunStart(_specifications: ReadonlyArray<TestSpecification>): void;
- onTestRunEnd(testModules: ReadonlyArray<TestModule>, unhandledErrors: ReadonlyArray<SerializedError>, _reason: TestRunEndReason): void;
- onTestCaseResult(testCase: TestCase): void;
- onTestSuiteResult(testSuite: TestSuite): void;
- onTestModuleEnd(testModule: TestModule): void;
- private logFailedTask;
- protected printTestModule(testModule: TestModule): void;
- protected printTestCase(moduleState: TestModuleState, test: TestCase): void;
- private getModuleLog;
- protected printTestSuite(testSuite: TestSuite): void;
- protected getTestName(test: Task, _separator?: string): string;
- protected getFullName(test: Task, separator?: string): string;
- protected getTestIndentation(test: Task): string;
- protected printAnnotations(test: TestCase, console: "log" | "error", padding?: number): void;
- protected getEntityPrefix(entity: TestCase | TestModule | TestSuite): string;
- protected getTestCaseSuffix(testCase: TestCase): string;
- protected getStateSymbol(test: TestCase | TestModule | TestSuite): string;
- private getDurationPrefix;
- onWatcherStart(files?: File[], errors?: unknown[]): void;
- onWatcherRerun(files: string[], trigger?: string): void;
- onUserConsoleLog(log: UserConsoleLog, taskState?: TestResult["state"]): void;
- onTestRemoved(trigger?: string): void;
- shouldLog(log: UserConsoleLog, taskState?: TestResult["state"]): boolean;
- onServerRestart(reason?: string): void;
- reportSummary(files: File[], errors: unknown[]): void;
- reportTestSummary(files: File[], errors: unknown[]): void;
- private printImportsBreakdown;
- private importDurationTime;
- private ellipsisPath;
- private printErrorsSummary;
- reportBenchmarkSummary(files: File[]): void;
- private printTaskErrors;
-}
-
-interface DefaultReporterOptions extends BaseOptions {
- summary?: boolean;
-}
-declare class DefaultReporter extends BaseReporter {
- private options;
- private summary?;
- constructor(options?: DefaultReporterOptions);
- onTestRunStart(specifications: ReadonlyArray<TestSpecification>): void;
- onTestRunEnd(testModules: ReadonlyArray<TestModule>, unhandledErrors: ReadonlyArray<SerializedError>, reason: TestRunEndReason): void;
- onTestModuleQueued(file: TestModule): void;
- onTestModuleCollected(module: TestModule): void;
- onTestModuleEnd(module: TestModule): void;
- onTestCaseReady(test: TestCase): void;
- onTestCaseResult(test: TestCase): void;
- onHookStart(hook: ReportedHookContext): void;
- onHookEnd(hook: ReportedHookContext): void;
- onInit(ctx: Vitest): void;
-}
-
-interface GithubActionsReporterOptions {
- onWritePath?: (path: string) => string;
- /**
- * @default true
- */
- displayAnnotations?: boolean;
-}
-declare class GithubActionsReporter implements Reporter {
- ctx: Vitest;
- options: GithubActionsReporterOptions;
- constructor(options?: GithubActionsReporterOptions);
- onInit(ctx: Vitest): void;
- onTestCaseAnnotate(testCase: TestCase, annotation: TestAnnotation): void;
- onTestRunEnd(testModules: ReadonlyArray<TestModule>, unhandledErrors: ReadonlyArray<SerializedError>): void;
-}
-
-interface HTMLOptions {
- outputFile?: string;
-}
-
-type Status = "passed" | "failed" | "skipped" | "pending" | "todo" | "disabled";
-type Milliseconds = number;
-interface Callsite {
- line: number;
- column: number;
-}
-interface JsonAssertionResult {
- ancestorTitles: Array<string>;
- fullName: string;
- status: Status;
- title: string;
- meta: TaskMeta;
- duration?: Milliseconds | null;
- failureMessages: Array<string> | null;
- location?: Callsite | null;
-}
-interface JsonTestResult {
- message: string;
- name: string;
- status: "failed" | "passed";
- startTime: number;
- endTime: number;
- assertionResults: Array<JsonAssertionResult>;
-}
-interface JsonTestResults {
- numFailedTests: number;
- numFailedTestSuites: number;
- numPassedTests: number;
- numPassedTestSuites: number;
- numPendingTests: number;
- numPendingTestSuites: number;
- numTodoTests: number;
- numTotalTests: number;
- numTotalTestSuites: number;
- startTime: number;
- success: boolean;
- testResults: Array<JsonTestResult>;
- snapshot: SnapshotSummary;
- coverageMap?: CoverageMap | null | undefined;
-}
-interface JsonOptions {
- outputFile?: string;
-}
-declare class JsonReporter implements Reporter {
- start: number;
- ctx: Vitest;
- options: JsonOptions;
- coverageMap?: CoverageMap;
- constructor(options: JsonOptions);
- onInit(ctx: Vitest): void;
- onCoverage(coverageMap: unknown): void;
- onTestRunEnd(testModules: ReadonlyArray<TestModule>): Promise<void>;
- /**
- * Writes the report to an output file if specified in the config,
- * or logs it to the console otherwise.
- * @param report
- */
- writeReport(report: string): Promise<void>;
-}
-
-interface ClassnameTemplateVariables {
- filename: string;
- filepath: string;
-}
-interface JUnitOptions {
- outputFile?: string;
- /**
- * Template for the classname attribute. Can be either a string or a function. The string can contain placeholders {filename} and {filepath}.
- */
- classnameTemplate?: string | ((classnameVariables: ClassnameTemplateVariables) => string);
- suiteName?: string;
- /**
- * Write <system-out> and <system-err> for console output
- * @default true
- */
- includeConsoleOutput?: boolean;
- /**
- * Add <testcase file="..."> attribute (validated on CIRCLE CI and GitLab CI)
- * @default false
- */
- addFileAttribute?: boolean;
-}
-declare class JUnitReporter implements Reporter {
- private ctx;
- private reportFile?;
- private baseLog;
- private logger;
- private _timeStart;
- private fileFd?;
- private options;
- constructor(options: JUnitOptions);
- onInit(ctx: Vitest): Promise<void>;
- writeElement(name: string, attrs: Record<string, any>, children: () => Promise<void>): Promise<void>;
- writeLogs(task: Task, type: "err" | "out"): Promise<void>;
- writeTasks(tasks: Task[], filename: string): Promise<void>;
- onTestRunEnd(testModules: ReadonlyArray<TestModule>): Promise<void>;
-}
-
-declare class DotReporter extends BaseReporter {
- private renderer?;
- private tests;
- private finishedTests;
- onInit(ctx: Vitest): void;
- printTestModule(): void;
- onWatcherRerun(files: string[], trigger?: string): void;
- onTestRunEnd(testModules: ReadonlyArray<TestModule>, unhandledErrors: ReadonlyArray<SerializedError>, reason: TestRunEndReason): void;
- onTestModuleCollected(module: TestModule): void;
- onTestCaseReady(test: TestCase): void;
- onTestCaseResult(test: TestCase): void;
- onTestModuleEnd(testModule: TestModule): void;
- private createSummary;
-}
-
-declare class HangingProcessReporter implements Reporter {
- whyRunning: (() => void) | undefined;
- onInit(): void;
- onProcessTimeout(): void;
-}
-
-declare class TapReporter implements Reporter {
- protected ctx: Vitest;
- private logger;
- onInit(ctx: Vitest): void;
- static getComment(task: Task): string;
- private logErrorDetails;
- protected logTasks(tasks: Task[]): void;
- onTestRunEnd(testModules: ReadonlyArray<TestModule>): void;
-}
-
-declare class TapFlatReporter extends TapReporter {
- onInit(ctx: Vitest): void;
- onTestRunEnd(testModules: ReadonlyArray<TestModule>): void;
-}
-
-declare class TreeReporter extends DefaultReporter {
- protected verbose: boolean;
- renderSucceed: boolean;
-}
-
-declare class VerboseReporter extends DefaultReporter {
- protected verbose: boolean;
- renderSucceed: boolean;
- printTestModule(_module: TestModule): void;
- onTestCaseResult(test: TestCase): void;
-}
-
-type FormattedBenchmarkResult = BenchmarkResult & {
- id: string;
-};
-
-declare function renderTable(options: {
- tasks: Task[];
- level: number;
- shallow?: boolean;
- showHeap: boolean;
- columns: number;
- slowTestThreshold: number;
- compare?: Record<Task["id"], FormattedBenchmarkResult>;
-}): string;
-
-declare class BenchmarkReporter extends DefaultReporter {
- compare?: Parameters<typeof renderTable>[0]["compare"];
- onInit(ctx: Vitest): Promise<void>;
- onTaskUpdate(packs: TaskResultPack[]): void;
- onTestSuiteResult(testSuite: TestSuite): void;
- protected printTestModule(testModule: TestModule): void;
- private printSuiteTable;
- onTestRunEnd(testModules: ReadonlyArray<TestModule>, unhandledErrors: ReadonlyArray<SerializedError>, reason: TestRunEndReason): Promise<void>;
-}
-
-declare class VerboseBenchmarkReporter extends BenchmarkReporter {
- protected verbose: boolean;
-}
-
-declare const BenchmarkReportsMap: {
- default: typeof BenchmarkReporter;
- verbose: typeof VerboseBenchmarkReporter;
-};
-type BenchmarkBuiltinReporters = keyof typeof BenchmarkReportsMap;
-
-declare const ReportersMap: {
- default: typeof DefaultReporter;
- blob: typeof BlobReporter;
- verbose: typeof VerboseReporter;
- dot: typeof DotReporter;
- json: typeof JsonReporter;
- tap: typeof TapReporter;
- "tap-flat": typeof TapFlatReporter;
- junit: typeof JUnitReporter;
- tree: typeof TreeReporter;
- "hanging-process": typeof HangingProcessReporter;
- "github-actions": typeof GithubActionsReporter;
-};
-type BuiltinReporters = keyof typeof ReportersMap;
-interface BuiltinReporterOptions {
- "default": DefaultReporterOptions;
- "verbose": DefaultReporterOptions;
- "dot": BaseOptions;
- "tree": BaseOptions;
- "json": JsonOptions;
- "blob": BlobOptions;
- "tap": never;
- "tap-flat": never;
- "junit": JUnitOptions;
- "hanging-process": never;
- "html": HTMLOptions;
- "github-actions": GithubActionsReporterOptions;
-}
-
-interface TestSequencer {
- /**
- * Slicing tests into shards. Will be run before `sort`.
- * Only run, if `shard` is defined.
- */
- shard: (files: TestSpecification[]) => Awaitable<TestSpecification[]>;
- sort: (files: TestSpecification[]) => Awaitable<TestSpecification[]>;
-}
-interface TestSequencerConstructor {
- new (ctx: Vitest): TestSequencer;
-}
-
-interface BenchmarkUserOptions {
- /**
- * Include globs for benchmark test files
- *
- * @default ['**\/*.{bench,benchmark}.?(c|m)[jt]s?(x)']
- */
- include?: string[];
- /**
- * Exclude globs for benchmark test files
- * @default ['**\/node_modules/**', '**\/dist/**', '**\/cypress/**', '**\/.{idea,git,cache,output,temp}/**', '**\/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build,eslint,prettier}.config.*']
- */
- exclude?: string[];
- /**
- * Include globs for in-source benchmark test files
- *
- * @default []
- */
- includeSource?: string[];
- /**
- * Custom reporter for output. Can contain one or more built-in report names, reporter instances,
- * and/or paths to custom reporters
- *
- * @default ['default']
- */
- reporters?: Arrayable<BenchmarkBuiltinReporters | Reporter>;
- /**
- * @deprecated Use `benchmark.outputJson` instead
- */
- outputFile?: string | (Partial<Record<BenchmarkBuiltinReporters, string>> & Record<string, string>);
- /**
- * benchmark output file to compare against
- */
- compare?: string;
- /**
- * benchmark output file
- */
- outputJson?: string;
- /**
- * Include `samples` array of benchmark results for API or custom reporter usages.
- * This is disabled by default to reduce memory usage.
- * @default false
- */
- includeSamples?: boolean;
-}
-
-type BuiltinEnvironment = "node" | "jsdom" | "happy-dom" | "edge-runtime";
-type VitestEnvironment = BuiltinEnvironment | (string & Record<never, never>);
-type CSSModuleScopeStrategy = "stable" | "scoped" | "non-scoped";
-type ApiConfig = Pick<ServerOptions, "port" | "strictPort" | "host" | "middlewareMode">;
-interface EnvironmentOptions {
- /**
- * jsdom options.
- */
- jsdom?: JSDOMOptions;
- happyDOM?: HappyDOMOptions;
- [x: string]: unknown;
-}
-
-type VitestRunMode = "test" | "benchmark";
-interface ProjectName {
- label: string;
- color?: LabelColor;
-}
-interface SequenceOptions {
- /**
- * Class that handles sorting and sharding algorithm.
- * If you only need to change sorting, you can extend
- * your custom sequencer from `BaseSequencer` from `vitest/node`.
- * @default BaseSequencer
- */
- sequencer?: TestSequencerConstructor;
- /**
- * Controls the order in which this project runs its tests when using multiple [projects](/guide/projects).
- *
- * - Projects with the same group order number will run together, and groups are run from lowest to highest.
- * - If you don’t set this option, all projects run in parallel.
- * - If several projects use the same group order, they will run at the same time.
- * @default 0
- */
- groupOrder?: number;
- /**
- * Should files and tests run in random order.
- * @default false
- */
- shuffle?: boolean | {
- /**
- * Should files run in random order. Long running tests will not start
- * earlier if you enable this option.
- * @default false
- */
- files?: boolean;
- /**
- * Should tests run in random order.
- * @default false
- */
- tests?: boolean;
- };
- /**
- * Should tests run in parallel.
- * @default false
- */
- concurrent?: boolean;
- /**
- * Defines how setup files should be ordered
- * - 'parallel' will run all setup files in parallel
- * - 'list' will run all setup files in the order they are defined in the config file
- * @default 'parallel'
- */
- setupFiles?: SequenceSetupFiles;
- /**
- * Seed for the random number generator.
- * @default Date.now()
- */
- seed?: number;
- /**
- * Defines how hooks should be ordered
- * - `stack` will order "after" hooks in reverse order, "before" hooks will run sequentially
- * - `list` will order hooks in the order they are defined
- * - `parallel` will run hooks in a single group in parallel
- * @default 'stack'
- */
- hooks?: SequenceHooks;
-}
-type DepsOptimizationOptions = Omit<DepOptimizationConfig, "disabled" | "noDiscovery"> & {
- enabled?: boolean;
-};
-interface DepsOptions {
- /**
- * Enable dependency optimization. This can improve the performance of your tests.
- */
- optimizer?: Partial<Record<"client" | "ssr" | ({} & string), DepsOptimizationOptions>>;
- web?: {
- /**
- * Should Vitest process assets (.png, .svg, .jpg, etc) files and resolve them like Vite does in the browser.
- *
- * These module will have a default export equal to the path to the asset, if no query is specified.
- *
- * **At the moment, this option only works with `{ pool: 'vmThreads' }`.**
- *
- * @default true
- */
- transformAssets?: boolean;
- /**
- * Should Vitest process CSS (.css, .scss, .sass, etc) files and resolve them like Vite does in the browser.
- *
- * If CSS files are disabled with `css` options, this option will just silence UNKNOWN_EXTENSION errors.
- *
- * **At the moment, this option only works with `{ pool: 'vmThreads' }`.**
- *
- * @default true
- */
- transformCss?: boolean;
- /**
- * Regexp pattern to match external files that should be transformed.
- *
- * By default, files inside `node_modules` are externalized and not transformed.
- *
- * **At the moment, this option only works with `{ pool: 'vmThreads' }`.**
- *
- * @default []
- */
- transformGlobPattern?: RegExp | RegExp[];
- };
- /**
- * Interpret CJS module's default as named exports
- *
- * @default true
- */
- interopDefault?: boolean;
- /**
- * A list of directories relative to the config file that should be treated as module directories.
- *
- * @default ['node_modules']
- */
- moduleDirectories?: string[];
-}
-type InlineReporter = Reporter;
-type ReporterName = BuiltinReporters | "html" | (string & {});
-type ReporterWithOptions<Name extends ReporterName = ReporterName> = Name extends keyof BuiltinReporterOptions ? BuiltinReporterOptions[Name] extends never ? [Name, object] : [Name, Partial<BuiltinReporterOptions[Name]>] : [Name, Record<string, unknown>];
-interface ResolveSnapshotPathHandlerContext {
- config: SerializedConfig;
-}
-type ResolveSnapshotPathHandler = (testPath: string, snapExtension: string, context: ResolveSnapshotPathHandlerContext) => string;
-type BuiltinPool = "browser" | "threads" | "forks" | "vmThreads" | "vmForks" | "typescript";
-type Pool = BuiltinPool | (string & {});
-interface InlineConfig {
- /**
- * Name of the project. Will be used to display in the reporter.
- */
- name?: string | ProjectName;
- /**
- * Benchmark options.
- *
- * @default {}
- */
- benchmark?: BenchmarkUserOptions;
- /**
- * A list of [glob patterns](https://superchupu.dev/tinyglobby/comparison) that match your test files.
- *
- * @default ['**\/*.{test,spec}.?(c|m)[jt]s?(x)']
- * @see {@link https://vitest.dev/config/include}
- */
- include?: string[];
- /**
- * Exclude globs for test files
- * @default ['**\/node_modules/**', '**\/.git/**']
- */
- exclude?: string[];
- /**
- * Include globs for in-source test files
- *
- * @default []
- */
- includeSource?: string[];
- /**
- * Handling for dependencies inlining or externalizing
- *
- */
- deps?: DepsOptions;
- server?: {
- deps?: ServerDepsOptions;
- debug?: {
- /**
- * The folder where Vitest stores the contents of transformed
- * test files that can be inspected manually.
- *
- * If `true`, Vitest dumps the files in `.vitest-dump` folder relative to the root of the project.
- *
- * You can also use `VITEST_DEBUG_DUMP` env variable to enable this.
- */
- dump?: string | true;
- /**
- * If dump is enabled, should Vitest load the files from there instead of transforming them.
- *
- * You can also use `VITEST_DEBUG_LOAD_DUMP` env variable to enable this.
- */
- load?: boolean;
- };
- };
- /**
- * Base directory to scan for the test files
- *
- * @default `config.root`
- */
- dir?: string;
- /**
- * Register apis globally
- *
- * @default false
- */
- globals?: boolean;
- /**
- * Running environment
- *
- * Supports 'node', 'jsdom', 'happy-dom', 'edge-runtime'
- *
- * If used unsupported string, will try to load the package `vitest-environment-${env}`
- *
- * @default 'node'
- */
- environment?: VitestEnvironment;
- /**
- * Environment options.
- */
- environmentOptions?: EnvironmentOptions;
- /**
- * Run tests in an isolated environment. This option has no effect on vmThreads pool.
- *
- * Disabling this option improves performance if your code doesn't rely on side effects.
- *
- * @default true
- */
- isolate?: boolean;
- /**
- * Pass additional arguments to `node` process when spawning the worker.
- *
- * See [Command-line API | Node.js](https://nodejs.org/docs/latest/api/cli.html) for more information.
- *
- * Set to `process.execArgv` to pass all arguments of the current process.
- *
- * Be careful when using, it as some options may crash worker, e.g. --prof, --title. See https://github.com/nodejs/node/issues/41103
- *
- * @default [] // no execution arguments are passed
- */
- execArgv?: string[];
- /**
- * Specifies the memory limit for `worker_thread` or `child_process` before they are recycled.
- * If you see memory leaks, try to tinker this value.
- */
- vmMemoryLimit?: string | number;
- /**
- * Pool used to run tests in.
- *
- * Supports 'threads', 'forks', 'vmThreads', 'vmForks'
- *
- * @default 'forks'
- */
- pool?: Exclude<Pool, "browser"> | PoolRunnerInitializer;
- /**
- * Maximum number or percentage of workers to run tests in.
- */
- maxWorkers?: number | string;
- /**
- * Should all test files run in parallel. Doesn't affect tests running in the same file.
- * Setting this to `false` will override `maxWorkers` option to `1`.
- *
- * @default true
- */
- fileParallelism?: boolean;
- /**
- * Options for projects
- */
- projects?: TestProjectConfiguration[];
- /**
- * Update snapshot
- *
- * @default false
- */
- update?: boolean;
- /**
- * Watch mode
- *
- * @default !process.env.CI
- */
- watch?: boolean;
- /**
- * Project root
- *
- * @default process.cwd()
- */
- root?: string;
- /**
- * Custom reporter for output. Can contain one or more built-in report names, reporter instances,
- * and/or paths to custom reporters.
- *
- * @default []
- */
- reporters?: Arrayable<ReporterName | InlineReporter> | ((ReporterName | InlineReporter) | [ReporterName] | ReporterWithOptions)[];
- /**
- * Write test results to a file when the --reporter=json` or `--reporter=junit` option is also specified.
- * Also definable individually per reporter by using an object instead.
- */
- outputFile?: string | (Partial<Record<BuiltinReporters, string>> & Record<string, string>);
- /**
- * Default timeout of a test in milliseconds
- *
- * @default 5000
- */
- testTimeout?: number;
- /**
- * Default timeout of a hook in milliseconds
- *
- * @default 10000
- */
- hookTimeout?: number;
- /**
- * Default timeout to wait for close when Vitest shuts down, in milliseconds
- *
- * @default 10000
- */
- teardownTimeout?: number;
- /**
- * Silent mode
- *
- * Use `'passed-only'` to see logs from failing tests only.
- *
- * @default false
- */
- silent?: boolean | "passed-only";
- /**
- * Hide logs for skipped tests
- *
- * @default false
- */
- hideSkippedTests?: boolean;
- /**
- * Path to setup files
- */
- setupFiles?: string | string[];
- /**
- * Path to global setup files
- */
- globalSetup?: string | string[];
- /**
- * Glob pattern of file paths that will trigger the whole suite rerun
- *
- * Useful if you are testing calling CLI commands
- *
- * @default ['**\/package.json/**', '**\/{vitest,vite}.config.*\/**']
- */
- forceRerunTriggers?: string[];
- /**
- * Pattern configuration to rerun only the tests that are affected
- * by the changes of specific files in the repository.
- */
- watchTriggerPatterns?: WatcherTriggerPattern[];
- /**
- * Coverage options
- */
- coverage?: CoverageOptions;
- /**
- * run test names with the specified pattern
- */
- testNamePattern?: string | RegExp;
- /**
- * Will call `.mockClear()` on all spies before each test
- * @default false
- */
- clearMocks?: boolean;
- /**
- * Will call `.mockReset()` on all spies before each test
- * @default false
- */
- mockReset?: boolean;
- /**
- * Will call `.mockRestore()` on all spies before each test
- * @default false
- */
- restoreMocks?: boolean;
- /**
- * Will restore all global stubs to their original values before each test
- * @default false
- */
- unstubGlobals?: boolean;
- /**
- * Will restore all env stubs to their original values before each test
- * @default false
- */
- unstubEnvs?: boolean;
- /**
- * Serve API options.
- *
- * When set to true, the default port is 51204.
- *
- * @default false
- */
- api?: boolean | number | ApiConfig;
- /**
- * Enable Vitest UI
- *
- * @default false
- */
- ui?: boolean;
- /**
- * options for test in a browser environment
- *
- * @default false
- */
- browser?: BrowserConfigOptions;
- /**
- * Open UI automatically.
- *
- * @default !process.env.CI
- */
- open?: boolean;
- /**
- * Base url for the UI
- *
- * @default '/__vitest__/'
- */
- uiBase?: string;
- /**
- * Format options for snapshot testing.
- */
- snapshotFormat?: Omit<PrettyFormatOptions, "plugins" | "compareKeys"> & {
- compareKeys?: null | undefined;
- };
- /**
- * Path to a module which has a default export of diff config.
- */
- diff?: string | SerializedDiffOptions;
- /**
- * Paths to snapshot serializer modules.
- */
- snapshotSerializers?: string[];
- /**
- * Resolve custom snapshot path
- */
- resolveSnapshotPath?: ResolveSnapshotPathHandler;
- /**
- * Path to a custom snapshot environment module that has a default export of `SnapshotEnvironment` object.
- */
- snapshotEnvironment?: string;
- /**
- * Pass with no tests
- */
- passWithNoTests?: boolean;
- /**
- * Allow tests and suites that are marked as only
- *
- * @default !process.env.CI
- */
- allowOnly?: boolean;
- /**
- * Show heap usage after each test. Useful for debugging memory leaks.
- */
- logHeapUsage?: boolean;
- /**
- * Custom environment variables assigned to `process.env` before running tests.
- */
- env?: Partial<NodeJS.ProcessEnv>;
- /**
- * Options for @sinon/fake-timers
- */
- fakeTimers?: FakeTimerInstallOpts;
- /**
- * Custom handler for console.log in tests.
- *
- * Return `false` to ignore the log.
- */
- onConsoleLog?: (log: string, type: "stdout" | "stderr", entity: TestModule | TestCase | TestSuite | undefined) => boolean | void;
- /**
- * Enable stack trace filtering. If absent, all stack trace frames
- * will be shown.
- *
- * Return `false` to omit the frame.
- */
- onStackTrace?: (error: TestError, frame: ParsedStack) => boolean | void;
- /**
- * A callback that can return `false` to ignore an unhandled error
- */
- onUnhandledError?: OnUnhandledErrorCallback;
- /**
- * Indicates if CSS files should be processed.
- *
- * When excluded, the CSS files will be replaced with empty strings to bypass the subsequent processing.
- *
- * @default { include: [], modules: { classNameStrategy: false } }
- */
- css?: boolean | {
- include?: RegExp | RegExp[];
- exclude?: RegExp | RegExp[];
- modules?: {
- classNameStrategy?: CSSModuleScopeStrategy;
- };
- };
- /**
- * A number of tests that are allowed to run at the same time marked with `test.concurrent`.
- * @default 5
- */
- maxConcurrency?: number;
- /**
- * Options for configuring cache policy.
- * @default { dir: 'node_modules/.vite/vitest/{project-hash}' }
- */
- cache?: false | {
- /**
- * @deprecated Use Vite's "cacheDir" instead if you want to change the cache director. Note caches will be written to "cacheDir\/vitest".
- */
- dir: string;
- };
- /**
- * Options for configuring the order of running tests.
- */
- sequence?: SequenceOptions;
- /**
- * Specifies an `Object`, or an `Array` of `Object`,
- * which defines aliases used to replace values in `import` or `require` statements.
- * Will be merged with the default aliases inside `resolve.alias`.
- */
- alias?: AliasOptions;
- /**
- * Ignore any unhandled errors that occur
- *
- * @default false
- */
- dangerouslyIgnoreUnhandledErrors?: boolean;
- /**
- * Options for configuring typechecking test environment.
- */
- typecheck?: Partial<TypecheckConfig>;
- /**
- * The number of milliseconds after which a test is considered slow and reported as such in the results.
- *
- * @default 300
- */
- slowTestThreshold?: number;
- /**
- * Path to a custom test runner.
- */
- runner?: string;
- /**
- * Debug tests by opening `node:inspector` in worker / child process.
- * Provides similar experience as `--inspect` Node CLI argument.
- *
- * Requires `fileParallelism: false`.
- */
- inspect?: boolean | string;
- /**
- * Debug tests by opening `node:inspector` in worker / child process and wait for debugger to connect.
- * Provides similar experience as `--inspect-brk` Node CLI argument.
- *
- * Requires `fileParallelism: false`.
- */
- inspectBrk?: boolean | string;
- /**
- * Inspector options. If `--inspect` or `--inspect-brk` is enabled, these options will be passed to the inspector.
- */
- inspector?: {
- /**
- * Enable inspector
- */
- enabled?: boolean;
- /**
- * Port to run inspector on
- */
- port?: number;
- /**
- * Host to run inspector on
- */
- host?: string;
- /**
- * Wait for debugger to connect before running tests
- */
- waitForDebugger?: boolean;
- };
- /**
- * Define variables that will be returned from `inject` in the test environment.
- * @example
- * ```ts
- * // vitest.config.ts
- * export default defineConfig({
- * test: {
- * provide: {
- * someKey: 'someValue'
- * }
- * }
- * })
- * ```
- * ```ts
- * // test file
- * import { inject } from 'vitest'
- * const value = inject('someKey') // 'someValue'
- * ```
- */
- provide?: Partial<ProvidedContext>;
- /**
- * Configuration options for expect() matches.
- */
- expect?: {
- /**
- * Throw an error if tests don't have any expect() assertions.
- */
- requireAssertions?: boolean;
- /**
- * Default options for expect.poll()
- */
- poll?: {
- /**
- * Timeout in milliseconds
- * @default 1000
- */
- timeout?: number;
- /**
- * Polling interval in milliseconds
- * @default 50
- */
- interval?: number;
- };
- };
- /**
- * Modify default Chai config. Vitest uses Chai for `expect` and `assert` matches.
- * https://github.com/chaijs/chai/blob/4.x.x/lib/chai/config.js
- */
- chaiConfig?: ChaiConfig;
- /**
- * Stop test execution when given number of tests have failed.
- */
- bail?: number;
- /**
- * Retry the test specific number of times if it fails.
- *
- * @default 0
- */
- retry?: number;
- /**
- * Show full diff when snapshot fails instead of a patch.
- */
- expandSnapshotDiff?: boolean;
- /**
- * By default, Vitest automatically intercepts console logging during tests for extra formatting of test file, test title, etc...
- * This is also required for console log preview on Vitest UI.
- * However, disabling such interception might help when you want to debug a code with normal synchronous terminal console logging.
- *
- * This option has no effect on browser pool since Vitest preserves original logging on browser devtools.
- *
- * @default false
- */
- disableConsoleIntercept?: boolean;
- /**
- * Always print console stack traces.
- *
- * @default false
- */
- printConsoleTrace?: boolean;
- /**
- * Include "location" property inside the test definition
- *
- * @default false
- */
- includeTaskLocation?: boolean;
- /**
- * Directory path for storing attachments created by `context.annotate`
- *
- * @default '.vitest-attachments'
- */
- attachmentsDir?: string;
- /**
- * Experimental features
- *
- * @experimental
- */
- experimental?: {
- /**
- * Enable caching of modules on the file system between reruns.
- */
- fsModuleCache?: boolean;
- /**
- * Path relative to the root of the project where the fs module cache will be stored.
- * @default node_modules/.experimental-vitest-cache
- */
- fsModuleCachePath?: string;
- /**
- * {@link https://vitest.dev/guide/open-telemetry}
- */
- openTelemetry?: {
- enabled: boolean;
- sdkPath?: string;
- browserSdkPath?: string;
- };
- /**
- * Show imports (top 10) that take a long time.
- *
- * Enabling this will also show a breakdown by default in UI, but you can always press a button to toggle it.
- */
- printImportBreakdown?: boolean;
- };
-}
-interface TypecheckConfig {
- /**
- * Run typechecking tests alongside regular tests.
- */
- enabled?: boolean;
- /**
- * When typechecking is enabled, only run typechecking tests.
- */
- only?: boolean;
- /**
- * What tools to use for type checking.
- *
- * @default 'tsc'
- */
- checker: "tsc" | "vue-tsc" | (string & Record<never, never>);
- /**
- * Pattern for files that should be treated as test files
- *
- * @default ['**\/*.{test,spec}-d.?(c|m)[jt]s?(x)']
- */
- include: string[];
- /**
- * Pattern for files that should not be treated as test files
- *
- * @default ['**\/node_modules/**', '**\/dist/**', '**\/cypress/**', '**\/.{idea,git,cache,output,temp}/**', '**\/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build,eslint,prettier}.config.*']
- */
- exclude: string[];
- /**
- * Check JS files that have `@ts-check` comment.
- * If you have it enabled in tsconfig, this will not overwrite it.
- */
- allowJs?: boolean;
- /**
- * Do not fail, if Vitest found errors outside the test files.
- */
- ignoreSourceErrors?: boolean;
- /**
- * Path to tsconfig, relative to the project root.
- */
- tsconfig?: string;
- /**
- * Minimum time in milliseconds it takes to spawn the typechecker.
- * @default 10_000
- */
- spawnTimeout?: number;
-}
-interface UserConfig extends InlineConfig {
- /**
- * Path to the config file.
- *
- * Default resolving to `vitest.config.*`, `vite.config.*`
- *
- * Setting to `false` will disable config resolving.
- */
- config?: string | false | undefined;
- /**
- * Do not run tests when Vitest starts.
- *
- * Vitest will only run tests if it's called programmatically or the test file changes.
- *
- * If CLI file filters are passed, standalone mode is ignored.
- */
- standalone?: boolean;
- /**
- * Use happy-dom
- */
- dom?: boolean;
- /**
- * Run tests that cover a list of source files
- */
- related?: string[] | string;
- /**
- * Overrides Vite mode
- * @default 'test'
- */
- mode?: string;
- /**
- * Runs tests that are affected by the changes in the repository, or between specified branch or commit hash
- * Requires initialized git repository
- * @default false
- */
- changed?: boolean | string;
- /**
- * Test suite shard to execute in a format of <index>/<count>.
- * Will divide tests into a `count` numbers, and run only the `indexed` part.
- * Cannot be used with enabled watch.
- * @example --shard=2/3
- */
- shard?: string;
- /**
- * Name of the project or projects to run.
- */
- project?: string | string[];
- /**
- * Additional exclude patterns
- */
- cliExclude?: string[];
- /**
- * Override vite config's clearScreen from cli
- */
- clearScreen?: boolean;
- /**
- * benchmark.compare option exposed at the top level for cli
- */
- compare?: string;
- /**
- * benchmark.outputJson option exposed at the top level for cli
- */
- outputJson?: string;
- /**
- * Directory of blob reports to merge
- * @default '.vitest-reports'
- */
- mergeReports?: string;
- /**
- * Delete all Vitest caches, including `experimental.fsModuleCache`.
- * @experimental
- */
- clearCache?: boolean;
-}
-type OnUnhandledErrorCallback = (error: (TestError | Error) & {
- type: string;
-}) => boolean | void;
-interface ResolvedConfig extends Omit<Required<UserConfig>, "project" | "config" | "filters" | "browser" | "coverage" | "testNamePattern" | "related" | "api" | "reporters" | "resolveSnapshotPath" | "benchmark" | "shard" | "cache" | "sequence" | "typecheck" | "runner" | "pool" | "cliExclude" | "diff" | "setupFiles" | "snapshotEnvironment" | "bail" | "name" | "vmMemoryLimit" | "fileParallelism"> {
- mode: VitestRunMode;
- name: ProjectName["label"];
- color?: ProjectName["color"];
- base?: string;
- diff?: string | SerializedDiffOptions;
- bail?: number;
- setupFiles: string[];
- snapshotEnvironment?: string;
- config?: string;
- filters?: string[];
- testNamePattern?: RegExp;
- related?: string[];
- coverage: ResolvedCoverageOptions;
- snapshotOptions: SnapshotStateOptions;
- browser: ResolvedBrowserOptions;
- pool: Pool;
- poolRunner?: PoolRunnerInitializer;
- reporters: (InlineReporter | ReporterWithOptions)[];
- defines: Record<string, any>;
- viteDefine: Record<string, any>;
- api: ApiConfig & {
- token: string;
- };
- cliExclude?: string[];
- project: string[];
- benchmark?: Required<Omit<BenchmarkUserOptions, "outputFile" | "compare" | "outputJson">> & Pick<BenchmarkUserOptions, "outputFile" | "compare" | "outputJson">;
- shard?: {
- index: number;
- count: number;
- };
- cache: {
- /**
- * @deprecated
- */
- dir: string;
- } | false;
- sequence: {
- sequencer: TestSequencerConstructor;
- hooks: SequenceHooks;
- setupFiles: SequenceSetupFiles;
- shuffle?: boolean;
- concurrent?: boolean;
- seed: number;
- groupOrder: number;
- };
- typecheck: Omit<TypecheckConfig, "enabled"> & {
- enabled: boolean;
- };
- runner?: string;
- maxWorkers: number;
- vmMemoryLimit?: UserConfig["vmMemoryLimit"];
- dumpDir?: string;
-}
-type NonProjectOptions = "shard" | "watch" | "run" | "cache" | "update" | "reporters" | "outputFile" | "teardownTimeout" | "silent" | "forceRerunTriggers" | "testNamePattern" | "ui" | "open" | "uiBase" | "snapshotFormat" | "resolveSnapshotPath" | "passWithNoTests" | "onConsoleLog" | "onStackTrace" | "dangerouslyIgnoreUnhandledErrors" | "slowTestThreshold" | "inspect" | "inspectBrk" | "coverage" | "watchTriggerPatterns";
-interface ServerDepsOptions {
- /**
- * Externalize means that Vite will bpass the package to native Node.
- *
- * Externalized dependencies will not be applied Vite's transformers and resolvers.
- * And does not support HMR on reload.
- *
- * Typically, packages under `node_modules` are externalized.
- */
- external?: (string | RegExp)[];
- /**
- * Vite will process inlined modules.
- *
- * This could be helpful to handle packages that ship `.js` in ESM format (that Node can't handle).
- *
- * If `true`, every dependency will be inlined
- */
- inline?: (string | RegExp)[] | true;
- /**
- * Try to guess the CJS version of a package when it's invalid ESM
- * @default false
- */
- fallbackCJS?: boolean;
-}
-type ProjectConfig = Omit<InlineConfig, NonProjectOptions | "sequencer" | "deps"> & {
- mode?: string;
- sequencer?: Omit<SequenceOptions, "sequencer" | "seed">;
- deps?: Omit<DepsOptions, "moduleDirectories">;
-};
-type ResolvedProjectConfig = Omit<ResolvedConfig, Exclude<NonProjectOptions, "coverage" | "watch">>;
-interface UserWorkspaceConfig extends UserConfig$1 {
- test?: ProjectConfig;
-}
-type UserProjectConfigFn = (env: ConfigEnv) => UserWorkspaceConfig | Promise<UserWorkspaceConfig>;
-type UserProjectConfigExport = UserWorkspaceConfig | Promise<UserWorkspaceConfig> | UserProjectConfigFn;
-type TestProjectInlineConfiguration = (UserWorkspaceConfig & {
- /**
- * Relative path to the extendable config. All other options will be merged with this config.
- * If `true`, the project will inherit all options from the root config.
- * @example '../vite.config.ts'
- */
- extends?: string | true;
-});
-type TestProjectConfiguration = string | TestProjectInlineConfiguration | Promise<UserWorkspaceConfig> | UserProjectConfigFn;
-
-export { CoverageMap as C, TestSuite as K, Logger as L, experimental_getRunnerTask as Q, TestProject as T, Vitest as V, BenchmarkReporter as aE, BenchmarkReportsMap as aF, DefaultReporter as aG, DotReporter as aH, GithubActionsReporter as aI, HangingProcessReporter as aJ, JsonReporter as aK, JUnitReporter as aL, ReportersMap as aM, TapFlatReporter as aN, TapReporter as aO, VerboseBenchmarkReporter as aP, VerboseReporter as aQ, BaseReporter as aR, TestSpecification as k, VitestPackageInstaller as p, TestCase as v, TestCollection as w, TestModule as y };
-export type { BrowserCommand as $, ApiConfig as A, TestResult as B, TestResultFailed as D, TestResultPassed as E, TestResultSkipped as F, TestState as G, HTMLOptions as H, InlineConfig as I, JsonOptions as J, ModuleDiagnostic as M, TestSuiteState as N, OnServerRestartHandler as O, PoolWorker as P, ResolvedCoverageOptions as R, SerializedTestProject as S, UserWorkspaceConfig as U, WatcherTriggerPattern as W, TestSequencerConstructor as X, BenchmarkUserOptions as Y, BrowserBuiltinProvider as Z, _BrowserNames as _, ReportContext as a, BrowserCommandContext as a0, BrowserConfigOptions as a1, BrowserInstanceOption as a2, BrowserModuleMocker as a3, BrowserOrchestrator as a4, BrowserProvider as a5, BrowserProviderOption as a6, BrowserScript as a7, BrowserServerFactory as a8, BrowserServerOptions as a9, TestRunResult as aA, ReportedHookContext as aB, Reporter as aC, TestRunEndReason as aD, BenchmarkBuiltinReporters as aS, BuiltinReporterOptions as aT, BuiltinReporters as aU, JsonAssertionResult as aV, JsonTestResult as aW, JsonTestResults as aX, BrowserServerState as aa, BrowserServerStateSession as ab, CDPSession as ac, ParentProjectBrowser as ad, ProjectBrowser as ae, ResolvedBrowserOptions as af, ToMatchScreenshotComparators as ag, ToMatchScreenshotOptions as ah, BuiltinEnvironment as ai, CSSModuleScopeStrategy as aj, DepsOptimizationOptions as ak, EnvironmentOptions as al, Pool as am, ProjectConfig as an, ResolvedProjectConfig as ao, ResolveSnapshotPathHandler as ap, ResolveSnapshotPathHandlerContext as aq, TypecheckConfig as ar, VitestEnvironment as as, BaseCoverageOptions as at, CoverageIstanbulOptions as au, CoverageOptions as av, CoverageProvider as aw, CoverageProviderModule as ax, CoverageReporter as ay, CustomProviderOptions as az, TestProjectConfiguration as b, CoverageV8Options as c, UserProjectConfigFn as d, UserProjectConfigExport as e, UserConfig as f, TestProjectInlineConfiguration as g, ResolvedConfig as h, VitestRunMode as i, VitestOptions as j, PoolOptions as l, WorkerRequest as m, TestSequencer as n, OnTestsRerunHandler as o, PoolRunnerInitializer as q, PoolTask as r, WorkerResponse as s, JUnitOptions as t, TaskOptions as u, TestDiagnostic as x, TestModuleState as z };
diff --git a/vanilla/node_modules/vitest/dist/chunks/rpc.BoxB0q7B.js b/vanilla/node_modules/vitest/dist/chunks/rpc.BoxB0q7B.js
deleted file mode 100644
index 0e6d395..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/rpc.BoxB0q7B.js
+++ /dev/null
@@ -1,76 +0,0 @@
-import { getSafeTimers } from '@vitest/utils/timers';
-import { c as createBirpc } from './index.Chj8NDwU.js';
-import { g as getWorkerState } from './utils.DvEY5TfP.js';
-
-const { get } = Reflect;
-function withSafeTimers(fn) {
- const { setTimeout, clearTimeout, nextTick, setImmediate, clearImmediate } = getSafeTimers();
- const currentSetTimeout = globalThis.setTimeout;
- const currentClearTimeout = globalThis.clearTimeout;
- const currentSetImmediate = globalThis.setImmediate;
- const currentClearImmediate = globalThis.clearImmediate;
- const currentNextTick = globalThis.process?.nextTick;
- try {
- globalThis.setTimeout = setTimeout;
- globalThis.clearTimeout = clearTimeout;
- if (setImmediate) globalThis.setImmediate = setImmediate;
- if (clearImmediate) globalThis.clearImmediate = clearImmediate;
- if (globalThis.process && nextTick) globalThis.process.nextTick = nextTick;
- return fn();
- } finally {
- globalThis.setTimeout = currentSetTimeout;
- globalThis.clearTimeout = currentClearTimeout;
- globalThis.setImmediate = currentSetImmediate;
- globalThis.clearImmediate = currentClearImmediate;
- if (globalThis.process && nextTick) nextTick(() => {
- globalThis.process.nextTick = currentNextTick;
- });
- }
-}
-const promises = /* @__PURE__ */ new Set();
-async function rpcDone() {
- if (!promises.size) return;
- const awaitable = Array.from(promises);
- return Promise.all(awaitable);
-}
-const onCancelCallbacks = [];
-function onCancel(callback) {
- onCancelCallbacks.push(callback);
-}
-function createRuntimeRpc(options) {
- return createSafeRpc(createBirpc({ async onCancel(reason) {
- await Promise.all(onCancelCallbacks.map((fn) => fn(reason)));
- } }, {
- eventNames: [
- "onUserConsoleLog",
- "onCollected",
- "onCancel"
- ],
- timeout: -1,
- ...options
- }));
-}
-function createSafeRpc(rpc) {
- return new Proxy(rpc, { get(target, p, handler) {
- // keep $rejectPendingCalls as sync function
- if (p === "$rejectPendingCalls") return rpc.$rejectPendingCalls;
- const sendCall = get(target, p, handler);
- const safeSendCall = (...args) => withSafeTimers(async () => {
- const result = sendCall(...args);
- promises.add(result);
- try {
- return await result;
- } finally {
- promises.delete(result);
- }
- });
- safeSendCall.asEvent = sendCall.asEvent;
- return safeSendCall;
- } });
-}
-function rpc() {
- const { rpc } = getWorkerState();
- return rpc;
-}
-
-export { rpcDone as a, createRuntimeRpc as c, onCancel as o, rpc as r };
diff --git a/vanilla/node_modules/vitest/dist/chunks/rpc.d.RH3apGEf.d.ts b/vanilla/node_modules/vitest/dist/chunks/rpc.d.RH3apGEf.d.ts
deleted file mode 100644
index ee0dbc5..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/rpc.d.RH3apGEf.d.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-import { CancelReason, File, TestArtifact, TaskResultPack, TaskEventPack } from '@vitest/runner';
-import { SnapshotResult } from '@vitest/snapshot';
-import { FetchFunctionOptions, FetchResult } from 'vite/module-runner';
-import { O as OTELCarrier } from './traces.d.402V_yFI.js';
-
-interface AfterSuiteRunMeta {
- coverage?: unknown;
- testFiles: string[];
- environment: string;
- projectName?: string;
-}
-interface UserConsoleLog {
- content: string;
- origin?: string;
- browser?: boolean;
- type: "stdout" | "stderr";
- taskId?: string;
- time: number;
- size: number;
-}
-interface ModuleGraphData {
- graph: Record<string, string[]>;
- externalized: string[];
- inlined: string[];
-}
-interface ProvidedContext {}
-interface ResolveFunctionResult {
- id: string;
- file: string;
- url: string;
-}
-interface FetchCachedFileSystemResult {
- cached: true;
- tmp: string;
- id: string;
- file: string | null;
- url: string;
- invalidate: boolean;
-}
-type LabelColor = "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan" | "white";
-
-interface RuntimeRPC {
- fetch: (id: string, importer: string | undefined, environment: string, options?: FetchFunctionOptions, otelCarrier?: OTELCarrier) => Promise<FetchResult | FetchCachedFileSystemResult>;
- resolve: (id: string, importer: string | undefined, environment: string) => Promise<ResolveFunctionResult | null>;
- transform: (id: string) => Promise<{
- code?: string;
- }>;
- onUserConsoleLog: (log: UserConsoleLog) => void;
- onUnhandledError: (err: unknown, type: string) => void;
- onQueued: (file: File) => void;
- onCollected: (files: File[]) => Promise<void>;
- onAfterSuiteRun: (meta: AfterSuiteRunMeta) => void;
- onTaskArtifactRecord: <Artifact extends TestArtifact>(testId: string, artifact: Artifact) => Promise<Artifact>;
- onTaskUpdate: (pack: TaskResultPack[], events: TaskEventPack[]) => Promise<void>;
- onCancel: (reason: CancelReason) => void;
- getCountOfFailedTests: () => number;
- snapshotSaved: (snapshot: SnapshotResult) => void;
- resolveSnapshotPath: (testPath: string) => string;
-}
-interface RunnerRPC {
- onCancel: (reason: CancelReason) => void;
-}
-
-export type { AfterSuiteRunMeta as A, LabelColor as L, ModuleGraphData as M, ProvidedContext as P, RuntimeRPC as R, UserConsoleLog as U, RunnerRPC as a };
diff --git a/vanilla/node_modules/vitest/dist/chunks/setup-common.Cm-kSBVi.js b/vanilla/node_modules/vitest/dist/chunks/setup-common.Cm-kSBVi.js
deleted file mode 100644
index d632e05..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/setup-common.Cm-kSBVi.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import { r as resolveCoverageProviderModule } from './coverage.D_JHT54q.js';
-import { addSerializer } from '@vitest/snapshot';
-import { setSafeTimers } from '@vitest/utils/timers';
-import { g as getWorkerState } from './utils.DvEY5TfP.js';
-
-async function startCoverageInsideWorker(options, loader, runtimeOptions) {
- const coverageModule = await resolveCoverageProviderModule(options, loader);
- if (coverageModule) return coverageModule.startCoverage?.(runtimeOptions);
- return null;
-}
-async function takeCoverageInsideWorker(options, loader) {
- const coverageModule = await resolveCoverageProviderModule(options, loader);
- if (coverageModule) return coverageModule.takeCoverage?.({ moduleExecutionInfo: loader.moduleExecutionInfo });
- return null;
-}
-async function stopCoverageInsideWorker(options, loader, runtimeOptions) {
- const coverageModule = await resolveCoverageProviderModule(options, loader);
- if (coverageModule) return coverageModule.stopCoverage?.(runtimeOptions);
- return null;
-}
-
-let globalSetup = false;
-async function setupCommonEnv(config) {
- setupDefines(config);
- setupEnv(config.env);
- if (globalSetup) return;
- globalSetup = true;
- setSafeTimers();
- if (config.globals) (await import('./globals.DOayXfHP.js')).registerApiGlobally();
-}
-function setupDefines(config) {
- for (const key in config.defines) globalThis[key] = config.defines[key];
-}
-function setupEnv(env) {
- const state = getWorkerState();
- // same boolean-to-string assignment as VitestPlugin.configResolved
- const { PROD, DEV, ...restEnvs } = env;
- state.metaEnv.PROD = PROD;
- state.metaEnv.DEV = DEV;
- for (const key in restEnvs) state.metaEnv[key] = env[key];
-}
-async function loadDiffConfig(config, moduleRunner) {
- if (typeof config.diff === "object") return config.diff;
- if (typeof config.diff !== "string") return;
- const diffModule = await moduleRunner.import(config.diff);
- if (diffModule && typeof diffModule.default === "object" && diffModule.default != null) return diffModule.default;
- else throw new Error(`invalid diff config file ${config.diff}. Must have a default export with config object`);
-}
-async function loadSnapshotSerializers(config, moduleRunner) {
- const files = config.snapshotSerializers;
- (await Promise.all(files.map(async (file) => {
- const mo = await moduleRunner.import(file);
- if (!mo || typeof mo.default !== "object" || mo.default === null) throw new Error(`invalid snapshot serializer file ${file}. Must export a default object`);
- const config = mo.default;
- if (typeof config.test !== "function" || typeof config.serialize !== "function" && typeof config.print !== "function") throw new TypeError(`invalid snapshot serializer in ${file}. Must have a 'test' method along with either a 'serialize' or 'print' method.`);
- return config;
- }))).forEach((serializer) => addSerializer(serializer));
-}
-
-export { stopCoverageInsideWorker as a, loadSnapshotSerializers as b, setupCommonEnv as c, loadDiffConfig as l, startCoverageInsideWorker as s, takeCoverageInsideWorker as t };
diff --git a/vanilla/node_modules/vitest/dist/chunks/startModuleRunner.DEj0jb3e.js b/vanilla/node_modules/vitest/dist/chunks/startModuleRunner.DEj0jb3e.js
deleted file mode 100644
index 35b8553..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/startModuleRunner.DEj0jb3e.js
+++ /dev/null
@@ -1,861 +0,0 @@
-import fs from 'node:fs';
-import { isBareImport } from '@vitest/utils/helpers';
-import { i as isBuiltin, a as isBrowserExternal, t as toBuiltin } from './modules.BJuCwlRJ.js';
-import { pathToFileURL } from 'node:url';
-import { normalize as normalize$1, join as join$1 } from 'pathe';
-import { distDir } from '../path.js';
-import { serializeValue } from '@vitest/utils/serialize';
-import { VitestModuleEvaluator, unwrapId } from '../module-evaluator.js';
-import { resolve as resolve$1, isAbsolute as isAbsolute$1 } from 'node:path';
-import vm from 'node:vm';
-import { MockerRegistry, mockObject, RedirectedModule, AutomockedModule } from '@vitest/mocker';
-import nodeModule from 'node:module';
-import * as viteModuleRunner from 'vite/module-runner';
-import { T as Traces } from './traces.CCmnQaNT.js';
-
-class VitestTransport {
- constructor(options) {
- this.options = options;
- }
- async invoke(event) {
- if (event.type !== "custom") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support Vite HMR events.`) };
- if (event.event !== "vite:invoke") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support ${event.event} event.`) };
- const { name, data } = event.data;
- if (name === "getBuiltins")
- // we return an empty array here to avoid client-side builtin check,
- // as we need builtins to go through `fetchModule`
- return { result: [] };
- if (name !== "fetchModule") return { error: /* @__PURE__ */ new Error(`Unknown method: ${name}. Expected "fetchModule".`) };
- try {
- return { result: await this.options.fetchModule(...data) };
- } catch (error) {
- return { error };
- }
- }
-}
-
-const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
-function normalizeWindowsPath(input = "") {
- if (!input) return input;
- return input.replace(/\\/g, "/").replace(_DRIVE_LETTER_START_RE, (r) => r.toUpperCase());
-}
-const _UNC_REGEX = /^[/\\]{2}/;
-const _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/;
-const _DRIVE_LETTER_RE = /^[A-Za-z]:$/;
-const _EXTNAME_RE = /.(\.[^./]+|\.)$/;
-const normalize = function(path) {
- if (path.length === 0) return ".";
- path = normalizeWindowsPath(path);
- const isUNCPath = path.match(_UNC_REGEX);
- const isPathAbsolute = isAbsolute(path);
- const trailingSeparator = path[path.length - 1] === "/";
- path = normalizeString(path, !isPathAbsolute);
- if (path.length === 0) {
- if (isPathAbsolute) return "/";
- return trailingSeparator ? "./" : ".";
- }
- if (trailingSeparator) path += "/";
- if (_DRIVE_LETTER_RE.test(path)) path += "/";
- if (isUNCPath) {
- if (!isPathAbsolute) return `//./${path}`;
- return `//${path}`;
- }
- return isPathAbsolute && !isAbsolute(path) ? `/${path}` : path;
-};
-const join = function(...segments) {
- let path = "";
- for (const seg of segments) {
- if (!seg) continue;
- if (path.length > 0) {
- const pathTrailing = path[path.length - 1] === "/";
- const segLeading = seg[0] === "/";
- if (pathTrailing && segLeading) path += seg.slice(1);
- else path += pathTrailing || segLeading ? seg : `/${seg}`;
- } else path += seg;
- }
- return normalize(path);
-};
-function cwd$1() {
- if (typeof process !== "undefined" && typeof process.cwd === "function") return process.cwd().replace(/\\/g, "/");
- return "/";
-}
-const resolve = function(...arguments_) {
- arguments_ = arguments_.map((argument) => normalizeWindowsPath(argument));
- let resolvedPath = "";
- let resolvedAbsolute = false;
- for (let index = arguments_.length - 1; index >= -1 && !resolvedAbsolute; index--) {
- const path = index >= 0 ? arguments_[index] : cwd$1();
- if (!path || path.length === 0) continue;
- resolvedPath = `${path}/${resolvedPath}`;
- resolvedAbsolute = isAbsolute(path);
- }
- resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute);
- if (resolvedAbsolute && !isAbsolute(resolvedPath)) return `/${resolvedPath}`;
- return resolvedPath.length > 0 ? resolvedPath : ".";
-};
-function normalizeString(path, allowAboveRoot) {
- let res = "";
- let lastSegmentLength = 0;
- let lastSlash = -1;
- let dots = 0;
- let char = null;
- for (let index = 0; index <= path.length; ++index) {
- if (index < path.length) char = path[index];
- else if (char === "/") break;
- else char = "/";
- if (char === "/") {
- if (lastSlash === index - 1 || dots === 1);
- else if (dots === 2) {
- if (res.length < 2 || lastSegmentLength !== 2 || res[res.length - 1] !== "." || res[res.length - 2] !== ".") {
- if (res.length > 2) {
- const lastSlashIndex = res.lastIndexOf("/");
- if (lastSlashIndex === -1) {
- res = "";
- lastSegmentLength = 0;
- } else {
- res = res.slice(0, lastSlashIndex);
- lastSegmentLength = res.length - 1 - res.lastIndexOf("/");
- }
- lastSlash = index;
- dots = 0;
- continue;
- } else if (res.length > 0) {
- res = "";
- lastSegmentLength = 0;
- lastSlash = index;
- dots = 0;
- continue;
- }
- }
- if (allowAboveRoot) {
- res += res.length > 0 ? "/.." : "..";
- lastSegmentLength = 2;
- }
- } else {
- if (res.length > 0) res += `/${path.slice(lastSlash + 1, index)}`;
- else res = path.slice(lastSlash + 1, index);
- lastSegmentLength = index - lastSlash - 1;
- }
- lastSlash = index;
- dots = 0;
- } else if (char === "." && dots !== -1) ++dots;
- else dots = -1;
- }
- return res;
-}
-const isAbsolute = function(p) {
- return _IS_ABSOLUTE_RE.test(p);
-};
-const extname = function(p) {
- if (p === "..") return "";
- const match = _EXTNAME_RE.exec(normalizeWindowsPath(p));
- return match && match[1] || "";
-};
-const dirname = function(p) {
- const segments = normalizeWindowsPath(p).replace(/\/$/, "").split("/").slice(0, -1);
- if (segments.length === 1 && _DRIVE_LETTER_RE.test(segments[0])) segments[0] += "/";
- return segments.join("/") || (isAbsolute(p) ? "/" : ".");
-};
-const basename = function(p, extension) {
- const segments = normalizeWindowsPath(p).split("/");
- let lastSegment = "";
- for (let i = segments.length - 1; i >= 0; i--) {
- const val = segments[i];
- if (val) {
- lastSegment = val;
- break;
- }
- }
- return extension && lastSegment.endsWith(extension) ? lastSegment.slice(0, -extension.length) : lastSegment;
-};
-
-const { existsSync, readdirSync, statSync } = fs;
-function findMockRedirect(root, mockPath, external) {
- const path = external || mockPath;
- // it's a node_module alias
- // all mocks should be inside <root>/__mocks__
- if (external || isNodeBuiltin(mockPath) || !existsSync(mockPath)) {
- const mockFolder = join(root, "__mocks__", dirname(path));
- if (!existsSync(mockFolder)) return null;
- const baseOriginal = basename(path);
- function findFile(mockFolder, baseOriginal) {
- const files = readdirSync(mockFolder);
- for (const file of files) if (basename(file, extname(file)) === baseOriginal) {
- const path = resolve(mockFolder, file);
- // if the same name, return the file
- if (statSync(path).isFile()) return path;
- else {
- // find folder/index.{js,ts}
- const indexFile = findFile(path, "index");
- if (indexFile) return indexFile;
- }
- }
- return null;
- }
- return findFile(mockFolder, baseOriginal);
- }
- const fullPath = resolve(dirname(path), "__mocks__", basename(path));
- return existsSync(fullPath) ? fullPath : null;
-}
-const builtins = new Set([
- ...nodeModule.builtinModules,
- "assert/strict",
- "diagnostics_channel",
- "dns/promises",
- "fs/promises",
- "path/posix",
- "path/win32",
- "readline/promises",
- "stream/consumers",
- "stream/promises",
- "stream/web",
- "timers/promises",
- "util/types",
- "wasi"
-]);
-// https://nodejs.org/api/modules.html#built-in-modules-with-mandatory-node-prefix
-const prefixedBuiltins$1 = new Set([
- "node:sea",
- "node:sqlite",
- "node:test",
- "node:test/reporters"
-]);
-const NODE_BUILTIN_NAMESPACE = "node:";
-function isNodeBuiltin(id) {
- // Added in v18.6.0
- if (nodeModule.isBuiltin) return nodeModule.isBuiltin(id);
- if (prefixedBuiltins$1.has(id)) return true;
- return builtins.has(id.startsWith(NODE_BUILTIN_NAMESPACE) ? id.slice(5) : id);
-}
-
-const spyModulePath = resolve$1(distDir, "spy.js");
-class VitestMocker {
- static pendingIds = [];
- spyModule;
- primitives;
- filterPublicKeys;
- registries = /* @__PURE__ */ new Map();
- mockContext = { callstack: null };
- _otel;
- constructor(moduleRunner, options) {
- this.moduleRunner = moduleRunner;
- this.options = options;
- const context = this.options.context;
- this._otel = options.traces;
- if (context) this.primitives = vm.runInContext("({ Object, Error, Function, RegExp, Symbol, Array, Map })", context);
- else this.primitives = {
- Object,
- Error,
- Function,
- RegExp,
- Symbol: globalThis.Symbol,
- Array,
- Map
- };
- if (options.spyModule) this.spyModule = options.spyModule;
- const Symbol = this.primitives.Symbol;
- this.filterPublicKeys = [
- "__esModule",
- Symbol.asyncIterator,
- Symbol.hasInstance,
- Symbol.isConcatSpreadable,
- Symbol.iterator,
- Symbol.match,
- Symbol.matchAll,
- Symbol.replace,
- Symbol.search,
- Symbol.split,
- Symbol.species,
- Symbol.toPrimitive,
- Symbol.toStringTag,
- Symbol.unscopables
- ];
- }
- get root() {
- return this.options.root;
- }
- get evaluatedModules() {
- return this.moduleRunner.evaluatedModules;
- }
- get moduleDirectories() {
- return this.options.moduleDirectories || [];
- }
- async initializeSpyModule() {
- if (this.spyModule) return;
- this.spyModule = await this.moduleRunner.import(spyModulePath);
- }
- getMockerRegistry() {
- const suite = this.getSuiteFilepath();
- if (!this.registries.has(suite)) this.registries.set(suite, new MockerRegistry());
- return this.registries.get(suite);
- }
- reset() {
- this.registries.clear();
- }
- invalidateModuleById(id) {
- const mockId = this.getMockPath(id);
- const node = this.evaluatedModules.getModuleById(mockId);
- if (node) {
- this.evaluatedModules.invalidateModule(node);
- node.mockedExports = void 0;
- }
- }
- isModuleDirectory(path) {
- return this.moduleDirectories.some((dir) => path.includes(dir));
- }
- getSuiteFilepath() {
- return this.options.getCurrentTestFilepath() || "global";
- }
- createError(message, codeFrame) {
- const Error = this.primitives.Error;
- const error = new Error(message);
- Object.assign(error, { codeFrame });
- return error;
- }
- async resolveId(rawId, importer) {
- return this._otel.$("vitest.mocker.resolve_id", { attributes: {
- "vitest.module.raw_id": rawId,
- "vitest.module.importer": rawId
- } }, async (span) => {
- const result = await this.options.resolveId(rawId, importer);
- if (!result) {
- span.addEvent("could not resolve id, fallback to unresolved values");
- const id = normalizeModuleId(rawId);
- span.setAttributes({
- "vitest.module.id": id,
- "vitest.module.url": rawId,
- "vitest.module.external": id,
- "vitest.module.fallback": true
- });
- return {
- id,
- url: rawId,
- external: id
- };
- }
- // external is node_module or unresolved module
- // for example, some people mock "vscode" and don't have it installed
- const external = !isAbsolute$1(result.file) || this.isModuleDirectory(result.file) ? normalizeModuleId(rawId) : null;
- const id = normalizeModuleId(result.id);
- span.setAttributes({
- "vitest.module.id": id,
- "vitest.module.url": result.url,
- "vitest.module.external": external ?? false
- });
- return {
- ...result,
- id,
- external
- };
- });
- }
- async resolveMocks() {
- if (!VitestMocker.pendingIds.length) return;
- await Promise.all(VitestMocker.pendingIds.map(async (mock) => {
- const { id, url, external } = await this.resolveId(mock.id, mock.importer);
- if (mock.action === "unmock") this.unmockPath(id);
- if (mock.action === "mock") this.mockPath(mock.id, id, url, external, mock.type, mock.factory);
- }));
- VitestMocker.pendingIds = [];
- }
- ensureModule(id, url) {
- const node = this.evaluatedModules.ensureModule(id, url);
- // TODO
- node.meta = {
- id,
- url,
- code: "",
- file: null,
- invalidate: false
- };
- return node;
- }
- async callFunctionMock(id, url, mock) {
- const node = this.ensureModule(id, url);
- if (node.exports) return node.exports;
- const exports$1 = await mock.resolve();
- const moduleExports = new Proxy(exports$1, { get: (target, prop) => {
- const val = target[prop];
- // 'then' can exist on non-Promise objects, need nested instanceof check for logic to work
- if (prop === "then") {
- if (target instanceof Promise) return target.then.bind(target);
- } else if (!(prop in target)) {
- if (this.filterPublicKeys.includes(prop)) return;
- throw this.createError(`[vitest] No "${String(prop)}" export is defined on the "${mock.raw}" mock. Did you forget to return it from "vi.mock"?
-If you need to partially mock a module, you can use "importOriginal" helper inside:
-`, `vi.mock(import("${mock.raw}"), async (importOriginal) => {
- const actual = await importOriginal()
- return {
- ...actual,
- // your mocked methods
- }
-})`);
- }
- return val;
- } });
- node.exports = moduleExports;
- return moduleExports;
- }
- // public method to avoid circular dependency
- getMockContext() {
- return this.mockContext;
- }
- // path used to store mocked dependencies
- getMockPath(dep) {
- return `mock:${dep}`;
- }
- getDependencyMock(id) {
- return this.getMockerRegistry().getById(fixLeadingSlashes(id));
- }
- findMockRedirect(mockPath, external) {
- return findMockRedirect(this.root, mockPath, external);
- }
- mockObject(object, mockExports = {}, behavior = "automock") {
- const createMockInstance = this.spyModule?.createMockInstance;
- if (!createMockInstance) throw this.createError("[vitest] `spyModule` is not defined. This is a Vitest error. Please open a new issue with reproduction.");
- return mockObject({
- globalConstructors: this.primitives,
- createMockInstance,
- type: behavior
- }, object, mockExports);
- }
- unmockPath(id) {
- this.getMockerRegistry().deleteById(id);
- this.invalidateModuleById(id);
- }
- mockPath(originalId, id, url, external, mockType, factory) {
- const registry = this.getMockerRegistry();
- if (mockType === "manual") registry.register("manual", originalId, id, url, factory);
- else if (mockType === "autospy") registry.register("autospy", originalId, id, url);
- else {
- const redirect = this.findMockRedirect(id, external);
- if (redirect) registry.register("redirect", originalId, id, url, redirect);
- else registry.register("automock", originalId, id, url);
- }
- // every time the mock is registered, we remove the previous one from the cache
- this.invalidateModuleById(id);
- }
- async importActual(rawId, importer, callstack) {
- const { url } = await this.resolveId(rawId, importer);
- const node = await this.moduleRunner.fetchModule(url, importer);
- return await this.moduleRunner.cachedRequest(node.url, node, callstack || [importer], void 0, true);
- }
- async importMock(rawId, importer) {
- const { id, url, external } = await this.resolveId(rawId, importer);
- let mock = this.getDependencyMock(id);
- if (!mock) {
- const redirect = this.findMockRedirect(id, external);
- if (redirect) mock = new RedirectedModule(rawId, id, rawId, redirect);
- else mock = new AutomockedModule(rawId, id, rawId);
- }
- if (mock.type === "automock" || mock.type === "autospy") {
- const node = await this.moduleRunner.fetchModule(url, importer);
- const mod = await this.moduleRunner.cachedRequest(url, node, [importer], void 0, true);
- const Object = this.primitives.Object;
- return this.mockObject(mod, Object.create(Object.prototype), mock.type);
- }
- if (mock.type === "manual") return this.callFunctionMock(id, url, mock);
- const node = await this.moduleRunner.fetchModule(mock.redirect);
- return this.moduleRunner.cachedRequest(mock.redirect, node, [importer], void 0, true);
- }
- async requestWithMockedModule(url, evaluatedNode, callstack, mock) {
- return this._otel.$("vitest.mocker.evaluate", async (span) => {
- const mockId = this.getMockPath(evaluatedNode.id);
- span.setAttributes({
- "vitest.module.id": mockId,
- "vitest.mock.type": mock.type,
- "vitest.mock.id": mock.id,
- "vitest.mock.url": mock.url,
- "vitest.mock.raw": mock.raw
- });
- if (mock.type === "automock" || mock.type === "autospy") {
- const cache = this.evaluatedModules.getModuleById(mockId);
- if (cache && cache.mockedExports) return cache.mockedExports;
- const Object = this.primitives.Object;
- // we have to define a separate object that will copy all properties into itself
- // and can't just use the same `exports` define automatically by Vite before the evaluator
- const exports$1 = Object.create(null);
- Object.defineProperty(exports$1, Symbol.toStringTag, {
- value: "Module",
- configurable: true,
- writable: true
- });
- const node = this.ensureModule(mockId, this.getMockPath(evaluatedNode.url));
- node.meta = evaluatedNode.meta;
- node.file = evaluatedNode.file;
- node.mockedExports = exports$1;
- const mod = await this.moduleRunner.cachedRequest(url, node, callstack, void 0, true);
- this.mockObject(mod, exports$1, mock.type);
- return exports$1;
- }
- if (mock.type === "manual" && !callstack.includes(mockId) && !callstack.includes(url)) try {
- callstack.push(mockId);
- // this will not work if user does Promise.all(import(), import())
- // we can also use AsyncLocalStorage to store callstack, but this won't work in the browser
- // maybe we should improve mock API in the future?
- this.mockContext.callstack = callstack;
- return await this.callFunctionMock(mockId, this.getMockPath(url), mock);
- } finally {
- this.mockContext.callstack = null;
- const indexMock = callstack.indexOf(mockId);
- callstack.splice(indexMock, 1);
- }
- else if (mock.type === "redirect" && !callstack.includes(mock.redirect)) {
- span.setAttribute("vitest.mock.redirect", mock.redirect);
- return mock.redirect;
- }
- });
- }
- async mockedRequest(url, evaluatedNode, callstack) {
- const mock = this.getDependencyMock(evaluatedNode.id);
- if (!mock) return;
- return this.requestWithMockedModule(url, evaluatedNode, callstack, mock);
- }
- queueMock(id, importer, factoryOrOptions) {
- const mockType = getMockType(factoryOrOptions);
- VitestMocker.pendingIds.push({
- action: "mock",
- id,
- importer,
- factory: typeof factoryOrOptions === "function" ? factoryOrOptions : void 0,
- type: mockType
- });
- }
- queueUnmock(id, importer) {
- VitestMocker.pendingIds.push({
- action: "unmock",
- id,
- importer
- });
- }
-}
-function getMockType(factoryOrOptions) {
- if (!factoryOrOptions) return "automock";
- if (typeof factoryOrOptions === "function") return "manual";
- return factoryOrOptions.spy ? "autospy" : "automock";
-}
-// unique id that is not available as "$bare_import" like "test"
-// https://nodejs.org/api/modules.html#built-in-modules-with-mandatory-node-prefix
-const prefixedBuiltins = new Set([
- "node:sea",
- "node:sqlite",
- "node:test",
- "node:test/reporters"
-]);
-const isWindows$1 = process.platform === "win32";
-// transform file url to id
-// virtual:custom -> virtual:custom
-// \0custom -> \0custom
-// /root/id -> /id
-// /root/id.js -> /id.js
-// C:/root/id.js -> /id.js
-// C:\root\id.js -> /id.js
-// TODO: expose this in vite/module-runner
-function normalizeModuleId(file) {
- if (prefixedBuiltins.has(file)) return file;
- // if it's not in the root, keep it as a path, not a URL
- return slash(file).replace(/^\/@fs\//, isWindows$1 ? "" : "/").replace(/^node:/, "").replace(/^\/+/, "/").replace(/^file:\//, "/");
-}
-const windowsSlashRE = /\\/g;
-function slash(p) {
- return p.replace(windowsSlashRE, "/");
-}
-const multipleSlashRe = /^\/+/;
-// module-runner incorrectly replaces file:///path with `///path`
-function fixLeadingSlashes(id) {
- if (id.startsWith("//")) return id.replace(multipleSlashRe, "/");
- return id;
-}
-
-const createNodeImportMeta = (modulePath) => {
- if (!viteModuleRunner.createDefaultImportMeta) throw new Error(`createNodeImportMeta is not supported in this version of Vite.`);
- const defaultMeta = viteModuleRunner.createDefaultImportMeta(modulePath);
- const href = defaultMeta.url;
- const importMetaResolver = createImportMetaResolver();
- return {
- ...defaultMeta,
- main: false,
- resolve(id, parent) {
- return (importMetaResolver ?? defaultMeta.resolve)(id, parent ?? href);
- }
- };
-};
-function createImportMetaResolver() {
- if (!import.meta.resolve) return;
- return (specifier, importer) => import.meta.resolve(specifier, importer);
-}
-// @ts-expect-error overriding private method
-class VitestModuleRunner extends viteModuleRunner.ModuleRunner {
- mocker;
- moduleExecutionInfo;
- _otel;
- constructor(vitestOptions) {
- const options = vitestOptions;
- const transport = new VitestTransport(options.transport);
- const evaluatedModules = options.evaluatedModules;
- super({
- transport,
- hmr: false,
- evaluatedModules,
- sourcemapInterceptor: "prepareStackTrace",
- createImportMeta: vitestOptions.createImportMeta
- }, options.evaluator);
- this.vitestOptions = vitestOptions;
- this._otel = vitestOptions.traces || new Traces({ enabled: false });
- this.moduleExecutionInfo = options.getWorkerState().moduleExecutionInfo;
- this.mocker = options.mocker || new VitestMocker(this, {
- spyModule: options.spyModule,
- context: options.vm?.context,
- traces: this._otel,
- resolveId: options.transport.resolveId,
- get root() {
- return options.getWorkerState().config.root;
- },
- get moduleDirectories() {
- return options.getWorkerState().config.deps.moduleDirectories || [];
- },
- getCurrentTestFilepath() {
- return options.getWorkerState().filepath;
- }
- });
- if (options.vm) options.vm.context.__vitest_mocker__ = this.mocker;
- else Object.defineProperty(globalThis, "__vitest_mocker__", {
- configurable: true,
- writable: true,
- value: this.mocker
- });
- }
- /**
- * Vite checks that the module has exports emulating the Node.js behaviour,
- * but Vitest is more relaxed.
- *
- * We should keep the Vite behavour when there is a `strict` flag.
- * @internal
- */
- processImport(exports$1) {
- return exports$1;
- }
- async import(rawId) {
- const resolved = await this._otel.$("vitest.module.resolve_id", { attributes: { "vitest.module.raw_id": rawId } }, async (span) => {
- const result = await this.vitestOptions.transport.resolveId(rawId);
- if (result) span.setAttributes({
- "vitest.module.url": result.url,
- "vitest.module.file": result.file,
- "vitest.module.id": result.id
- });
- return result;
- });
- return super.import(resolved ? resolved.url : rawId);
- }
- async fetchModule(url, importer) {
- return await this.cachedModule(url, importer);
- }
- _cachedRequest(url, module, callstack = [], metadata) {
- // @ts-expect-error "cachedRequest" is private
- return super.cachedRequest(url, module, callstack, metadata);
- }
- /**
- * @internal
- */
- async cachedRequest(url, mod, callstack = [], metadata, ignoreMock = false) {
- if (ignoreMock) return this._cachedRequest(url, mod, callstack, metadata);
- let mocked;
- if (mod.meta && "mockedModule" in mod.meta) mocked = await this.mocker.requestWithMockedModule(url, mod, callstack, mod.meta.mockedModule);
- else mocked = await this.mocker.mockedRequest(url, mod, callstack);
- if (typeof mocked === "string") {
- const node = await this.fetchModule(mocked);
- return this._cachedRequest(mocked, node, callstack, metadata);
- }
- if (mocked != null && typeof mocked === "object") return mocked;
- return this._cachedRequest(url, mod, callstack, metadata);
- }
- /** @internal */
- _invalidateSubTreeById(ids, invalidated = /* @__PURE__ */ new Set()) {
- for (const id of ids) {
- if (invalidated.has(id)) continue;
- const node = this.evaluatedModules.getModuleById(id);
- if (!node) continue;
- invalidated.add(id);
- const subIds = Array.from(this.evaluatedModules.idToModuleMap).filter(([, mod]) => mod.importers.has(id)).map(([key]) => key);
- if (subIds.length) this._invalidateSubTreeById(subIds, invalidated);
- this.evaluatedModules.invalidateModule(node);
- }
- }
-}
-
-const bareVitestRegexp = /^@?vitest(?:\/|$)/;
-const normalizedDistDir = normalize$1(distDir);
-const relativeIds = {};
-const externalizeMap = /* @__PURE__ */ new Map();
-// all Vitest imports always need to be externalized
-function getCachedVitestImport(id, state) {
- if (id.startsWith("/@fs/") || id.startsWith("\\@fs\\")) id = id.slice(process.platform === "win32" ? 5 : 4);
- if (externalizeMap.has(id)) return {
- externalize: externalizeMap.get(id),
- type: "module"
- };
- // always externalize Vitest because we import from there before running tests
- // so we already have it cached by Node.js
- const root = state().config.root;
- const relativeRoot = relativeIds[root] ?? (relativeIds[root] = normalizedDistDir.slice(root.length));
- if (id.includes(distDir) || id.includes(normalizedDistDir)) {
- const externalize = id.startsWith("file://") ? id : pathToFileURL(id).toString();
- externalizeMap.set(id, externalize);
- return {
- externalize,
- type: "module"
- };
- }
- if (relativeRoot && relativeRoot !== "/" && id.startsWith(relativeRoot)) {
- const externalize = pathToFileURL(join$1(root, id)).toString();
- externalizeMap.set(id, externalize);
- return {
- externalize,
- type: "module"
- };
- }
- if (bareVitestRegexp.test(id)) {
- externalizeMap.set(id, id);
- return {
- externalize: id,
- type: "module"
- };
- }
- return null;
-}
-
-// Store globals in case tests overwrite them
-const processListeners = process.listeners.bind(process);
-const processOn = process.on.bind(process);
-const processOff = process.off.bind(process);
-const dispose = [];
-function listenForErrors(state) {
- dispose.forEach((fn) => fn());
- dispose.length = 0;
- function catchError(err, type, event) {
- const worker = state();
- // if there is another listener, assume that it's handled by user code
- // one is Vitest's own listener
- if (processListeners(event).length > 1) return;
- const error = serializeValue(err);
- if (typeof error === "object" && error != null) {
- error.VITEST_TEST_NAME = worker.current?.type === "test" ? worker.current.name : void 0;
- if (worker.filepath) error.VITEST_TEST_PATH = worker.filepath;
- }
- state().rpc.onUnhandledError(error, type);
- }
- const uncaughtException = (e) => catchError(e, "Uncaught Exception", "uncaughtException");
- const unhandledRejection = (e) => catchError(e, "Unhandled Rejection", "unhandledRejection");
- processOn("uncaughtException", uncaughtException);
- processOn("unhandledRejection", unhandledRejection);
- dispose.push(() => {
- processOff("uncaughtException", uncaughtException);
- processOff("unhandledRejection", unhandledRejection);
- });
-}
-
-const { readFileSync } = fs;
-const VITEST_VM_CONTEXT_SYMBOL = "__vitest_vm_context__";
-const cwd = process.cwd();
-const isWindows = process.platform === "win32";
-function startVitestModuleRunner(options) {
- const traces = options.traces;
- const state = () => globalThis.__vitest_worker__ || options.state;
- const rpc = () => state().rpc;
- process.exit = (code = process.exitCode || 0) => {
- throw new Error(`process.exit unexpectedly called with "${code}"`);
- };
- listenForErrors(state);
- const environment = () => {
- const environment = state().environment;
- return environment.viteEnvironment || environment.name;
- };
- const vm = options.context && options.externalModulesExecutor ? {
- context: options.context,
- externalModulesExecutor: options.externalModulesExecutor
- } : void 0;
- const evaluator = options.evaluator || new VitestModuleEvaluator(vm, {
- traces,
- evaluatedModules: options.evaluatedModules,
- get moduleExecutionInfo() {
- return state().moduleExecutionInfo;
- },
- get interopDefault() {
- return state().config.deps.interopDefault;
- },
- getCurrentTestFilepath: () => state().filepath
- });
- const moduleRunner = new VitestModuleRunner({
- spyModule: options.spyModule,
- evaluatedModules: options.evaluatedModules,
- evaluator,
- traces,
- mocker: options.mocker,
- transport: {
- async fetchModule(id, importer, options) {
- const resolvingModules = state().resolvingModules;
- if (isWindows) {
- if (id[1] === ":") {
- // The drive letter is different for whatever reason, we need to normalize it to CWD
- if (id[0] !== cwd[0] && id[0].toUpperCase() === cwd[0].toUpperCase()) id = (cwd[0].toUpperCase() === cwd[0] ? id[0].toUpperCase() : id[0].toLowerCase()) + id.slice(1);
- // always mark absolute windows paths, otherwise Vite will externalize it
- id = `/@id/${id}`;
- }
- }
- const vitest = getCachedVitestImport(id, state);
- if (vitest) return vitest;
- const rawId = unwrapId(id);
- resolvingModules.add(rawId);
- try {
- if (VitestMocker.pendingIds.length) await moduleRunner.mocker.resolveMocks();
- const resolvedMock = moduleRunner.mocker.getDependencyMock(rawId);
- if (resolvedMock?.type === "manual" || resolvedMock?.type === "redirect") return {
- code: "",
- file: null,
- id,
- url: id,
- invalidate: false,
- mockedModule: resolvedMock
- };
- if (isBuiltin(rawId)) return {
- externalize: rawId,
- type: "builtin"
- };
- if (isBrowserExternal(rawId)) return {
- externalize: toBuiltin(rawId),
- type: "builtin"
- };
- // if module is invalidated, the worker will be recreated,
- // so cached is always true in a single worker
- if (options?.cached) return { cache: true };
- const otelCarrier = traces?.getContextCarrier();
- const result = await rpc().fetch(id, importer, environment(), options, otelCarrier);
- if ("cached" in result) return {
- code: readFileSync(result.tmp, "utf-8"),
- ...result
- };
- return result;
- } catch (cause) {
- // rethrow vite error if it cannot load the module because it's not resolved
- if (typeof cause === "object" && cause != null && cause.code === "ERR_LOAD_URL" || typeof cause?.message === "string" && cause.message.includes("Failed to load url") || typeof cause?.message === "string" && cause.message.startsWith("Cannot find module '")) {
- const error = new Error(`Cannot find ${isBareImport(id) ? "package" : "module"} '${id}'${importer ? ` imported from '${importer}'` : ""}`, { cause });
- error.code = "ERR_MODULE_NOT_FOUND";
- throw error;
- }
- throw cause;
- } finally {
- resolvingModules.delete(rawId);
- }
- },
- resolveId(id, importer) {
- return rpc().resolve(id, importer, environment());
- }
- },
- getWorkerState: state,
- vm,
- createImportMeta: options.createImportMeta
- });
- return moduleRunner;
-}
-
-export { VitestModuleRunner as V, VITEST_VM_CONTEXT_SYMBOL as a, VitestTransport as b, createNodeImportMeta as c, startVitestModuleRunner as s };
diff --git a/vanilla/node_modules/vitest/dist/chunks/suite.d.BJWk38HB.d.ts b/vanilla/node_modules/vitest/dist/chunks/suite.d.BJWk38HB.d.ts
deleted file mode 100644
index 6e669f4..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/suite.d.BJWk38HB.d.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { Test } from '@vitest/runner';
-import { c as BenchmarkAPI, a as BenchFunction } from './benchmark.d.DAaHLpsq.js';
-import { Options } from 'tinybench';
-import '@vitest/runner/utils';
-
-declare function getBenchOptions(key: Test): Options;
-declare function getBenchFn(key: Test): BenchFunction;
-declare const bench: BenchmarkAPI;
-
-export { getBenchOptions as a, bench as b, getBenchFn as g };
diff --git a/vanilla/node_modules/vitest/dist/chunks/test.B8ej_ZHS.js b/vanilla/node_modules/vitest/dist/chunks/test.B8ej_ZHS.js
deleted file mode 100644
index 78b4853..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/test.B8ej_ZHS.js
+++ /dev/null
@@ -1,254 +0,0 @@
-import { updateTask } from '@vitest/runner';
-import { createDefer } from '@vitest/utils/helpers';
-import { getSafeTimers } from '@vitest/utils/timers';
-import { a as getBenchOptions, g as getBenchFn } from './benchmark.B3N2zMcH.js';
-import { g as getWorkerState } from './utils.DvEY5TfP.js';
-import { setState, GLOBAL_EXPECT, getState } from '@vitest/expect';
-import { getTests, getNames, getTestName } from '@vitest/runner/utils';
-import { processError } from '@vitest/utils/error';
-import { normalize } from 'pathe';
-import { a as getSnapshotClient, i as inject, c as createExpect, v as vi } from './vi.2VT5v0um.js';
-import { r as rpc } from './rpc.BoxB0q7B.js';
-
-function createBenchmarkResult(name) {
- return {
- name,
- rank: 0,
- rme: 0,
- samples: []
- };
-}
-const benchmarkTasks = /* @__PURE__ */ new WeakMap();
-async function runBenchmarkSuite(suite, runner) {
- const { Task, Bench } = await runner.importTinybench();
- const start = performance.now();
- const benchmarkGroup = [];
- const benchmarkSuiteGroup = [];
- for (const task of suite.tasks) {
- if (task.mode !== "run" && task.mode !== "queued") continue;
- if (task.meta?.benchmark) benchmarkGroup.push(task);
- else if (task.type === "suite") benchmarkSuiteGroup.push(task);
- }
- // run sub suites sequentially
- for (const subSuite of benchmarkSuiteGroup) await runBenchmarkSuite(subSuite, runner);
- if (benchmarkGroup.length) {
- const defer = createDefer();
- suite.result = {
- state: "run",
- startTime: start,
- benchmark: createBenchmarkResult(suite.name)
- };
- updateTask$1("suite-prepare", suite);
- const addBenchTaskListener = (task, benchmark) => {
- task.addEventListener("complete", (e) => {
- const taskRes = e.task.result;
- const result = benchmark.result.benchmark;
- benchmark.result.state = "pass";
- Object.assign(result, taskRes);
- // compute extra stats and free raw samples as early as possible
- const samples = result.samples;
- result.sampleCount = samples.length;
- result.median = samples.length % 2 ? samples[Math.floor(samples.length / 2)] : (samples[samples.length / 2] + samples[samples.length / 2 - 1]) / 2;
- if (!runner.config.benchmark?.includeSamples) result.samples.length = 0;
- updateTask$1("test-finished", benchmark);
- }, { once: true });
- task.addEventListener("error", (e) => {
- const task = e.task;
- defer.reject(benchmark ? task.result.error : e);
- }, { once: true });
- };
- benchmarkGroup.forEach((benchmark) => {
- const benchmarkInstance = new Bench(getBenchOptions(benchmark));
- const benchmarkFn = getBenchFn(benchmark);
- benchmark.result = {
- state: "run",
- startTime: start,
- benchmark: createBenchmarkResult(benchmark.name)
- };
- const task = new Task(benchmarkInstance, benchmark.name, benchmarkFn);
- benchmarkTasks.set(benchmark, task);
- addBenchTaskListener(task, benchmark);
- });
- const { setTimeout } = getSafeTimers();
- const tasks = [];
- for (const benchmark of benchmarkGroup) {
- const task = benchmarkTasks.get(benchmark);
- updateTask$1("test-prepare", benchmark);
- await task.warmup();
- tasks.push([await new Promise((resolve) => setTimeout(async () => {
- resolve(await task.run());
- })), benchmark]);
- }
- suite.result.duration = performance.now() - start;
- suite.result.state = "pass";
- updateTask$1("suite-finished", suite);
- defer.resolve(null);
- await defer;
- }
- function updateTask$1(event, task) {
- updateTask(event, task, runner);
- }
-}
-class NodeBenchmarkRunner {
- moduleRunner;
- constructor(config) {
- this.config = config;
- }
- async importTinybench() {
- return await import('tinybench');
- }
- importFile(filepath, source) {
- if (source === "setup") {
- const moduleNode = getWorkerState().evaluatedModules.getModuleById(filepath);
- if (moduleNode) getWorkerState().evaluatedModules.invalidateModule(moduleNode);
- }
- return this.moduleRunner.import(filepath);
- }
- async runSuite(suite) {
- await runBenchmarkSuite(suite, this);
- }
- async runTask() {
- throw new Error("`test()` and `it()` is only available in test mode.");
- }
-}
-
-// worker context is shared between all tests
-const workerContext = Object.create(null);
-class VitestTestRunner {
- snapshotClient = getSnapshotClient();
- workerState = getWorkerState();
- moduleRunner;
- cancelRun = false;
- assertionsErrors = /* @__PURE__ */ new WeakMap();
- pool = this.workerState.ctx.pool;
- _otel;
- viteEnvironment;
- constructor(config) {
- this.config = config;
- const environment = this.workerState.environment;
- this.viteEnvironment = environment.viteEnvironment || environment.name;
- }
- importFile(filepath, source) {
- if (source === "setup") {
- const moduleNode = this.workerState.evaluatedModules.getModuleById(filepath);
- if (moduleNode) this.workerState.evaluatedModules.invalidateModule(moduleNode);
- }
- return this._otel.$(`vitest.module.import_${source === "setup" ? "setup" : "spec"}`, { attributes: { "code.file.path": filepath } }, () => this.moduleRunner.import(filepath));
- }
- onCollectStart(file) {
- this.workerState.current = file;
- }
- onCleanupWorkerContext(listener) {
- this.workerState.onCleanup(listener);
- }
- onAfterRunFiles() {
- this.snapshotClient.clear();
- this.workerState.current = void 0;
- }
- getWorkerContext() {
- return workerContext;
- }
- async onAfterRunSuite(suite) {
- if (this.config.logHeapUsage && typeof process !== "undefined") suite.result.heap = process.memoryUsage().heapUsed;
- if (suite.mode !== "skip" && "filepath" in suite) {
- // mark snapshots in skipped tests as not obsolete
- for (const test of getTests(suite)) if (test.mode === "skip") {
- const name = getNames(test).slice(1).join(" > ");
- this.snapshotClient.skipTest(suite.file.filepath, name);
- }
- const result = await this.snapshotClient.finish(suite.file.filepath);
- if (this.workerState.config.snapshotOptions.updateSnapshot === "none" && result.unchecked) {
- let message = `Obsolete snapshots found when no snapshot update is expected.\n`;
- for (const key of result.uncheckedKeys) message += `· ${key}\n`;
- suite.result.errors ??= [];
- suite.result.errors.push(processError(new Error(message)));
- suite.result.state = "fail";
- }
- await rpc().snapshotSaved(result);
- }
- this.workerState.current = suite.suite || suite.file;
- }
- onAfterRunTask(test) {
- if (this.config.logHeapUsage && typeof process !== "undefined") test.result.heap = process.memoryUsage().heapUsed;
- this.workerState.current = test.suite || test.file;
- }
- cancel(_reason) {
- this.cancelRun = true;
- }
- injectValue(key) {
- // inject has a very limiting type controlled by ProvidedContext
- // some tests override it which causes the build to fail
- return inject(key);
- }
- async onBeforeRunTask(test) {
- if (this.cancelRun) test.mode = "skip";
- if (test.mode !== "run" && test.mode !== "queued") return;
- this.workerState.current = test;
- }
- async onBeforeRunSuite(suite) {
- if (this.cancelRun) suite.mode = "skip";
- // initialize snapshot state before running file suite
- if (suite.mode !== "skip" && "filepath" in suite) await this.snapshotClient.setup(suite.file.filepath, this.workerState.config.snapshotOptions);
- this.workerState.current = suite;
- }
- onBeforeTryTask(test) {
- clearModuleMocks(this.config);
- this.snapshotClient.clearTest(test.file.filepath, test.id);
- setState({
- assertionCalls: 0,
- isExpectingAssertions: false,
- isExpectingAssertionsError: null,
- expectedAssertionsNumber: null,
- expectedAssertionsNumberErrorGen: null,
- currentTestName: getTestName(test),
- snapshotState: this.snapshotClient.getSnapshotState(test.file.filepath)
- }, globalThis[GLOBAL_EXPECT]);
- }
- onAfterTryTask(test) {
- const { assertionCalls, expectedAssertionsNumber, expectedAssertionsNumberErrorGen, isExpectingAssertions, isExpectingAssertionsError } = test.context._local ? test.context.expect.getState() : getState(globalThis[GLOBAL_EXPECT]);
- if (expectedAssertionsNumber !== null && assertionCalls !== expectedAssertionsNumber) throw expectedAssertionsNumberErrorGen();
- if (isExpectingAssertions === true && assertionCalls === 0) throw isExpectingAssertionsError;
- if (this.config.expect.requireAssertions && assertionCalls === 0) throw this.assertionsErrors.get(test);
- }
- extendTaskContext(context) {
- // create error during the test initialization so we have a nice stack trace
- if (this.config.expect.requireAssertions) this.assertionsErrors.set(context.task, /* @__PURE__ */ new Error("expected any number of assertion, but got none"));
- let _expect;
- Object.defineProperty(context, "expect", { get() {
- if (!_expect) _expect = createExpect(context.task);
- return _expect;
- } });
- Object.defineProperty(context, "_local", { get() {
- return _expect != null;
- } });
- return context;
- }
- getImportDurations() {
- const importDurations = {};
- const entries = this.workerState.moduleExecutionInfo?.entries() || [];
- for (const [filepath, { duration, selfTime, external, importer }] of entries) importDurations[normalize(filepath)] = {
- selfTime,
- totalTime: duration,
- external,
- importer
- };
- return importDurations;
- }
- trace = (name, attributes, cb) => {
- const options = typeof attributes === "object" ? { attributes } : {};
- return this._otel.$(`vitest.test.runner.${name}`, options, cb || attributes);
- };
- __setTraces(traces) {
- this._otel = traces;
- }
-}
-function clearModuleMocks(config) {
- const { clearMocks, mockReset, restoreMocks, unstubEnvs, unstubGlobals } = config;
- if (restoreMocks) vi.restoreAllMocks();
- if (mockReset) vi.resetAllMocks();
- if (clearMocks) vi.clearAllMocks();
- if (unstubEnvs) vi.unstubAllEnvs();
- if (unstubGlobals) vi.unstubAllGlobals();
-}
-
-export { NodeBenchmarkRunner as N, VitestTestRunner as V };
diff --git a/vanilla/node_modules/vitest/dist/chunks/traces.CCmnQaNT.js b/vanilla/node_modules/vitest/dist/chunks/traces.CCmnQaNT.js
deleted file mode 100644
index b94a0c4..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/traces.CCmnQaNT.js
+++ /dev/null
@@ -1,217 +0,0 @@
-class Traces {
- /**
- * otel stands for OpenTelemetry
- */
- #otel = null;
- #sdk = null;
- #init = null;
- #noopSpan = createNoopSpan();
- #noopContext = createNoopContext();
- #initStartTime = performance.now();
- #initEndTime = 0;
- #initRecorded = false;
- constructor(options) {
- if (options.enabled) {
- const apiInit = import('@opentelemetry/api').then((api) => {
- this.#otel = {
- tracer: api.trace.getTracer(options.tracerName || "vitest"),
- context: api.context,
- propagation: api.propagation,
- trace: api.trace,
- SpanKind: api.SpanKind,
- SpanStatusCode: api.SpanStatusCode
- };
- }).catch(() => {
- throw new Error(`"@opentelemetry/api" is not installed locally. Make sure you have setup OpenTelemetry instrumentation: https://vitest.dev/guide/open-telemetry`);
- });
- const sdkInit = (options.sdkPath ? import(
- /* @vite-ignore */
- options.sdkPath
-) : Promise.resolve()).catch((cause) => {
- throw new Error(`Failed to import custom OpenTelemetry SDK script (${options.sdkPath}): ${cause.message}`);
- });
- this.#init = Promise.all([sdkInit, apiInit]).then(([sdk]) => {
- if (sdk != null) {
- if (sdk.default != null && typeof sdk.default === "object" && typeof sdk.default.shutdown === "function") this.#sdk = sdk.default;
- else if (options.watchMode !== true && process.env.VITEST_MODE !== "watch") console.warn(`OpenTelemetry instrumentation module (${options.sdkPath}) does not have a default export with a "shutdown" method. Vitest won't be able to ensure that all traces are processed in time. Try running Vitest in watch mode instead.`);
- }
- }).finally(() => {
- this.#initEndTime = performance.now();
- this.#init = null;
- });
- }
- }
- isEnabled() {
- return !!this.#otel;
- }
- /**
- * @internal
- */
- async waitInit() {
- if (this.#init) await this.#init;
- return this;
- }
- /**
- * @internal
- */
- recordInitSpan(context) {
- if (this.#initRecorded) return;
- this.#initRecorded = true;
- this.startSpan("vitest.runtime.traces", { startTime: this.#initStartTime }, context).end(this.#initEndTime);
- }
- /**
- * @internal
- */
- startContextSpan(name, currentContext) {
- if (!this.#otel) return {
- span: this.#noopSpan,
- context: this.#noopContext
- };
- const activeContext = currentContext || this.#otel.context.active();
- const span = this.#otel.tracer.startSpan(name, {}, activeContext);
- return {
- span,
- context: this.#otel.trace.setSpan(activeContext, span)
- };
- }
- /**
- * @internal
- */
- getContextFromCarrier(carrier) {
- if (!this.#otel) return this.#noopContext;
- const activeContext = this.#otel.context.active();
- if (!carrier) return activeContext;
- return this.#otel.propagation.extract(activeContext, carrier);
- }
- /**
- * @internal
- */
- getContextFromEnv(env) {
- if (!this.#otel) return this.#noopContext;
- // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/env-carriers.md
- // some tools sets only `TRACEPARENT` but not `TRACESTATE`
- const carrier = {};
- if (typeof env.TRACEPARENT === "string") carrier.traceparent = env.TRACEPARENT;
- if (typeof env.TRACESTATE === "string") carrier.tracestate = env.TRACESTATE;
- return this.getContextFromCarrier(carrier);
- }
- /**
- * @internal
- */
- getContextCarrier(context) {
- if (!this.#otel) return;
- const carrier = {};
- this.#otel.propagation.inject(context || this.#otel.context.active(), carrier);
- return carrier;
- }
- #callActiveSpan(span, callback) {
- const otel = this.#otel;
- let result;
- try {
- result = callback(span);
- if (result instanceof Promise) return result.catch((error) => {
- span.recordException({
- name: error.name,
- message: error.message,
- stack: error.stack
- });
- span.setStatus({ code: otel.SpanStatusCode.ERROR });
- throw error;
- }).finally(() => span.end());
- return result;
- } catch (error) {
- if (error instanceof Error) {
- span.recordException({
- name: error.name,
- message: error.message,
- stack: error.stack
- });
- span.setStatus({ code: otel.SpanStatusCode.ERROR });
- }
- throw error;
- } finally {
- // end sync callbcak
- if (!(result instanceof Promise)) span.end();
- }
- }
- /**
- * @internal
- */
- $(name, optionsOrFn, fn) {
- const callback = typeof optionsOrFn === "function" ? optionsOrFn : fn;
- if (!this.#otel) return callback(this.#noopSpan);
- const otel = this.#otel;
- const options = typeof optionsOrFn === "function" ? {} : optionsOrFn;
- const context = options.context;
- if (context) return otel.tracer.startActiveSpan(name, options, context, (span) => this.#callActiveSpan(span, callback));
- return otel.tracer.startActiveSpan(name, options, (span) => this.#callActiveSpan(span, callback));
- }
- /**
- * @internal
- */
- startSpan(name, options, context) {
- if (!this.#otel) return this.#noopSpan;
- const { tracer } = this.#otel;
- return tracer.startSpan(name, options, context);
- }
- // On browser mode, async context is not automatically propagated,
- // so we manually bind the `$` calls to the provided context.
- // TODO: this doesn't bind to user land's `@optelemetry/api` calls
- /**
- * @internal
- */
- bind(context) {
- if (!this.#otel) return;
- const original = this.$.__original ?? this.$;
- this.$ = this.#otel.context.bind(context, original);
- this.$.__original = original;
- }
- /**
- * @internal
- */
- async finish() {
- await this.#sdk?.shutdown();
- }
- /**
- * @internal
- */
- async flush() {
- await this.#sdk?.forceFlush?.();
- }
-}
-function noopSpan() {
- return this;
-}
-function createNoopSpan() {
- return {
- setAttribute: noopSpan,
- setStatus: noopSpan,
- addEvent: noopSpan,
- addLink: noopSpan,
- addLinks: noopSpan,
- setAttributes: noopSpan,
- updateName: noopSpan,
- end: () => {},
- isRecording: () => false,
- recordException: noopSpan,
- spanContext() {
- return {
- spanId: "",
- traceFlags: 0,
- traceId: ""
- };
- }
- };
-}
-function noopContext() {
- return this;
-}
-function createNoopContext() {
- return {
- getValue: noopContext,
- setValue: noopContext,
- deleteValue: noopContext
- };
-}
-
-export { Traces as T };
diff --git a/vanilla/node_modules/vitest/dist/chunks/traces.d.402V_yFI.d.ts b/vanilla/node_modules/vitest/dist/chunks/traces.d.402V_yFI.d.ts
deleted file mode 100644
index d9b7ada..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/traces.d.402V_yFI.d.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-interface OTELCarrier {
- traceparent?: string;
- tracestate?: string;
-}
-interface TracesOptions {
- enabled: boolean;
- watchMode?: boolean;
- sdkPath?: string;
- tracerName?: string;
-}
-declare class Traces {
- #private;
- constructor(options: TracesOptions);
- isEnabled(): boolean;
-}
-
-export { Traces as T };
-export type { OTELCarrier as O };
diff --git a/vanilla/node_modules/vitest/dist/chunks/utils.DvEY5TfP.js b/vanilla/node_modules/vitest/dist/chunks/utils.DvEY5TfP.js
deleted file mode 100644
index a4087d5..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/utils.DvEY5TfP.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import { getSafeTimers } from '@vitest/utils/timers';
-
-const NAME_WORKER_STATE = "__vitest_worker__";
-function getWorkerState() {
- // @ts-expect-error untyped global
- const workerState = globalThis[NAME_WORKER_STATE];
- if (!workerState) throw new Error("Vitest failed to access its internal state.\n\nOne of the following is possible:\n- \"vitest\" is imported directly without running \"vitest\" command\n- \"vitest\" is imported inside \"globalSetup\" (to fix this, use \"setupFiles\" instead, because \"globalSetup\" runs in a different context)\n- \"vitest\" is imported inside Vite / Vitest config file\n- Otherwise, it might be a Vitest bug. Please report it to https://github.com/vitest-dev/vitest/issues\n");
- return workerState;
-}
-function provideWorkerState(context, state) {
- Object.defineProperty(context, NAME_WORKER_STATE, {
- value: state,
- configurable: true,
- writable: true,
- enumerable: false
- });
- return state;
-}
-function isChildProcess() {
- return typeof process !== "undefined" && !!process.send;
-}
-function resetModules(modules, resetMocks = false) {
- const skipPaths = [
- /\/vitest\/dist\//,
- /vitest-virtual-\w+\/dist/,
- /@vitest\/dist/,
- ...!resetMocks ? [/^mock:/] : []
- ];
- modules.idToModuleMap.forEach((node, path) => {
- if (skipPaths.some((re) => re.test(path))) return;
- node.promise = void 0;
- node.exports = void 0;
- node.evaluated = false;
- node.importers.clear();
- });
-}
-function waitNextTick() {
- const { setTimeout } = getSafeTimers();
- return new Promise((resolve) => setTimeout(resolve, 0));
-}
-async function waitForImportsToResolve() {
- await waitNextTick();
- const state = getWorkerState();
- const promises = [];
- const resolvingCount = state.resolvingModules.size;
- for (const [_, mod] of state.evaluatedModules.idToModuleMap) if (mod.promise && !mod.evaluated) promises.push(mod.promise);
- if (!promises.length && !resolvingCount) return;
- await Promise.allSettled(promises);
- await waitForImportsToResolve();
-}
-
-export { getWorkerState as g, isChildProcess as i, provideWorkerState as p, resetModules as r, waitForImportsToResolve as w };
diff --git a/vanilla/node_modules/vitest/dist/chunks/vi.2VT5v0um.js b/vanilla/node_modules/vitest/dist/chunks/vi.2VT5v0um.js
deleted file mode 100644
index 1e3d35a..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/vi.2VT5v0um.js
+++ /dev/null
@@ -1,3919 +0,0 @@
-import { chai, equals, iterableEquality, subsetEquality, JestExtend, JestChaiExpect, JestAsymmetricMatchers, GLOBAL_EXPECT, ASYMMETRIC_MATCHERS_OBJECT, getState, setState, addCustomEqualityTesters, customMatchers } from '@vitest/expect';
-import { getCurrentTest } from '@vitest/runner';
-import { g as getWorkerState, i as isChildProcess, w as waitForImportsToResolve, r as resetModules } from './utils.DvEY5TfP.js';
-import { getSafeTimers, delay } from '@vitest/utils/timers';
-import { getNames } from '@vitest/runner/utils';
-import { stripSnapshotIndentation, addSerializer, SnapshotClient } from '@vitest/snapshot';
-import '@vitest/utils/error';
-import { assertTypes, createSimpleStackTrace } from '@vitest/utils/helpers';
-import { fn, spyOn, restoreAllMocks, resetAllMocks, clearAllMocks, isMockFunction } from '@vitest/spy';
-import '@vitest/utils/offset';
-import { parseSingleStack } from '@vitest/utils/source-map';
-import { c as commonjsGlobal } from './_commonjsHelpers.D26ty3Ew.js';
-import { R as RealDate, r as resetDate, m as mockDate } from './date.Bq6ZW5rf.js';
-
-// these matchers are not supported because they don't make sense with poll
-const unsupported = [
- "matchSnapshot",
- "toMatchSnapshot",
- "toMatchInlineSnapshot",
- "toThrowErrorMatchingSnapshot",
- "toThrowErrorMatchingInlineSnapshot",
- "throws",
- "Throw",
- "throw",
- "toThrow",
- "toThrowError"
-];
-/**
-* Attaches a `cause` property to the error if missing, copies the stack trace from the source, and throws.
-*
-* @param error - The error to throw
-* @param source - Error to copy the stack trace from
-*
-* @throws Always throws the provided error with an amended stack trace
-*/
-function throwWithCause(error, source) {
- if (error.cause == null) error.cause = /* @__PURE__ */ new Error("Matcher did not succeed in time.");
- throw copyStackTrace$1(error, source);
-}
-function createExpectPoll(expect) {
- return function poll(fn, options = {}) {
- const defaults = getWorkerState().config.expect?.poll ?? {};
- const { interval = defaults.interval ?? 50, timeout = defaults.timeout ?? 1e3, message } = options;
- // @ts-expect-error private poll access
- const assertion = expect(null, message).withContext({ poll: true });
- fn = fn.bind(assertion);
- const test = chai.util.flag(assertion, "vitest-test");
- if (!test) throw new Error("expect.poll() must be called inside a test");
- const proxy = new Proxy(assertion, { get(target, key, receiver) {
- const assertionFunction = Reflect.get(target, key, receiver);
- if (typeof assertionFunction !== "function") return assertionFunction instanceof chai.Assertion ? proxy : assertionFunction;
- if (key === "assert") return assertionFunction;
- if (typeof key === "string" && unsupported.includes(key)) throw new SyntaxError(`expect.poll() is not supported in combination with .${key}(). Use vi.waitFor() if your assertion condition is unstable.`);
- return function(...args) {
- const STACK_TRACE_ERROR = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
- const promise = async () => {
- const { setTimeout, clearTimeout } = getSafeTimers();
- let executionPhase = "fn";
- let hasTimedOut = false;
- const timerId = setTimeout(() => {
- hasTimedOut = true;
- }, timeout);
- chai.util.flag(assertion, "_name", key);
- try {
- while (true) {
- const isLastAttempt = hasTimedOut;
- if (isLastAttempt) chai.util.flag(assertion, "_isLastPollAttempt", true);
- try {
- executionPhase = "fn";
- const obj = await fn();
- chai.util.flag(assertion, "object", obj);
- executionPhase = "assertion";
- return await assertionFunction.call(assertion, ...args);
- } catch (err) {
- if (isLastAttempt || executionPhase === "assertion" && chai.util.flag(assertion, "_poll.assert_once")) throwWithCause(err, STACK_TRACE_ERROR);
- await delay(interval, setTimeout);
- }
- }
- } finally {
- clearTimeout(timerId);
- }
- };
- let awaited = false;
- test.onFinished ??= [];
- test.onFinished.push(() => {
- if (!awaited) {
- const negated = chai.util.flag(assertion, "negate") ? "not." : "";
- const assertionString = `expect.${chai.util.flag(assertion, "_poll.element") ? "element(locator)" : "poll(assertion)"}.${negated}${String(key)}()`;
- throw copyStackTrace$1(/* @__PURE__ */ new Error(`${assertionString} was not awaited. This assertion is asynchronous and must be awaited; otherwise, it is not executed to avoid unhandled rejections:\n\nawait ${assertionString}\n`), STACK_TRACE_ERROR);
- }
- });
- let resultPromise;
- // only .then is enough to check awaited, but we type this as `Promise<void>` in global types
- // so let's follow it
- return {
- then(onFulfilled, onRejected) {
- awaited = true;
- return (resultPromise ||= promise()).then(onFulfilled, onRejected);
- },
- catch(onRejected) {
- return (resultPromise ||= promise()).catch(onRejected);
- },
- finally(onFinally) {
- return (resultPromise ||= promise()).finally(onFinally);
- },
- [Symbol.toStringTag]: "Promise"
- };
- };
- } });
- return proxy;
- };
-}
-function copyStackTrace$1(target, source) {
- if (source.stack !== void 0) target.stack = source.stack.replace(source.message, target.message);
- return target;
-}
-
-function createAssertionMessage(util, assertion, hasArgs) {
- const not = util.flag(assertion, "negate") ? "not." : "";
- const name = `${util.flag(assertion, "_name")}(${"expected" })`;
- const promiseName = util.flag(assertion, "promise");
- return `expect(actual)${promiseName ? `.${promiseName}` : ""}.${not}${name}`;
-}
-function recordAsyncExpect(_test, promise, assertion, error) {
- const test = _test;
- // record promise for test, that resolves before test ends
- if (test && promise instanceof Promise) {
- // if promise is explicitly awaited, remove it from the list
- promise = promise.finally(() => {
- if (!test.promises) return;
- const index = test.promises.indexOf(promise);
- if (index !== -1) test.promises.splice(index, 1);
- });
- // record promise
- if (!test.promises) test.promises = [];
- test.promises.push(promise);
- let resolved = false;
- test.onFinished ??= [];
- test.onFinished.push(() => {
- if (!resolved) {
- const stack = (globalThis.__vitest_worker__?.onFilterStackTrace || ((s) => s || ""))(error.stack);
- console.warn([
- `Promise returned by \`${assertion}\` was not awaited. `,
- "Vitest currently auto-awaits hanging assertions at the end of the test, but this will cause the test to fail in Vitest 3. ",
- "Please remember to await the assertion.\n",
- stack
- ].join(""));
- }
- });
- return {
- then(onFulfilled, onRejected) {
- resolved = true;
- return promise.then(onFulfilled, onRejected);
- },
- catch(onRejected) {
- return promise.catch(onRejected);
- },
- finally(onFinally) {
- return promise.finally(onFinally);
- },
- [Symbol.toStringTag]: "Promise"
- };
- }
- return promise;
-}
-
-let _client;
-function getSnapshotClient() {
- if (!_client) _client = new SnapshotClient({ isEqual: (received, expected) => {
- return equals(received, expected, [iterableEquality, subsetEquality]);
- } });
- return _client;
-}
-function getError(expected, promise) {
- if (typeof expected !== "function") {
- if (!promise) throw new Error(`expected must be a function, received ${typeof expected}`);
- // when "promised", it receives thrown error
- return expected;
- }
- try {
- expected();
- } catch (e) {
- return e;
- }
- throw new Error("snapshot function didn't throw");
-}
-function getTestNames(test) {
- return {
- filepath: test.file.filepath,
- name: getNames(test).slice(1).join(" > "),
- testId: test.id
- };
-}
-const SnapshotPlugin = (chai, utils) => {
- function getTest(assertionName, obj) {
- const test = utils.flag(obj, "vitest-test");
- if (!test) throw new Error(`'${assertionName}' cannot be used without test context`);
- return test;
- }
- for (const key of ["matchSnapshot", "toMatchSnapshot"]) utils.addMethod(chai.Assertion.prototype, key, function(properties, message) {
- utils.flag(this, "_name", key);
- if (utils.flag(this, "negate")) throw new Error(`${key} cannot be used with "not"`);
- const expected = utils.flag(this, "object");
- const test = getTest(key, this);
- if (typeof properties === "string" && typeof message === "undefined") {
- message = properties;
- properties = void 0;
- }
- const errorMessage = utils.flag(this, "message");
- getSnapshotClient().assert({
- received: expected,
- message,
- isInline: false,
- properties,
- errorMessage,
- ...getTestNames(test)
- });
- });
- utils.addMethod(chai.Assertion.prototype, "toMatchFileSnapshot", function(file, message) {
- utils.flag(this, "_name", "toMatchFileSnapshot");
- if (utils.flag(this, "negate")) throw new Error("toMatchFileSnapshot cannot be used with \"not\"");
- const error = /* @__PURE__ */ new Error("resolves");
- const expected = utils.flag(this, "object");
- const test = getTest("toMatchFileSnapshot", this);
- const errorMessage = utils.flag(this, "message");
- return recordAsyncExpect(test, getSnapshotClient().assertRaw({
- received: expected,
- message,
- isInline: false,
- rawSnapshot: { file },
- errorMessage,
- ...getTestNames(test)
- }), createAssertionMessage(utils, this), error);
- });
- utils.addMethod(chai.Assertion.prototype, "toMatchInlineSnapshot", function __INLINE_SNAPSHOT__(properties, inlineSnapshot, message) {
- utils.flag(this, "_name", "toMatchInlineSnapshot");
- if (utils.flag(this, "negate")) throw new Error("toMatchInlineSnapshot cannot be used with \"not\"");
- const test = getTest("toMatchInlineSnapshot", this);
- if (test.each || test.suite?.each) throw new Error("InlineSnapshot cannot be used inside of test.each or describe.each");
- const expected = utils.flag(this, "object");
- const error = utils.flag(this, "error");
- if (typeof properties === "string") {
- message = inlineSnapshot;
- inlineSnapshot = properties;
- properties = void 0;
- }
- if (inlineSnapshot) inlineSnapshot = stripSnapshotIndentation(inlineSnapshot);
- const errorMessage = utils.flag(this, "message");
- getSnapshotClient().assert({
- received: expected,
- message,
- isInline: true,
- properties,
- inlineSnapshot,
- error,
- errorMessage,
- ...getTestNames(test)
- });
- });
- utils.addMethod(chai.Assertion.prototype, "toThrowErrorMatchingSnapshot", function(message) {
- utils.flag(this, "_name", "toThrowErrorMatchingSnapshot");
- if (utils.flag(this, "negate")) throw new Error("toThrowErrorMatchingSnapshot cannot be used with \"not\"");
- const expected = utils.flag(this, "object");
- const test = getTest("toThrowErrorMatchingSnapshot", this);
- const promise = utils.flag(this, "promise");
- const errorMessage = utils.flag(this, "message");
- getSnapshotClient().assert({
- received: getError(expected, promise),
- message,
- errorMessage,
- ...getTestNames(test)
- });
- });
- utils.addMethod(chai.Assertion.prototype, "toThrowErrorMatchingInlineSnapshot", function __INLINE_SNAPSHOT__(inlineSnapshot, message) {
- if (utils.flag(this, "negate")) throw new Error("toThrowErrorMatchingInlineSnapshot cannot be used with \"not\"");
- const test = getTest("toThrowErrorMatchingInlineSnapshot", this);
- if (test.each || test.suite?.each) throw new Error("InlineSnapshot cannot be used inside of test.each or describe.each");
- const expected = utils.flag(this, "object");
- const error = utils.flag(this, "error");
- const promise = utils.flag(this, "promise");
- const errorMessage = utils.flag(this, "message");
- if (inlineSnapshot) inlineSnapshot = stripSnapshotIndentation(inlineSnapshot);
- getSnapshotClient().assert({
- received: getError(expected, promise),
- message,
- inlineSnapshot,
- isInline: true,
- error,
- errorMessage,
- ...getTestNames(test)
- });
- });
- utils.addMethod(chai.expect, "addSnapshotSerializer", addSerializer);
-};
-
-chai.use(JestExtend);
-chai.use(JestChaiExpect);
-chai.use(SnapshotPlugin);
-chai.use(JestAsymmetricMatchers);
-
-function createExpect(test) {
- const expect = ((value, message) => {
- const { assertionCalls } = getState(expect);
- setState({ assertionCalls: assertionCalls + 1 }, expect);
- const assert = chai.expect(value, message);
- const _test = test || getCurrentTest();
- if (_test)
- // @ts-expect-error internal
- return assert.withTest(_test);
- else return assert;
- });
- Object.assign(expect, chai.expect);
- Object.assign(expect, globalThis[ASYMMETRIC_MATCHERS_OBJECT]);
- expect.getState = () => getState(expect);
- expect.setState = (state) => setState(state, expect);
- // @ts-expect-error global is not typed
- const globalState = getState(globalThis[GLOBAL_EXPECT]) || {};
- setState({
- ...globalState,
- assertionCalls: 0,
- isExpectingAssertions: false,
- isExpectingAssertionsError: null,
- expectedAssertionsNumber: null,
- expectedAssertionsNumberErrorGen: null,
- get testPath() {
- return getWorkerState().filepath;
- },
- currentTestName: test ? test.fullTestName ?? "" : globalState.currentTestName
- }, expect);
- expect.assert = chai.assert;
- // @ts-expect-error untyped
- expect.extend = (matchers) => chai.expect.extend(expect, matchers);
- expect.addEqualityTesters = (customTesters) => addCustomEqualityTesters(customTesters);
- expect.soft = (...args) => {
- // @ts-expect-error private soft access
- return expect(...args).withContext({ soft: true });
- };
- expect.poll = createExpectPoll(expect);
- expect.unreachable = (message) => {
- chai.assert.fail(`expected${message ? ` "${message}" ` : " "}not to be reached`);
- };
- function assertions(expected) {
- const errorGen = () => /* @__PURE__ */ new Error(`expected number of assertions to be ${expected}, but got ${expect.getState().assertionCalls}`);
- if (Error.captureStackTrace) Error.captureStackTrace(errorGen(), assertions);
- expect.setState({
- expectedAssertionsNumber: expected,
- expectedAssertionsNumberErrorGen: errorGen
- });
- }
- function hasAssertions() {
- const error = /* @__PURE__ */ new Error("expected any number of assertion, but got none");
- if (Error.captureStackTrace) Error.captureStackTrace(error, hasAssertions);
- expect.setState({
- isExpectingAssertions: true,
- isExpectingAssertionsError: error
- });
- }
- chai.util.addMethod(expect, "assertions", assertions);
- chai.util.addMethod(expect, "hasAssertions", hasAssertions);
- expect.extend(customMatchers);
- return expect;
-}
-const globalExpect = createExpect();
-Object.defineProperty(globalThis, GLOBAL_EXPECT, {
- value: globalExpect,
- writable: true,
- configurable: true
-});
-const assert = chai.assert;
-const should = chai.should;
-
-/**
-* Gives access to injected context provided from the main thread.
-* This usually returns a value provided by `globalSetup` or an external library.
-*/
-function inject(key) {
- return getWorkerState().providedContext[key];
-}
-
-var fakeTimersSrc = {};
-
-var global;
-var hasRequiredGlobal;
-
-function requireGlobal () {
- if (hasRequiredGlobal) return global;
- hasRequiredGlobal = 1;
-
- /**
- * A reference to the global object
- * @type {object} globalObject
- */
- var globalObject;
-
- /* istanbul ignore else */
- if (typeof commonjsGlobal !== "undefined") {
- // Node
- globalObject = commonjsGlobal;
- } else if (typeof window !== "undefined") {
- // Browser
- globalObject = window;
- } else {
- // WebWorker
- globalObject = self;
- }
-
- global = globalObject;
- return global;
-}
-
-var throwsOnProto_1;
-var hasRequiredThrowsOnProto;
-
-function requireThrowsOnProto () {
- if (hasRequiredThrowsOnProto) return throwsOnProto_1;
- hasRequiredThrowsOnProto = 1;
-
- /**
- * Is true when the environment causes an error to be thrown for accessing the
- * __proto__ property.
- * This is necessary in order to support `node --disable-proto=throw`.
- *
- * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto
- * @type {boolean}
- */
- let throwsOnProto;
- try {
- const object = {};
- // eslint-disable-next-line no-proto, no-unused-expressions
- object.__proto__;
- throwsOnProto = false;
- } catch (_) {
- // This branch is covered when tests are run with `--disable-proto=throw`,
- // however we can test both branches at the same time, so this is ignored
- /* istanbul ignore next */
- throwsOnProto = true;
- }
-
- throwsOnProto_1 = throwsOnProto;
- return throwsOnProto_1;
-}
-
-var copyPrototypeMethods;
-var hasRequiredCopyPrototypeMethods;
-
-function requireCopyPrototypeMethods () {
- if (hasRequiredCopyPrototypeMethods) return copyPrototypeMethods;
- hasRequiredCopyPrototypeMethods = 1;
-
- var call = Function.call;
- var throwsOnProto = requireThrowsOnProto();
-
- var disallowedProperties = [
- // ignore size because it throws from Map
- "size",
- "caller",
- "callee",
- "arguments",
- ];
-
- // This branch is covered when tests are run with `--disable-proto=throw`,
- // however we can test both branches at the same time, so this is ignored
- /* istanbul ignore next */
- if (throwsOnProto) {
- disallowedProperties.push("__proto__");
- }
-
- copyPrototypeMethods = function copyPrototypeMethods(prototype) {
- // eslint-disable-next-line @sinonjs/no-prototype-methods/no-prototype-methods
- return Object.getOwnPropertyNames(prototype).reduce(function (
- result,
- name
- ) {
- if (disallowedProperties.includes(name)) {
- return result;
- }
-
- if (typeof prototype[name] !== "function") {
- return result;
- }
-
- result[name] = call.bind(prototype[name]);
-
- return result;
- },
- Object.create(null));
- };
- return copyPrototypeMethods;
-}
-
-var array;
-var hasRequiredArray;
-
-function requireArray () {
- if (hasRequiredArray) return array;
- hasRequiredArray = 1;
-
- var copyPrototype = requireCopyPrototypeMethods();
-
- array = copyPrototype(Array.prototype);
- return array;
-}
-
-var calledInOrder_1;
-var hasRequiredCalledInOrder;
-
-function requireCalledInOrder () {
- if (hasRequiredCalledInOrder) return calledInOrder_1;
- hasRequiredCalledInOrder = 1;
-
- var every = requireArray().every;
-
- /**
- * @private
- */
- function hasCallsLeft(callMap, spy) {
- if (callMap[spy.id] === undefined) {
- callMap[spy.id] = 0;
- }
-
- return callMap[spy.id] < spy.callCount;
- }
-
- /**
- * @private
- */
- function checkAdjacentCalls(callMap, spy, index, spies) {
- var calledBeforeNext = true;
-
- if (index !== spies.length - 1) {
- calledBeforeNext = spy.calledBefore(spies[index + 1]);
- }
-
- if (hasCallsLeft(callMap, spy) && calledBeforeNext) {
- callMap[spy.id] += 1;
- return true;
- }
-
- return false;
- }
-
- /**
- * A Sinon proxy object (fake, spy, stub)
- * @typedef {object} SinonProxy
- * @property {Function} calledBefore - A method that determines if this proxy was called before another one
- * @property {string} id - Some id
- * @property {number} callCount - Number of times this proxy has been called
- */
-
- /**
- * Returns true when the spies have been called in the order they were supplied in
- * @param {SinonProxy[] | SinonProxy} spies An array of proxies, or several proxies as arguments
- * @returns {boolean} true when spies are called in order, false otherwise
- */
- function calledInOrder(spies) {
- var callMap = {};
- // eslint-disable-next-line no-underscore-dangle
- var _spies = arguments.length > 1 ? arguments : spies;
-
- return every(_spies, checkAdjacentCalls.bind(null, callMap));
- }
-
- calledInOrder_1 = calledInOrder;
- return calledInOrder_1;
-}
-
-var className_1;
-var hasRequiredClassName;
-
-function requireClassName () {
- if (hasRequiredClassName) return className_1;
- hasRequiredClassName = 1;
-
- /**
- * Returns a display name for a value from a constructor
- * @param {object} value A value to examine
- * @returns {(string|null)} A string or null
- */
- function className(value) {
- const name = value.constructor && value.constructor.name;
- return name || null;
- }
-
- className_1 = className;
- return className_1;
-}
-
-var deprecated = {};
-
-/* eslint-disable no-console */
-
-var hasRequiredDeprecated;
-
-function requireDeprecated () {
- if (hasRequiredDeprecated) return deprecated;
- hasRequiredDeprecated = 1;
- (function (exports$1) {
-
- /**
- * Returns a function that will invoke the supplied function and print a
- * deprecation warning to the console each time it is called.
- * @param {Function} func
- * @param {string} msg
- * @returns {Function}
- */
- exports$1.wrap = function (func, msg) {
- var wrapped = function () {
- exports$1.printWarning(msg);
- return func.apply(this, arguments);
- };
- if (func.prototype) {
- wrapped.prototype = func.prototype;
- }
- return wrapped;
- };
-
- /**
- * Returns a string which can be supplied to `wrap()` to notify the user that a
- * particular part of the sinon API has been deprecated.
- * @param {string} packageName
- * @param {string} funcName
- * @returns {string}
- */
- exports$1.defaultMsg = function (packageName, funcName) {
- return `${packageName}.${funcName} is deprecated and will be removed from the public API in a future version of ${packageName}.`;
- };
-
- /**
- * Prints a warning on the console, when it exists
- * @param {string} msg
- * @returns {undefined}
- */
- exports$1.printWarning = function (msg) {
- /* istanbul ignore next */
- if (typeof process === "object" && process.emitWarning) {
- // Emit Warnings in Node
- process.emitWarning(msg);
- } else if (console.info) {
- console.info(msg);
- } else {
- console.log(msg);
- }
- };
- } (deprecated));
- return deprecated;
-}
-
-var every;
-var hasRequiredEvery;
-
-function requireEvery () {
- if (hasRequiredEvery) return every;
- hasRequiredEvery = 1;
-
- /**
- * Returns true when fn returns true for all members of obj.
- * This is an every implementation that works for all iterables
- * @param {object} obj
- * @param {Function} fn
- * @returns {boolean}
- */
- every = function every(obj, fn) {
- var pass = true;
-
- try {
- // eslint-disable-next-line @sinonjs/no-prototype-methods/no-prototype-methods
- obj.forEach(function () {
- if (!fn.apply(this, arguments)) {
- // Throwing an error is the only way to break `forEach`
- throw new Error();
- }
- });
- } catch (e) {
- pass = false;
- }
-
- return pass;
- };
- return every;
-}
-
-var functionName;
-var hasRequiredFunctionName;
-
-function requireFunctionName () {
- if (hasRequiredFunctionName) return functionName;
- hasRequiredFunctionName = 1;
-
- /**
- * Returns a display name for a function
- * @param {Function} func
- * @returns {string}
- */
- functionName = function functionName(func) {
- if (!func) {
- return "";
- }
-
- try {
- return (
- func.displayName ||
- func.name ||
- // Use function decomposition as a last resort to get function
- // name. Does not rely on function decomposition to work - if it
- // doesn't debugging will be slightly less informative
- // (i.e. toString will say 'spy' rather than 'myFunc').
- (String(func).match(/function ([^\s(]+)/) || [])[1]
- );
- } catch (e) {
- // Stringify may fail and we might get an exception, as a last-last
- // resort fall back to empty string.
- return "";
- }
- };
- return functionName;
-}
-
-var orderByFirstCall_1;
-var hasRequiredOrderByFirstCall;
-
-function requireOrderByFirstCall () {
- if (hasRequiredOrderByFirstCall) return orderByFirstCall_1;
- hasRequiredOrderByFirstCall = 1;
-
- var sort = requireArray().sort;
- var slice = requireArray().slice;
-
- /**
- * @private
- */
- function comparator(a, b) {
- // uuid, won't ever be equal
- var aCall = a.getCall(0);
- var bCall = b.getCall(0);
- var aId = (aCall && aCall.callId) || -1;
- var bId = (bCall && bCall.callId) || -1;
-
- return aId < bId ? -1 : 1;
- }
-
- /**
- * A Sinon proxy object (fake, spy, stub)
- * @typedef {object} SinonProxy
- * @property {Function} getCall - A method that can return the first call
- */
-
- /**
- * Sorts an array of SinonProxy instances (fake, spy, stub) by their first call
- * @param {SinonProxy[] | SinonProxy} spies
- * @returns {SinonProxy[]}
- */
- function orderByFirstCall(spies) {
- return sort(slice(spies), comparator);
- }
-
- orderByFirstCall_1 = orderByFirstCall;
- return orderByFirstCall_1;
-}
-
-var _function;
-var hasRequired_function;
-
-function require_function () {
- if (hasRequired_function) return _function;
- hasRequired_function = 1;
-
- var copyPrototype = requireCopyPrototypeMethods();
-
- _function = copyPrototype(Function.prototype);
- return _function;
-}
-
-var map;
-var hasRequiredMap;
-
-function requireMap () {
- if (hasRequiredMap) return map;
- hasRequiredMap = 1;
-
- var copyPrototype = requireCopyPrototypeMethods();
-
- map = copyPrototype(Map.prototype);
- return map;
-}
-
-var object;
-var hasRequiredObject;
-
-function requireObject () {
- if (hasRequiredObject) return object;
- hasRequiredObject = 1;
-
- var copyPrototype = requireCopyPrototypeMethods();
-
- object = copyPrototype(Object.prototype);
- return object;
-}
-
-var set;
-var hasRequiredSet;
-
-function requireSet () {
- if (hasRequiredSet) return set;
- hasRequiredSet = 1;
-
- var copyPrototype = requireCopyPrototypeMethods();
-
- set = copyPrototype(Set.prototype);
- return set;
-}
-
-var string;
-var hasRequiredString;
-
-function requireString () {
- if (hasRequiredString) return string;
- hasRequiredString = 1;
-
- var copyPrototype = requireCopyPrototypeMethods();
-
- string = copyPrototype(String.prototype);
- return string;
-}
-
-var prototypes;
-var hasRequiredPrototypes;
-
-function requirePrototypes () {
- if (hasRequiredPrototypes) return prototypes;
- hasRequiredPrototypes = 1;
-
- prototypes = {
- array: requireArray(),
- function: require_function(),
- map: requireMap(),
- object: requireObject(),
- set: requireSet(),
- string: requireString(),
- };
- return prototypes;
-}
-
-var typeDetect$1 = {exports: {}};
-
-var typeDetect = typeDetect$1.exports;
-
-var hasRequiredTypeDetect;
-
-function requireTypeDetect () {
- if (hasRequiredTypeDetect) return typeDetect$1.exports;
- hasRequiredTypeDetect = 1;
- (function (module, exports$1) {
- (function (global, factory) {
- module.exports = factory() ;
- }(typeDetect, (function () {
- /* !
- * type-detect
- * Copyright(c) 2013 jake luer <jake@alogicalparadox.com>
- * MIT Licensed
- */
- var promiseExists = typeof Promise === 'function';
-
- /* eslint-disable no-undef */
- var globalObject = typeof self === 'object' ? self : commonjsGlobal; // eslint-disable-line id-blacklist
-
- var symbolExists = typeof Symbol !== 'undefined';
- var mapExists = typeof Map !== 'undefined';
- var setExists = typeof Set !== 'undefined';
- var weakMapExists = typeof WeakMap !== 'undefined';
- var weakSetExists = typeof WeakSet !== 'undefined';
- var dataViewExists = typeof DataView !== 'undefined';
- var symbolIteratorExists = symbolExists && typeof Symbol.iterator !== 'undefined';
- var symbolToStringTagExists = symbolExists && typeof Symbol.toStringTag !== 'undefined';
- var setEntriesExists = setExists && typeof Set.prototype.entries === 'function';
- var mapEntriesExists = mapExists && typeof Map.prototype.entries === 'function';
- var setIteratorPrototype = setEntriesExists && Object.getPrototypeOf(new Set().entries());
- var mapIteratorPrototype = mapEntriesExists && Object.getPrototypeOf(new Map().entries());
- var arrayIteratorExists = symbolIteratorExists && typeof Array.prototype[Symbol.iterator] === 'function';
- var arrayIteratorPrototype = arrayIteratorExists && Object.getPrototypeOf([][Symbol.iterator]());
- var stringIteratorExists = symbolIteratorExists && typeof String.prototype[Symbol.iterator] === 'function';
- var stringIteratorPrototype = stringIteratorExists && Object.getPrototypeOf(''[Symbol.iterator]());
- var toStringLeftSliceLength = 8;
- var toStringRightSliceLength = -1;
- /**
- * ### typeOf (obj)
- *
- * Uses `Object.prototype.toString` to determine the type of an object,
- * normalising behaviour across engine versions & well optimised.
- *
- * @param {Mixed} object
- * @return {String} object type
- * @api public
- */
- function typeDetect(obj) {
- /* ! Speed optimisation
- * Pre:
- * string literal x 3,039,035 ops/sec ±1.62% (78 runs sampled)
- * boolean literal x 1,424,138 ops/sec ±4.54% (75 runs sampled)
- * number literal x 1,653,153 ops/sec ±1.91% (82 runs sampled)
- * undefined x 9,978,660 ops/sec ±1.92% (75 runs sampled)
- * function x 2,556,769 ops/sec ±1.73% (77 runs sampled)
- * Post:
- * string literal x 38,564,796 ops/sec ±1.15% (79 runs sampled)
- * boolean literal x 31,148,940 ops/sec ±1.10% (79 runs sampled)
- * number literal x 32,679,330 ops/sec ±1.90% (78 runs sampled)
- * undefined x 32,363,368 ops/sec ±1.07% (82 runs sampled)
- * function x 31,296,870 ops/sec ±0.96% (83 runs sampled)
- */
- var typeofObj = typeof obj;
- if (typeofObj !== 'object') {
- return typeofObj;
- }
-
- /* ! Speed optimisation
- * Pre:
- * null x 28,645,765 ops/sec ±1.17% (82 runs sampled)
- * Post:
- * null x 36,428,962 ops/sec ±1.37% (84 runs sampled)
- */
- if (obj === null) {
- return 'null';
- }
-
- /* ! Spec Conformance
- * Test: `Object.prototype.toString.call(window)``
- * - Node === "[object global]"
- * - Chrome === "[object global]"
- * - Firefox === "[object Window]"
- * - PhantomJS === "[object Window]"
- * - Safari === "[object Window]"
- * - IE 11 === "[object Window]"
- * - IE Edge === "[object Window]"
- * Test: `Object.prototype.toString.call(this)``
- * - Chrome Worker === "[object global]"
- * - Firefox Worker === "[object DedicatedWorkerGlobalScope]"
- * - Safari Worker === "[object DedicatedWorkerGlobalScope]"
- * - IE 11 Worker === "[object WorkerGlobalScope]"
- * - IE Edge Worker === "[object WorkerGlobalScope]"
- */
- if (obj === globalObject) {
- return 'global';
- }
-
- /* ! Speed optimisation
- * Pre:
- * array literal x 2,888,352 ops/sec ±0.67% (82 runs sampled)
- * Post:
- * array literal x 22,479,650 ops/sec ±0.96% (81 runs sampled)
- */
- if (
- Array.isArray(obj) &&
- (symbolToStringTagExists === false || !(Symbol.toStringTag in obj))
- ) {
- return 'Array';
- }
-
- // Not caching existence of `window` and related properties due to potential
- // for `window` to be unset before tests in quasi-browser environments.
- if (typeof window === 'object' && window !== null) {
- /* ! Spec Conformance
- * (https://html.spec.whatwg.org/multipage/browsers.html#location)
- * WhatWG HTML$7.7.3 - The `Location` interface
- * Test: `Object.prototype.toString.call(window.location)``
- * - IE <=11 === "[object Object]"
- * - IE Edge <=13 === "[object Object]"
- */
- if (typeof window.location === 'object' && obj === window.location) {
- return 'Location';
- }
-
- /* ! Spec Conformance
- * (https://html.spec.whatwg.org/#document)
- * WhatWG HTML$3.1.1 - The `Document` object
- * Note: Most browsers currently adher to the W3C DOM Level 2 spec
- * (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-26809268)
- * which suggests that browsers should use HTMLTableCellElement for
- * both TD and TH elements. WhatWG separates these.
- * WhatWG HTML states:
- * > For historical reasons, Window objects must also have a
- * > writable, configurable, non-enumerable property named
- * > HTMLDocument whose value is the Document interface object.
- * Test: `Object.prototype.toString.call(document)``
- * - Chrome === "[object HTMLDocument]"
- * - Firefox === "[object HTMLDocument]"
- * - Safari === "[object HTMLDocument]"
- * - IE <=10 === "[object Document]"
- * - IE 11 === "[object HTMLDocument]"
- * - IE Edge <=13 === "[object HTMLDocument]"
- */
- if (typeof window.document === 'object' && obj === window.document) {
- return 'Document';
- }
-
- if (typeof window.navigator === 'object') {
- /* ! Spec Conformance
- * (https://html.spec.whatwg.org/multipage/webappapis.html#mimetypearray)
- * WhatWG HTML$8.6.1.5 - Plugins - Interface MimeTypeArray
- * Test: `Object.prototype.toString.call(navigator.mimeTypes)``
- * - IE <=10 === "[object MSMimeTypesCollection]"
- */
- if (typeof window.navigator.mimeTypes === 'object' &&
- obj === window.navigator.mimeTypes) {
- return 'MimeTypeArray';
- }
-
- /* ! Spec Conformance
- * (https://html.spec.whatwg.org/multipage/webappapis.html#pluginarray)
- * WhatWG HTML$8.6.1.5 - Plugins - Interface PluginArray
- * Test: `Object.prototype.toString.call(navigator.plugins)``
- * - IE <=10 === "[object MSPluginsCollection]"
- */
- if (typeof window.navigator.plugins === 'object' &&
- obj === window.navigator.plugins) {
- return 'PluginArray';
- }
- }
-
- if ((typeof window.HTMLElement === 'function' ||
- typeof window.HTMLElement === 'object') &&
- obj instanceof window.HTMLElement) {
- /* ! Spec Conformance
- * (https://html.spec.whatwg.org/multipage/webappapis.html#pluginarray)
- * WhatWG HTML$4.4.4 - The `blockquote` element - Interface `HTMLQuoteElement`
- * Test: `Object.prototype.toString.call(document.createElement('blockquote'))``
- * - IE <=10 === "[object HTMLBlockElement]"
- */
- if (obj.tagName === 'BLOCKQUOTE') {
- return 'HTMLQuoteElement';
- }
-
- /* ! Spec Conformance
- * (https://html.spec.whatwg.org/#htmltabledatacellelement)
- * WhatWG HTML$4.9.9 - The `td` element - Interface `HTMLTableDataCellElement`
- * Note: Most browsers currently adher to the W3C DOM Level 2 spec
- * (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-82915075)
- * which suggests that browsers should use HTMLTableCellElement for
- * both TD and TH elements. WhatWG separates these.
- * Test: Object.prototype.toString.call(document.createElement('td'))
- * - Chrome === "[object HTMLTableCellElement]"
- * - Firefox === "[object HTMLTableCellElement]"
- * - Safari === "[object HTMLTableCellElement]"
- */
- if (obj.tagName === 'TD') {
- return 'HTMLTableDataCellElement';
- }
-
- /* ! Spec Conformance
- * (https://html.spec.whatwg.org/#htmltableheadercellelement)
- * WhatWG HTML$4.9.9 - The `td` element - Interface `HTMLTableHeaderCellElement`
- * Note: Most browsers currently adher to the W3C DOM Level 2 spec
- * (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-82915075)
- * which suggests that browsers should use HTMLTableCellElement for
- * both TD and TH elements. WhatWG separates these.
- * Test: Object.prototype.toString.call(document.createElement('th'))
- * - Chrome === "[object HTMLTableCellElement]"
- * - Firefox === "[object HTMLTableCellElement]"
- * - Safari === "[object HTMLTableCellElement]"
- */
- if (obj.tagName === 'TH') {
- return 'HTMLTableHeaderCellElement';
- }
- }
- }
-
- /* ! Speed optimisation
- * Pre:
- * Float64Array x 625,644 ops/sec ±1.58% (80 runs sampled)
- * Float32Array x 1,279,852 ops/sec ±2.91% (77 runs sampled)
- * Uint32Array x 1,178,185 ops/sec ±1.95% (83 runs sampled)
- * Uint16Array x 1,008,380 ops/sec ±2.25% (80 runs sampled)
- * Uint8Array x 1,128,040 ops/sec ±2.11% (81 runs sampled)
- * Int32Array x 1,170,119 ops/sec ±2.88% (80 runs sampled)
- * Int16Array x 1,176,348 ops/sec ±5.79% (86 runs sampled)
- * Int8Array x 1,058,707 ops/sec ±4.94% (77 runs sampled)
- * Uint8ClampedArray x 1,110,633 ops/sec ±4.20% (80 runs sampled)
- * Post:
- * Float64Array x 7,105,671 ops/sec ±13.47% (64 runs sampled)
- * Float32Array x 5,887,912 ops/sec ±1.46% (82 runs sampled)
- * Uint32Array x 6,491,661 ops/sec ±1.76% (79 runs sampled)
- * Uint16Array x 6,559,795 ops/sec ±1.67% (82 runs sampled)
- * Uint8Array x 6,463,966 ops/sec ±1.43% (85 runs sampled)
- * Int32Array x 5,641,841 ops/sec ±3.49% (81 runs sampled)
- * Int16Array x 6,583,511 ops/sec ±1.98% (80 runs sampled)
- * Int8Array x 6,606,078 ops/sec ±1.74% (81 runs sampled)
- * Uint8ClampedArray x 6,602,224 ops/sec ±1.77% (83 runs sampled)
- */
- var stringTag = (symbolToStringTagExists && obj[Symbol.toStringTag]);
- if (typeof stringTag === 'string') {
- return stringTag;
- }
-
- var objPrototype = Object.getPrototypeOf(obj);
- /* ! Speed optimisation
- * Pre:
- * regex literal x 1,772,385 ops/sec ±1.85% (77 runs sampled)
- * regex constructor x 2,143,634 ops/sec ±2.46% (78 runs sampled)
- * Post:
- * regex literal x 3,928,009 ops/sec ±0.65% (78 runs sampled)
- * regex constructor x 3,931,108 ops/sec ±0.58% (84 runs sampled)
- */
- if (objPrototype === RegExp.prototype) {
- return 'RegExp';
- }
-
- /* ! Speed optimisation
- * Pre:
- * date x 2,130,074 ops/sec ±4.42% (68 runs sampled)
- * Post:
- * date x 3,953,779 ops/sec ±1.35% (77 runs sampled)
- */
- if (objPrototype === Date.prototype) {
- return 'Date';
- }
-
- /* ! Spec Conformance
- * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-promise.prototype-@@tostringtag)
- * ES6$25.4.5.4 - Promise.prototype[@@toStringTag] should be "Promise":
- * Test: `Object.prototype.toString.call(Promise.resolve())``
- * - Chrome <=47 === "[object Object]"
- * - Edge <=20 === "[object Object]"
- * - Firefox 29-Latest === "[object Promise]"
- * - Safari 7.1-Latest === "[object Promise]"
- */
- if (promiseExists && objPrototype === Promise.prototype) {
- return 'Promise';
- }
-
- /* ! Speed optimisation
- * Pre:
- * set x 2,222,186 ops/sec ±1.31% (82 runs sampled)
- * Post:
- * set x 4,545,879 ops/sec ±1.13% (83 runs sampled)
- */
- if (setExists && objPrototype === Set.prototype) {
- return 'Set';
- }
-
- /* ! Speed optimisation
- * Pre:
- * map x 2,396,842 ops/sec ±1.59% (81 runs sampled)
- * Post:
- * map x 4,183,945 ops/sec ±6.59% (82 runs sampled)
- */
- if (mapExists && objPrototype === Map.prototype) {
- return 'Map';
- }
-
- /* ! Speed optimisation
- * Pre:
- * weakset x 1,323,220 ops/sec ±2.17% (76 runs sampled)
- * Post:
- * weakset x 4,237,510 ops/sec ±2.01% (77 runs sampled)
- */
- if (weakSetExists && objPrototype === WeakSet.prototype) {
- return 'WeakSet';
- }
-
- /* ! Speed optimisation
- * Pre:
- * weakmap x 1,500,260 ops/sec ±2.02% (78 runs sampled)
- * Post:
- * weakmap x 3,881,384 ops/sec ±1.45% (82 runs sampled)
- */
- if (weakMapExists && objPrototype === WeakMap.prototype) {
- return 'WeakMap';
- }
-
- /* ! Spec Conformance
- * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-dataview.prototype-@@tostringtag)
- * ES6$24.2.4.21 - DataView.prototype[@@toStringTag] should be "DataView":
- * Test: `Object.prototype.toString.call(new DataView(new ArrayBuffer(1)))``
- * - Edge <=13 === "[object Object]"
- */
- if (dataViewExists && objPrototype === DataView.prototype) {
- return 'DataView';
- }
-
- /* ! Spec Conformance
- * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%mapiteratorprototype%-@@tostringtag)
- * ES6$23.1.5.2.2 - %MapIteratorPrototype%[@@toStringTag] should be "Map Iterator":
- * Test: `Object.prototype.toString.call(new Map().entries())``
- * - Edge <=13 === "[object Object]"
- */
- if (mapExists && objPrototype === mapIteratorPrototype) {
- return 'Map Iterator';
- }
-
- /* ! Spec Conformance
- * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%setiteratorprototype%-@@tostringtag)
- * ES6$23.2.5.2.2 - %SetIteratorPrototype%[@@toStringTag] should be "Set Iterator":
- * Test: `Object.prototype.toString.call(new Set().entries())``
- * - Edge <=13 === "[object Object]"
- */
- if (setExists && objPrototype === setIteratorPrototype) {
- return 'Set Iterator';
- }
-
- /* ! Spec Conformance
- * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%arrayiteratorprototype%-@@tostringtag)
- * ES6$22.1.5.2.2 - %ArrayIteratorPrototype%[@@toStringTag] should be "Array Iterator":
- * Test: `Object.prototype.toString.call([][Symbol.iterator]())``
- * - Edge <=13 === "[object Object]"
- */
- if (arrayIteratorExists && objPrototype === arrayIteratorPrototype) {
- return 'Array Iterator';
- }
-
- /* ! Spec Conformance
- * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%stringiteratorprototype%-@@tostringtag)
- * ES6$21.1.5.2.2 - %StringIteratorPrototype%[@@toStringTag] should be "String Iterator":
- * Test: `Object.prototype.toString.call(''[Symbol.iterator]())``
- * - Edge <=13 === "[object Object]"
- */
- if (stringIteratorExists && objPrototype === stringIteratorPrototype) {
- return 'String Iterator';
- }
-
- /* ! Speed optimisation
- * Pre:
- * object from null x 2,424,320 ops/sec ±1.67% (76 runs sampled)
- * Post:
- * object from null x 5,838,000 ops/sec ±0.99% (84 runs sampled)
- */
- if (objPrototype === null) {
- return 'Object';
- }
-
- return Object
- .prototype
- .toString
- .call(obj)
- .slice(toStringLeftSliceLength, toStringRightSliceLength);
- }
-
- return typeDetect;
-
- })));
- } (typeDetect$1));
- return typeDetect$1.exports;
-}
-
-var typeOf;
-var hasRequiredTypeOf;
-
-function requireTypeOf () {
- if (hasRequiredTypeOf) return typeOf;
- hasRequiredTypeOf = 1;
-
- var type = requireTypeDetect();
-
- /**
- * Returns the lower-case result of running type from type-detect on the value
- * @param {*} value
- * @returns {string}
- */
- typeOf = function typeOf(value) {
- return type(value).toLowerCase();
- };
- return typeOf;
-}
-
-var valueToString_1;
-var hasRequiredValueToString;
-
-function requireValueToString () {
- if (hasRequiredValueToString) return valueToString_1;
- hasRequiredValueToString = 1;
-
- /**
- * Returns a string representation of the value
- * @param {*} value
- * @returns {string}
- */
- function valueToString(value) {
- if (value && value.toString) {
- // eslint-disable-next-line @sinonjs/no-prototype-methods/no-prototype-methods
- return value.toString();
- }
- return String(value);
- }
-
- valueToString_1 = valueToString;
- return valueToString_1;
-}
-
-var lib;
-var hasRequiredLib;
-
-function requireLib () {
- if (hasRequiredLib) return lib;
- hasRequiredLib = 1;
-
- lib = {
- global: requireGlobal(),
- calledInOrder: requireCalledInOrder(),
- className: requireClassName(),
- deprecated: requireDeprecated(),
- every: requireEvery(),
- functionName: requireFunctionName(),
- orderByFirstCall: requireOrderByFirstCall(),
- prototypes: requirePrototypes(),
- typeOf: requireTypeOf(),
- valueToString: requireValueToString(),
- };
- return lib;
-}
-
-var hasRequiredFakeTimersSrc;
-
-function requireFakeTimersSrc () {
- if (hasRequiredFakeTimersSrc) return fakeTimersSrc;
- hasRequiredFakeTimersSrc = 1;
-
- const globalObject = requireLib().global;
- let timersModule, timersPromisesModule;
- if (typeof __vitest_required__ !== 'undefined') {
- try {
- timersModule = __vitest_required__.timers;
- } catch (e) {
- // ignored
- }
- try {
- timersPromisesModule = __vitest_required__.timersPromises;
- } catch (e) {
- // ignored
- }
- }
-
- /**
- * @typedef {object} IdleDeadline
- * @property {boolean} didTimeout - whether or not the callback was called before reaching the optional timeout
- * @property {function():number} timeRemaining - a floating-point value providing an estimate of the number of milliseconds remaining in the current idle period
- */
-
- /**
- * Queues a function to be called during a browser's idle periods
- * @callback RequestIdleCallback
- * @param {function(IdleDeadline)} callback
- * @param {{timeout: number}} options - an options object
- * @returns {number} the id
- */
-
- /**
- * @callback NextTick
- * @param {VoidVarArgsFunc} callback - the callback to run
- * @param {...*} args - optional arguments to call the callback with
- * @returns {void}
- */
-
- /**
- * @callback SetImmediate
- * @param {VoidVarArgsFunc} callback - the callback to run
- * @param {...*} args - optional arguments to call the callback with
- * @returns {NodeImmediate}
- */
-
- /**
- * @callback VoidVarArgsFunc
- * @param {...*} callback - the callback to run
- * @returns {void}
- */
-
- /**
- * @typedef RequestAnimationFrame
- * @property {function(number):void} requestAnimationFrame
- * @returns {number} - the id
- */
-
- /**
- * @typedef Performance
- * @property {function(): number} now
- */
-
- /* eslint-disable jsdoc/require-property-description */
- /**
- * @typedef {object} Clock
- * @property {number} now - the current time
- * @property {Date} Date - the Date constructor
- * @property {number} loopLimit - the maximum number of timers before assuming an infinite loop
- * @property {RequestIdleCallback} requestIdleCallback
- * @property {function(number):void} cancelIdleCallback
- * @property {setTimeout} setTimeout
- * @property {clearTimeout} clearTimeout
- * @property {NextTick} nextTick
- * @property {queueMicrotask} queueMicrotask
- * @property {setInterval} setInterval
- * @property {clearInterval} clearInterval
- * @property {SetImmediate} setImmediate
- * @property {function(NodeImmediate):void} clearImmediate
- * @property {function():number} countTimers
- * @property {RequestAnimationFrame} requestAnimationFrame
- * @property {function(number):void} cancelAnimationFrame
- * @property {function():void} runMicrotasks
- * @property {function(string | number): number} tick
- * @property {function(string | number): Promise<number>} tickAsync
- * @property {function(): number} next
- * @property {function(): Promise<number>} nextAsync
- * @property {function(): number} runAll
- * @property {function(): number} runToFrame
- * @property {function(): Promise<number>} runAllAsync
- * @property {function(): number} runToLast
- * @property {function(): Promise<number>} runToLastAsync
- * @property {function(): void} reset
- * @property {function(number | Date): void} setSystemTime
- * @property {function(number): void} jump
- * @property {Performance} performance
- * @property {function(number[]): number[]} hrtime - process.hrtime (legacy)
- * @property {function(): void} uninstall Uninstall the clock.
- * @property {Function[]} methods - the methods that are faked
- * @property {boolean} [shouldClearNativeTimers] inherited from config
- * @property {{methodName:string, original:any}[] | undefined} timersModuleMethods
- * @property {{methodName:string, original:any}[] | undefined} timersPromisesModuleMethods
- * @property {Map<function(): void, AbortSignal>} abortListenerMap
- */
- /* eslint-enable jsdoc/require-property-description */
-
- /**
- * Configuration object for the `install` method.
- * @typedef {object} Config
- * @property {number|Date} [now] a number (in milliseconds) or a Date object (default epoch)
- * @property {string[]} [toFake] names of the methods that should be faked.
- * @property {number} [loopLimit] the maximum number of timers that will be run when calling runAll()
- * @property {boolean} [shouldAdvanceTime] tells FakeTimers to increment mocked time automatically (default false)
- * @property {number} [advanceTimeDelta] increment mocked time every <<advanceTimeDelta>> ms (default: 20ms)
- * @property {boolean} [shouldClearNativeTimers] forwards clear timer calls to native functions if they are not fakes (default: false)
- * @property {boolean} [ignoreMissingTimers] default is false, meaning asking to fake timers that are not present will throw an error
- */
-
- /* eslint-disable jsdoc/require-property-description */
- /**
- * The internal structure to describe a scheduled fake timer
- * @typedef {object} Timer
- * @property {Function} func
- * @property {*[]} args
- * @property {number} delay
- * @property {number} callAt
- * @property {number} createdAt
- * @property {boolean} immediate
- * @property {number} id
- * @property {Error} [error]
- */
-
- /**
- * A Node timer
- * @typedef {object} NodeImmediate
- * @property {function(): boolean} hasRef
- * @property {function(): NodeImmediate} ref
- * @property {function(): NodeImmediate} unref
- */
- /* eslint-enable jsdoc/require-property-description */
-
- /* eslint-disable complexity */
-
- /**
- * Mocks available features in the specified global namespace.
- * @param {*} _global Namespace to mock (e.g. `window`)
- * @returns {FakeTimers}
- */
- function withGlobal(_global) {
- const maxTimeout = Math.pow(2, 31) - 1; //see https://heycam.github.io/webidl/#abstract-opdef-converttoint
- const idCounterStart = 1e12; // arbitrarily large number to avoid collisions with native timer IDs
- const NOOP = function () {
- return undefined;
- };
- const NOOP_ARRAY = function () {
- return [];
- };
- const isPresent = {};
- let timeoutResult,
- addTimerReturnsObject = false;
-
- if (_global.setTimeout) {
- isPresent.setTimeout = true;
- timeoutResult = _global.setTimeout(NOOP, 0);
- addTimerReturnsObject = typeof timeoutResult === "object";
- }
- isPresent.clearTimeout = Boolean(_global.clearTimeout);
- isPresent.setInterval = Boolean(_global.setInterval);
- isPresent.clearInterval = Boolean(_global.clearInterval);
- isPresent.hrtime =
- _global.process && typeof _global.process.hrtime === "function";
- isPresent.hrtimeBigint =
- isPresent.hrtime && typeof _global.process.hrtime.bigint === "function";
- isPresent.nextTick =
- _global.process && typeof _global.process.nextTick === "function";
- const utilPromisify = _global.process && _global.__vitest_required__ && _global.__vitest_required__.util.promisify;
- isPresent.performance =
- _global.performance && typeof _global.performance.now === "function";
- const hasPerformancePrototype =
- _global.Performance &&
- (typeof _global.Performance).match(/^(function|object)$/);
- const hasPerformanceConstructorPrototype =
- _global.performance &&
- _global.performance.constructor &&
- _global.performance.constructor.prototype;
- isPresent.queueMicrotask = _global.hasOwnProperty("queueMicrotask");
- isPresent.requestAnimationFrame =
- _global.requestAnimationFrame &&
- typeof _global.requestAnimationFrame === "function";
- isPresent.cancelAnimationFrame =
- _global.cancelAnimationFrame &&
- typeof _global.cancelAnimationFrame === "function";
- isPresent.requestIdleCallback =
- _global.requestIdleCallback &&
- typeof _global.requestIdleCallback === "function";
- isPresent.cancelIdleCallbackPresent =
- _global.cancelIdleCallback &&
- typeof _global.cancelIdleCallback === "function";
- isPresent.setImmediate =
- _global.setImmediate && typeof _global.setImmediate === "function";
- isPresent.clearImmediate =
- _global.clearImmediate && typeof _global.clearImmediate === "function";
- isPresent.Intl = _global.Intl && typeof _global.Intl === "object";
-
- if (_global.clearTimeout) {
- _global.clearTimeout(timeoutResult);
- }
-
- const NativeDate = _global.Date;
- const NativeIntl = isPresent.Intl
- ? Object.defineProperties(
- Object.create(null),
- Object.getOwnPropertyDescriptors(_global.Intl),
- )
- : undefined;
- let uniqueTimerId = idCounterStart;
-
- if (NativeDate === undefined) {
- throw new Error(
- "The global scope doesn't have a `Date` object" +
- " (see https://github.com/sinonjs/sinon/issues/1852#issuecomment-419622780)",
- );
- }
- isPresent.Date = true;
-
- /**
- * The PerformanceEntry object encapsulates a single performance metric
- * that is part of the browser's performance timeline.
- *
- * This is an object returned by the `mark` and `measure` methods on the Performance prototype
- */
- class FakePerformanceEntry {
- constructor(name, entryType, startTime, duration) {
- this.name = name;
- this.entryType = entryType;
- this.startTime = startTime;
- this.duration = duration;
- }
-
- toJSON() {
- return JSON.stringify({ ...this });
- }
- }
-
- /**
- * @param {number} num
- * @returns {boolean}
- */
- function isNumberFinite(num) {
- if (Number.isFinite) {
- return Number.isFinite(num);
- }
-
- return isFinite(num);
- }
-
- let isNearInfiniteLimit = false;
-
- /**
- * @param {Clock} clock
- * @param {number} i
- */
- function checkIsNearInfiniteLimit(clock, i) {
- if (clock.loopLimit && i === clock.loopLimit - 1) {
- isNearInfiniteLimit = true;
- }
- }
-
- /**
- *
- */
- function resetIsNearInfiniteLimit() {
- isNearInfiniteLimit = false;
- }
-
- /**
- * Parse strings like "01:10:00" (meaning 1 hour, 10 minutes, 0 seconds) into
- * number of milliseconds. This is used to support human-readable strings passed
- * to clock.tick()
- * @param {string} str
- * @returns {number}
- */
- function parseTime(str) {
- if (!str) {
- return 0;
- }
-
- const strings = str.split(":");
- const l = strings.length;
- let i = l;
- let ms = 0;
- let parsed;
-
- if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
- throw new Error(
- "tick only understands numbers, 'm:s' and 'h:m:s'. Each part must be two digits",
- );
- }
-
- while (i--) {
- parsed = parseInt(strings[i], 10);
-
- if (parsed >= 60) {
- throw new Error(`Invalid time ${str}`);
- }
-
- ms += parsed * Math.pow(60, l - i - 1);
- }
-
- return ms * 1000;
- }
-
- /**
- * Get the decimal part of the millisecond value as nanoseconds
- * @param {number} msFloat the number of milliseconds
- * @returns {number} an integer number of nanoseconds in the range [0,1e6)
- *
- * Example: nanoRemainer(123.456789) -> 456789
- */
- function nanoRemainder(msFloat) {
- const modulo = 1e6;
- const remainder = (msFloat * 1e6) % modulo;
- const positiveRemainder =
- remainder < 0 ? remainder + modulo : remainder;
-
- return Math.floor(positiveRemainder);
- }
-
- /**
- * Used to grok the `now` parameter to createClock.
- * @param {Date|number} epoch the system time
- * @returns {number}
- */
- function getEpoch(epoch) {
- if (!epoch) {
- return 0;
- }
- if (typeof epoch.getTime === "function") {
- return epoch.getTime();
- }
- if (typeof epoch === "number") {
- return epoch;
- }
- throw new TypeError("now should be milliseconds since UNIX epoch");
- }
-
- /**
- * @param {number} from
- * @param {number} to
- * @param {Timer} timer
- * @returns {boolean}
- */
- function inRange(from, to, timer) {
- return timer && timer.callAt >= from && timer.callAt <= to;
- }
-
- /**
- * @param {Clock} clock
- * @param {Timer} job
- */
- function getInfiniteLoopError(clock, job) {
- const infiniteLoopError = new Error(
- `Aborting after running ${clock.loopLimit} timers, assuming an infinite loop!`,
- );
-
- if (!job.error) {
- return infiniteLoopError;
- }
-
- // pattern never matched in Node
- const computedTargetPattern = /target\.*[<|(|[].*?[>|\]|)]\s*/;
- let clockMethodPattern = new RegExp(
- String(Object.keys(clock).join("|")),
- );
-
- if (addTimerReturnsObject) {
- // node.js environment
- clockMethodPattern = new RegExp(
- `\\s+at (Object\\.)?(?:${Object.keys(clock).join("|")})\\s+`,
- );
- }
-
- let matchedLineIndex = -1;
- job.error.stack.split("\n").some(function (line, i) {
- // If we've matched a computed target line (e.g. setTimeout) then we
- // don't need to look any further. Return true to stop iterating.
- const matchedComputedTarget = line.match(computedTargetPattern);
- /* istanbul ignore if */
- if (matchedComputedTarget) {
- matchedLineIndex = i;
- return true;
- }
-
- // If we've matched a clock method line, then there may still be
- // others further down the trace. Return false to keep iterating.
- const matchedClockMethod = line.match(clockMethodPattern);
- if (matchedClockMethod) {
- matchedLineIndex = i;
- return false;
- }
-
- // If we haven't matched anything on this line, but we matched
- // previously and set the matched line index, then we can stop.
- // If we haven't matched previously, then we should keep iterating.
- return matchedLineIndex >= 0;
- });
-
- const stack = `${infiniteLoopError}\n${job.type || "Microtask"} - ${
- job.func.name || "anonymous"
- }\n${job.error.stack
- .split("\n")
- .slice(matchedLineIndex + 1)
- .join("\n")}`;
-
- try {
- Object.defineProperty(infiniteLoopError, "stack", {
- value: stack,
- });
- } catch (e) {
- // noop
- }
-
- return infiniteLoopError;
- }
-
- //eslint-disable-next-line jsdoc/require-jsdoc
- function createDate() {
- class ClockDate extends NativeDate {
- /**
- * @param {number} year
- * @param {number} month
- * @param {number} date
- * @param {number} hour
- * @param {number} minute
- * @param {number} second
- * @param {number} ms
- * @returns void
- */
- // eslint-disable-next-line no-unused-vars
- constructor(year, month, date, hour, minute, second, ms) {
- // Defensive and verbose to avoid potential harm in passing
- // explicit undefined when user does not pass argument
- if (arguments.length === 0) {
- super(ClockDate.clock.now);
- } else {
- super(...arguments);
- }
-
- // ensures identity checks using the constructor prop still works
- // this should have no other functional effect
- Object.defineProperty(this, "constructor", {
- value: NativeDate,
- enumerable: false,
- });
- }
-
- static [Symbol.hasInstance](instance) {
- return instance instanceof NativeDate;
- }
- }
-
- ClockDate.isFake = true;
-
- if (NativeDate.now) {
- ClockDate.now = function now() {
- return ClockDate.clock.now;
- };
- }
-
- if (NativeDate.toSource) {
- ClockDate.toSource = function toSource() {
- return NativeDate.toSource();
- };
- }
-
- ClockDate.toString = function toString() {
- return NativeDate.toString();
- };
-
- // noinspection UnnecessaryLocalVariableJS
- /**
- * A normal Class constructor cannot be called without `new`, but Date can, so we need
- * to wrap it in a Proxy in order to ensure this functionality of Date is kept intact
- * @type {ClockDate}
- */
- const ClockDateProxy = new Proxy(ClockDate, {
- // handler for [[Call]] invocations (i.e. not using `new`)
- apply() {
- // the Date constructor called as a function, ref Ecma-262 Edition 5.1, section 15.9.2.
- // This remains so in the 10th edition of 2019 as well.
- if (this instanceof ClockDate) {
- throw new TypeError(
- "A Proxy should only capture `new` calls with the `construct` handler. This is not supposed to be possible, so check the logic.",
- );
- }
-
- return new NativeDate(ClockDate.clock.now).toString();
- },
- });
-
- return ClockDateProxy;
- }
-
- /**
- * Mirror Intl by default on our fake implementation
- *
- * Most of the properties are the original native ones,
- * but we need to take control of those that have a
- * dependency on the current clock.
- * @returns {object} the partly fake Intl implementation
- */
- function createIntl() {
- const ClockIntl = {};
- /*
- * All properties of Intl are non-enumerable, so we need
- * to do a bit of work to get them out.
- */
- Object.getOwnPropertyNames(NativeIntl).forEach(
- (property) => (ClockIntl[property] = NativeIntl[property]),
- );
-
- ClockIntl.DateTimeFormat = function (...args) {
- const realFormatter = new NativeIntl.DateTimeFormat(...args);
- const formatter = {};
-
- ["formatRange", "formatRangeToParts", "resolvedOptions"].forEach(
- (method) => {
- formatter[method] =
- realFormatter[method].bind(realFormatter);
- },
- );
-
- ["format", "formatToParts"].forEach((method) => {
- formatter[method] = function (date) {
- return realFormatter[method](date || ClockIntl.clock.now);
- };
- });
-
- return formatter;
- };
-
- ClockIntl.DateTimeFormat.prototype = Object.create(
- NativeIntl.DateTimeFormat.prototype,
- );
-
- ClockIntl.DateTimeFormat.supportedLocalesOf =
- NativeIntl.DateTimeFormat.supportedLocalesOf;
-
- return ClockIntl;
- }
-
- //eslint-disable-next-line jsdoc/require-jsdoc
- function enqueueJob(clock, job) {
- // enqueues a microtick-deferred task - ecma262/#sec-enqueuejob
- if (!clock.jobs) {
- clock.jobs = [];
- }
- clock.jobs.push(job);
- }
-
- //eslint-disable-next-line jsdoc/require-jsdoc
- function runJobs(clock) {
- // runs all microtick-deferred tasks - ecma262/#sec-runjobs
- if (!clock.jobs) {
- return;
- }
- for (let i = 0; i < clock.jobs.length; i++) {
- const job = clock.jobs[i];
- job.func.apply(null, job.args);
-
- checkIsNearInfiniteLimit(clock, i);
- if (clock.loopLimit && i > clock.loopLimit) {
- throw getInfiniteLoopError(clock, job);
- }
- }
- resetIsNearInfiniteLimit();
- clock.jobs = [];
- }
-
- /**
- * @param {Clock} clock
- * @param {Timer} timer
- * @returns {number} id of the created timer
- */
- function addTimer(clock, timer) {
- if (timer.func === undefined) {
- throw new Error("Callback must be provided to timer calls");
- }
-
- if (addTimerReturnsObject) {
- // Node.js environment
- if (typeof timer.func !== "function") {
- throw new TypeError(
- `[ERR_INVALID_CALLBACK]: Callback must be a function. Received ${
- timer.func
- } of type ${typeof timer.func}`,
- );
- }
- }
-
- if (isNearInfiniteLimit) {
- timer.error = new Error();
- }
-
- timer.type = timer.immediate ? "Immediate" : "Timeout";
-
- if (timer.hasOwnProperty("delay")) {
- if (typeof timer.delay !== "number") {
- timer.delay = parseInt(timer.delay, 10);
- }
-
- if (!isNumberFinite(timer.delay)) {
- timer.delay = 0;
- }
- timer.delay = timer.delay > maxTimeout ? 1 : timer.delay;
- timer.delay = Math.max(0, timer.delay);
- }
-
- if (timer.hasOwnProperty("interval")) {
- timer.type = "Interval";
- timer.interval = timer.interval > maxTimeout ? 1 : timer.interval;
- }
-
- if (timer.hasOwnProperty("animation")) {
- timer.type = "AnimationFrame";
- timer.animation = true;
- }
-
- if (timer.hasOwnProperty("idleCallback")) {
- timer.type = "IdleCallback";
- timer.idleCallback = true;
- }
-
- if (!clock.timers) {
- clock.timers = {};
- }
-
- timer.id = uniqueTimerId++;
- timer.createdAt = clock.now;
- timer.callAt =
- clock.now + (parseInt(timer.delay) || (clock.duringTick ? 1 : 0));
-
- clock.timers[timer.id] = timer;
-
- if (addTimerReturnsObject) {
- const res = {
- refed: true,
- ref: function () {
- this.refed = true;
- return res;
- },
- unref: function () {
- this.refed = false;
- return res;
- },
- hasRef: function () {
- return this.refed;
- },
- refresh: function () {
- timer.callAt =
- clock.now +
- (parseInt(timer.delay) || (clock.duringTick ? 1 : 0));
-
- // it _might_ have been removed, but if not the assignment is perfectly fine
- clock.timers[timer.id] = timer;
-
- return res;
- },
- [Symbol.toPrimitive]: function () {
- return timer.id;
- },
- };
- return res;
- }
-
- return timer.id;
- }
-
- /* eslint consistent-return: "off" */
- /**
- * Timer comparitor
- * @param {Timer} a
- * @param {Timer} b
- * @returns {number}
- */
- function compareTimers(a, b) {
- // Sort first by absolute timing
- if (a.callAt < b.callAt) {
- return -1;
- }
- if (a.callAt > b.callAt) {
- return 1;
- }
-
- // Sort next by immediate, immediate timers take precedence
- if (a.immediate && !b.immediate) {
- return -1;
- }
- if (!a.immediate && b.immediate) {
- return 1;
- }
-
- // Sort next by creation time, earlier-created timers take precedence
- if (a.createdAt < b.createdAt) {
- return -1;
- }
- if (a.createdAt > b.createdAt) {
- return 1;
- }
-
- // Sort next by id, lower-id timers take precedence
- if (a.id < b.id) {
- return -1;
- }
- if (a.id > b.id) {
- return 1;
- }
-
- // As timer ids are unique, no fallback `0` is necessary
- }
-
- /**
- * @param {Clock} clock
- * @param {number} from
- * @param {number} to
- * @returns {Timer}
- */
- function firstTimerInRange(clock, from, to) {
- const timers = clock.timers;
- let timer = null;
- let id, isInRange;
-
- for (id in timers) {
- if (timers.hasOwnProperty(id)) {
- isInRange = inRange(from, to, timers[id]);
-
- if (
- isInRange &&
- (!timer || compareTimers(timer, timers[id]) === 1)
- ) {
- timer = timers[id];
- }
- }
- }
-
- return timer;
- }
-
- /**
- * @param {Clock} clock
- * @returns {Timer}
- */
- function firstTimer(clock) {
- const timers = clock.timers;
- let timer = null;
- let id;
-
- for (id in timers) {
- if (timers.hasOwnProperty(id)) {
- if (!timer || compareTimers(timer, timers[id]) === 1) {
- timer = timers[id];
- }
- }
- }
-
- return timer;
- }
-
- /**
- * @param {Clock} clock
- * @returns {Timer}
- */
- function lastTimer(clock) {
- const timers = clock.timers;
- let timer = null;
- let id;
-
- for (id in timers) {
- if (timers.hasOwnProperty(id)) {
- if (!timer || compareTimers(timer, timers[id]) === -1) {
- timer = timers[id];
- }
- }
- }
-
- return timer;
- }
-
- /**
- * @param {Clock} clock
- * @param {Timer} timer
- */
- function callTimer(clock, timer) {
- if (typeof timer.interval === "number") {
- clock.timers[timer.id].callAt += timer.interval;
- } else {
- delete clock.timers[timer.id];
- }
-
- if (typeof timer.func === "function") {
- timer.func.apply(null, timer.args);
- } else {
- /* eslint no-eval: "off" */
- const eval2 = eval;
- (function () {
- eval2(timer.func);
- })();
- }
- }
-
- /**
- * Gets clear handler name for a given timer type
- * @param {string} ttype
- */
- function getClearHandler(ttype) {
- if (ttype === "IdleCallback" || ttype === "AnimationFrame") {
- return `cancel${ttype}`;
- }
- return `clear${ttype}`;
- }
-
- /**
- * Gets schedule handler name for a given timer type
- * @param {string} ttype
- */
- function getScheduleHandler(ttype) {
- if (ttype === "IdleCallback" || ttype === "AnimationFrame") {
- return `request${ttype}`;
- }
- return `set${ttype}`;
- }
-
- /**
- * Creates an anonymous function to warn only once
- */
- function createWarnOnce() {
- let calls = 0;
- return function (msg) {
- // eslint-disable-next-line
- !calls++ && console.warn(msg);
- };
- }
- const warnOnce = createWarnOnce();
-
- /**
- * @param {Clock} clock
- * @param {number} timerId
- * @param {string} ttype
- */
- function clearTimer(clock, timerId, ttype) {
- if (!timerId) {
- // null appears to be allowed in most browsers, and appears to be
- // relied upon by some libraries, like Bootstrap carousel
- return;
- }
-
- if (!clock.timers) {
- clock.timers = {};
- }
-
- // in Node, the ID is stored as the primitive value for `Timeout` objects
- // for `Immediate` objects, no ID exists, so it gets coerced to NaN
- const id = Number(timerId);
-
- if (Number.isNaN(id) || id < idCounterStart) {
- const handlerName = getClearHandler(ttype);
-
- if (clock.shouldClearNativeTimers === true) {
- const nativeHandler = clock[`_${handlerName}`];
- return typeof nativeHandler === "function"
- ? nativeHandler(timerId)
- : undefined;
- }
- warnOnce(
- `FakeTimers: ${handlerName} was invoked to clear a native timer instead of one created by this library.` +
- "\nTo automatically clean-up native timers, use `shouldClearNativeTimers`.",
- );
- }
-
- if (clock.timers.hasOwnProperty(id)) {
- // check that the ID matches a timer of the correct type
- const timer = clock.timers[id];
- if (
- timer.type === ttype ||
- (timer.type === "Timeout" && ttype === "Interval") ||
- (timer.type === "Interval" && ttype === "Timeout")
- ) {
- delete clock.timers[id];
- } else {
- const clear = getClearHandler(ttype);
- const schedule = getScheduleHandler(timer.type);
- throw new Error(
- `Cannot clear timer: timer created with ${schedule}() but cleared with ${clear}()`,
- );
- }
- }
- }
-
- /**
- * @param {Clock} clock
- * @param {Config} config
- * @returns {Timer[]}
- */
- function uninstall(clock, config) {
- let method, i, l;
- const installedHrTime = "_hrtime";
- const installedNextTick = "_nextTick";
-
- for (i = 0, l = clock.methods.length; i < l; i++) {
- method = clock.methods[i];
- if (method === "hrtime" && _global.process) {
- _global.process.hrtime = clock[installedHrTime];
- } else if (method === "nextTick" && _global.process) {
- _global.process.nextTick = clock[installedNextTick];
- } else if (method === "performance") {
- const originalPerfDescriptor = Object.getOwnPropertyDescriptor(
- clock,
- `_${method}`,
- );
- if (
- originalPerfDescriptor &&
- originalPerfDescriptor.get &&
- !originalPerfDescriptor.set
- ) {
- Object.defineProperty(
- _global,
- method,
- originalPerfDescriptor,
- );
- } else if (originalPerfDescriptor.configurable) {
- _global[method] = clock[`_${method}`];
- }
- } else {
- if (_global[method] && _global[method].hadOwnProperty) {
- _global[method] = clock[`_${method}`];
- } else {
- try {
- delete _global[method];
- } catch (ignore) {
- /* eslint no-empty: "off" */
- }
- }
- }
- if (clock.timersModuleMethods !== undefined) {
- for (let j = 0; j < clock.timersModuleMethods.length; j++) {
- const entry = clock.timersModuleMethods[j];
- timersModule[entry.methodName] = entry.original;
- }
- }
- if (clock.timersPromisesModuleMethods !== undefined) {
- for (
- let j = 0;
- j < clock.timersPromisesModuleMethods.length;
- j++
- ) {
- const entry = clock.timersPromisesModuleMethods[j];
- timersPromisesModule[entry.methodName] = entry.original;
- }
- }
- }
-
- if (config.shouldAdvanceTime === true) {
- _global.clearInterval(clock.attachedInterval);
- }
-
- // Prevent multiple executions which will completely remove these props
- clock.methods = [];
-
- for (const [listener, signal] of clock.abortListenerMap.entries()) {
- signal.removeEventListener("abort", listener);
- clock.abortListenerMap.delete(listener);
- }
-
- // return pending timers, to enable checking what timers remained on uninstall
- if (!clock.timers) {
- return [];
- }
- return Object.keys(clock.timers).map(function mapper(key) {
- return clock.timers[key];
- });
- }
-
- /**
- * @param {object} target the target containing the method to replace
- * @param {string} method the keyname of the method on the target
- * @param {Clock} clock
- */
- function hijackMethod(target, method, clock) {
- clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(
- target,
- method,
- );
- clock[`_${method}`] = target[method];
-
- if (method === "Date") {
- target[method] = clock[method];
- } else if (method === "Intl") {
- target[method] = clock[method];
- } else if (method === "performance") {
- const originalPerfDescriptor = Object.getOwnPropertyDescriptor(
- target,
- method,
- );
- // JSDOM has a read only performance field so we have to save/copy it differently
- if (
- originalPerfDescriptor &&
- originalPerfDescriptor.get &&
- !originalPerfDescriptor.set
- ) {
- Object.defineProperty(
- clock,
- `_${method}`,
- originalPerfDescriptor,
- );
-
- const perfDescriptor = Object.getOwnPropertyDescriptor(
- clock,
- method,
- );
- Object.defineProperty(target, method, perfDescriptor);
- } else {
- target[method] = clock[method];
- }
- } else {
- target[method] = function () {
- return clock[method].apply(clock, arguments);
- };
-
- Object.defineProperties(
- target[method],
- Object.getOwnPropertyDescriptors(clock[method]),
- );
- }
-
- target[method].clock = clock;
- }
-
- /**
- * @param {Clock} clock
- * @param {number} advanceTimeDelta
- */
- function doIntervalTick(clock, advanceTimeDelta) {
- clock.tick(advanceTimeDelta);
- }
-
- /**
- * @typedef {object} Timers
- * @property {setTimeout} setTimeout
- * @property {clearTimeout} clearTimeout
- * @property {setInterval} setInterval
- * @property {clearInterval} clearInterval
- * @property {Date} Date
- * @property {Intl} Intl
- * @property {SetImmediate=} setImmediate
- * @property {function(NodeImmediate): void=} clearImmediate
- * @property {function(number[]):number[]=} hrtime
- * @property {NextTick=} nextTick
- * @property {Performance=} performance
- * @property {RequestAnimationFrame=} requestAnimationFrame
- * @property {boolean=} queueMicrotask
- * @property {function(number): void=} cancelAnimationFrame
- * @property {RequestIdleCallback=} requestIdleCallback
- * @property {function(number): void=} cancelIdleCallback
- */
-
- /** @type {Timers} */
- const timers = {
- setTimeout: _global.setTimeout,
- clearTimeout: _global.clearTimeout,
- setInterval: _global.setInterval,
- clearInterval: _global.clearInterval,
- Date: _global.Date,
- };
-
- if (isPresent.setImmediate) {
- timers.setImmediate = _global.setImmediate;
- }
-
- if (isPresent.clearImmediate) {
- timers.clearImmediate = _global.clearImmediate;
- }
-
- if (isPresent.hrtime) {
- timers.hrtime = _global.process.hrtime;
- }
-
- if (isPresent.nextTick) {
- timers.nextTick = _global.process.nextTick;
- }
-
- if (isPresent.performance) {
- timers.performance = _global.performance;
- }
-
- if (isPresent.requestAnimationFrame) {
- timers.requestAnimationFrame = _global.requestAnimationFrame;
- }
-
- if (isPresent.queueMicrotask) {
- timers.queueMicrotask = _global.queueMicrotask;
- }
-
- if (isPresent.cancelAnimationFrame) {
- timers.cancelAnimationFrame = _global.cancelAnimationFrame;
- }
-
- if (isPresent.requestIdleCallback) {
- timers.requestIdleCallback = _global.requestIdleCallback;
- }
-
- if (isPresent.cancelIdleCallback) {
- timers.cancelIdleCallback = _global.cancelIdleCallback;
- }
-
- if (isPresent.Intl) {
- timers.Intl = NativeIntl;
- }
-
- const originalSetTimeout = _global.setImmediate || _global.setTimeout;
-
- /**
- * @param {Date|number} [start] the system time - non-integer values are floored
- * @param {number} [loopLimit] maximum number of timers that will be run when calling runAll()
- * @returns {Clock}
- */
- function createClock(start, loopLimit) {
- // eslint-disable-next-line no-param-reassign
- start = Math.floor(getEpoch(start));
- // eslint-disable-next-line no-param-reassign
- loopLimit = loopLimit || 1000;
- let nanos = 0;
- const adjustedSystemTime = [0, 0]; // [millis, nanoremainder]
-
- const clock = {
- now: start,
- Date: createDate(),
- loopLimit: loopLimit,
- };
-
- clock.Date.clock = clock;
-
- //eslint-disable-next-line jsdoc/require-jsdoc
- function getTimeToNextFrame() {
- return 16 - ((clock.now - start) % 16);
- }
-
- //eslint-disable-next-line jsdoc/require-jsdoc
- function hrtime(prev) {
- const millisSinceStart = clock.now - adjustedSystemTime[0] - start;
- const secsSinceStart = Math.floor(millisSinceStart / 1000);
- const remainderInNanos =
- (millisSinceStart - secsSinceStart * 1e3) * 1e6 +
- nanos -
- adjustedSystemTime[1];
-
- if (Array.isArray(prev)) {
- if (prev[1] > 1e9) {
- throw new TypeError(
- "Number of nanoseconds can't exceed a billion",
- );
- }
-
- const oldSecs = prev[0];
- let nanoDiff = remainderInNanos - prev[1];
- let secDiff = secsSinceStart - oldSecs;
-
- if (nanoDiff < 0) {
- nanoDiff += 1e9;
- secDiff -= 1;
- }
-
- return [secDiff, nanoDiff];
- }
- return [secsSinceStart, remainderInNanos];
- }
-
- /**
- * A high resolution timestamp in milliseconds.
- * @typedef {number} DOMHighResTimeStamp
- */
-
- /**
- * performance.now()
- * @returns {DOMHighResTimeStamp}
- */
- function fakePerformanceNow() {
- const hrt = hrtime();
- const millis = hrt[0] * 1000 + hrt[1] / 1e6;
- return millis;
- }
-
- if (isPresent.hrtimeBigint) {
- hrtime.bigint = function () {
- const parts = hrtime();
- return BigInt(parts[0]) * BigInt(1e9) + BigInt(parts[1]); // eslint-disable-line
- };
- }
-
- if (isPresent.Intl) {
- clock.Intl = createIntl();
- clock.Intl.clock = clock;
- }
-
- clock.requestIdleCallback = function requestIdleCallback(
- func,
- timeout,
- ) {
- let timeToNextIdlePeriod = 0;
-
- if (clock.countTimers() > 0) {
- timeToNextIdlePeriod = 50; // const for now
- }
-
- const result = addTimer(clock, {
- func: func,
- args: Array.prototype.slice.call(arguments, 2),
- delay:
- typeof timeout === "undefined"
- ? timeToNextIdlePeriod
- : Math.min(timeout, timeToNextIdlePeriod),
- idleCallback: true,
- });
-
- return Number(result);
- };
-
- clock.cancelIdleCallback = function cancelIdleCallback(timerId) {
- return clearTimer(clock, timerId, "IdleCallback");
- };
-
- clock.setTimeout = function setTimeout(func, timeout) {
- return addTimer(clock, {
- func: func,
- args: Array.prototype.slice.call(arguments, 2),
- delay: timeout,
- });
- };
- if (typeof _global.Promise !== "undefined" && utilPromisify) {
- clock.setTimeout[utilPromisify.custom] =
- function promisifiedSetTimeout(timeout, arg) {
- return new _global.Promise(function setTimeoutExecutor(
- resolve,
- ) {
- addTimer(clock, {
- func: resolve,
- args: [arg],
- delay: timeout,
- });
- });
- };
- }
-
- clock.clearTimeout = function clearTimeout(timerId) {
- return clearTimer(clock, timerId, "Timeout");
- };
-
- clock.nextTick = function nextTick(func) {
- return enqueueJob(clock, {
- func: func,
- args: Array.prototype.slice.call(arguments, 1),
- error: isNearInfiniteLimit ? new Error() : null,
- });
- };
-
- clock.queueMicrotask = function queueMicrotask(func) {
- return clock.nextTick(func); // explicitly drop additional arguments
- };
-
- clock.setInterval = function setInterval(func, timeout) {
- // eslint-disable-next-line no-param-reassign
- timeout = parseInt(timeout, 10);
- return addTimer(clock, {
- func: func,
- args: Array.prototype.slice.call(arguments, 2),
- delay: timeout,
- interval: timeout,
- });
- };
-
- clock.clearInterval = function clearInterval(timerId) {
- return clearTimer(clock, timerId, "Interval");
- };
-
- if (isPresent.setImmediate) {
- clock.setImmediate = function setImmediate(func) {
- return addTimer(clock, {
- func: func,
- args: Array.prototype.slice.call(arguments, 1),
- immediate: true,
- });
- };
-
- if (typeof _global.Promise !== "undefined" && utilPromisify) {
- clock.setImmediate[utilPromisify.custom] =
- function promisifiedSetImmediate(arg) {
- return new _global.Promise(
- function setImmediateExecutor(resolve) {
- addTimer(clock, {
- func: resolve,
- args: [arg],
- immediate: true,
- });
- },
- );
- };
- }
-
- clock.clearImmediate = function clearImmediate(timerId) {
- return clearTimer(clock, timerId, "Immediate");
- };
- }
-
- clock.countTimers = function countTimers() {
- return (
- Object.keys(clock.timers || {}).length +
- (clock.jobs || []).length
- );
- };
-
- clock.requestAnimationFrame = function requestAnimationFrame(func) {
- const result = addTimer(clock, {
- func: func,
- delay: getTimeToNextFrame(),
- get args() {
- return [fakePerformanceNow()];
- },
- animation: true,
- });
-
- return Number(result);
- };
-
- clock.cancelAnimationFrame = function cancelAnimationFrame(timerId) {
- return clearTimer(clock, timerId, "AnimationFrame");
- };
-
- clock.runMicrotasks = function runMicrotasks() {
- runJobs(clock);
- };
-
- /**
- * @param {number|string} tickValue milliseconds or a string parseable by parseTime
- * @param {boolean} isAsync
- * @param {Function} resolve
- * @param {Function} reject
- * @returns {number|undefined} will return the new `now` value or nothing for async
- */
- function doTick(tickValue, isAsync, resolve, reject) {
- const msFloat =
- typeof tickValue === "number"
- ? tickValue
- : parseTime(tickValue);
- const ms = Math.floor(msFloat);
- const remainder = nanoRemainder(msFloat);
- let nanosTotal = nanos + remainder;
- let tickTo = clock.now + ms;
-
- if (msFloat < 0) {
- throw new TypeError("Negative ticks are not supported");
- }
-
- // adjust for positive overflow
- if (nanosTotal >= 1e6) {
- tickTo += 1;
- nanosTotal -= 1e6;
- }
-
- nanos = nanosTotal;
- let tickFrom = clock.now;
- let previous = clock.now;
- // ESLint fails to detect this correctly
- /* eslint-disable prefer-const */
- let timer,
- firstException,
- oldNow,
- nextPromiseTick,
- compensationCheck,
- postTimerCall;
- /* eslint-enable prefer-const */
-
- clock.duringTick = true;
-
- // perform microtasks
- oldNow = clock.now;
- runJobs(clock);
- if (oldNow !== clock.now) {
- // compensate for any setSystemTime() call during microtask callback
- tickFrom += clock.now - oldNow;
- tickTo += clock.now - oldNow;
- }
-
- //eslint-disable-next-line jsdoc/require-jsdoc
- function doTickInner() {
- // perform each timer in the requested range
- timer = firstTimerInRange(clock, tickFrom, tickTo);
- // eslint-disable-next-line no-unmodified-loop-condition
- while (timer && tickFrom <= tickTo) {
- if (clock.timers[timer.id]) {
- tickFrom = timer.callAt;
- clock.now = timer.callAt;
- oldNow = clock.now;
- try {
- runJobs(clock);
- callTimer(clock, timer);
- } catch (e) {
- firstException = firstException || e;
- }
-
- if (isAsync) {
- // finish up after native setImmediate callback to allow
- // all native es6 promises to process their callbacks after
- // each timer fires.
- originalSetTimeout(nextPromiseTick);
- return;
- }
-
- compensationCheck();
- }
-
- postTimerCall();
- }
-
- // perform process.nextTick()s again
- oldNow = clock.now;
- runJobs(clock);
- if (oldNow !== clock.now) {
- // compensate for any setSystemTime() call during process.nextTick() callback
- tickFrom += clock.now - oldNow;
- tickTo += clock.now - oldNow;
- }
- clock.duringTick = false;
-
- // corner case: during runJobs new timers were scheduled which could be in the range [clock.now, tickTo]
- timer = firstTimerInRange(clock, tickFrom, tickTo);
- if (timer) {
- try {
- clock.tick(tickTo - clock.now); // do it all again - for the remainder of the requested range
- } catch (e) {
- firstException = firstException || e;
- }
- } else {
- // no timers remaining in the requested range: move the clock all the way to the end
- clock.now = tickTo;
-
- // update nanos
- nanos = nanosTotal;
- }
- if (firstException) {
- throw firstException;
- }
-
- if (isAsync) {
- resolve(clock.now);
- } else {
- return clock.now;
- }
- }
-
- nextPromiseTick =
- isAsync &&
- function () {
- try {
- compensationCheck();
- postTimerCall();
- doTickInner();
- } catch (e) {
- reject(e);
- }
- };
-
- compensationCheck = function () {
- // compensate for any setSystemTime() call during timer callback
- if (oldNow !== clock.now) {
- tickFrom += clock.now - oldNow;
- tickTo += clock.now - oldNow;
- previous += clock.now - oldNow;
- }
- };
-
- postTimerCall = function () {
- timer = firstTimerInRange(clock, previous, tickTo);
- previous = tickFrom;
- };
-
- return doTickInner();
- }
-
- /**
- * @param {string|number} tickValue number of milliseconds or a human-readable value like "01:11:15"
- * @returns {number} will return the new `now` value
- */
- clock.tick = function tick(tickValue) {
- return doTick(tickValue, false);
- };
-
- if (typeof _global.Promise !== "undefined") {
- /**
- * @param {string|number} tickValue number of milliseconds or a human-readable value like "01:11:15"
- * @returns {Promise}
- */
- clock.tickAsync = function tickAsync(tickValue) {
- return new _global.Promise(function (resolve, reject) {
- originalSetTimeout(function () {
- try {
- doTick(tickValue, true, resolve, reject);
- } catch (e) {
- reject(e);
- }
- });
- });
- };
- }
-
- clock.next = function next() {
- runJobs(clock);
- const timer = firstTimer(clock);
- if (!timer) {
- return clock.now;
- }
-
- clock.duringTick = true;
- try {
- clock.now = timer.callAt;
- callTimer(clock, timer);
- runJobs(clock);
- return clock.now;
- } finally {
- clock.duringTick = false;
- }
- };
-
- if (typeof _global.Promise !== "undefined") {
- clock.nextAsync = function nextAsync() {
- return new _global.Promise(function (resolve, reject) {
- originalSetTimeout(function () {
- try {
- const timer = firstTimer(clock);
- if (!timer) {
- resolve(clock.now);
- return;
- }
-
- let err;
- clock.duringTick = true;
- clock.now = timer.callAt;
- try {
- callTimer(clock, timer);
- } catch (e) {
- err = e;
- }
- clock.duringTick = false;
-
- originalSetTimeout(function () {
- if (err) {
- reject(err);
- } else {
- resolve(clock.now);
- }
- });
- } catch (e) {
- reject(e);
- }
- });
- });
- };
- }
-
- clock.runAll = function runAll() {
- let numTimers, i;
- runJobs(clock);
- for (i = 0; i < clock.loopLimit; i++) {
- if (!clock.timers) {
- resetIsNearInfiniteLimit();
- return clock.now;
- }
-
- numTimers = Object.keys(clock.timers).length;
- if (numTimers === 0) {
- resetIsNearInfiniteLimit();
- return clock.now;
- }
-
- clock.next();
- checkIsNearInfiniteLimit(clock, i);
- }
-
- const excessJob = firstTimer(clock);
- throw getInfiniteLoopError(clock, excessJob);
- };
-
- clock.runToFrame = function runToFrame() {
- return clock.tick(getTimeToNextFrame());
- };
-
- if (typeof _global.Promise !== "undefined") {
- clock.runAllAsync = function runAllAsync() {
- return new _global.Promise(function (resolve, reject) {
- let i = 0;
- /**
- *
- */
- function doRun() {
- originalSetTimeout(function () {
- try {
- runJobs(clock);
-
- let numTimers;
- if (i < clock.loopLimit) {
- if (!clock.timers) {
- resetIsNearInfiniteLimit();
- resolve(clock.now);
- return;
- }
-
- numTimers = Object.keys(
- clock.timers,
- ).length;
- if (numTimers === 0) {
- resetIsNearInfiniteLimit();
- resolve(clock.now);
- return;
- }
-
- clock.next();
-
- i++;
-
- doRun();
- checkIsNearInfiniteLimit(clock, i);
- return;
- }
-
- const excessJob = firstTimer(clock);
- reject(getInfiniteLoopError(clock, excessJob));
- } catch (e) {
- reject(e);
- }
- });
- }
- doRun();
- });
- };
- }
-
- clock.runToLast = function runToLast() {
- const timer = lastTimer(clock);
- if (!timer) {
- runJobs(clock);
- return clock.now;
- }
-
- return clock.tick(timer.callAt - clock.now);
- };
-
- if (typeof _global.Promise !== "undefined") {
- clock.runToLastAsync = function runToLastAsync() {
- return new _global.Promise(function (resolve, reject) {
- originalSetTimeout(function () {
- try {
- const timer = lastTimer(clock);
- if (!timer) {
- runJobs(clock);
- resolve(clock.now);
- }
-
- resolve(clock.tickAsync(timer.callAt - clock.now));
- } catch (e) {
- reject(e);
- }
- });
- });
- };
- }
-
- clock.reset = function reset() {
- nanos = 0;
- clock.timers = {};
- clock.jobs = [];
- clock.now = start;
- };
-
- clock.setSystemTime = function setSystemTime(systemTime) {
- // determine time difference
- const newNow = getEpoch(systemTime);
- const difference = newNow - clock.now;
- let id, timer;
-
- adjustedSystemTime[0] = adjustedSystemTime[0] + difference;
- adjustedSystemTime[1] = adjustedSystemTime[1] + nanos;
- // update 'system clock'
- clock.now = newNow;
- nanos = 0;
-
- // update timers and intervals to keep them stable
- for (id in clock.timers) {
- if (clock.timers.hasOwnProperty(id)) {
- timer = clock.timers[id];
- timer.createdAt += difference;
- timer.callAt += difference;
- }
- }
- };
-
- /**
- * @param {string|number} tickValue number of milliseconds or a human-readable value like "01:11:15"
- * @returns {number} will return the new `now` value
- */
- clock.jump = function jump(tickValue) {
- const msFloat =
- typeof tickValue === "number"
- ? tickValue
- : parseTime(tickValue);
- const ms = Math.floor(msFloat);
-
- for (const timer of Object.values(clock.timers)) {
- if (clock.now + ms > timer.callAt) {
- timer.callAt = clock.now + ms;
- }
- }
- clock.tick(ms);
- };
-
- if (isPresent.performance) {
- clock.performance = Object.create(null);
- clock.performance.now = fakePerformanceNow;
- }
-
- if (isPresent.hrtime) {
- clock.hrtime = hrtime;
- }
-
- return clock;
- }
-
- /* eslint-disable complexity */
-
- /**
- * @param {Config=} [config] Optional config
- * @returns {Clock}
- */
- function install(config) {
- if (
- arguments.length > 1 ||
- config instanceof Date ||
- Array.isArray(config) ||
- typeof config === "number"
- ) {
- throw new TypeError(
- `FakeTimers.install called with ${String(
- config,
- )} install requires an object parameter`,
- );
- }
-
- if (_global.Date.isFake === true) {
- // Timers are already faked; this is a problem.
- // Make the user reset timers before continuing.
- throw new TypeError(
- "Can't install fake timers twice on the same global object.",
- );
- }
-
- // eslint-disable-next-line no-param-reassign
- config = typeof config !== "undefined" ? config : {};
- config.shouldAdvanceTime = config.shouldAdvanceTime || false;
- config.advanceTimeDelta = config.advanceTimeDelta || 20;
- config.shouldClearNativeTimers =
- config.shouldClearNativeTimers || false;
-
- if (config.target) {
- throw new TypeError(
- "config.target is no longer supported. Use `withGlobal(target)` instead.",
- );
- }
-
- /**
- * @param {string} timer/object the name of the thing that is not present
- * @param timer
- */
- function handleMissingTimer(timer) {
- if (config.ignoreMissingTimers) {
- return;
- }
-
- throw new ReferenceError(
- `non-existent timers and/or objects cannot be faked: '${timer}'`,
- );
- }
-
- let i, l;
- const clock = createClock(config.now, config.loopLimit);
- clock.shouldClearNativeTimers = config.shouldClearNativeTimers;
-
- clock.uninstall = function () {
- return uninstall(clock, config);
- };
-
- clock.abortListenerMap = new Map();
-
- clock.methods = config.toFake || [];
-
- if (clock.methods.length === 0) {
- clock.methods = Object.keys(timers);
- }
-
- if (config.shouldAdvanceTime === true) {
- const intervalTick = doIntervalTick.bind(
- null,
- clock,
- config.advanceTimeDelta,
- );
- const intervalId = _global.setInterval(
- intervalTick,
- config.advanceTimeDelta,
- );
- clock.attachedInterval = intervalId;
- }
-
- if (clock.methods.includes("performance")) {
- const proto = (() => {
- if (hasPerformanceConstructorPrototype) {
- return _global.performance.constructor.prototype;
- }
- if (hasPerformancePrototype) {
- return _global.Performance.prototype;
- }
- })();
- if (proto) {
- Object.getOwnPropertyNames(proto).forEach(function (name) {
- if (name !== "now") {
- clock.performance[name] =
- name.indexOf("getEntries") === 0
- ? NOOP_ARRAY
- : NOOP;
- }
- });
- // ensure `mark` returns a value that is valid
- clock.performance.mark = (name) =>
- new FakePerformanceEntry(name, "mark", 0, 0);
- clock.performance.measure = (name) =>
- new FakePerformanceEntry(name, "measure", 0, 100);
- // `timeOrigin` should return the time of when the Window session started
- // (or the Worker was installed)
- clock.performance.timeOrigin = getEpoch(config.now);
- } else if ((config.toFake || []).includes("performance")) {
- return handleMissingTimer("performance");
- }
- }
- if (_global === globalObject && timersModule) {
- clock.timersModuleMethods = [];
- }
- if (_global === globalObject && timersPromisesModule) {
- clock.timersPromisesModuleMethods = [];
- }
- for (i = 0, l = clock.methods.length; i < l; i++) {
- const nameOfMethodToReplace = clock.methods[i];
-
- if (!isPresent[nameOfMethodToReplace]) {
- handleMissingTimer(nameOfMethodToReplace);
- // eslint-disable-next-line
- continue;
- }
-
- if (nameOfMethodToReplace === "hrtime") {
- if (
- _global.process &&
- typeof _global.process.hrtime === "function"
- ) {
- hijackMethod(_global.process, nameOfMethodToReplace, clock);
- }
- } else if (nameOfMethodToReplace === "nextTick") {
- if (
- _global.process &&
- typeof _global.process.nextTick === "function"
- ) {
- hijackMethod(_global.process, nameOfMethodToReplace, clock);
- }
- } else {
- hijackMethod(_global, nameOfMethodToReplace, clock);
- }
- if (
- clock.timersModuleMethods !== undefined &&
- timersModule[nameOfMethodToReplace]
- ) {
- const original = timersModule[nameOfMethodToReplace];
- clock.timersModuleMethods.push({
- methodName: nameOfMethodToReplace,
- original: original,
- });
- timersModule[nameOfMethodToReplace] =
- _global[nameOfMethodToReplace];
- }
- if (clock.timersPromisesModuleMethods !== undefined) {
- if (nameOfMethodToReplace === "setTimeout") {
- clock.timersPromisesModuleMethods.push({
- methodName: "setTimeout",
- original: timersPromisesModule.setTimeout,
- });
-
- timersPromisesModule.setTimeout = (
- delay,
- value,
- options = {},
- ) =>
- new Promise((resolve, reject) => {
- const abort = () => {
- options.signal.removeEventListener(
- "abort",
- abort,
- );
- clock.abortListenerMap.delete(abort);
-
- // This is safe, there is no code path that leads to this function
- // being invoked before handle has been assigned.
- // eslint-disable-next-line no-use-before-define
- clock.clearTimeout(handle);
- reject(options.signal.reason);
- };
-
- const handle = clock.setTimeout(() => {
- if (options.signal) {
- options.signal.removeEventListener(
- "abort",
- abort,
- );
- clock.abortListenerMap.delete(abort);
- }
-
- resolve(value);
- }, delay);
-
- if (options.signal) {
- if (options.signal.aborted) {
- abort();
- } else {
- options.signal.addEventListener(
- "abort",
- abort,
- );
- clock.abortListenerMap.set(
- abort,
- options.signal,
- );
- }
- }
- });
- } else if (nameOfMethodToReplace === "setImmediate") {
- clock.timersPromisesModuleMethods.push({
- methodName: "setImmediate",
- original: timersPromisesModule.setImmediate,
- });
-
- timersPromisesModule.setImmediate = (value, options = {}) =>
- new Promise((resolve, reject) => {
- const abort = () => {
- options.signal.removeEventListener(
- "abort",
- abort,
- );
- clock.abortListenerMap.delete(abort);
-
- // This is safe, there is no code path that leads to this function
- // being invoked before handle has been assigned.
- // eslint-disable-next-line no-use-before-define
- clock.clearImmediate(handle);
- reject(options.signal.reason);
- };
-
- const handle = clock.setImmediate(() => {
- if (options.signal) {
- options.signal.removeEventListener(
- "abort",
- abort,
- );
- clock.abortListenerMap.delete(abort);
- }
-
- resolve(value);
- });
-
- if (options.signal) {
- if (options.signal.aborted) {
- abort();
- } else {
- options.signal.addEventListener(
- "abort",
- abort,
- );
- clock.abortListenerMap.set(
- abort,
- options.signal,
- );
- }
- }
- });
- } else if (nameOfMethodToReplace === "setInterval") {
- clock.timersPromisesModuleMethods.push({
- methodName: "setInterval",
- original: timersPromisesModule.setInterval,
- });
-
- timersPromisesModule.setInterval = (
- delay,
- value,
- options = {},
- ) => ({
- [Symbol.asyncIterator]: () => {
- const createResolvable = () => {
- let resolve, reject;
- const promise = new Promise((res, rej) => {
- resolve = res;
- reject = rej;
- });
- promise.resolve = resolve;
- promise.reject = reject;
- return promise;
- };
-
- let done = false;
- let hasThrown = false;
- let returnCall;
- let nextAvailable = 0;
- const nextQueue = [];
-
- const handle = clock.setInterval(() => {
- if (nextQueue.length > 0) {
- nextQueue.shift().resolve();
- } else {
- nextAvailable++;
- }
- }, delay);
-
- const abort = () => {
- options.signal.removeEventListener(
- "abort",
- abort,
- );
- clock.abortListenerMap.delete(abort);
-
- clock.clearInterval(handle);
- done = true;
- for (const resolvable of nextQueue) {
- resolvable.resolve();
- }
- };
-
- if (options.signal) {
- if (options.signal.aborted) {
- done = true;
- } else {
- options.signal.addEventListener(
- "abort",
- abort,
- );
- clock.abortListenerMap.set(
- abort,
- options.signal,
- );
- }
- }
-
- return {
- next: async () => {
- if (options.signal?.aborted && !hasThrown) {
- hasThrown = true;
- throw options.signal.reason;
- }
-
- if (done) {
- return { done: true, value: undefined };
- }
-
- if (nextAvailable > 0) {
- nextAvailable--;
- return { done: false, value: value };
- }
-
- const resolvable = createResolvable();
- nextQueue.push(resolvable);
-
- await resolvable;
-
- if (returnCall && nextQueue.length === 0) {
- returnCall.resolve();
- }
-
- if (options.signal?.aborted && !hasThrown) {
- hasThrown = true;
- throw options.signal.reason;
- }
-
- if (done) {
- return { done: true, value: undefined };
- }
-
- return { done: false, value: value };
- },
- return: async () => {
- if (done) {
- return { done: true, value: undefined };
- }
-
- if (nextQueue.length > 0) {
- returnCall = createResolvable();
- await returnCall;
- }
-
- clock.clearInterval(handle);
- done = true;
-
- if (options.signal) {
- options.signal.removeEventListener(
- "abort",
- abort,
- );
- clock.abortListenerMap.delete(abort);
- }
-
- return { done: true, value: undefined };
- },
- };
- },
- });
- }
- }
- }
-
- return clock;
- }
-
- /* eslint-enable complexity */
-
- return {
- timers: timers,
- createClock: createClock,
- install: install,
- withGlobal: withGlobal,
- };
- }
-
- /**
- * @typedef {object} FakeTimers
- * @property {Timers} timers
- * @property {createClock} createClock
- * @property {Function} install
- * @property {withGlobal} withGlobal
- */
-
- /* eslint-enable complexity */
-
- /** @type {FakeTimers} */
- const defaultImplementation = withGlobal(globalObject);
-
- fakeTimersSrc.timers = defaultImplementation.timers;
- fakeTimersSrc.createClock = defaultImplementation.createClock;
- fakeTimersSrc.install = defaultImplementation.install;
- fakeTimersSrc.withGlobal = withGlobal;
- return fakeTimersSrc;
-}
-
-var fakeTimersSrcExports = requireFakeTimersSrc();
-
-class FakeTimers {
- _global;
- _clock;
- // | _fakingTime | _fakingDate |
- // +-------------+-------------+
- // | false | falsy | initial
- // | false | truthy | vi.setSystemTime called first (for mocking only Date without fake timers)
- // | true | falsy | vi.useFakeTimers called first
- // | true | truthy | unreachable
- _fakingTime;
- _fakingDate;
- _fakeTimers;
- _userConfig;
- _now = RealDate.now;
- constructor({ global, config }) {
- this._userConfig = config;
- this._fakingDate = null;
- this._fakingTime = false;
- this._fakeTimers = fakeTimersSrcExports.withGlobal(global);
- this._global = global;
- }
- clearAllTimers() {
- if (this._fakingTime) this._clock.reset();
- }
- dispose() {
- this.useRealTimers();
- }
- runAllTimers() {
- if (this._checkFakeTimers()) this._clock.runAll();
- }
- async runAllTimersAsync() {
- if (this._checkFakeTimers()) await this._clock.runAllAsync();
- }
- runOnlyPendingTimers() {
- if (this._checkFakeTimers()) this._clock.runToLast();
- }
- async runOnlyPendingTimersAsync() {
- if (this._checkFakeTimers()) await this._clock.runToLastAsync();
- }
- advanceTimersToNextTimer(steps = 1) {
- if (this._checkFakeTimers()) for (let i = steps; i > 0; i--) {
- this._clock.next();
- // Fire all timers at this point: https://github.com/sinonjs/fake-timers/issues/250
- this._clock.tick(0);
- if (this._clock.countTimers() === 0) break;
- }
- }
- async advanceTimersToNextTimerAsync(steps = 1) {
- if (this._checkFakeTimers()) for (let i = steps; i > 0; i--) {
- await this._clock.nextAsync();
- // Fire all timers at this point: https://github.com/sinonjs/fake-timers/issues/250
- this._clock.tick(0);
- if (this._clock.countTimers() === 0) break;
- }
- }
- advanceTimersByTime(msToRun) {
- if (this._checkFakeTimers()) this._clock.tick(msToRun);
- }
- async advanceTimersByTimeAsync(msToRun) {
- if (this._checkFakeTimers()) await this._clock.tickAsync(msToRun);
- }
- advanceTimersToNextFrame() {
- if (this._checkFakeTimers()) this._clock.runToFrame();
- }
- runAllTicks() {
- if (this._checkFakeTimers())
- // @ts-expect-error method not exposed
- this._clock.runMicrotasks();
- }
- useRealTimers() {
- if (this._fakingDate) {
- resetDate();
- this._fakingDate = null;
- }
- if (this._fakingTime) {
- this._clock.uninstall();
- this._fakingTime = false;
- }
- }
- useFakeTimers() {
- const fakeDate = this._fakingDate || Date.now();
- if (this._fakingDate) {
- resetDate();
- this._fakingDate = null;
- }
- if (this._fakingTime) this._clock.uninstall();
- const toFake = Object.keys(this._fakeTimers.timers).filter((timer) => timer !== "nextTick" && timer !== "queueMicrotask");
- if (this._userConfig?.toFake?.includes("nextTick") && isChildProcess()) throw new Error("process.nextTick cannot be mocked inside child_process");
- this._clock = this._fakeTimers.install({
- now: fakeDate,
- ...this._userConfig,
- toFake: this._userConfig?.toFake || toFake,
- ignoreMissingTimers: true
- });
- this._fakingTime = true;
- }
- reset() {
- if (this._checkFakeTimers()) {
- const { now } = this._clock;
- this._clock.reset();
- this._clock.setSystemTime(now);
- }
- }
- setSystemTime(now) {
- const date = typeof now === "undefined" || now instanceof Date ? now : new Date(now);
- if (this._fakingTime) this._clock.setSystemTime(date);
- else {
- this._fakingDate = date ?? new Date(this.getRealSystemTime());
- mockDate(this._fakingDate);
- }
- }
- getMockedSystemTime() {
- return this._fakingTime ? new Date(this._clock.now) : this._fakingDate;
- }
- getRealSystemTime() {
- return this._now();
- }
- getTimerCount() {
- if (this._checkFakeTimers()) return this._clock.countTimers();
- return 0;
- }
- configure(config) {
- this._userConfig = config;
- }
- isFakeTimers() {
- return this._fakingTime;
- }
- _checkFakeTimers() {
- if (!this._fakingTime) throw new Error("A function to advance timers was called but the timers APIs are not mocked. Call `vi.useFakeTimers()` in the test file first.");
- return this._fakingTime;
- }
-}
-
-function copyStackTrace(target, source) {
- if (source.stack !== void 0) target.stack = source.stack.replace(source.message, target.message);
- return target;
-}
-function waitFor(callback, options = {}) {
- const { setTimeout, setInterval, clearTimeout, clearInterval } = getSafeTimers();
- const { interval = 50, timeout = 1e3 } = typeof options === "number" ? { timeout: options } : options;
- const STACK_TRACE_ERROR = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
- return new Promise((resolve, reject) => {
- let lastError;
- let promiseStatus = "idle";
- let timeoutId;
- let intervalId;
- const onResolve = (result) => {
- if (timeoutId) clearTimeout(timeoutId);
- if (intervalId) clearInterval(intervalId);
- resolve(result);
- };
- const handleTimeout = () => {
- if (intervalId) clearInterval(intervalId);
- let error = lastError;
- if (!error) error = copyStackTrace(/* @__PURE__ */ new Error("Timed out in waitFor!"), STACK_TRACE_ERROR);
- reject(error);
- };
- const checkCallback = () => {
- if (vi.isFakeTimers()) vi.advanceTimersByTime(interval);
- if (promiseStatus === "pending") return;
- try {
- const result = callback();
- if (result !== null && typeof result === "object" && typeof result.then === "function") {
- const thenable = result;
- promiseStatus = "pending";
- thenable.then((resolvedValue) => {
- promiseStatus = "resolved";
- onResolve(resolvedValue);
- }, (rejectedValue) => {
- promiseStatus = "rejected";
- lastError = rejectedValue;
- });
- } else {
- onResolve(result);
- return true;
- }
- } catch (error) {
- lastError = error;
- }
- };
- if (checkCallback() === true) return;
- timeoutId = setTimeout(handleTimeout, timeout);
- intervalId = setInterval(checkCallback, interval);
- });
-}
-function waitUntil(callback, options = {}) {
- const { setTimeout, setInterval, clearTimeout, clearInterval } = getSafeTimers();
- const { interval = 50, timeout = 1e3 } = typeof options === "number" ? { timeout: options } : options;
- const STACK_TRACE_ERROR = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
- return new Promise((resolve, reject) => {
- let promiseStatus = "idle";
- let timeoutId;
- let intervalId;
- const onReject = (error) => {
- if (intervalId) clearInterval(intervalId);
- if (!error) error = copyStackTrace(/* @__PURE__ */ new Error("Timed out in waitUntil!"), STACK_TRACE_ERROR);
- reject(error);
- };
- const onResolve = (result) => {
- if (!result) return;
- if (timeoutId) clearTimeout(timeoutId);
- if (intervalId) clearInterval(intervalId);
- resolve(result);
- return true;
- };
- const checkCallback = () => {
- if (vi.isFakeTimers()) vi.advanceTimersByTime(interval);
- if (promiseStatus === "pending") return;
- try {
- const result = callback();
- if (result !== null && typeof result === "object" && typeof result.then === "function") {
- const thenable = result;
- promiseStatus = "pending";
- thenable.then((resolvedValue) => {
- promiseStatus = "resolved";
- onResolve(resolvedValue);
- }, (rejectedValue) => {
- promiseStatus = "rejected";
- onReject(rejectedValue);
- });
- } else return onResolve(result);
- } catch (error) {
- onReject(error);
- }
- };
- if (checkCallback() === true) return;
- timeoutId = setTimeout(onReject, timeout);
- intervalId = setInterval(checkCallback, interval);
- });
-}
-
-function createVitest() {
- let _config = null;
- const state = () => getWorkerState();
- let _timers;
- const timers = () => _timers ||= new FakeTimers({
- global: globalThis,
- config: state().config.fakeTimers
- });
- const _stubsGlobal = /* @__PURE__ */ new Map();
- const _stubsEnv = /* @__PURE__ */ new Map();
- const _envBooleans = [
- "PROD",
- "DEV",
- "SSR"
- ];
- const utils = {
- useFakeTimers(config) {
- if (isChildProcess()) {
- if (config?.toFake?.includes("nextTick") || state().config?.fakeTimers?.toFake?.includes("nextTick")) throw new Error("vi.useFakeTimers({ toFake: [\"nextTick\"] }) is not supported in node:child_process. Use --pool=threads if mocking nextTick is required.");
- }
- if (config) timers().configure({
- ...state().config.fakeTimers,
- ...config
- });
- else timers().configure(state().config.fakeTimers);
- timers().useFakeTimers();
- return utils;
- },
- isFakeTimers() {
- return timers().isFakeTimers();
- },
- useRealTimers() {
- timers().useRealTimers();
- return utils;
- },
- runOnlyPendingTimers() {
- timers().runOnlyPendingTimers();
- return utils;
- },
- async runOnlyPendingTimersAsync() {
- await timers().runOnlyPendingTimersAsync();
- return utils;
- },
- runAllTimers() {
- timers().runAllTimers();
- return utils;
- },
- async runAllTimersAsync() {
- await timers().runAllTimersAsync();
- return utils;
- },
- runAllTicks() {
- timers().runAllTicks();
- return utils;
- },
- advanceTimersByTime(ms) {
- timers().advanceTimersByTime(ms);
- return utils;
- },
- async advanceTimersByTimeAsync(ms) {
- await timers().advanceTimersByTimeAsync(ms);
- return utils;
- },
- advanceTimersToNextTimer() {
- timers().advanceTimersToNextTimer();
- return utils;
- },
- async advanceTimersToNextTimerAsync() {
- await timers().advanceTimersToNextTimerAsync();
- return utils;
- },
- advanceTimersToNextFrame() {
- timers().advanceTimersToNextFrame();
- return utils;
- },
- getTimerCount() {
- return timers().getTimerCount();
- },
- setSystemTime(time) {
- timers().setSystemTime(time);
- return utils;
- },
- getMockedSystemTime() {
- return timers().getMockedSystemTime();
- },
- getRealSystemTime() {
- return timers().getRealSystemTime();
- },
- clearAllTimers() {
- timers().clearAllTimers();
- return utils;
- },
- spyOn,
- fn,
- waitFor,
- waitUntil,
- hoisted(factory) {
- assertTypes(factory, "\"vi.hoisted\" factory", ["function"]);
- return factory();
- },
- mock(path, factory) {
- if (typeof path !== "string") throw new TypeError(`vi.mock() expects a string path, but received a ${typeof path}`);
- const importer = getImporter("mock");
- _mocker().queueMock(path, importer, typeof factory === "function" ? () => factory(() => _mocker().importActual(path, importer, _mocker().getMockContext().callstack)) : factory);
- },
- unmock(path) {
- if (typeof path !== "string") throw new TypeError(`vi.unmock() expects a string path, but received a ${typeof path}`);
- _mocker().queueUnmock(path, getImporter("unmock"));
- },
- doMock(path, factory) {
- if (typeof path !== "string") throw new TypeError(`vi.doMock() expects a string path, but received a ${typeof path}`);
- const importer = getImporter("doMock");
- _mocker().queueMock(path, importer, typeof factory === "function" ? () => factory(() => _mocker().importActual(path, importer, _mocker().getMockContext().callstack)) : factory);
- },
- doUnmock(path) {
- if (typeof path !== "string") throw new TypeError(`vi.doUnmock() expects a string path, but received a ${typeof path}`);
- const importer = getImporter("doUnmock");
- _mocker().queueUnmock(path, importer);
- },
- async importActual(path) {
- const importer = getImporter("importActual");
- return _mocker().importActual(path, importer, _mocker().getMockContext().callstack);
- },
- async importMock(path) {
- const importer = getImporter("importMock");
- return _mocker().importMock(path, importer);
- },
- mockObject(value, options) {
- return _mocker().mockObject({ value }, void 0, options?.spy ? "autospy" : "automock").value;
- },
- mocked(item, _options = {}) {
- return item;
- },
- isMockFunction(fn) {
- return isMockFunction(fn);
- },
- clearAllMocks() {
- clearAllMocks();
- return utils;
- },
- resetAllMocks() {
- resetAllMocks();
- return utils;
- },
- restoreAllMocks() {
- restoreAllMocks();
- return utils;
- },
- stubGlobal(name, value) {
- if (!_stubsGlobal.has(name)) _stubsGlobal.set(name, Object.getOwnPropertyDescriptor(globalThis, name));
- Object.defineProperty(globalThis, name, {
- value,
- writable: true,
- configurable: true,
- enumerable: true
- });
- return utils;
- },
- stubEnv(name, value) {
- const env = state().metaEnv;
- if (!_stubsEnv.has(name)) _stubsEnv.set(name, env[name]);
- if (_envBooleans.includes(name)) env[name] = value ? "1" : "";
- else if (value === void 0) delete env[name];
- else env[name] = String(value);
- return utils;
- },
- unstubAllGlobals() {
- _stubsGlobal.forEach((original, name) => {
- if (!original) Reflect.deleteProperty(globalThis, name);
- else Object.defineProperty(globalThis, name, original);
- });
- _stubsGlobal.clear();
- return utils;
- },
- unstubAllEnvs() {
- const env = state().metaEnv;
- _stubsEnv.forEach((original, name) => {
- if (original === void 0) delete env[name];
- else env[name] = original;
- });
- _stubsEnv.clear();
- return utils;
- },
- resetModules() {
- resetModules(state().evaluatedModules);
- return utils;
- },
- async dynamicImportSettled() {
- return waitForImportsToResolve();
- },
- setConfig(config) {
- if (!_config) _config = { ...state().config };
- Object.assign(state().config, config);
- },
- resetConfig() {
- if (_config) Object.assign(state().config, _config);
- }
- };
- return utils;
-}
-const vitest = createVitest();
-const vi = vitest;
-function _mocker() {
- // @ts-expect-error injected by vite-nide
- return typeof __vitest_mocker__ !== "undefined" ? __vitest_mocker__ : new Proxy({}, { get(_, name) {
- throw new Error(`Vitest mocker was not initialized in this environment. vi.${String(name)}() is forbidden.`);
- } });
-}
-function getImporter(name) {
- const stackArray = createSimpleStackTrace({ stackTraceLimit: 5 }).split("\n");
- return parseSingleStack(stackArray[stackArray.findLastIndex((stack) => {
- return stack.includes(` at Object.${name}`) || stack.includes(`${name}@`) || stack.includes(` at ${name} (`);
- }) + 1])?.file || "";
-}
-
-export { getSnapshotClient as a, assert as b, createExpect as c, vitest as d, globalExpect as g, inject as i, should as s, vi as v };
diff --git a/vanilla/node_modules/vitest/dist/chunks/vm.D3epNOPZ.js b/vanilla/node_modules/vitest/dist/chunks/vm.D3epNOPZ.js
deleted file mode 100644
index 6820f9e..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/vm.D3epNOPZ.js
+++ /dev/null
@@ -1,744 +0,0 @@
-import { fileURLToPath, pathToFileURL } from 'node:url';
-import vm, { isContext, runInContext } from 'node:vm';
-import { dirname, basename, extname, normalize, resolve } from 'pathe';
-import { l as loadEnvironment, e as emitModuleRunner } from './init.B6MLFIaN.js';
-import { distDir } from '../path.js';
-import { createCustomConsole } from './console.Cf-YriPC.js';
-import fs from 'node:fs';
-import { createRequire, Module, isBuiltin } from 'node:module';
-import { toArray, isBareImport } from '@vitest/utils/helpers';
-import { findNearestPackageData } from '@vitest/utils/resolver';
-import { dirname as dirname$1 } from 'node:path';
-import { CSS_LANGS_RE, KNOWN_ASSET_RE } from '@vitest/utils/constants';
-import { getDefaultRequestStubs } from '../module-evaluator.js';
-import { s as startVitestModuleRunner, c as createNodeImportMeta, a as VITEST_VM_CONTEXT_SYMBOL } from './startModuleRunner.DEj0jb3e.js';
-import { p as provideWorkerState } from './utils.DvEY5TfP.js';
-
-function interopCommonJsModule(interopDefault, mod) {
- if (isPrimitive(mod) || Array.isArray(mod) || mod instanceof Promise) return {
- keys: [],
- moduleExports: {},
- defaultExport: mod
- };
- if (interopDefault !== false && "__esModule" in mod && !isPrimitive(mod.default)) {
- const defaultKets = Object.keys(mod.default);
- const moduleKeys = Object.keys(mod);
- const allKeys = new Set([...defaultKets, ...moduleKeys]);
- allKeys.delete("default");
- return {
- keys: Array.from(allKeys),
- moduleExports: new Proxy(mod, { get(mod, prop) {
- return mod[prop] ?? mod.default?.[prop];
- } }),
- defaultExport: mod
- };
- }
- return {
- keys: Object.keys(mod).filter((key) => key !== "default"),
- moduleExports: mod,
- defaultExport: mod
- };
-}
-function isPrimitive(obj) {
- return !(obj != null && (typeof obj === "object" || typeof obj === "function"));
-}
-const SyntheticModule = vm.SyntheticModule;
-const SourceTextModule = vm.SourceTextModule;
-
-const _require = createRequire(import.meta.url);
-const requiresCache = /* @__PURE__ */ new WeakMap();
-class CommonjsExecutor {
- context;
- requireCache = /* @__PURE__ */ new Map();
- publicRequireCache = this.createProxyCache();
- moduleCache = /* @__PURE__ */ new Map();
- builtinCache = Object.create(null);
- extensions = Object.create(null);
- fs;
- Module;
- interopDefault;
- constructor(options) {
- this.context = options.context;
- this.fs = options.fileMap;
- this.interopDefault = options.interopDefault;
- const primitives = vm.runInContext("({ Object, Array, Error })", this.context);
- // eslint-disable-next-line ts/no-this-alias
- const executor = this;
- this.Module = class Module$1 {
- exports;
- isPreloading = false;
- id;
- filename;
- loaded;
- parent;
- children = [];
- path;
- paths = [];
- constructor(id = "", parent) {
- this.exports = primitives.Object.create(Object.prototype);
- // in our case the path should always be resolved already
- this.path = dirname(id);
- this.id = id;
- this.filename = id;
- this.loaded = false;
- this.parent = parent;
- }
- get require() {
- const require = requiresCache.get(this);
- if (require) return require;
- const _require = Module$1.createRequire(this.id);
- requiresCache.set(this, _require);
- return _require;
- }
- static getSourceMapsSupport = () => ({
- enabled: false,
- nodeModules: false,
- generatedCode: false
- });
- static setSourceMapsSupport = () => {
- // noop
- };
- static register = () => {
- throw new Error(`[vitest] "register" is not available when running in Vitest.`);
- };
- static registerHooks = () => {
- throw new Error(`[vitest] "registerHooks" is not available when running in Vitest.`);
- };
- _compile(code, filename) {
- const cjsModule = Module$1.wrap(code);
- const script = new vm.Script(cjsModule, {
- filename,
- importModuleDynamically: options.importModuleDynamically
- });
- // @ts-expect-error mark script with current identifier
- script.identifier = filename;
- const fn = script.runInContext(executor.context);
- const __dirname = dirname(filename);
- executor.requireCache.set(filename, this);
- try {
- fn(this.exports, this.require, this, filename, __dirname);
- return this.exports;
- } finally {
- this.loaded = true;
- }
- }
- // exposed for external use, Node.js does the opposite
- static _load = (request, parent, _isMain) => {
- return Module$1.createRequire(parent?.filename ?? request)(request);
- };
- static wrap = (script) => {
- return Module$1.wrapper[0] + script + Module$1.wrapper[1];
- };
- static wrapper = new primitives.Array("(function (exports, require, module, __filename, __dirname) { ", "\n});");
- static builtinModules = Module.builtinModules;
- static findSourceMap = Module.findSourceMap;
- static SourceMap = Module.SourceMap;
- static syncBuiltinESMExports = Module.syncBuiltinESMExports;
- static _cache = executor.publicRequireCache;
- static _extensions = executor.extensions;
- static createRequire = (filename) => {
- return executor.createRequire(filename);
- };
- static runMain = () => {
- throw new primitives.Error("[vitest] \"runMain\" is not implemented.");
- };
- // @ts-expect-error not typed
- static _resolveFilename = Module._resolveFilename;
- // @ts-expect-error not typed
- static _findPath = Module._findPath;
- // @ts-expect-error not typed
- static _initPaths = Module._initPaths;
- // @ts-expect-error not typed
- static _preloadModules = Module._preloadModules;
- // @ts-expect-error not typed
- static _resolveLookupPaths = Module._resolveLookupPaths;
- // @ts-expect-error not typed
- static globalPaths = Module.globalPaths;
- static isBuiltin = Module.isBuiltin;
- static constants = Module.constants;
- static enableCompileCache = Module.enableCompileCache;
- static getCompileCacheDir = Module.getCompileCacheDir;
- static flushCompileCache = Module.flushCompileCache;
- static stripTypeScriptTypes = Module.stripTypeScriptTypes;
- static findPackageJSON = Module.findPackageJSON;
- static Module = Module$1;
- };
- this.extensions[".js"] = this.requireJs;
- this.extensions[".json"] = this.requireJson;
- }
- requireJs = (m, filename) => {
- const content = this.fs.readFile(filename);
- m._compile(content, filename);
- };
- requireJson = (m, filename) => {
- const code = this.fs.readFile(filename);
- m.exports = JSON.parse(code);
- };
- createRequire = (filename) => {
- const _require = createRequire(filename);
- const require = ((id) => {
- const resolved = _require.resolve(id);
- if (extname(resolved) === ".node" || isBuiltin(resolved)) return this.requireCoreModule(resolved);
- const module = new this.Module(resolved);
- return this.loadCommonJSModule(module, resolved);
- });
- require.resolve = _require.resolve;
- Object.defineProperty(require, "extensions", {
- get: () => this.extensions,
- set: () => {},
- configurable: true
- });
- require.main = void 0;
- require.cache = this.publicRequireCache;
- return require;
- };
- createProxyCache() {
- return new Proxy(Object.create(null), {
- defineProperty: () => true,
- deleteProperty: () => true,
- set: () => true,
- get: (_, key) => this.requireCache.get(key),
- has: (_, key) => this.requireCache.has(key),
- ownKeys: () => Array.from(this.requireCache.keys()),
- getOwnPropertyDescriptor() {
- return {
- configurable: true,
- enumerable: true
- };
- }
- });
- }
- // very naive implementation for Node.js require
- loadCommonJSModule(module, filename) {
- const cached = this.requireCache.get(filename);
- if (cached) return cached.exports;
- const extension = this.findLongestRegisteredExtension(filename);
- (this.extensions[extension] || this.extensions[".js"])(module, filename);
- return module.exports;
- }
- findLongestRegisteredExtension(filename) {
- const name = basename(filename);
- let currentExtension;
- let index;
- let startIndex = 0;
- // eslint-disable-next-line no-cond-assign
- while ((index = name.indexOf(".", startIndex)) !== -1) {
- startIndex = index + 1;
- if (index === 0) continue;
- currentExtension = name.slice(index);
- if (this.extensions[currentExtension]) return currentExtension;
- }
- return ".js";
- }
- getCoreSyntheticModule(identifier) {
- if (this.moduleCache.has(identifier)) return this.moduleCache.get(identifier);
- const exports$1 = this.require(identifier);
- const keys = Object.keys(exports$1);
- const module = new SyntheticModule([...keys, "default"], () => {
- for (const key of keys) module.setExport(key, exports$1[key]);
- module.setExport("default", exports$1);
- }, {
- context: this.context,
- identifier
- });
- this.moduleCache.set(identifier, module);
- return module;
- }
- getCjsSyntheticModule(path, identifier) {
- if (this.moduleCache.has(identifier)) return this.moduleCache.get(identifier);
- const exports$1 = this.require(path);
- // TODO: technically module should be parsed to find static exports, implement for strict mode in #2854
- const { keys, moduleExports, defaultExport } = interopCommonJsModule(this.interopDefault, exports$1);
- const module = new SyntheticModule([...keys, "default"], function() {
- for (const key of keys) this.setExport(key, moduleExports[key]);
- this.setExport("default", defaultExport);
- }, {
- context: this.context,
- identifier
- });
- this.moduleCache.set(identifier, module);
- return module;
- }
- // TODO: use this in strict mode, when available in #2854
- // private _getNamedCjsExports(path: string): Set<string> {
- // const cachedNamedExports = this.cjsNamedExportsMap.get(path)
- // if (cachedNamedExports) {
- // return cachedNamedExports
- // }
- // if (extname(path) === '.node') {
- // const moduleExports = this.require(path)
- // const namedExports = new Set(Object.keys(moduleExports))
- // this.cjsNamedExportsMap.set(path, namedExports)
- // return namedExports
- // }
- // const code = this.fs.readFile(path)
- // const { exports, reexports } = parseCjs(code, path)
- // const namedExports = new Set(exports)
- // this.cjsNamedExportsMap.set(path, namedExports)
- // for (const reexport of reexports) {
- // if (isNodeBuiltin(reexport)) {
- // const exports = this.require(reexport)
- // if (exports !== null && typeof exports === 'object') {
- // for (const e of Object.keys(exports)) {
- // namedExports.add(e)
- // }
- // }
- // }
- // else {
- // const require = this.createRequire(path)
- // const resolved = require.resolve(reexport)
- // const exports = this._getNamedCjsExports(resolved)
- // for (const e of exports) {
- // namedExports.add(e)
- // }
- // }
- // }
- // return namedExports
- // }
- require(identifier) {
- if (extname(identifier) === ".node" || isBuiltin(identifier)) return this.requireCoreModule(identifier);
- const module = new this.Module(identifier);
- return this.loadCommonJSModule(module, identifier);
- }
- requireCoreModule(identifier) {
- const normalized = identifier.replace(/^node:/, "");
- if (this.builtinCache[normalized]) return this.builtinCache[normalized].exports;
- const moduleExports = _require(identifier);
- if (identifier === "node:module" || identifier === "module") {
- const module = new this.Module("/module.js");
- module.exports = this.Module;
- this.builtinCache[normalized] = module;
- return module.exports;
- }
- this.builtinCache[normalized] = _require.cache[normalized];
- // TODO: should we wrap module to rethrow context errors?
- return moduleExports;
- }
-}
-
-const dataURIRegex = /^data:(?<mime>text\/javascript|application\/json|application\/wasm)(?:;(?<encoding>charset=utf-8|base64))?,(?<code>.*)$/;
-class EsmExecutor {
- moduleCache = /* @__PURE__ */ new Map();
- esmLinkMap = /* @__PURE__ */ new WeakMap();
- context;
- #httpIp = IPnumber("127.0.0.0");
- constructor(executor, options) {
- this.executor = executor;
- this.context = options.context;
- }
- async evaluateModule(m) {
- if (m.status === "unlinked") this.esmLinkMap.set(m, m.link((identifier, referencer) => this.executor.resolveModule(identifier, referencer.identifier)));
- await this.esmLinkMap.get(m);
- if (m.status === "linked") await m.evaluate();
- return m;
- }
- async createEsModule(fileURL, getCode) {
- const cached = this.moduleCache.get(fileURL);
- if (cached) return cached;
- const promise = this.loadEsModule(fileURL, getCode);
- this.moduleCache.set(fileURL, promise);
- return promise;
- }
- async loadEsModule(fileURL, getCode) {
- const code = await getCode();
- // TODO: should not be allowed in strict mode, implement in #2854
- if (fileURL.endsWith(".json")) {
- const m = new SyntheticModule(["default"], function() {
- const result = JSON.parse(code);
- this.setExport("default", result);
- });
- this.moduleCache.set(fileURL, m);
- return m;
- }
- const m = new SourceTextModule(code, {
- identifier: fileURL,
- context: this.context,
- importModuleDynamically: this.executor.importModuleDynamically,
- initializeImportMeta: (meta, mod) => {
- meta.url = mod.identifier;
- if (mod.identifier.startsWith("file:")) {
- const filename = fileURLToPath(mod.identifier);
- meta.filename = filename;
- meta.dirname = dirname$1(filename);
- }
- meta.resolve = (specifier, importer) => {
- return this.executor.resolve(specifier, importer != null ? importer.toString() : mod.identifier);
- };
- }
- });
- this.moduleCache.set(fileURL, m);
- return m;
- }
- async createWebAssemblyModule(fileUrl, getCode) {
- const cached = this.moduleCache.get(fileUrl);
- if (cached) return cached;
- const m = this.loadWebAssemblyModule(getCode(), fileUrl);
- this.moduleCache.set(fileUrl, m);
- return m;
- }
- async createNetworkModule(fileUrl) {
- // https://nodejs.org/api/esm.html#https-and-http-imports
- if (fileUrl.startsWith("http:")) {
- const url = new URL(fileUrl);
- if (url.hostname !== "localhost" && url.hostname !== "::1" && (IPnumber(url.hostname) & IPmask(8)) !== this.#httpIp) throw new Error(
- // we don't know the importer, so it's undefined (the same happens in --pool=threads)
- `import of '${fileUrl}' by undefined is not supported: http can only be used to load local resources (use https instead).`
- );
- }
- return this.createEsModule(fileUrl, () => fetch(fileUrl).then((r) => r.text()));
- }
- async loadWebAssemblyModule(source, identifier) {
- const cached = this.moduleCache.get(identifier);
- if (cached) return cached;
- const wasmModule = await WebAssembly.compile(source);
- const exports$1 = WebAssembly.Module.exports(wasmModule);
- const imports = WebAssembly.Module.imports(wasmModule);
- const moduleLookup = {};
- for (const { module } of imports) if (moduleLookup[module] === void 0) moduleLookup[module] = await this.executor.resolveModule(module, identifier);
- const evaluateModule = (module) => this.evaluateModule(module);
- return new SyntheticModule(exports$1.map(({ name }) => name), async function() {
- const importsObject = {};
- for (const { module, name } of imports) {
- if (!importsObject[module]) importsObject[module] = {};
- await evaluateModule(moduleLookup[module]);
- importsObject[module][name] = moduleLookup[module].namespace[name];
- }
- const wasmInstance = new WebAssembly.Instance(wasmModule, importsObject);
- for (const { name } of exports$1) this.setExport(name, wasmInstance.exports[name]);
- }, {
- context: this.context,
- identifier
- });
- }
- cacheModule(identifier, module) {
- this.moduleCache.set(identifier, module);
- }
- resolveCachedModule(identifier) {
- return this.moduleCache.get(identifier);
- }
- async createDataModule(identifier) {
- const cached = this.moduleCache.get(identifier);
- if (cached) return cached;
- const match = identifier.match(dataURIRegex);
- if (!match || !match.groups) throw new Error("Invalid data URI");
- const mime = match.groups.mime;
- const encoding = match.groups.encoding;
- if (mime === "application/wasm") {
- if (!encoding) throw new Error("Missing data URI encoding");
- if (encoding !== "base64") throw new Error(`Invalid data URI encoding: ${encoding}`);
- const module = this.loadWebAssemblyModule(Buffer.from(match.groups.code, "base64"), identifier);
- this.moduleCache.set(identifier, module);
- return module;
- }
- let code = match.groups.code;
- if (!encoding || encoding === "charset=utf-8") code = decodeURIComponent(code);
- else if (encoding === "base64") code = Buffer.from(code, "base64").toString();
- else throw new Error(`Invalid data URI encoding: ${encoding}`);
- if (mime === "application/json") {
- const module = new SyntheticModule(["default"], function() {
- const obj = JSON.parse(code);
- this.setExport("default", obj);
- }, {
- context: this.context,
- identifier
- });
- this.moduleCache.set(identifier, module);
- return module;
- }
- return this.createEsModule(identifier, () => code);
- }
-}
-function IPnumber(address) {
- const ip = address.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/);
- if (ip) return (+ip[1] << 24) + (+ip[2] << 16) + (+ip[3] << 8) + +ip[4];
- throw new Error(`Expected IP address, received ${address}`);
-}
-function IPmask(maskSize) {
- return -1 << 32 - maskSize;
-}
-
-const CLIENT_ID = "/@vite/client";
-const CLIENT_FILE = pathToFileURL(CLIENT_ID).href;
-class ViteExecutor {
- esm;
- constructor(options) {
- this.options = options;
- this.esm = options.esmExecutor;
- }
- resolve = (identifier) => {
- if (identifier === CLIENT_ID) return identifier;
- };
- get workerState() {
- return this.options.context.__vitest_worker__;
- }
- async createViteModule(fileUrl) {
- if (fileUrl === CLIENT_FILE || fileUrl === CLIENT_ID) return this.createViteClientModule();
- const cached = this.esm.resolveCachedModule(fileUrl);
- if (cached) return cached;
- return this.esm.createEsModule(fileUrl, async () => {
- try {
- const result = await this.options.transform(fileUrl);
- if (result.code) return result.code;
- } catch (cause) {
- // rethrow vite error if it cannot load the module because it's not resolved
- if (typeof cause === "object" && cause.code === "ERR_LOAD_URL" || typeof cause?.message === "string" && cause.message.includes("Failed to load url")) {
- const error = new Error(`Cannot find module '${fileUrl}'`, { cause });
- error.code = "ERR_MODULE_NOT_FOUND";
- throw error;
- }
- }
- throw new Error(`[vitest] Failed to transform ${fileUrl}. Does the file exist?`);
- });
- }
- createViteClientModule() {
- const identifier = CLIENT_ID;
- const cached = this.esm.resolveCachedModule(identifier);
- if (cached) return cached;
- const stub = this.options.viteClientModule;
- const moduleKeys = Object.keys(stub);
- const module = new SyntheticModule(moduleKeys, function() {
- moduleKeys.forEach((key) => {
- this.setExport(key, stub[key]);
- });
- }, {
- context: this.options.context,
- identifier
- });
- this.esm.cacheModule(identifier, module);
- return module;
- }
- canResolve = (fileUrl) => {
- if (fileUrl === CLIENT_FILE) return true;
- const config = this.workerState.config.deps?.web || {};
- const [modulePath] = fileUrl.split("?");
- if (config.transformCss && CSS_LANGS_RE.test(modulePath)) return true;
- if (config.transformAssets && KNOWN_ASSET_RE.test(modulePath)) return true;
- if (toArray(config.transformGlobPattern).some((pattern) => pattern.test(modulePath))) return true;
- return false;
- };
-}
-
-const { existsSync } = fs;
-// always defined when we use vm pool
-const nativeResolve = import.meta.resolve;
-// TODO: improve Node.js strict mode support in #2854
-class ExternalModulesExecutor {
- cjs;
- esm;
- vite;
- context;
- fs;
- resolvers = [];
- #networkSupported = null;
- constructor(options) {
- this.options = options;
- this.context = options.context;
- this.fs = options.fileMap;
- this.esm = new EsmExecutor(this, { context: this.context });
- this.cjs = new CommonjsExecutor({
- context: this.context,
- importModuleDynamically: this.importModuleDynamically,
- fileMap: options.fileMap,
- interopDefault: options.interopDefault
- });
- this.vite = new ViteExecutor({
- esmExecutor: this.esm,
- context: this.context,
- transform: options.transform,
- viteClientModule: options.viteClientModule
- });
- this.resolvers = [this.vite.resolve];
- }
- async import(identifier) {
- const module = await this.createModule(identifier);
- await this.esm.evaluateModule(module);
- return module.namespace;
- }
- require(identifier) {
- return this.cjs.require(identifier);
- }
- createRequire(identifier) {
- return this.cjs.createRequire(identifier);
- }
- // dynamic import can be used in both ESM and CJS, so we have it in the executor
- importModuleDynamically = async (specifier, referencer) => {
- const module = await this.resolveModule(specifier, referencer.identifier);
- return await this.esm.evaluateModule(module);
- };
- resolveModule = async (specifier, referencer) => {
- let identifier = this.resolve(specifier, referencer);
- if (identifier instanceof Promise) identifier = await identifier;
- return await this.createModule(identifier);
- };
- resolve(specifier, parent) {
- for (const resolver of this.resolvers) {
- const id = resolver(specifier, parent);
- if (id) return id;
- }
- // import.meta.resolve can be asynchronous in older +18 Node versions
- return nativeResolve(specifier, parent);
- }
- getModuleInformation(identifier) {
- if (identifier.startsWith("data:")) return {
- type: "data",
- url: identifier,
- path: identifier
- };
- const extension = extname(identifier);
- if (extension === ".node" || isBuiltin(identifier)) return {
- type: "builtin",
- url: identifier,
- path: identifier
- };
- if (this.isNetworkSupported && (identifier.startsWith("http:") || identifier.startsWith("https:"))) return {
- type: "network",
- url: identifier,
- path: identifier
- };
- const isFileUrl = identifier.startsWith("file://");
- const pathUrl = isFileUrl ? fileURLToPath(identifier.split("?")[0]) : identifier;
- const fileUrl = isFileUrl ? identifier : pathToFileURL(pathUrl).toString();
- let type;
- if (this.vite.canResolve(fileUrl)) type = "vite";
- else if (extension === ".mjs") type = "module";
- else if (extension === ".cjs") type = "commonjs";
- else if (extension === ".wasm")
- // still experimental on NodeJS --experimental-wasm-modules
- // cf. ESM_FILE_FORMAT(url) in https://nodejs.org/docs/latest-v20.x/api/esm.html#resolution-algorithm
- type = "wasm";
- else type = findNearestPackageData(normalize(pathUrl)).type === "module" ? "module" : "commonjs";
- return {
- type,
- path: pathUrl,
- url: fileUrl
- };
- }
- createModule(identifier) {
- const { type, url, path } = this.getModuleInformation(identifier);
- // create ERR_MODULE_NOT_FOUND on our own since latest NodeJS's import.meta.resolve doesn't throw on non-existing namespace or path
- // https://github.com/nodejs/node/pull/49038
- if ((type === "module" || type === "commonjs" || type === "wasm") && !existsSync(path)) {
- const error = /* @__PURE__ */ new Error(`Cannot find ${isBareImport(path) ? "package" : "module"} '${path}'`);
- error.code = "ERR_MODULE_NOT_FOUND";
- throw error;
- }
- switch (type) {
- case "data": return this.esm.createDataModule(identifier);
- case "builtin": return this.cjs.getCoreSyntheticModule(identifier);
- case "vite": return this.vite.createViteModule(url);
- case "wasm": return this.esm.createWebAssemblyModule(url, () => this.fs.readBuffer(path));
- case "module": return this.esm.createEsModule(url, () => this.fs.readFileAsync(path));
- case "commonjs": return this.cjs.getCjsSyntheticModule(path, identifier);
- case "network": return this.esm.createNetworkModule(url);
- default: return type;
- }
- }
- get isNetworkSupported() {
- if (this.#networkSupported == null) if (process.execArgv.includes("--experimental-network-imports")) this.#networkSupported = true;
- else if (process.env.NODE_OPTIONS?.includes("--experimental-network-imports")) this.#networkSupported = true;
- else this.#networkSupported = false;
- return this.#networkSupported;
- }
-}
-
-const { promises, readFileSync } = fs;
-class FileMap {
- fsCache = /* @__PURE__ */ new Map();
- fsBufferCache = /* @__PURE__ */ new Map();
- async readFileAsync(path) {
- const cached = this.fsCache.get(path);
- if (cached != null) return cached;
- const source = await promises.readFile(path, "utf-8");
- this.fsCache.set(path, source);
- return source;
- }
- readFile(path) {
- const cached = this.fsCache.get(path);
- if (cached != null) return cached;
- const source = readFileSync(path, "utf-8");
- this.fsCache.set(path, source);
- return source;
- }
- readBuffer(path) {
- const cached = this.fsBufferCache.get(path);
- if (cached != null) return cached;
- const buffer = readFileSync(path);
- this.fsBufferCache.set(path, buffer);
- return buffer;
- }
-}
-
-const entryFile = pathToFileURL(resolve(distDir, "workers/runVmTests.js")).href;
-const fileMap = new FileMap();
-const packageCache = /* @__PURE__ */ new Map();
-async function runVmTests(method, state, traces) {
- const { ctx, rpc } = state;
- const beforeEnvironmentTime = performance.now();
- const { environment } = await loadEnvironment(ctx.environment.name, ctx.config.root, rpc, traces);
- state.environment = environment;
- if (!environment.setupVM) {
- const envName = ctx.environment.name;
- const packageId = envName[0] === "." ? envName : `vitest-environment-${envName}`;
- throw new TypeError(`Environment "${ctx.environment.name}" is not a valid environment. Path "${packageId}" doesn't support vm environment because it doesn't provide "setupVM" method.`);
- }
- const vm = await traces.$("vitest.runtime.environment.setup", { attributes: {
- "vitest.environment": environment.name,
- "vitest.environment.vite_environment": environment.viteEnvironment || environment.name
- } }, () => environment.setupVM(ctx.environment.options || ctx.config.environmentOptions || {}));
- state.durations.environment = performance.now() - beforeEnvironmentTime;
- process.env.VITEST_VM_POOL = "1";
- if (!vm.getVmContext) throw new TypeError(`Environment ${environment.name} doesn't provide "getVmContext" method. It should return a context created by "vm.createContext" method.`);
- const context = vm.getVmContext();
- if (!isContext(context)) throw new TypeError(`Environment ${environment.name} doesn't provide a valid context. It should be created by "vm.createContext" method.`);
- provideWorkerState(context, state);
- // this is unfortunately needed for our own dependencies
- // we need to find a way to not rely on this by default
- // because browser doesn't provide these globals
- context.process = process;
- context.global = context;
- context.console = state.config.disableConsoleIntercept ? console : createCustomConsole(state);
- // TODO: don't hardcode setImmediate in fake timers defaults
- context.setImmediate = setImmediate;
- context.clearImmediate = clearImmediate;
- const stubs = getDefaultRequestStubs(context);
- const externalModulesExecutor = new ExternalModulesExecutor({
- context,
- fileMap,
- packageCache,
- transform: rpc.transform,
- viteClientModule: stubs["/@vite/client"]
- });
- const moduleRunner = startVitestModuleRunner({
- context,
- evaluatedModules: state.evaluatedModules,
- state,
- externalModulesExecutor,
- createImportMeta: createNodeImportMeta,
- traces
- });
- emitModuleRunner(moduleRunner);
- Object.defineProperty(context, VITEST_VM_CONTEXT_SYMBOL, {
- value: {
- context,
- externalModulesExecutor
- },
- configurable: true,
- enumerable: false,
- writable: false
- });
- context.__vitest_mocker__ = moduleRunner.mocker;
- if (ctx.config.serializedDefines) try {
- runInContext(ctx.config.serializedDefines, context, { filename: "virtual:load-defines.js" });
- } catch (error) {
- throw new Error(`Failed to load custom "defines": ${error.message}`);
- }
- await moduleRunner.mocker.initializeSpyModule();
- const { run } = await moduleRunner.import(entryFile);
- try {
- await run(method, ctx.files, ctx.config, moduleRunner, traces);
- } finally {
- await traces.$("vitest.runtime.environment.teardown", () => vm.teardown?.());
- }
-}
-
-export { runVmTests as r };
diff --git a/vanilla/node_modules/vitest/dist/chunks/worker.d.Dyxm8DEL.d.ts b/vanilla/node_modules/vitest/dist/chunks/worker.d.Dyxm8DEL.d.ts
deleted file mode 100644
index 3177880..0000000
--- a/vanilla/node_modules/vitest/dist/chunks/worker.d.Dyxm8DEL.d.ts
+++ /dev/null
@@ -1,255 +0,0 @@
-import { FileSpecification, Task, CancelReason } from '@vitest/runner';
-import { EvaluatedModules } from 'vite/module-runner';
-import { S as SerializedConfig } from './config.d.Cy95HiCx.js';
-import { E as Environment } from './environment.d.CrsxCzP1.js';
-import { R as RuntimeRPC, a as RunnerRPC } from './rpc.d.RH3apGEf.js';
-
-//#region src/messages.d.ts
-declare const TYPE_REQUEST: "q";
-interface RpcRequest {
- /**
- * Type
- */
- t: typeof TYPE_REQUEST;
- /**
- * ID
- */
- i?: string;
- /**
- * Method
- */
- m: string;
- /**
- * Arguments
- */
- a: any[];
- /**
- * Optional
- */
- o?: boolean;
-}
-//#endregion
-//#region src/utils.d.ts
-type ArgumentsType<T> = T extends ((...args: infer A) => any) ? A : never;
-type ReturnType<T> = T extends ((...args: any) => infer R) ? R : never;
-type Thenable<T> = T | PromiseLike<T>;
-//#endregion
-//#region src/main.d.ts
-type PromisifyFn<T> = ReturnType<T> extends Promise<any> ? T : (...args: ArgumentsType<T>) => Promise<Awaited<ReturnType<T>>>;
-type BirpcResolver<This> = (this: This, name: string, resolved: (...args: unknown[]) => unknown) => Thenable<((...args: any[]) => any) | undefined>;
-interface ChannelOptions {
- /**
- * Function to post raw message
- */
- post: (data: any, ...extras: any[]) => Thenable<any>;
- /**
- * Listener to receive raw message
- */
- on: (fn: (data: any, ...extras: any[]) => void) => Thenable<any>;
- /**
- * Clear the listener when `$close` is called
- */
- off?: (fn: (data: any, ...extras: any[]) => void) => Thenable<any>;
- /**
- * Custom function to serialize data
- *
- * by default it passes the data as-is
- */
- serialize?: (data: any) => any;
- /**
- * Custom function to deserialize data
- *
- * by default it passes the data as-is
- */
- deserialize?: (data: any) => any;
- /**
- * Call the methods with the RPC context or the original functions object
- */
- bind?: 'rpc' | 'functions';
- /**
- * Custom meta data to attached to the RPC instance's `$meta` property
- */
- meta?: any;
-}
-interface EventOptions<RemoteFunctions extends object = Record<string, unknown>, LocalFunctions extends object = Record<string, unknown>, Proxify extends boolean = true> {
- /**
- * Names of remote functions that do not need response.
- */
- eventNames?: (keyof RemoteFunctions)[];
- /**
- * Maximum timeout for waiting for response, in milliseconds.
- *
- * @default 60_000
- */
- timeout?: number;
- /**
- * Whether to proxy the remote functions.
- *
- * When `proxify` is false, calling the remote function
- * with `rpc.$call('method', ...args)` instead of `rpc.method(...args)`
- * explicitly is required.
- *
- * @default true
- */
- proxify?: Proxify;
- /**
- * Custom resolver to resolve function to be called
- *
- * For advanced use cases only
- */
- resolver?: BirpcResolver<BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>>;
- /**
- * Hook triggered before an event is sent to the remote
- *
- * @param req - Request parameters
- * @param next - Function to continue the request
- * @param resolve - Function to resolve the response directly
- */
- onRequest?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, req: RpcRequest, next: (req?: RpcRequest) => Promise<any>, resolve: (res: any) => void) => void | Promise<void>;
- /**
- * Custom error handler for errors occurred in local functions being called
- *
- * @returns `true` to prevent the error from being thrown
- */
- onFunctionError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, error: Error, functionName: string, args: any[]) => boolean | void;
- /**
- * Custom error handler for errors occurred during serialization or messsaging
- *
- * @returns `true` to prevent the error from being thrown
- */
- onGeneralError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, error: Error, functionName?: string, args?: any[]) => boolean | void;
- /**
- * Custom error handler for timeouts
- *
- * @returns `true` to prevent the error from being thrown
- */
- onTimeoutError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, functionName: string, args: any[]) => boolean | void;
-}
-type BirpcOptions<RemoteFunctions extends object = Record<string, unknown>, LocalFunctions extends object = Record<string, unknown>, Proxify extends boolean = true> = EventOptions<RemoteFunctions, LocalFunctions, Proxify> & ChannelOptions;
-type BirpcFn<T> = PromisifyFn<T> & {
- /**
- * Send event without asking for response
- */
- asEvent: (...args: ArgumentsType<T>) => Promise<void>;
-};
-interface BirpcReturnBuiltin<RemoteFunctions, LocalFunctions = Record<string, unknown>> {
- /**
- * Raw functions object
- */
- $functions: LocalFunctions;
- /**
- * Whether the RPC is closed
- */
- readonly $closed: boolean;
- /**
- * Custom meta data attached to the RPC instance
- */
- readonly $meta: any;
- /**
- * Close the RPC connection
- */
- $close: (error?: Error) => void;
- /**
- * Reject pending calls
- */
- $rejectPendingCalls: (handler?: PendingCallHandler) => Promise<void>[];
- /**
- * Call the remote function and wait for the result.
- * An alternative to directly calling the function
- */
- $call: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<Awaited<ReturnType<RemoteFunctions[K$1]>>>;
- /**
- * Same as `$call`, but returns `undefined` if the function is not defined on the remote side.
- */
- $callOptional: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<Awaited<ReturnType<RemoteFunctions[K$1]> | undefined>>;
- /**
- * Send event without asking for response
- */
- $callEvent: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<void>;
- /**
- * Call the remote function with the raw options.
- */
- $callRaw: (options: {
- method: string;
- args: unknown[];
- event?: boolean;
- optional?: boolean;
- }) => Promise<Awaited<ReturnType<any>>[]>;
-}
-type ProxifiedRemoteFunctions<RemoteFunctions extends object = Record<string, unknown>> = { [K in keyof RemoteFunctions]: BirpcFn<RemoteFunctions[K]> };
-type BirpcReturn<RemoteFunctions extends object = Record<string, unknown>, LocalFunctions extends object = Record<string, unknown>, Proxify extends boolean = true> = Proxify extends true ? ProxifiedRemoteFunctions<RemoteFunctions> & BirpcReturnBuiltin<RemoteFunctions, LocalFunctions> : BirpcReturnBuiltin<RemoteFunctions, LocalFunctions>;
-type PendingCallHandler = (options: Pick<PromiseEntry, 'method' | 'reject'>) => void | Promise<void>;
-interface PromiseEntry {
- resolve: (arg: any) => void;
- reject: (error: any) => void;
- method: string;
- timeoutId?: ReturnType<typeof setTimeout>;
-}
-declare const setTimeout: typeof globalThis.setTimeout;
-
-type WorkerRPC = BirpcReturn<RuntimeRPC, RunnerRPC>;
-interface ContextTestEnvironment {
- name: string;
- options: Record<string, any> | null;
-}
-interface WorkerTestEnvironment {
- name: string;
- options: Record<string, any> | null;
-}
-type TestExecutionMethod = "run" | "collect";
-interface WorkerExecuteContext {
- files: FileSpecification[];
- providedContext: Record<string, any>;
- invalidates?: string[];
- environment: ContextTestEnvironment;
- /** Exposed to test runner as `VITEST_WORKER_ID`. Value is unique per each isolated worker. */
- workerId: number;
-}
-interface ContextRPC {
- pool: string;
- config: SerializedConfig;
- projectName: string;
- environment: WorkerTestEnvironment;
- rpc: WorkerRPC;
- files: FileSpecification[];
- providedContext: Record<string, any>;
- invalidates?: string[];
- /** Exposed to test runner as `VITEST_WORKER_ID`. Value is unique per each isolated worker. */
- workerId: number;
-}
-interface WorkerSetupContext {
- environment: WorkerTestEnvironment;
- pool: string;
- config: SerializedConfig;
- projectName: string;
- rpc: WorkerRPC;
-}
-interface WorkerGlobalState {
- ctx: ContextRPC;
- config: SerializedConfig;
- rpc: WorkerRPC;
- current?: Task;
- filepath?: string;
- metaEnv: {
- [key: string]: any;
- BASE_URL: string;
- MODE: string;
- DEV: boolean;
- PROD: boolean;
- SSR: boolean;
- };
- environment: Environment;
- evaluatedModules: EvaluatedModules;
- resolvingModules: Set<string>;
- moduleExecutionInfo: Map<string, any>;
- onCancel: (listener: (reason: CancelReason) => unknown) => void;
- onCleanup: (listener: () => unknown) => void;
- providedContext: Record<string, any>;
- durations: {
- environment: number;
- prepare: number;
- };
- onFilterStackTrace?: (trace: string) => string;
-}
-
-export type { BirpcOptions as B, ContextRPC as C, TestExecutionMethod as T, WorkerGlobalState as W, WorkerSetupContext as a, BirpcReturn as b, ContextTestEnvironment as c, WorkerExecuteContext as d, WorkerTestEnvironment as e };
diff --git a/vanilla/node_modules/vitest/dist/cli.js b/vanilla/node_modules/vitest/dist/cli.js
deleted file mode 100644
index 1109d10..0000000
--- a/vanilla/node_modules/vitest/dist/cli.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import { c as createCLI } from './chunks/cac.DVeoLl0M.js';
-import '@vitest/utils/helpers';
-import 'events';
-import 'pathe';
-import 'tinyrainbow';
-import './chunks/constants.D_Q9UYh-.js';
-import './chunks/index.M8mOzt4Y.js';
-import 'node:fs';
-import 'node:fs/promises';
-import 'node:perf_hooks';
-import '@vitest/runner/utils';
-import '@vitest/utils/source-map';
-import './chunks/env.D4Lgay0q.js';
-import 'std-env';
-import 'node:util';
-import 'node:console';
-import 'node:stream';
-import '@vitest/utils/display';
-import 'node:os';
-import 'tinyexec';
-import './path.js';
-import 'node:path';
-import 'node:url';
-import 'vite';
-import '@vitest/utils/offset';
-import 'node:module';
-
-createCLI().parse();
diff --git a/vanilla/node_modules/vitest/dist/config.cjs b/vanilla/node_modules/vitest/dist/config.cjs
deleted file mode 100644
index 1a9cb51..0000000
--- a/vanilla/node_modules/vitest/dist/config.cjs
+++ /dev/null
@@ -1,94 +0,0 @@
-'use strict';
-
-var os = require('node:os');
-var stdEnv = require('std-env');
-var vite = require('vite');
-
-const isNode = typeof process < "u" && typeof process.stdout < "u" && !process.versions?.deno && !globalThis.window;
-const isDeno = typeof process < "u" && typeof process.stdout < "u" && process.versions?.deno !== void 0;
-(isNode || isDeno) && process.platform === "win32";
-(isNode || isDeno) && process.stdout?.isTTY && !stdEnv.isCI;
-
-// if changed, update also jsdocs and docs
-const defaultBrowserPort = 63315;
-
-const defaultInclude = ["**/*.{test,spec}.?(c|m)[jt]s?(x)"];
-const defaultExclude = ["**/node_modules/**", "**/.git/**"];
-// These are the generic defaults for coverage. Providers may also set some provider specific defaults.
-const coverageConfigDefaults = {
- provider: "v8",
- enabled: false,
- clean: true,
- cleanOnRerun: true,
- reportsDirectory: "./coverage",
- exclude: [],
- reportOnFailure: false,
- reporter: [
- ["text", {}],
- ["html", {}],
- ["clover", {}],
- ["json", {}]
- ],
- allowExternal: false,
- excludeAfterRemap: false,
- processingConcurrency: Math.min(20, os.availableParallelism?.() ?? os.cpus().length)
-};
-const fakeTimersDefaults = {
- loopLimit: 1e4,
- shouldClearNativeTimers: true
-};
-const configDefaults = Object.freeze({
- allowOnly: !stdEnv.isCI,
- isolate: true,
- watch: !stdEnv.isCI && process.stdin.isTTY,
- globals: false,
- environment: "node",
- clearMocks: false,
- restoreMocks: false,
- mockReset: false,
- unstubGlobals: false,
- unstubEnvs: false,
- include: defaultInclude,
- exclude: defaultExclude,
- teardownTimeout: 1e4,
- forceRerunTriggers: ["**/package.json/**", "**/{vitest,vite}.config.*/**"],
- update: false,
- reporters: [],
- silent: false,
- hideSkippedTests: false,
- api: false,
- ui: false,
- uiBase: "/__vitest__/",
- open: !stdEnv.isCI,
- css: { include: [] },
- coverage: coverageConfigDefaults,
- fakeTimers: fakeTimersDefaults,
- maxConcurrency: 5,
- dangerouslyIgnoreUnhandledErrors: false,
- typecheck: {
- checker: "tsc",
- include: ["**/*.{test,spec}-d.?(c|m)[jt]s?(x)"],
- exclude: defaultExclude
- },
- slowTestThreshold: 300,
- disableConsoleIntercept: false
-});
-
-function defineConfig(config) {
- return config;
-}
-function defineProject(config) {
- return config;
-}
-
-Object.defineProperty(exports, "mergeConfig", {
- enumerable: true,
- get: function () { return vite.mergeConfig; }
-});
-exports.configDefaults = configDefaults;
-exports.coverageConfigDefaults = coverageConfigDefaults;
-exports.defaultBrowserPort = defaultBrowserPort;
-exports.defaultExclude = defaultExclude;
-exports.defaultInclude = defaultInclude;
-exports.defineConfig = defineConfig;
-exports.defineProject = defineProject;
diff --git a/vanilla/node_modules/vitest/dist/config.d.ts b/vanilla/node_modules/vitest/dist/config.d.ts
deleted file mode 100644
index f2e721a..0000000
--- a/vanilla/node_modules/vitest/dist/config.d.ts
+++ /dev/null
@@ -1,104 +0,0 @@
-import { HookHandler, ConfigEnv, UserConfig } from 'vite';
-export { ConfigEnv, Plugin, UserConfig as ViteUserConfig, mergeConfig } from 'vite';
-import { I as InlineConfig, c as CoverageV8Options, R as ResolvedCoverageOptions, U as UserWorkspaceConfig, d as UserProjectConfigFn, e as UserProjectConfigExport } from './chunks/reporters.d.CWXNI2jG.js';
-export { b as TestProjectConfiguration, g as TestProjectInlineConfiguration, f as TestUserConfig, W as WatcherTriggerPattern } from './chunks/reporters.d.CWXNI2jG.js';
-import { V as VitestPluginContext } from './chunks/plugin.d.CtqpEehP.js';
-import { F as FakeTimerInstallOpts } from './chunks/config.d.Cy95HiCx.js';
-import '@vitest/runner';
-import '@vitest/utils';
-import './chunks/rpc.d.RH3apGEf.js';
-import '@vitest/snapshot';
-import 'vite/module-runner';
-import './chunks/traces.d.402V_yFI.js';
-import 'node:stream';
-import './chunks/browser.d.ChKACdzH.js';
-import './chunks/worker.d.Dyxm8DEL.js';
-import './chunks/environment.d.CrsxCzP1.js';
-import '@vitest/mocker';
-import '@vitest/utils/source-map';
-import 'vitest/browser';
-import '@vitest/pretty-format';
-import '@vitest/utils/diff';
-import '@vitest/expect';
-import 'vitest/optional-types.js';
-import './chunks/benchmark.d.DAaHLpsq.js';
-import '@vitest/runner/utils';
-import 'tinybench';
-import './chunks/coverage.d.BZtK59WP.js';
-import '@vitest/snapshot/manager';
-import 'node:console';
-import 'node:fs';
-
-type VitestInlineConfig = InlineConfig;
-declare module "vite" {
- interface UserConfig {
- /**
- * Options for Vitest
- */
- test?: VitestInlineConfig;
- }
- interface Plugin<A = any> {
- configureVitest?: HookHandler<(context: VitestPluginContext) => void>;
- }
-}
-
-declare const defaultBrowserPort = 63315;
-
-declare const defaultInclude: string[];
-declare const defaultExclude: string[];
-declare const coverageConfigDefaults: ResolvedCoverageOptions;
-declare const configDefaults: Readonly<{
- allowOnly: boolean;
- isolate: boolean;
- watch: boolean;
- globals: boolean;
- environment: "node";
- clearMocks: boolean;
- restoreMocks: boolean;
- mockReset: boolean;
- unstubGlobals: boolean;
- unstubEnvs: boolean;
- include: string[];
- exclude: string[];
- teardownTimeout: number;
- forceRerunTriggers: string[];
- update: boolean;
- reporters: never[];
- silent: boolean;
- hideSkippedTests: boolean;
- api: boolean;
- ui: boolean;
- uiBase: string;
- open: boolean;
- css: {
- include: never[];
- };
- coverage: CoverageV8Options;
- fakeTimers: FakeTimerInstallOpts;
- maxConcurrency: number;
- dangerouslyIgnoreUnhandledErrors: boolean;
- typecheck: {
- checker: "tsc";
- include: string[];
- exclude: string[];
- };
- slowTestThreshold: number;
- disableConsoleIntercept: boolean;
-}>;
-
-type ViteUserConfigFnObject = (env: ConfigEnv) => UserConfig;
-type ViteUserConfigFnPromise = (env: ConfigEnv) => Promise<UserConfig>;
-type ViteUserConfigFn = (env: ConfigEnv) => UserConfig | Promise<UserConfig>;
-type ViteUserConfigExport = UserConfig | Promise<UserConfig> | ViteUserConfigFnObject | ViteUserConfigFnPromise | ViteUserConfigFn;
-declare function defineConfig(config: UserConfig): UserConfig;
-declare function defineConfig(config: Promise<UserConfig>): Promise<UserConfig>;
-declare function defineConfig(config: ViteUserConfigFnObject): ViteUserConfigFnObject;
-declare function defineConfig(config: ViteUserConfigFnPromise): ViteUserConfigFnPromise;
-declare function defineConfig(config: ViteUserConfigExport): ViteUserConfigExport;
-declare function defineProject(config: UserWorkspaceConfig): UserWorkspaceConfig;
-declare function defineProject(config: Promise<UserWorkspaceConfig>): Promise<UserWorkspaceConfig>;
-declare function defineProject(config: UserProjectConfigFn): UserProjectConfigFn;
-declare function defineProject(config: UserProjectConfigExport): UserProjectConfigExport;
-
-export { UserProjectConfigExport, UserProjectConfigFn, UserWorkspaceConfig, configDefaults, coverageConfigDefaults, defaultBrowserPort, defaultExclude, defaultInclude, defineConfig, defineProject };
-export type { ViteUserConfigExport, ViteUserConfigFn, ViteUserConfigFnObject, ViteUserConfigFnPromise };
diff --git a/vanilla/node_modules/vitest/dist/config.js b/vanilla/node_modules/vitest/dist/config.js
deleted file mode 100644
index d88992b..0000000
--- a/vanilla/node_modules/vitest/dist/config.js
+++ /dev/null
@@ -1,15 +0,0 @@
-export { c as configDefaults, a as coverageConfigDefaults, d as defaultExclude, b as defaultInclude } from './chunks/defaults.BOqNVLsY.js';
-export { mergeConfig } from 'vite';
-export { d as defaultBrowserPort } from './chunks/constants.D_Q9UYh-.js';
-import 'node:os';
-import './chunks/env.D4Lgay0q.js';
-import 'std-env';
-
-function defineConfig(config) {
- return config;
-}
-function defineProject(config) {
- return config;
-}
-
-export { defineConfig, defineProject };
diff --git a/vanilla/node_modules/vitest/dist/coverage.d.ts b/vanilla/node_modules/vitest/dist/coverage.d.ts
deleted file mode 100644
index 73d4e4b..0000000
--- a/vanilla/node_modules/vitest/dist/coverage.d.ts
+++ /dev/null
@@ -1,118 +0,0 @@
-import { R as ResolvedCoverageOptions, V as Vitest, C as CoverageMap, a as ReportContext } from './chunks/reporters.d.CWXNI2jG.js';
-import { TransformResult } from 'vite';
-import { A as AfterSuiteRunMeta } from './chunks/rpc.d.RH3apGEf.js';
-import '@vitest/runner';
-import '@vitest/utils';
-import 'node:stream';
-import './chunks/browser.d.ChKACdzH.js';
-import './chunks/traces.d.402V_yFI.js';
-import './chunks/worker.d.Dyxm8DEL.js';
-import 'vite/module-runner';
-import './chunks/config.d.Cy95HiCx.js';
-import '@vitest/pretty-format';
-import '@vitest/snapshot';
-import '@vitest/utils/diff';
-import './chunks/environment.d.CrsxCzP1.js';
-import '@vitest/mocker';
-import '@vitest/utils/source-map';
-import 'vitest/browser';
-import '@vitest/expect';
-import 'vitest/optional-types.js';
-import './chunks/benchmark.d.DAaHLpsq.js';
-import '@vitest/runner/utils';
-import 'tinybench';
-import './chunks/coverage.d.BZtK59WP.js';
-import '@vitest/snapshot/manager';
-import 'node:console';
-import 'node:fs';
-
-type Threshold = "lines" | "functions" | "statements" | "branches";
-interface ResolvedThreshold {
- coverageMap: CoverageMap;
- name: string;
- thresholds: Partial<Record<Threshold, number | undefined>>;
-}
-/**
-* Holds info about raw coverage results that are stored on file system:
-*
-* ```json
-* "project-a": {
-* "web": {
-* "tests/math.test.ts": "coverage-1.json",
-* "tests/utils.test.ts": "coverage-2.json",
-* // ^^^^^^^^^^^^^^^ Raw coverage on file system
-* },
-* "ssr": { ... },
-* "browser": { ... },
-* },
-* "project-b": ...
-* ```
-*/
-type CoverageFiles = Map<NonNullable<AfterSuiteRunMeta["projectName"]> | symbol, Record<AfterSuiteRunMeta["environment"], {
- [TestFilenames: string]: string;
-}>>;
-declare class BaseCoverageProvider<Options extends ResolvedCoverageOptions<"istanbul" | "v8">> {
- ctx: Vitest;
- readonly name: "v8" | "istanbul";
- version: string;
- options: Options;
- globCache: Map<string, boolean>;
- coverageFiles: CoverageFiles;
- pendingPromises: Promise<void>[];
- coverageFilesDirectory: string;
- roots: string[];
- _initialize(ctx: Vitest): void;
- /**
- * Check if file matches `coverage.include` but not `coverage.exclude`
- */
- isIncluded(_filename: string, root?: string): boolean;
- private getUntestedFilesByRoot;
- getUntestedFiles(testedFiles: string[]): Promise<string[]>;
- createCoverageMap(): CoverageMap;
- generateReports(_: CoverageMap, __: boolean | undefined): Promise<void>;
- parseConfigModule(_: string): Promise<{
- generate: () => {
- code: string;
- };
- }>;
- resolveOptions(): Options;
- clean(clean?: boolean): Promise<void>;
- onAfterSuiteRun({ coverage, environment, projectName, testFiles }: AfterSuiteRunMeta): void;
- readCoverageFiles<CoverageType>({ onFileRead, onFinished, onDebug }: {
- /** Callback invoked with a single coverage result */
- onFileRead: (data: CoverageType) => void;
- /** Callback invoked once all results of a project for specific transform mode are read */
- onFinished: (project: Vitest["projects"][number], environment: string) => Promise<void>;
- onDebug: ((...logs: any[]) => void) & {
- enabled: boolean;
- };
- }): Promise<void>;
- cleanAfterRun(): Promise<void>;
- onTestFailure(): Promise<void>;
- reportCoverage(coverageMap: unknown, { allTestsRun }: ReportContext): Promise<void>;
- reportThresholds(coverageMap: CoverageMap, allTestsRun: boolean | undefined): Promise<void>;
- /**
- * Constructs collected coverage and users' threshold options into separate sets
- * where each threshold set holds their own coverage maps. Threshold set is either
- * for specific files defined by glob pattern or global for all other files.
- */
- private resolveThresholds;
- /**
- * Check collected coverage against configured thresholds. Sets exit code to 1 when thresholds not reached.
- */
- private checkThresholds;
- /**
- * Check if current coverage is above configured thresholds and bump the thresholds if needed
- */
- updateThresholds({ thresholds: allThresholds, onUpdate, configurationFile }: {
- thresholds: ResolvedThreshold[];
- configurationFile: unknown;
- onUpdate: () => void;
- }): Promise<void>;
- mergeReports(coverageMaps: unknown[]): Promise<void>;
- hasTerminalReporter(reporters: ResolvedCoverageOptions["reporter"]): boolean;
- toSlices<T>(array: T[], size: number): T[][];
- createUncoveredFileTransformer(ctx: Vitest): (filename: string) => Promise<TransformResult | null | undefined>;
-}
-
-export { BaseCoverageProvider };
diff --git a/vanilla/node_modules/vitest/dist/coverage.js b/vanilla/node_modules/vitest/dist/coverage.js
deleted file mode 100644
index 3131a64..0000000
--- a/vanilla/node_modules/vitest/dist/coverage.js
+++ /dev/null
@@ -1,23 +0,0 @@
-export { B as BaseCoverageProvider } from './chunks/coverage.AVPTjMgw.js';
-import 'node:fs';
-import 'node:path';
-import '@vitest/utils/helpers';
-import 'pathe';
-import 'picomatch';
-import 'tinyglobby';
-import 'tinyrainbow';
-import './chunks/defaults.BOqNVLsY.js';
-import 'node:os';
-import './chunks/env.D4Lgay0q.js';
-import 'std-env';
-import 'node:crypto';
-import 'node:url';
-import 'node:module';
-import 'node:process';
-import 'node:fs/promises';
-import 'node:assert';
-import 'node:v8';
-import 'node:util';
-import 'vite';
-import './chunks/constants.D_Q9UYh-.js';
-import './chunks/coverage.D_JHT54q.js';
diff --git a/vanilla/node_modules/vitest/dist/environments.d.ts b/vanilla/node_modules/vitest/dist/environments.d.ts
deleted file mode 100644
index 58d23ee..0000000
--- a/vanilla/node_modules/vitest/dist/environments.d.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { E as Environment } from './chunks/environment.d.CrsxCzP1.js';
-export { a as EnvironmentReturn, V as VmEnvironmentReturn } from './chunks/environment.d.CrsxCzP1.js';
-import '@vitest/utils';
-
-declare const environments: {
- "node": Environment;
- "jsdom": Environment;
- "happy-dom": Environment;
- "edge-runtime": Environment;
-};
-
-interface PopulateOptions {
- bindFunctions?: boolean;
- additionalKeys?: string[];
-}
-declare function populateGlobal(global: any, win: any, options?: PopulateOptions): {
- keys: Set<string>;
- skipKeys: string[];
- originals: Map<string | symbol, any>;
-};
-
-export { Environment, environments as builtinEnvironments, populateGlobal };
diff --git a/vanilla/node_modules/vitest/dist/environments.js b/vanilla/node_modules/vitest/dist/environments.js
deleted file mode 100644
index dc075b7..0000000
--- a/vanilla/node_modules/vitest/dist/environments.js
+++ /dev/null
@@ -1,3 +0,0 @@
-export { e as builtinEnvironments, p as populateGlobal } from './chunks/index.CyBMJtT7.js';
-import 'node:url';
-import 'node:console';
diff --git a/vanilla/node_modules/vitest/dist/index.d.ts b/vanilla/node_modules/vitest/dist/index.d.ts
deleted file mode 100644
index e113b88..0000000
--- a/vanilla/node_modules/vitest/dist/index.d.ts
+++ /dev/null
@@ -1,510 +0,0 @@
-import { M as ModuleDefinitionDurationsDiagnostic, U as UntrackedModuleDefinitionDiagnostic, S as SerializedTestSpecification, a as ModuleDefinitionDiagnostic, b as ModuleDefinitionLocation, c as SourceModuleDiagnostic, d as SourceModuleLocations } from './chunks/browser.d.ChKACdzH.js';
-export { B as BrowserTesterOptions } from './chunks/browser.d.ChKACdzH.js';
-import './chunks/global.d.B15mdLcR.js';
-import { File, TestAnnotation, TestArtifact, TaskResultPack, TaskEventPack, Test, TaskPopulated } from '@vitest/runner';
-export { CancelReason, ImportDuration, OnTestFailedHandler, OnTestFinishedHandler, RunMode, Task as RunnerTask, TaskBase as RunnerTaskBase, TaskEventPack as RunnerTaskEventPack, TaskResult as RunnerTaskResult, TaskResultPack as RunnerTaskResultPack, Test as RunnerTestCase, File as RunnerTestFile, Suite as RunnerTestSuite, SuiteAPI, SuiteCollector, SuiteFactory, TaskCustomOptions, TaskMeta, TaskState, TestAPI, TestAnnotation, TestAnnotationArtifact, TestArtifact, TestArtifactBase, TestArtifactLocation, TestArtifactRegistry, TestAttachment, TestContext, TestFunction, TestOptions, afterAll, afterEach, beforeAll, beforeEach, describe, it, onTestFailed, onTestFinished, recordArtifact, suite, test } from '@vitest/runner';
-import { Awaitable } from '@vitest/utils';
-export { ParsedStack, SerializedError, TestError } from '@vitest/utils';
-import { b as BirpcReturn } from './chunks/worker.d.Dyxm8DEL.js';
-export { C as ContextRPC, c as ContextTestEnvironment, T as TestExecutionMethod, W as WorkerGlobalState } from './chunks/worker.d.Dyxm8DEL.js';
-import { S as SerializedConfig, F as FakeTimerInstallOpts, R as RuntimeOptions } from './chunks/config.d.Cy95HiCx.js';
-export { b as RuntimeConfig, a as SerializedCoverageConfig } from './chunks/config.d.Cy95HiCx.js';
-import { U as UserConsoleLog, L as LabelColor, M as ModuleGraphData, P as ProvidedContext } from './chunks/rpc.d.RH3apGEf.js';
-export { A as AfterSuiteRunMeta, a as RunnerRPC, R as RuntimeRPC } from './chunks/rpc.d.RH3apGEf.js';
-import { ExpectStatic } from '@vitest/expect';
-export { Assertion, AsymmetricMatchersContaining, DeeplyAllowMatchers, ExpectPollOptions, ExpectStatic, JestAssertion, Matchers, chai } from '@vitest/expect';
-import { spyOn, fn, MaybeMockedDeep, MaybeMocked, MaybePartiallyMocked, MaybePartiallyMockedDeep, MockInstance } from '@vitest/spy';
-export { Mock, MockContext, MockInstance, MockResult, MockResultIncomplete, MockResultReturn, MockResultThrow, MockSettledResult, MockSettledResultFulfilled, MockSettledResultIncomplete, MockSettledResultRejected, Mocked, MockedClass, MockedFunction, MockedObject } from '@vitest/spy';
-export { b as bench } from './chunks/suite.d.BJWk38HB.js';
-export { V as EvaluatedModules } from './chunks/evaluatedModules.d.BxJ5omdx.js';
-export { a as BenchFunction, b as Benchmark, c as BenchmarkAPI, B as BenchmarkResult } from './chunks/benchmark.d.DAaHLpsq.js';
-export { ExpectTypeOf, expectTypeOf } from 'expect-type';
-export { SnapshotData, SnapshotMatchOptions, SnapshotResult, SnapshotSerializer, SnapshotStateOptions, SnapshotSummary, SnapshotUpdateState, UncheckedSnapshot } from '@vitest/snapshot';
-export { DiffOptions } from '@vitest/utils/diff';
-export { Bench as BenchFactory, Options as BenchOptions, Task as BenchTask, TaskResult as BenchTaskResult } from 'tinybench';
-import './chunks/traces.d.402V_yFI.js';
-import '@vitest/pretty-format';
-import 'vite/module-runner';
-import './chunks/environment.d.CrsxCzP1.js';
-import '@vitest/runner/utils';
-
-interface SourceMap {
- file: string;
- mappings: string;
- names: string[];
- sources: string[];
- sourcesContent?: string[];
- version: number;
- toString: () => string;
- toUrl: () => string;
-}
-interface ExternalResult {
- source?: string;
-}
-interface TransformResultWithSource {
- code: string;
- map: SourceMap | {
- mappings: "";
- } | null;
- etag?: string;
- deps?: string[];
- dynamicDeps?: string[];
- source?: string;
- transformTime?: number;
- modules?: ModuleDefinitionDurationsDiagnostic[];
- untrackedModules?: UntrackedModuleDefinitionDiagnostic[];
-}
-interface WebSocketHandlers {
- onTaskUpdate: (packs: TaskResultPack[], events: TaskEventPack[]) => void;
- getFiles: () => File[];
- getTestFiles: () => Promise<SerializedTestSpecification[]>;
- getPaths: () => string[];
- getConfig: () => SerializedConfig;
- getResolvedProjectLabels: () => {
- name: string;
- color?: LabelColor;
- }[];
- getModuleGraph: (projectName: string, id: string, browser?: boolean) => Promise<ModuleGraphData>;
- getTransformResult: (projectName: string, id: string, testFileId: string, browser?: boolean) => Promise<TransformResultWithSource | undefined>;
- getExternalResult: (id: string, testFileId: string) => Promise<ExternalResult | undefined>;
- readTestFile: (id: string) => Promise<string | null>;
- saveTestFile: (id: string, content: string) => Promise<void>;
- rerun: (files: string[], resetTestNamePattern?: boolean) => Promise<void>;
- rerunTask: (id: string) => Promise<void>;
- updateSnapshot: (file?: File) => Promise<void>;
- getUnhandledErrors: () => unknown[];
-}
-interface WebSocketEvents {
- onCollected?: (files?: File[]) => Awaitable<void>;
- onFinished?: (files: File[], errors: unknown[], coverage?: unknown, executionTime?: number) => Awaitable<void>;
- onTestAnnotate?: (testId: string, annotation: TestAnnotation) => Awaitable<void>;
- onTestArtifactRecord?: (testId: string, artifact: TestArtifact) => Awaitable<void>;
- onTaskUpdate?: (packs: TaskResultPack[], events: TaskEventPack[]) => Awaitable<void>;
- onUserConsoleLog?: (log: UserConsoleLog) => Awaitable<void>;
- onPathsCollected?: (paths?: string[]) => Awaitable<void>;
- onSpecsCollected?: (specs?: SerializedTestSpecification[], startTime?: number) => Awaitable<void>;
- onFinishedReportCoverage: () => void;
-}
-type WebSocketRPC = BirpcReturn<WebSocketEvents, WebSocketHandlers>;
-
-declare function createExpect(test?: Test | TaskPopulated): ExpectStatic;
-declare const globalExpect: ExpectStatic;
-declare const assert: Chai.Assert;
-declare const should: () => Chai.Should;
-
-/**
-* Gives access to injected context provided from the main thread.
-* This usually returns a value provided by `globalSetup` or an external library.
-*/
-declare function inject<T extends keyof ProvidedContext & string>(key: T): ProvidedContext[T];
-
-type Promisable<T> = T | Promise<T>;
-type MockFactoryWithHelper<M = unknown> = (importOriginal: <T extends M = M>() => Promise<T>) => Promisable<Partial<M>>;
-interface MockOptions {
- spy?: boolean;
-}
-
-type WaitForCallback<T> = () => T | Promise<T>;
-interface WaitForOptions {
- /**
- * @description Time in ms between each check callback
- * @default 50ms
- */
- interval?: number;
- /**
- * @description Time in ms after which the throw a timeout error
- * @default 1000ms
- */
- timeout?: number;
-}
-declare function waitFor<T>(callback: WaitForCallback<T>, options?: number | WaitForOptions): Promise<T>;
-type WaitUntilCallback<T> = () => T | Promise<T>;
-interface WaitUntilOptions extends Pick<WaitForOptions, "interval" | "timeout"> {}
-type Truthy<T> = T extends false | "" | 0 | null | undefined ? never : T;
-declare function waitUntil<T>(callback: WaitUntilCallback<T>, options?: number | WaitUntilOptions): Promise<Truthy<T>>;
-
-type ESModuleExports = Record<string, unknown>;
-interface VitestUtils {
- /**
- * Checks if fake timers are enabled.
- */
- isFakeTimers: () => boolean;
- /**
- * This method wraps all further calls to timers until [`vi.useRealTimers()`](https://vitest.dev/api/vi#vi-userealtimers) is called.
- */
- useFakeTimers: (config?: FakeTimerInstallOpts) => VitestUtils;
- /**
- * Restores mocked timers to their original implementations. All timers that were scheduled before will be discarded.
- */
- useRealTimers: () => VitestUtils;
- /**
- * This method will call every timer that was initiated after [`vi.useFakeTimers`](https://vitest.dev/api/vi#vi-usefaketimers) call.
- * It will not fire any timer that was initiated during its call.
- */
- runOnlyPendingTimers: () => VitestUtils;
- /**
- * This method will asynchronously call every timer that was initiated after [`vi.useFakeTimers`](https://vitest.dev/api/vi#vi-usefaketimers) call, even asynchronous ones.
- * It will not fire any timer that was initiated during its call.
- */
- runOnlyPendingTimersAsync: () => Promise<VitestUtils>;
- /**
- * This method will invoke every initiated timer until the timer queue is empty. It means that every timer called during `runAllTimers` will be fired.
- * If you have an infinite interval, it will throw after 10,000 tries (can be configured with [`fakeTimers.loopLimit`](https://vitest.dev/config/#faketimers-looplimit)).
- */
- runAllTimers: () => VitestUtils;
- /**
- * This method will asynchronously invoke every initiated timer until the timer queue is empty. It means that every timer called during `runAllTimersAsync` will be fired even asynchronous timers.
- * If you have an infinite interval, it will throw after 10 000 tries (can be configured with [`fakeTimers.loopLimit`](https://vitest.dev/config/#faketimers-looplimit)).
- */
- runAllTimersAsync: () => Promise<VitestUtils>;
- /**
- * Calls every microtask that was queued by `process.nextTick`. This will also run all microtasks scheduled by themselves.
- */
- runAllTicks: () => VitestUtils;
- /**
- * This method will invoke every initiated timer until the specified number of milliseconds is passed or the queue is empty - whatever comes first.
- */
- advanceTimersByTime: (ms: number) => VitestUtils;
- /**
- * This method will invoke every initiated timer until the specified number of milliseconds is passed or the queue is empty - whatever comes first. This will include and await asynchronously set timers.
- */
- advanceTimersByTimeAsync: (ms: number) => Promise<VitestUtils>;
- /**
- * Will call next available timer. Useful to make assertions between each timer call. You can chain call it to manage timers by yourself.
- */
- advanceTimersToNextTimer: () => VitestUtils;
- /**
- * Will call next available timer and wait until it's resolved if it was set asynchronously. Useful to make assertions between each timer call.
- */
- advanceTimersToNextTimerAsync: () => Promise<VitestUtils>;
- /**
- * Similar to [`vi.advanceTimersByTime`](https://vitest.dev/api/vi#vi-advancetimersbytime), but will advance timers by the milliseconds needed to execute callbacks currently scheduled with `requestAnimationFrame`.
- */
- advanceTimersToNextFrame: () => VitestUtils;
- /**
- * Get the number of waiting timers.
- */
- getTimerCount: () => number;
- /**
- * If fake timers are enabled, this method simulates a user changing the system clock (will affect date related API like `hrtime`, `performance.now` or `new Date()`) - however, it will not fire any timers.
- * If fake timers are not enabled, this method will only mock `Date.*` and `new Date()` calls.
- */
- setSystemTime: (time: number | string | Date) => VitestUtils;
- /**
- * Returns mocked current date. If date is not mocked the method will return `null`.
- */
- getMockedSystemTime: () => Date | null;
- /**
- * When using `vi.useFakeTimers`, `Date.now` calls are mocked. If you need to get real time in milliseconds, you can call this function.
- */
- getRealSystemTime: () => number;
- /**
- * Removes all timers that are scheduled to run. These timers will never run in the future.
- */
- clearAllTimers: () => VitestUtils;
- /**
- * Creates a spy on a method or getter/setter of an object similar to [`vi.fn()`](https://vitest.dev/api/vi#vi-fn). It returns a [mock function](https://vitest.dev/api/mock).
- * @example
- * ```ts
- * const cart = {
- * getApples: () => 42
- * }
- *
- * const spy = vi.spyOn(cart, 'getApples').mockReturnValue(10)
- *
- * expect(cart.getApples()).toBe(10)
- * expect(spy).toHaveBeenCalled()
- * expect(spy).toHaveReturnedWith(10)
- * ```
- */
- spyOn: typeof spyOn;
- /**
- * Creates a spy on a function, though can be initiated without one. Every time a function is invoked, it stores its call arguments, returns, and instances. Also, you can manipulate its behavior with [methods](https://vitest.dev/api/mock).
- *
- * If no function is given, mock will return `undefined`, when invoked.
- * @example
- * ```ts
- * const getApples = vi.fn(() => 0)
- *
- * getApples()
- *
- * expect(getApples).toHaveBeenCalled()
- * expect(getApples).toHaveReturnedWith(0)
- *
- * getApples.mockReturnValueOnce(5)
- *
- * expect(getApples()).toBe(5)
- * expect(getApples).toHaveNthReturnedWith(2, 5)
- * ```
- */
- fn: typeof fn;
- /**
- * Wait for the callback to execute successfully. If the callback throws an error or returns a rejected promise it will continue to wait until it succeeds or times out.
- *
- * This is very useful when you need to wait for some asynchronous action to complete, for example, when you start a server and need to wait for it to start.
- * @example
- * ```ts
- * const server = createServer()
- *
- * await vi.waitFor(
- * () => {
- * if (!server.isReady)
- * throw new Error('Server not started')
- *
- * console.log('Server started')
- * }, {
- * timeout: 500, // default is 1000
- * interval: 20, // default is 50
- * }
- * )
- * ```
- */
- waitFor: typeof waitFor;
- /**
- * This is similar to [`vi.waitFor`](https://vitest.dev/api/vi#vi-waitfor), but if the callback throws any errors, execution is immediately interrupted and an error message is received.
- *
- * If the callback returns a falsy value, the next check will continue until a truthy value is returned. This is useful when you need to wait for something to exist before taking the next step.
- * @example
- * ```ts
- * const element = await vi.waitUntil(
- * () => document.querySelector('.element'),
- * {
- * timeout: 500, // default is 1000
- * interval: 20, // default is 50
- * }
- * )
- *
- * // do something with the element
- * expect(element.querySelector('.element-child')).toBeTruthy()
- * ```
- */
- waitUntil: typeof waitUntil;
- /**
- * Run the factory before imports are evaluated. You can return a value from the factory
- * to reuse it inside your [`vi.mock`](https://vitest.dev/api/vi#vi-mock) factory and tests.
- *
- * If used with [`vi.mock`](https://vitest.dev/api/vi#vi-mock), both will be hoisted in the order they are defined in.
- */
- hoisted: <T>(factory: () => T) => T;
- /**
- * Mocks every import call to the module even if it was already statically imported.
- *
- * The call to `vi.mock` is hoisted to the top of the file, so you don't have access to variables declared in the global file scope
- * unless they are defined with [`vi.hoisted`](https://vitest.dev/api/vi#vi-hoisted) before this call.
- *
- * Mocking algorithm is described in [documentation](https://vitest.dev/guide/mocking/modules).
- * @param path Path to the module. Can be aliased, if your Vitest config supports it
- * @param factory Mocked module factory. The result of this function will be an exports object
- */
- mock(path: string, factory?: MockFactoryWithHelper | MockOptions): void;
- mock<T>(module: Promise<T>, factory?: MockFactoryWithHelper<T> | MockOptions): void;
- /**
- * Removes module from mocked registry. All calls to import will return the original module even if it was mocked before.
- *
- * This call is hoisted to the top of the file, so it will only unmock modules that were defined in `setupFiles`, for example.
- * @param path Path to the module. Can be aliased, if your Vitest config supports it
- */
- unmock(path: string): void;
- unmock(module: Promise<unknown>): void;
- /**
- * Mocks every subsequent [dynamic import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) call.
- *
- * Unlike [`vi.mock`](https://vitest.dev/api/vi#vi-mock), this method will not mock statically imported modules because it is not hoisted to the top of the file.
- *
- * Mocking algorithm is described in [documentation](https://vitest.dev/guide/mocking/modules).
- * @param path Path to the module. Can be aliased, if your Vitest config supports it
- * @param factory Mocked module factory. The result of this function will be an exports object
- */
- doMock(path: string, factory?: MockFactoryWithHelper | MockOptions): void;
- doMock<T>(module: Promise<T>, factory?: MockFactoryWithHelper<T> | MockOptions): void;
- /**
- * Removes module from mocked registry. All subsequent calls to import will return original module.
- *
- * Unlike [`vi.unmock`](https://vitest.dev/api/vi#vi-unmock), this method is not hoisted to the top of the file.
- * @param path Path to the module. Can be aliased, if your Vitest config supports it
- */
- doUnmock(path: string): void;
- doUnmock(module: Promise<unknown>): void;
- /**
- * Imports module, bypassing all checks if it should be mocked.
- * Can be useful if you want to mock module partially.
- * @example
- * ```ts
- * vi.mock('./example.js', async () => {
- * const axios = await vi.importActual<typeof import('./example.js')>('./example.js')
- *
- * return { ...axios, get: vi.fn() }
- * })
- * ```
- * @param path Path to the module. Can be aliased, if your config supports it
- */
- importActual: <T = ESModuleExports>(path: string) => Promise<T>;
- /**
- * Imports a module with all of its properties and nested properties mocked.
- *
- * Mocking algorithm is described in [documentation](https://vitest.dev/guide/mocking/modules).
- * @example
- * ```ts
- * const example = await vi.importMock<typeof import('./example.js')>('./example.js')
- * example.calc.mockReturnValue(10)
- * expect(example.calc()).toBe(10)
- * ```
- * @param path Path to the module. Can be aliased, if your config supports it
- * @returns Fully mocked module
- */
- importMock: <T = ESModuleExports>(path: string) => Promise<MaybeMockedDeep<T>>;
- /**
- * Deeply mocks properties and methods of a given object
- * in the same way as `vi.mock()` mocks module exports.
- *
- * @example
- * ```ts
- * const original = {
- * simple: () => 'value',
- * nested: {
- * method: () => 'real'
- * },
- * prop: 'foo',
- * }
- *
- * const mocked = vi.mockObject(original)
- * expect(mocked.simple()).toBe(undefined)
- * expect(mocked.nested.method()).toBe(undefined)
- * expect(mocked.prop).toBe('foo')
- *
- * mocked.simple.mockReturnValue('mocked')
- * mocked.nested.method.mockReturnValue('mocked nested')
- *
- * expect(mocked.simple()).toBe('mocked')
- * expect(mocked.nested.method()).toBe('mocked nested')
- *
- * const spied = vi.mockObject(original, { spy: true })
- * expect(spied.simple()).toBe('value')
- * expect(spied.simple).toHaveBeenCalled()
- * expect(spied.simple.mock.results[0]).toEqual({ type: 'return', value: 'value' })
- * ```
- *
- * @param value - The object to be mocked
- * @returns A deeply mocked version of the input object
- */
- mockObject: <T>(value: T, options?: MockOptions) => MaybeMockedDeep<T>;
- /**
- * Type helper for TypeScript. Just returns the object that was passed.
- *
- * When `partial` is `true` it will expect a `Partial<T>` as a return value. By default, this will only make TypeScript believe that
- * the first level values are mocked. You can pass down `{ deep: true }` as a second argument to tell TypeScript that the whole object is mocked, if it actually is.
- * @example
- * ```ts
- * import example from './example.js'
- * vi.mock('./example.js')
- *
- * test('1 + 1 equals 10' async () => {
- * vi.mocked(example.calc).mockReturnValue(10)
- * expect(example.calc(1, '+', 1)).toBe(10)
- * })
- * ```
- * @param item Anything that can be mocked
- * @param deep If the object is deeply mocked
- * @param options If the object is partially or deeply mocked
- */
- mocked: (<T>(item: T, deep?: false) => MaybeMocked<T>) & (<T>(item: T, deep: true) => MaybeMockedDeep<T>) & (<T>(item: T, options: {
- partial?: false;
- deep?: false;
- }) => MaybeMocked<T>) & (<T>(item: T, options: {
- partial?: false;
- deep: true;
- }) => MaybeMockedDeep<T>) & (<T>(item: T, options: {
- partial: true;
- deep?: false;
- }) => MaybePartiallyMocked<T>) & (<T>(item: T, options: {
- partial: true;
- deep: true;
- }) => MaybePartiallyMockedDeep<T>) & (<T>(item: T) => MaybeMocked<T>);
- /**
- * Checks that a given parameter is a mock function. If you are using TypeScript, it will also narrow down its type.
- */
- isMockFunction: (fn: any) => fn is MockInstance;
- /**
- * Calls [`.mockClear()`](https://vitest.dev/api/mock#mockclear) on every mocked function.
- *
- * This will only empty `.mock` state, it will not affect mock implementations.
- *
- * This is useful if you need to clean up mocks between different assertions within a test.
- */
- clearAllMocks: () => VitestUtils;
- /**
- * Calls [`.mockReset()`](https://vitest.dev/api/mock#mockreset) on every mocked function.
- *
- * This will empty `.mock` state, reset "once" implementations, and reset each mock's base implementation to its original.
- *
- * This is useful when you want to reset all mocks to their original states.
- */
- resetAllMocks: () => VitestUtils;
- /**
- * Calls [`.mockRestore()`](https://vitest.dev/api/mock#mockrestore) on every mocked function.
- *
- * This will empty `.mock` state, restore all original mock implementations, and restore original descriptors of spied-on objects.
- *
- * This is useful for inter-test cleanup and/or removing mocks created by [`vi.spyOn(...)`](https://vitest.dev/api/vi#vi-spyon).
- */
- restoreAllMocks: () => VitestUtils;
- /**
- * Makes value available on global namespace.
- * Useful, if you want to have global variables available, like `IntersectionObserver`.
- * You can return it back to original value with `vi.unstubAllGlobals`, or by enabling `unstubGlobals` config option.
- */
- stubGlobal: (name: string | symbol | number, value: unknown) => VitestUtils;
- /**
- * Changes the value of `import.meta.env` and `process.env`.
- * You can return it back to original value with `vi.unstubAllEnvs`, or by enabling `unstubEnvs` config option.
- */
- stubEnv: <T extends string>(name: T, value: T extends "PROD" | "DEV" | "SSR" ? boolean : string | undefined) => VitestUtils;
- /**
- * Reset the value to original value that was available before first `vi.stubGlobal` was called.
- */
- unstubAllGlobals: () => VitestUtils;
- /**
- * Reset environmental variables to the ones that were available before first `vi.stubEnv` was called.
- */
- unstubAllEnvs: () => VitestUtils;
- /**
- * Resets modules registry by clearing the cache of all modules. This allows modules to be reevaluated when reimported.
- * Top-level imports cannot be re-evaluated. Might be useful to isolate modules where local state conflicts between tests.
- *
- * This method does not reset mocks registry. To clear mocks registry, use [`vi.unmock`](https://vitest.dev/api/vi#vi-unmock) or [`vi.doUnmock`](https://vitest.dev/api/vi#vi-dounmock).
- */
- resetModules: () => VitestUtils;
- /**
- * Wait for all imports to load. Useful, if you have a synchronous call that starts
- * importing a module that you cannot await otherwise.
- * Will also wait for new imports, started during the wait.
- */
- dynamicImportSettled: () => Promise<void>;
- /**
- * Updates runtime config. You can only change values that are used when executing tests.
- */
- setConfig: (config: RuntimeOptions) => void;
- /**
- * If config was changed with `vi.setConfig`, this will reset it to the original state().
- */
- resetConfig: () => void;
-}
-declare const vitest: VitestUtils;
-declare const vi: VitestUtils;
-
-interface AssertType {
- <T>(value: T): void;
-}
-declare const assertType: AssertType;
-
-interface BrowserUI {
- setCurrentFileId: (fileId: string) => void;
- setIframeViewport: (width: number, height: number) => Promise<void>;
-}
-
-declare namespace Experimental {
- export { ModuleDefinitionDiagnostic, ModuleDefinitionDurationsDiagnostic, ModuleDefinitionLocation, SourceModuleDiagnostic, SourceModuleLocations, UntrackedModuleDefinitionDiagnostic };
-}
-
-export { Experimental, LabelColor, ModuleGraphData, ProvidedContext, SerializedConfig, SerializedTestSpecification, UserConsoleLog, assert, assertType, createExpect, globalExpect as expect, inject, should, vi, vitest };
-export type { AssertType, BrowserUI, ExternalResult, TransformResultWithSource, VitestUtils, WebSocketEvents, WebSocketHandlers, WebSocketRPC };
diff --git a/vanilla/node_modules/vitest/dist/index.js b/vanilla/node_modules/vitest/dist/index.js
deleted file mode 100644
index a4a8c1d..0000000
--- a/vanilla/node_modules/vitest/dist/index.js
+++ /dev/null
@@ -1,20 +0,0 @@
-export { b as assert, c as createExpect, g as expect, i as inject, s as should, v as vi, d as vitest } from './chunks/vi.2VT5v0um.js';
-export { b as bench } from './chunks/benchmark.B3N2zMcH.js';
-export { V as EvaluatedModules } from './chunks/evaluatedModules.Dg1zASAC.js';
-export { a as assertType } from './chunks/index.Z5E_ObnR.js';
-export { expectTypeOf } from 'expect-type';
-export { afterAll, afterEach, beforeAll, beforeEach, describe, it, onTestFailed, onTestFinished, recordArtifact, suite, test } from '@vitest/runner';
-export { chai } from '@vitest/expect';
-import './chunks/utils.DvEY5TfP.js';
-import '@vitest/utils/timers';
-import '@vitest/runner/utils';
-import '@vitest/snapshot';
-import '@vitest/utils/error';
-import '@vitest/utils/helpers';
-import '@vitest/spy';
-import '@vitest/utils/offset';
-import '@vitest/utils/source-map';
-import './chunks/_commonjsHelpers.D26ty3Ew.js';
-import './chunks/date.Bq6ZW5rf.js';
-import 'pathe';
-import 'vite/module-runner';
diff --git a/vanilla/node_modules/vitest/dist/mocker.d.ts b/vanilla/node_modules/vitest/dist/mocker.d.ts
deleted file mode 100644
index f7dc96a..0000000
--- a/vanilla/node_modules/vitest/dist/mocker.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from '@vitest/mocker';
diff --git a/vanilla/node_modules/vitest/dist/mocker.js b/vanilla/node_modules/vitest/dist/mocker.js
deleted file mode 100644
index f7dc96a..0000000
--- a/vanilla/node_modules/vitest/dist/mocker.js
+++ /dev/null
@@ -1 +0,0 @@
-export * from '@vitest/mocker';
diff --git a/vanilla/node_modules/vitest/dist/module-evaluator.d.ts b/vanilla/node_modules/vitest/dist/module-evaluator.d.ts
deleted file mode 100644
index c87577d..0000000
--- a/vanilla/node_modules/vitest/dist/module-evaluator.d.ts
+++ /dev/null
@@ -1,124 +0,0 @@
-import { ModuleEvaluator, ModuleRunnerImportMeta, ModuleRunnerContext, EvaluatedModuleNode } from 'vite/module-runner';
-import { V as VitestEvaluatedModules } from './chunks/evaluatedModules.d.BxJ5omdx.js';
-import vm from 'node:vm';
-import { R as RuntimeRPC } from './chunks/rpc.d.RH3apGEf.js';
-import '@vitest/runner';
-import '@vitest/snapshot';
-import './chunks/traces.d.402V_yFI.js';
-
-type ModuleExecutionInfo = Map<string, ModuleExecutionInfoEntry>;
-interface ModuleExecutionInfoEntry {
- startOffset: number;
- /** The duration that was spent executing the module. */
- duration: number;
- /** The time that was spent executing the module itself and externalized imports. */
- selfTime: number;
- external?: boolean;
- importer?: string;
-}
-
-declare class FileMap {
- private fsCache;
- private fsBufferCache;
- readFileAsync(path: string): Promise<string>;
- readFile(path: string): string;
- readBuffer(path: string): Buffer<ArrayBuffer>;
-}
-
-interface ModuleEvaluateOptions {
- timeout?: vm.RunningScriptOptions["timeout"] | undefined;
- breakOnSigint?: vm.RunningScriptOptions["breakOnSigint"] | undefined;
-}
-type ModuleLinker = (specifier: string, referencingModule: VMModule, extra: {
- assert: object;
-}) => VMModule | Promise<VMModule>;
-type ModuleStatus = "unlinked" | "linking" | "linked" | "evaluating" | "evaluated" | "errored";
-declare class VMModule {
- dependencySpecifiers: readonly string[];
- error: any;
- identifier: string;
- context: vm.Context;
- namespace: object;
- status: ModuleStatus;
- evaluate(options?: ModuleEvaluateOptions): Promise<void>;
- link(linker: ModuleLinker): Promise<void>;
-}
-
-interface ExternalModulesExecutorOptions {
- context: vm.Context;
- fileMap: FileMap;
- packageCache: Map<string, any>;
- transform: RuntimeRPC["transform"];
- interopDefault?: boolean;
- viteClientModule: Record<string, unknown>;
-}
-declare class ExternalModulesExecutor {
- #private;
- private options;
- private cjs;
- private esm;
- private vite;
- private context;
- private fs;
- private resolvers;
- constructor(options: ExternalModulesExecutorOptions);
- import(identifier: string): Promise<object>;
- require(identifier: string): any;
- createRequire(identifier: string): NodeJS.Require;
- importModuleDynamically: (specifier: string, referencer: VMModule) => Promise<VMModule>;
- resolveModule: (specifier: string, referencer: string) => Promise<VMModule>;
- resolve(specifier: string, parent: string): string;
- private getModuleInformation;
- private createModule;
- private get isNetworkSupported();
-}
-
-declare module "vite/module-runner" {
- interface EvaluatedModuleNode {
- /**
- * @internal
- */
- mockedExports?: Record<string, any>;
- }
-}
-
-interface VitestVmOptions {
- context: vm.Context;
- externalModulesExecutor: ExternalModulesExecutor;
-}
-
-interface VitestModuleEvaluatorOptions {
- evaluatedModules?: VitestEvaluatedModules;
- interopDefault?: boolean | undefined;
- moduleExecutionInfo?: ModuleExecutionInfo;
- getCurrentTestFilepath?: () => string | undefined;
- compiledFunctionArgumentsNames?: string[];
- compiledFunctionArgumentsValues?: unknown[];
-}
-declare class VitestModuleEvaluator implements ModuleEvaluator {
- private options;
- stubs: Record<string, any>;
- env: ModuleRunnerImportMeta["env"];
- private vm;
- private compiledFunctionArgumentsNames?;
- private compiledFunctionArgumentsValues;
- private primitives;
- private debug;
- private _otel;
- private _evaluatedModules?;
- constructor(vmOptions?: VitestVmOptions | undefined, options?: VitestModuleEvaluatorOptions);
- private convertIdToImportUrl;
- runExternalModule(id: string): Promise<any>;
- runInlinedModule(context: ModuleRunnerContext, code: string, module: Readonly<EvaluatedModuleNode>): Promise<any>;
- private _runInlinedModule;
- private createRequire;
- private shouldInterop;
-}
-declare function createImportMetaEnvProxy(): ModuleRunnerImportMeta["env"];
-declare function getDefaultRequestStubs(context?: vm.Context): Record<string, any>;
-declare function isPrimitive(v: any): boolean;
-declare function wrapId(id: string): string;
-declare function unwrapId(id: string): string;
-
-export { VitestModuleEvaluator, createImportMetaEnvProxy, getDefaultRequestStubs, isPrimitive, unwrapId, wrapId };
-export type { VitestModuleEvaluatorOptions };
diff --git a/vanilla/node_modules/vitest/dist/module-evaluator.js b/vanilla/node_modules/vitest/dist/module-evaluator.js
deleted file mode 100644
index 0ff253b..0000000
--- a/vanilla/node_modules/vitest/dist/module-evaluator.js
+++ /dev/null
@@ -1,343 +0,0 @@
-import { isBuiltin, createRequire } from 'node:module';
-import { pathToFileURL, fileURLToPath } from 'node:url';
-import vm from 'node:vm';
-import { ssrModuleExportsKey, ssrImportMetaKey, ssrImportKey, ssrDynamicImportKey, ssrExportAllKey } from 'vite/module-runner';
-import { T as Traces } from './chunks/traces.CCmnQaNT.js';
-
-const performanceNow = performance.now.bind(performance);
-class ModuleDebug {
- executionStack = [];
- startCalculateModuleExecutionInfo(filename, options) {
- const startTime = performanceNow();
- this.executionStack.push({
- filename,
- startTime,
- subImportTime: 0
- });
- return () => {
- const duration = performanceNow() - startTime;
- const currentExecution = this.executionStack.pop();
- if (currentExecution == null) throw new Error("Execution stack is empty, this should never happen");
- const selfTime = duration - currentExecution.subImportTime;
- if (this.executionStack.length > 0) this.executionStack.at(-1).subImportTime += duration;
- return {
- startOffset: options.startOffset,
- external: options.external,
- importer: options.importer,
- duration,
- selfTime
- };
- };
- }
-}
-
-const isWindows = process.platform === "win32";
-class VitestModuleEvaluator {
- stubs = {};
- env = createImportMetaEnvProxy();
- vm;
- compiledFunctionArgumentsNames;
- compiledFunctionArgumentsValues = [];
- primitives;
- debug = new ModuleDebug();
- _otel;
- _evaluatedModules;
- constructor(vmOptions, options = {}) {
- this.options = options;
- this._otel = options.traces || new Traces({ enabled: false });
- this.vm = vmOptions;
- this.stubs = getDefaultRequestStubs(vmOptions?.context);
- this._evaluatedModules = options.evaluatedModules;
- if (options.compiledFunctionArgumentsNames) this.compiledFunctionArgumentsNames = options.compiledFunctionArgumentsNames;
- if (options.compiledFunctionArgumentsValues) this.compiledFunctionArgumentsValues = options.compiledFunctionArgumentsValues;
- if (vmOptions) this.primitives = vm.runInContext("({ Object, Proxy, Reflect })", vmOptions.context);
- else this.primitives = {
- Object,
- Proxy,
- Reflect
- };
- }
- convertIdToImportUrl(id) {
- // TODO: vitest returns paths for external modules, but Vite returns file://
- // REMOVE WHEN VITE 6 SUPPORT IS OVER
- // unfortunetly, there is a bug in Vite where ID is resolved incorrectly, so we can't return files until the fix is merged
- // https://github.com/vitejs/vite/pull/20449
- if (!isWindows || isBuiltin(id) || /^(?:node:|data:|http:|https:|file:)/.test(id)) return id;
- const [filepath, query] = id.split("?");
- if (query) return `${pathToFileURL(filepath).toString()}?${query}`;
- return pathToFileURL(filepath).toString();
- }
- async runExternalModule(id) {
- if (id in this.stubs) return this.stubs[id];
- const file = this.convertIdToImportUrl(id);
- const importer = (this._evaluatedModules?.getModuleById(id)?.importers)?.values().next().value;
- const filename = id.startsWith("file://") ? fileURLToPath(id) : id;
- const finishModuleExecutionInfo = this.debug.startCalculateModuleExecutionInfo(filename, {
- startOffset: 0,
- external: true,
- importer
- });
- const namespace = await this._otel.$("vitest.module.external", { attributes: { "code.file.path": file } }, () => this.vm ? this.vm.externalModulesExecutor.import(file) : import(file)).finally(() => {
- this.options.moduleExecutionInfo?.set(filename, finishModuleExecutionInfo());
- });
- if (!this.shouldInterop(file, namespace)) return namespace;
- const { mod, defaultExport } = interopModule(namespace);
- const { Proxy, Reflect } = this.primitives;
- return new Proxy(mod, {
- get(mod, prop) {
- if (prop === "default") return defaultExport;
- return mod[prop] ?? defaultExport?.[prop];
- },
- has(mod, prop) {
- if (prop === "default") return defaultExport !== void 0;
- return prop in mod || defaultExport && prop in defaultExport;
- },
- getOwnPropertyDescriptor(mod, prop) {
- const descriptor = Reflect.getOwnPropertyDescriptor(mod, prop);
- if (descriptor) return descriptor;
- if (prop === "default" && defaultExport !== void 0) return {
- value: defaultExport,
- enumerable: true,
- configurable: true
- };
- }
- });
- }
- async runInlinedModule(context, code, module) {
- return this._otel.$("vitest.module.inline", (span) => this._runInlinedModule(context, code, module, span));
- }
- async _runInlinedModule(context, code, module, span) {
- context.__vite_ssr_import_meta__.env = this.env;
- const { Reflect, Proxy, Object } = this.primitives;
- const exportsObject = context[ssrModuleExportsKey];
- const SYMBOL_NOT_DEFINED = Symbol("not defined");
- let moduleExports = SYMBOL_NOT_DEFINED;
- // this proxy is triggered only on exports.{name} and module.exports access
- // inside the module itself. imported module is always "exports"
- const cjsExports = new Proxy(exportsObject, {
- get: (target, p, receiver) => {
- if (Reflect.has(target, p)) return Reflect.get(target, p, receiver);
- return Reflect.get(Object.prototype, p, receiver);
- },
- getPrototypeOf: () => Object.prototype,
- set: (_, p, value) => {
- span.addEvent(`cjs export proxy is triggered for ${String(p)}`);
- // treat "module.exports =" the same as "exports.default =" to not have nested "default.default",
- // so "exports.default" becomes the actual module
- if (p === "default" && this.shouldInterop(module.file, { default: value }) && cjsExports !== value) {
- span.addEvent("`exports.default` is assigned, copying values");
- exportAll(cjsExports, value);
- exportsObject.default = value;
- return true;
- }
- if (!Reflect.has(exportsObject, "default")) exportsObject.default = {};
- // returns undefined, when accessing named exports, if default is not an object
- // but is still present inside hasOwnKeys, this is Node behaviour for CJS
- if (moduleExports !== SYMBOL_NOT_DEFINED && isPrimitive(moduleExports)) {
- span.addEvent(`\`exports.${String(p)}\` is assigned, but module.exports is a primitive. assigning "undefined" values instead to comply with ESM`);
- defineExport(exportsObject, p, () => void 0);
- return true;
- }
- if (!isPrimitive(exportsObject.default)) exportsObject.default[p] = value;
- if (p !== "default") defineExport(exportsObject, p, () => value);
- return true;
- }
- });
- const moduleProxy = {
- set exports(value) {
- span.addEvent("`module.exports` is assigned directly, copying all properties to `exports`");
- exportAll(cjsExports, value);
- exportsObject.default = value;
- moduleExports = value;
- },
- get exports() {
- return cjsExports;
- }
- };
- const meta = context[ssrImportMetaKey];
- if (this.options.getCurrentTestFilepath?.() === module.file) {
- const globalNamespace = this.vm?.context || globalThis;
- Object.defineProperty(meta, "vitest", { get: () => globalNamespace.__vitest_index__ });
- }
- const filename = meta.filename;
- const dirname = meta.dirname;
- span.setAttributes({ "code.file.path": filename });
- const require = this.createRequire(meta.url);
- const argumentsList = [
- ssrModuleExportsKey,
- ssrImportMetaKey,
- ssrImportKey,
- ssrDynamicImportKey,
- ssrExportAllKey,
- "__vite_ssr_exportName__",
- "__filename",
- "__dirname",
- "module",
- "exports",
- "require"
- ];
- if (this.compiledFunctionArgumentsNames) argumentsList.push(...this.compiledFunctionArgumentsNames);
- span.setAttribute("vitest.module.arguments", argumentsList);
- // add 'use strict' since ESM enables it by default
- const codeDefinition = `'use strict';async (${argumentsList.join(",")})=>{{`;
- const wrappedCode = `${codeDefinition}${code}\n}}`;
- const options = {
- filename: module.id,
- lineOffset: 0,
- columnOffset: -codeDefinition.length
- };
- // this will always be 1 element because it's cached after load
- const importer = module.importers.values().next().value;
- const finishModuleExecutionInfo = this.debug.startCalculateModuleExecutionInfo(options.filename, {
- startOffset: codeDefinition.length,
- importer
- });
- try {
- await (this.vm ? vm.runInContext(wrappedCode, this.vm.context, options) : vm.runInThisContext(wrappedCode, options))(
- context[ssrModuleExportsKey],
- context[ssrImportMetaKey],
- context[ssrImportKey],
- context[ssrDynamicImportKey],
- context[ssrExportAllKey],
- // vite 7 support, remove when vite 7+ is supported
- context.__vite_ssr_exportName__ || ((name, getter) => Object.defineProperty(exportsObject, name, {
- enumerable: true,
- configurable: true,
- get: getter
- })),
- filename,
- dirname,
- moduleProxy,
- cjsExports,
- require,
- ...this.compiledFunctionArgumentsValues
- );
- } finally {
- // moduleExecutionInfo needs to use Node filename instead of the normalized one
- // because we rely on this behaviour in coverage-v8, for example
- this.options.moduleExecutionInfo?.set(options.filename, finishModuleExecutionInfo());
- }
- }
- createRequire(filename) {
- return this.vm ? this.vm.externalModulesExecutor.createRequire(filename) : createRequire(filename);
- }
- shouldInterop(path, mod) {
- if (this.options.interopDefault === false) return false;
- // never interop ESM modules
- // TODO: should also skip for `.js` with `type="module"`
- return !path.endsWith(".mjs") && "default" in mod;
- }
-}
-function createImportMetaEnvProxy() {
- // packages/vitest/src/node/plugins/index.ts:146
- const booleanKeys = [
- "DEV",
- "PROD",
- "SSR"
- ];
- return new Proxy(process.env, {
- get(_, key) {
- if (typeof key !== "string") return;
- if (booleanKeys.includes(key)) return !!process.env[key];
- return process.env[key];
- },
- set(_, key, value) {
- if (typeof key !== "string") return true;
- if (booleanKeys.includes(key)) process.env[key] = value ? "1" : "";
- else process.env[key] = value;
- return true;
- }
- });
-}
-function updateStyle(id, css) {
- if (typeof document === "undefined") return;
- const element = document.querySelector(`[data-vite-dev-id="${id}"]`);
- if (element) {
- element.textContent = css;
- return;
- }
- const head = document.querySelector("head");
- const style = document.createElement("style");
- style.setAttribute("type", "text/css");
- style.setAttribute("data-vite-dev-id", id);
- style.textContent = css;
- head?.appendChild(style);
-}
-function removeStyle(id) {
- if (typeof document === "undefined") return;
- const sheet = document.querySelector(`[data-vite-dev-id="${id}"]`);
- if (sheet) document.head.removeChild(sheet);
-}
-const defaultClientStub = {
- injectQuery: (id) => id,
- createHotContext: () => {
- return {
- accept: () => {},
- prune: () => {},
- dispose: () => {},
- decline: () => {},
- invalidate: () => {},
- on: () => {},
- send: () => {}
- };
- },
- updateStyle: () => {},
- removeStyle: () => {}
-};
-function getDefaultRequestStubs(context) {
- if (!context) {
- const clientStub = {
- ...defaultClientStub,
- updateStyle,
- removeStyle
- };
- return { "/@vite/client": clientStub };
- }
- const clientStub = vm.runInContext(`(defaultClient) => ({ ...defaultClient, updateStyle: ${updateStyle.toString()}, removeStyle: ${removeStyle.toString()} })`, context)(defaultClientStub);
- return { "/@vite/client": clientStub };
-}
-function exportAll(exports$1, sourceModule) {
- // #1120 when a module exports itself it causes
- // call stack error
- if (exports$1 === sourceModule) return;
- if (isPrimitive(sourceModule) || Array.isArray(sourceModule) || sourceModule instanceof Promise) return;
- for (const key in sourceModule) if (key !== "default" && !(key in exports$1)) try {
- defineExport(exports$1, key, () => sourceModule[key]);
- } catch {}
-}
-// keep consistency with Vite on how exports are defined
-function defineExport(exports$1, key, value) {
- Object.defineProperty(exports$1, key, {
- enumerable: true,
- configurable: true,
- get: value
- });
-}
-function isPrimitive(v) {
- return !(typeof v === "object" || typeof v === "function") || v == null;
-}
-function interopModule(mod) {
- if (isPrimitive(mod)) return {
- mod: { default: mod },
- defaultExport: mod
- };
- let defaultExport = "default" in mod ? mod.default : mod;
- if (!isPrimitive(defaultExport) && "__esModule" in defaultExport) {
- mod = defaultExport;
- if ("default" in defaultExport) defaultExport = defaultExport.default;
- }
- return {
- mod,
- defaultExport
- };
-}
-const VALID_ID_PREFIX = `/@id/`;
-const NULL_BYTE_PLACEHOLDER = `__x00__`;
-function wrapId(id) {
- return id.startsWith(VALID_ID_PREFIX) ? id : VALID_ID_PREFIX + id.replace("\0", NULL_BYTE_PLACEHOLDER);
-}
-function unwrapId(id) {
- return id.startsWith(VALID_ID_PREFIX) ? id.slice(VALID_ID_PREFIX.length).replace(NULL_BYTE_PLACEHOLDER, "\0") : id;
-}
-
-export { VitestModuleEvaluator, createImportMetaEnvProxy, getDefaultRequestStubs, isPrimitive, unwrapId, wrapId };
diff --git a/vanilla/node_modules/vitest/dist/module-runner.js b/vanilla/node_modules/vitest/dist/module-runner.js
deleted file mode 100644
index 38a46b5..0000000
--- a/vanilla/node_modules/vitest/dist/module-runner.js
+++ /dev/null
@@ -1,17 +0,0 @@
-export { VitestModuleEvaluator } from './module-evaluator.js';
-export { a as VITEST_VM_CONTEXT_SYMBOL, V as VitestModuleRunner, s as startVitestModuleRunner } from './chunks/startModuleRunner.DEj0jb3e.js';
-export { g as getWorkerState } from './chunks/utils.DvEY5TfP.js';
-import 'node:module';
-import 'node:url';
-import 'node:vm';
-import 'vite/module-runner';
-import './chunks/traces.CCmnQaNT.js';
-import 'node:fs';
-import '@vitest/utils/helpers';
-import './chunks/modules.BJuCwlRJ.js';
-import 'pathe';
-import './path.js';
-import 'node:path';
-import '@vitest/utils/serialize';
-import '@vitest/mocker';
-import '@vitest/utils/timers';
diff --git a/vanilla/node_modules/vitest/dist/node.d.ts b/vanilla/node_modules/vitest/dist/node.d.ts
deleted file mode 100644
index 0295c1c..0000000
--- a/vanilla/node_modules/vitest/dist/node.d.ts
+++ /dev/null
@@ -1,251 +0,0 @@
-import * as vite from 'vite';
-import { InlineConfig, UserConfig as UserConfig$1, Plugin, ResolvedConfig as ResolvedConfig$1, ViteDevServer, LogLevel, LoggerOptions, Logger as Logger$1 } from 'vite';
-export { vite as Vite };
-export { esbuildVersion, isCSSRequest, isFileLoadingAllowed, parseAst, parseAstAsync, rollupVersion, version as viteVersion } from 'vite';
-import { IncomingMessage } from 'node:http';
-import { h as ResolvedConfig, f as UserConfig, i as VitestRunMode, j as VitestOptions, V as Vitest, A as ApiConfig, k as TestSpecification, T as TestProject, P as PoolWorker, l as PoolOptions, m as WorkerRequest, n as TestSequencer, L as Logger } from './chunks/reporters.d.CWXNI2jG.js';
-export { at as BaseCoverageOptions, Y as BenchmarkUserOptions, Z as BrowserBuiltinProvider, $ as BrowserCommand, a0 as BrowserCommandContext, a1 as BrowserConfigOptions, a2 as BrowserInstanceOption, a3 as BrowserModuleMocker, a4 as BrowserOrchestrator, a5 as BrowserProvider, a6 as BrowserProviderOption, a7 as BrowserScript, a8 as BrowserServerFactory, a9 as BrowserServerOptions, aa as BrowserServerState, ab as BrowserServerStateSession, ai as BuiltinEnvironment, ac as CDPSession, aj as CSSModuleScopeStrategy, au as CoverageIstanbulOptions, av as CoverageOptions, aw as CoverageProvider, ax as CoverageProviderModule, ay as CoverageReporter, c as CoverageV8Options, az as CustomProviderOptions, ak as DepsOptimizationOptions, al as EnvironmentOptions, H as HTMLOptions, I as InlineConfig, t as JUnitOptions, J as JsonOptions, M as ModuleDiagnostic, O as OnServerRestartHandler, o as OnTestsRerunHandler, ad as ParentProjectBrowser, am as Pool, q as PoolRunnerInitializer, r as PoolTask, ae as ProjectBrowser, an as ProjectConfig, a as ReportContext, aB as ReportedHookContext, aC as Reporter, ap as ResolveSnapshotPathHandler, aq as ResolveSnapshotPathHandlerContext, af as ResolvedBrowserOptions, R as ResolvedCoverageOptions, ao as ResolvedProjectConfig, S as SerializedTestProject, u as TaskOptions, v as TestCase, w as TestCollection, x as TestDiagnostic, y as TestModule, z as TestModuleState, B as TestResult, D as TestResultFailed, E as TestResultPassed, F as TestResultSkipped, aD as TestRunEndReason, aA as TestRunResult, X as TestSequencerConstructor, G as TestState, K as TestSuite, N as TestSuiteState, ag as ToMatchScreenshotComparators, ah as ToMatchScreenshotOptions, ar as TypecheckConfig, U as UserWorkspaceConfig, as as VitestEnvironment, p as VitestPackageInstaller, W as WatcherTriggerPattern, s as WorkerResponse, _ as _BrowserNames, Q as experimental_getRunnerTask } from './chunks/reporters.d.CWXNI2jG.js';
-export { C as CacheKeyIdGenerator, a as CacheKeyIdGeneratorContext, V as VitestPluginContext } from './chunks/plugin.d.CtqpEehP.js';
-import { Awaitable } from '@vitest/utils';
-export { SerializedError } from '@vitest/utils';
-import { R as RuntimeRPC } from './chunks/rpc.d.RH3apGEf.js';
-import { Writable } from 'node:stream';
-import { C as ContextRPC } from './chunks/worker.d.Dyxm8DEL.js';
-export { T as TestExecutionType } from './chunks/worker.d.Dyxm8DEL.js';
-import { Debugger } from 'obug';
-import './chunks/global.d.B15mdLcR.js';
-export { Task as RunnerTask, TaskResult as RunnerTaskResult, TaskResultPack as RunnerTaskResultPack, Test as RunnerTestCase, File as RunnerTestFile, Suite as RunnerTestSuite, SequenceHooks, SequenceSetupFiles } from '@vitest/runner';
-export { b as RuntimeConfig } from './chunks/config.d.Cy95HiCx.js';
-export { generateFileHash } from '@vitest/runner/utils';
-import './chunks/browser.d.ChKACdzH.js';
-import './chunks/traces.d.402V_yFI.js';
-import '@vitest/mocker';
-import '@vitest/utils/source-map';
-import 'vitest/browser';
-import '@vitest/pretty-format';
-import '@vitest/snapshot';
-import '@vitest/utils/diff';
-import '@vitest/expect';
-import 'vitest/optional-types.js';
-import './chunks/benchmark.d.DAaHLpsq.js';
-import 'tinybench';
-import './chunks/coverage.d.BZtK59WP.js';
-import '@vitest/snapshot/manager';
-import 'node:console';
-import 'node:fs';
-import 'vite/module-runner';
-import './chunks/environment.d.CrsxCzP1.js';
-
-type RawErrsMap = Map<string, TscErrorInfo[]>;
-interface TscErrorInfo {
- filePath: string;
- errCode: number;
- errMsg: string;
- line: number;
- column: number;
-}
-interface CollectLineNumbers {
- target: number;
- next: number;
- prev?: number;
-}
-type CollectLines = { [key in keyof CollectLineNumbers] : string };
-interface RootAndTarget {
- root: string;
- targetAbsPath: string;
-}
-type Context = RootAndTarget & {
- rawErrsMap: RawErrsMap;
- openedDirs: Set<string>;
- lastActivePath?: string;
-};
-
-declare function isValidApiRequest(config: ResolvedConfig, req: IncomingMessage): boolean;
-
-declare function escapeTestName(label: string, dynamic: boolean): string;
-
-interface CliOptions extends UserConfig {
- /**
- * Override the watch mode
- */
- run?: boolean;
- /**
- * Removes colors from the console output
- */
- color?: boolean;
- /**
- * Output collected tests as JSON or to a file
- */
- json?: string | boolean;
- /**
- * Output collected test files only
- */
- filesOnly?: boolean;
- /**
- * Override vite config's configLoader from cli.
- * Use `bundle` to bundle the config with esbuild or `runner` (experimental) to process it on the fly (default: `bundle`).
- * This is only available with **vite version 6.1.0** and above.
- * @experimental
- */
- configLoader?: InlineConfig extends {
- configLoader?: infer T;
- } ? T : never;
-}
-/**
-* Start Vitest programmatically
-*
-* Returns a Vitest instance if initialized successfully.
-*/
-declare function startVitest(mode: VitestRunMode, cliFilters?: string[], options?: CliOptions, viteOverrides?: UserConfig$1, vitestOptions?: VitestOptions): Promise<Vitest>;
-
-interface CliParseOptions {
- allowUnknownOptions?: boolean;
-}
-declare function parseCLI(argv: string | string[], config?: CliParseOptions): {
- filter: string[];
- options: CliOptions;
-};
-
-declare function resolveApiServerConfig<Options extends ApiConfig & Omit<UserConfig, "expect">>(options: Options, defaultPort: number): ApiConfig | undefined;
-
-declare function createVitest(mode: VitestRunMode, options: CliOptions, viteOverrides?: UserConfig$1, vitestOptions?: VitestOptions): Promise<Vitest>;
-
-declare class FilesNotFoundError extends Error {
- code: string;
- constructor(mode: "test" | "benchmark");
-}
-declare class GitNotFoundError extends Error {
- code: string;
- constructor();
-}
-
-declare function VitestPlugin(options?: UserConfig, vitest?: Vitest): Promise<Plugin[]>;
-
-declare function resolveConfig(options?: UserConfig, viteOverrides?: UserConfig$1): Promise<{
- vitestConfig: ResolvedConfig;
- viteConfig: ResolvedConfig$1;
-}>;
-
-declare function resolveFsAllow(projectRoot: string, rootConfigFile: string | false | undefined): string[];
-
-type RunWithFiles = (files: TestSpecification[], invalidates?: string[]) => Promise<void>;
-interface ProcessPool {
- name: string;
- runTests: RunWithFiles;
- collectTests: RunWithFiles;
- close?: () => Awaitable<void>;
-}
-declare function getFilePoolName(project: TestProject): ResolvedConfig["pool"];
-
-interface MethodsOptions {
- cacheFs?: boolean;
- collect?: boolean;
-}
-declare function createMethodsRPC(project: TestProject, methodsOptions?: MethodsOptions): RuntimeRPC;
-
-/** @experimental */
-declare class ForksPoolWorker implements PoolWorker {
- readonly name: string;
- readonly cacheFs: boolean;
- protected readonly entrypoint: string;
- protected execArgv: string[];
- protected env: Partial<NodeJS.ProcessEnv>;
- private _fork?;
- private stdout;
- private stderr;
- constructor(options: PoolOptions);
- on(event: string, callback: (arg: any) => void): void;
- off(event: string, callback: (arg: any) => void): void;
- send(message: WorkerRequest): void;
- start(): Promise<void>;
- stop(): Promise<void>;
- deserialize(data: unknown): unknown;
- private get fork();
-}
-
-/** @experimental */
-declare class ThreadsPoolWorker implements PoolWorker {
- readonly name: string;
- protected readonly entrypoint: string;
- protected execArgv: string[];
- protected env: Partial<NodeJS.ProcessEnv>;
- private _thread?;
- private stdout;
- private stderr;
- constructor(options: PoolOptions);
- on(event: string, callback: (arg: any) => void): void;
- off(event: string, callback: (arg: any) => void): void;
- send(message: WorkerRequest): void;
- start(): Promise<void>;
- stop(): Promise<void>;
- deserialize(data: unknown): unknown;
- private get thread();
-}
-
-/** @experimental */
-declare class TypecheckPoolWorker implements PoolWorker {
- readonly name: string;
- private readonly project;
- private _eventEmitter;
- constructor(options: PoolOptions);
- start(): Promise<void>;
- stop(): Promise<void>;
- canReuse(): boolean;
- send(message: WorkerRequest): void;
- on(event: string, callback: (arg: any) => any): void;
- off(event: string, callback: (arg: any) => any): void;
- deserialize(data: unknown): unknown;
-}
-
-/** @experimental */
-declare class VmForksPoolWorker extends ForksPoolWorker {
- readonly name = "vmForks";
- readonly reportMemory: true;
- protected readonly entrypoint: string;
- constructor(options: PoolOptions);
- canReuse(): boolean;
-}
-
-/** @experimental */
-declare class VmThreadsPoolWorker extends ThreadsPoolWorker {
- readonly name = "vmThreads";
- readonly reportMemory: true;
- protected readonly entrypoint: string;
- constructor(options: PoolOptions);
- canReuse(): boolean;
-}
-
-declare class BaseSequencer implements TestSequencer {
- protected ctx: Vitest;
- constructor(ctx: Vitest);
- shard(files: TestSpecification[]): Promise<TestSpecification[]>;
- sort(files: TestSpecification[]): Promise<TestSpecification[]>;
- private calculateShardRange;
-}
-
-declare function registerConsoleShortcuts(ctx: Vitest, stdin: NodeJS.ReadStream | undefined, stdout: NodeJS.WriteStream | Writable): () => void;
-
-interface WorkerContext extends ContextRPC {}
-
-/**
-* Check if the url is allowed to be served, via the `server.fs` config.
-* @deprecated Use the `isFileLoadingAllowed` function instead.
-*/
-declare function isFileServingAllowed(config: ResolvedConfig$1, url: string): boolean;
-declare function isFileServingAllowed(url: string, server: ViteDevServer): boolean;
-
-declare function createViteLogger(console: Logger, level?: LogLevel, options?: LoggerOptions): Logger$1;
-
-declare const rootDir: string;
-declare const distDir: string;
-
-declare function createDebugger(namespace: `vitest:${string}`): Debugger | undefined;
-
-declare const version: string;
-
-declare const createViteServer: typeof vite.createServer;
-
-declare const rolldownVersion: string | undefined;
-
-export { ApiConfig, BaseSequencer, ForksPoolWorker, GitNotFoundError, PoolOptions, PoolWorker, ResolvedConfig, TestProject, TestSequencer, TestSpecification, UserConfig as TestUserConfig, FilesNotFoundError as TestsNotFoundError, ThreadsPoolWorker, TypecheckPoolWorker, Vitest, VitestOptions, VitestPlugin, VitestRunMode, VmForksPoolWorker, VmThreadsPoolWorker, WorkerRequest, createDebugger, createMethodsRPC, createViteLogger, createViteServer, createVitest, distDir, escapeTestName, getFilePoolName, isFileServingAllowed, isValidApiRequest, parseCLI, registerConsoleShortcuts, resolveApiServerConfig, resolveConfig, resolveFsAllow, rolldownVersion, rootDir, startVitest, version };
-export type { CliOptions, CliParseOptions, ProcessPool, CollectLineNumbers as TypeCheckCollectLineNumbers, CollectLines as TypeCheckCollectLines, Context as TypeCheckContext, TscErrorInfo as TypeCheckErrorInfo, RawErrsMap as TypeCheckRawErrorsMap, RootAndTarget as TypeCheckRootAndTarget, WorkerContext };
diff --git a/vanilla/node_modules/vitest/dist/node.js b/vanilla/node_modules/vitest/dist/node.js
deleted file mode 100644
index 5d786b1..0000000
--- a/vanilla/node_modules/vitest/dist/node.js
+++ /dev/null
@@ -1,98 +0,0 @@
-import * as vite from 'vite';
-import { resolveConfig as resolveConfig$1, mergeConfig } from 'vite';
-export { esbuildVersion, isCSSRequest, isFileLoadingAllowed, parseAst, parseAstAsync, rollupVersion, version as viteVersion } from 'vite';
-import { V as Vitest, a as VitestPlugin } from './chunks/cli-api.B7PN_QUv.js';
-export { f as ForksPoolWorker, G as GitNotFoundError, F as TestsNotFoundError, T as ThreadsPoolWorker, h as TypecheckPoolWorker, b as VitestPackageInstaller, j as VmForksPoolWorker, k as VmThreadsPoolWorker, p as createDebugger, d as createMethodsRPC, o as createViteLogger, c as createVitest, e as escapeTestName, l as experimental_getRunnerTask, g as getFilePoolName, n as isFileServingAllowed, i as isValidApiRequest, m as registerConsoleShortcuts, r as resolveFsAllow, s as startVitest } from './chunks/cli-api.B7PN_QUv.js';
-export { p as parseCLI } from './chunks/cac.DVeoLl0M.js';
-import { r as resolveConfig$2 } from './chunks/coverage.AVPTjMgw.js';
-export { b as BaseSequencer, a as resolveApiServerConfig } from './chunks/coverage.AVPTjMgw.js';
-import { slash, deepClone } from '@vitest/utils/helpers';
-import { a as any } from './chunks/index.D4KonVSU.js';
-import { resolve } from 'pathe';
-import { c as configFiles } from './chunks/constants.D_Q9UYh-.js';
-export { distDir, rootDir } from './path.js';
-export { generateFileHash } from '@vitest/runner/utils';
-import 'node:fs';
-import './chunks/coverage.D_JHT54q.js';
-import 'node:path';
-import 'node:os';
-import '@vitest/snapshot/manager';
-import 'node:perf_hooks';
-import './chunks/index.Chj8NDwU.js';
-import './chunks/index.M8mOzt4Y.js';
-import 'node:fs/promises';
-import '@vitest/utils/source-map';
-import 'tinyrainbow';
-import './chunks/env.D4Lgay0q.js';
-import 'std-env';
-import 'node:util';
-import 'node:console';
-import 'node:stream';
-import '@vitest/utils/display';
-import 'tinyexec';
-import '@vitest/utils/offset';
-import 'node:module';
-import 'events';
-import 'https';
-import 'http';
-import 'net';
-import 'tls';
-import 'crypto';
-import 'stream';
-import 'url';
-import 'zlib';
-import 'buffer';
-import './chunks/_commonjsHelpers.D26ty3Ew.js';
-import 'node:crypto';
-import './chunks/traces.CCmnQaNT.js';
-import 'obug';
-import '#module-evaluator';
-import 'vite/module-runner';
-import '@vitest/utils/highlight';
-import 'node:url';
-import 'node:tty';
-import 'node:events';
-import './chunks/modules.BJuCwlRJ.js';
-import 'node:child_process';
-import 'node:worker_threads';
-import 'picomatch';
-import 'tinyglobby';
-import 'magic-string';
-import '@vitest/mocker/node';
-import './chunks/defaults.BOqNVLsY.js';
-import '@vitest/utils/constants';
-import '@vitest/utils/resolver';
-import 'es-module-lexer';
-import './chunks/index.C5r1PdPD.js';
-import 'node:assert';
-import '@vitest/utils/serialize';
-import 'node:readline';
-import 'node:process';
-import 'node:v8';
-import 'readline';
-
-// this is only exported as a public function and not used inside vitest
-async function resolveConfig(options = {}, viteOverrides = {}) {
- const root = slash(resolve(options.root || process.cwd()));
- const configPath = options.config === false ? false : options.config ? resolve(root, options.config) : any(configFiles, { cwd: root });
- options.config = configPath;
- const vitest = new Vitest("test", deepClone(options));
- const config = await resolveConfig$1(mergeConfig({
- configFile: configPath,
- mode: options.mode || "test",
- plugins: [await VitestPlugin(options, vitest)]
- }, mergeConfig(viteOverrides, { root: options.root })), "serve");
- const vitestConfig = resolveConfig$2(vitest, Reflect.get(config, "_vitest"), config);
- await vitest.close();
- return {
- viteConfig: config,
- vitestConfig
- };
-}
-
-const version = Vitest.version;
-const createViteServer = vite.createServer;
-// rolldownVersion is exported only by rolldown-vite
-const rolldownVersion = vite.rolldownVersion;
-
-export { VitestPlugin, createViteServer, resolveConfig, rolldownVersion, version };
diff --git a/vanilla/node_modules/vitest/dist/path.js b/vanilla/node_modules/vitest/dist/path.js
deleted file mode 100644
index 0acf87b..0000000
--- a/vanilla/node_modules/vitest/dist/path.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { resolve } from 'node:path';
-import url from 'node:url';
-
-const rootDir = resolve(url.fileURLToPath(import.meta.url), "../../");
-const distDir = resolve(url.fileURLToPath(import.meta.url), "../../dist");
-
-export { distDir, rootDir };
diff --git a/vanilla/node_modules/vitest/dist/reporters.d.ts b/vanilla/node_modules/vitest/dist/reporters.d.ts
deleted file mode 100644
index 5185539..0000000
--- a/vanilla/node_modules/vitest/dist/reporters.d.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-export { aR as BaseReporter, aS as BenchmarkBuiltinReporters, aE as BenchmarkReporter, aF as BenchmarkReportsMap, aT as BuiltinReporterOptions, aU as BuiltinReporters, aG as DefaultReporter, aH as DotReporter, aI as GithubActionsReporter, aJ as HangingProcessReporter, aL as JUnitReporter, aV as JsonAssertionResult, aK as JsonReporter, aW as JsonTestResult, aX as JsonTestResults, aB as ReportedHookContext, aC as Reporter, aM as ReportersMap, aN as TapFlatReporter, aO as TapReporter, aD as TestRunEndReason, aP as VerboseBenchmarkReporter, aQ as VerboseReporter } from './chunks/reporters.d.CWXNI2jG.js';
-import '@vitest/runner';
-import '@vitest/utils';
-import './chunks/rpc.d.RH3apGEf.js';
-import '@vitest/snapshot';
-import 'vite/module-runner';
-import './chunks/traces.d.402V_yFI.js';
-import 'node:stream';
-import 'vite';
-import './chunks/browser.d.ChKACdzH.js';
-import './chunks/worker.d.Dyxm8DEL.js';
-import './chunks/config.d.Cy95HiCx.js';
-import '@vitest/pretty-format';
-import '@vitest/utils/diff';
-import './chunks/environment.d.CrsxCzP1.js';
-import '@vitest/mocker';
-import '@vitest/utils/source-map';
-import 'vitest/browser';
-import '@vitest/expect';
-import 'vitest/optional-types.js';
-import './chunks/benchmark.d.DAaHLpsq.js';
-import '@vitest/runner/utils';
-import 'tinybench';
-import './chunks/coverage.d.BZtK59WP.js';
-import '@vitest/snapshot/manager';
-import 'node:console';
-import 'node:fs';
diff --git a/vanilla/node_modules/vitest/dist/reporters.js b/vanilla/node_modules/vitest/dist/reporters.js
deleted file mode 100644
index 6ea7b9e..0000000
--- a/vanilla/node_modules/vitest/dist/reporters.js
+++ /dev/null
@@ -1,24 +0,0 @@
-export { D as DefaultReporter, a as DotReporter, G as GithubActionsReporter, H as HangingProcessReporter, b as JUnitReporter, J as JsonReporter, R as ReportersMap, T as TapFlatReporter, c as TapReporter, V as VerboseReporter } from './chunks/index.M8mOzt4Y.js';
-export { B as BenchmarkReporter, a as BenchmarkReportsMap, V as VerboseBenchmarkReporter } from './chunks/index.C5r1PdPD.js';
-import 'node:fs';
-import 'node:fs/promises';
-import 'pathe';
-import 'node:perf_hooks';
-import '@vitest/runner/utils';
-import '@vitest/utils/helpers';
-import '@vitest/utils/source-map';
-import 'tinyrainbow';
-import './chunks/env.D4Lgay0q.js';
-import 'std-env';
-import 'node:util';
-import 'node:console';
-import 'node:stream';
-import '@vitest/utils/display';
-import 'node:os';
-import 'tinyexec';
-import './path.js';
-import 'node:path';
-import 'node:url';
-import 'vite';
-import '@vitest/utils/offset';
-import 'node:module';
diff --git a/vanilla/node_modules/vitest/dist/runners.d.ts b/vanilla/node_modules/vitest/dist/runners.d.ts
deleted file mode 100644
index 20f7584..0000000
--- a/vanilla/node_modules/vitest/dist/runners.d.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import * as tinybench from 'tinybench';
-import { VitestRunner, VitestRunnerImportSource, Suite, File, Task, CancelReason, Test, TestContext, ImportDuration } from '@vitest/runner';
-export { VitestRunner } from '@vitest/runner';
-import { S as SerializedConfig } from './chunks/config.d.Cy95HiCx.js';
-import { T as Traces } from './chunks/traces.d.402V_yFI.js';
-import '@vitest/pretty-format';
-import '@vitest/snapshot';
-import '@vitest/utils/diff';
-
-declare class NodeBenchmarkRunner implements VitestRunner {
- config: SerializedConfig;
- private moduleRunner;
- constructor(config: SerializedConfig);
- importTinybench(): Promise<typeof tinybench>;
- importFile(filepath: string, source: VitestRunnerImportSource): unknown;
- runSuite(suite: Suite): Promise<void>;
- runTask(): Promise<void>;
-}
-
-declare class VitestTestRunner implements VitestRunner {
- config: SerializedConfig;
- private snapshotClient;
- private workerState;
- private moduleRunner;
- private cancelRun;
- private assertionsErrors;
- pool: string;
- private _otel;
- viteEnvironment: string;
- constructor(config: SerializedConfig);
- importFile(filepath: string, source: VitestRunnerImportSource): unknown;
- onCollectStart(file: File): void;
- onCleanupWorkerContext(listener: () => unknown): void;
- onAfterRunFiles(): void;
- getWorkerContext(): Record<string, unknown>;
- onAfterRunSuite(suite: Suite): Promise<void>;
- onAfterRunTask(test: Task): void;
- cancel(_reason: CancelReason): void;
- injectValue(key: string): any;
- onBeforeRunTask(test: Task): Promise<void>;
- onBeforeRunSuite(suite: Suite): Promise<void>;
- onBeforeTryTask(test: Task): void;
- onAfterTryTask(test: Test): void;
- extendTaskContext(context: TestContext): TestContext;
- getImportDurations(): Record<string, ImportDuration>;
- trace: <T>(name: string, attributes: Record<string, any> | (() => T), cb?: () => T) => T;
- __setTraces(traces: Traces): void;
-}
-
-export { NodeBenchmarkRunner, VitestTestRunner };
diff --git a/vanilla/node_modules/vitest/dist/runners.js b/vanilla/node_modules/vitest/dist/runners.js
deleted file mode 100644
index 5447710..0000000
--- a/vanilla/node_modules/vitest/dist/runners.js
+++ /dev/null
@@ -1,19 +0,0 @@
-export { N as NodeBenchmarkRunner, V as VitestTestRunner } from './chunks/test.B8ej_ZHS.js';
-import '@vitest/runner';
-import '@vitest/utils/helpers';
-import '@vitest/utils/timers';
-import './chunks/benchmark.B3N2zMcH.js';
-import '@vitest/runner/utils';
-import './chunks/utils.DvEY5TfP.js';
-import '@vitest/expect';
-import '@vitest/utils/error';
-import 'pathe';
-import './chunks/vi.2VT5v0um.js';
-import '@vitest/snapshot';
-import '@vitest/spy';
-import '@vitest/utils/offset';
-import '@vitest/utils/source-map';
-import './chunks/_commonjsHelpers.D26ty3Ew.js';
-import './chunks/date.Bq6ZW5rf.js';
-import './chunks/rpc.BoxB0q7B.js';
-import './chunks/index.Chj8NDwU.js';
diff --git a/vanilla/node_modules/vitest/dist/snapshot.d.ts b/vanilla/node_modules/vitest/dist/snapshot.d.ts
deleted file mode 100644
index 966a627..0000000
--- a/vanilla/node_modules/vitest/dist/snapshot.d.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { NodeSnapshotEnvironment } from '@vitest/snapshot/environment';
-export { SnapshotEnvironment } from '@vitest/snapshot/environment';
-
-declare class VitestNodeSnapshotEnvironment extends NodeSnapshotEnvironment {
- getHeader(): string;
- resolvePath(filepath: string): Promise<string>;
-}
-
-export { VitestNodeSnapshotEnvironment as VitestSnapshotEnvironment };
diff --git a/vanilla/node_modules/vitest/dist/snapshot.js b/vanilla/node_modules/vitest/dist/snapshot.js
deleted file mode 100644
index c4c2430..0000000
--- a/vanilla/node_modules/vitest/dist/snapshot.js
+++ /dev/null
@@ -1,4 +0,0 @@
-export { VitestNodeSnapshotEnvironment as VitestSnapshotEnvironment } from './chunks/node.Ce0vMQM7.js';
-import '@vitest/snapshot/environment';
-import './chunks/utils.DvEY5TfP.js';
-import '@vitest/utils/timers';
diff --git a/vanilla/node_modules/vitest/dist/spy.js b/vanilla/node_modules/vitest/dist/spy.js
deleted file mode 100644
index d2b1e1d..0000000
--- a/vanilla/node_modules/vitest/dist/spy.js
+++ /dev/null
@@ -1 +0,0 @@
-export * from '@vitest/spy';
diff --git a/vanilla/node_modules/vitest/dist/suite.d.ts b/vanilla/node_modules/vitest/dist/suite.d.ts
deleted file mode 100644
index a34ed3d..0000000
--- a/vanilla/node_modules/vitest/dist/suite.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export { g as getBenchFn, a as getBenchOptions } from './chunks/suite.d.BJWk38HB.js';
-export { VitestRunner, VitestRunnerConfig, createTaskCollector, getCurrentSuite, getCurrentTest, getFn, getHooks, setFn, setHooks } from '@vitest/runner';
-export { createChainable } from '@vitest/runner/utils';
-import './chunks/benchmark.d.DAaHLpsq.js';
-import 'tinybench';
diff --git a/vanilla/node_modules/vitest/dist/suite.js b/vanilla/node_modules/vitest/dist/suite.js
deleted file mode 100644
index f65cebc..0000000
--- a/vanilla/node_modules/vitest/dist/suite.js
+++ /dev/null
@@ -1,6 +0,0 @@
-export { g as getBenchFn, a as getBenchOptions } from './chunks/benchmark.B3N2zMcH.js';
-export { createTaskCollector, getCurrentSuite, getCurrentTest, getFn, getHooks, setFn, setHooks } from '@vitest/runner';
-export { createChainable } from '@vitest/runner/utils';
-import '@vitest/utils/helpers';
-import './chunks/utils.DvEY5TfP.js';
-import '@vitest/utils/timers';
diff --git a/vanilla/node_modules/vitest/dist/worker.d.ts b/vanilla/node_modules/vitest/dist/worker.d.ts
deleted file mode 100644
index 03ceeb0..0000000
--- a/vanilla/node_modules/vitest/dist/worker.d.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { W as WorkerGlobalState, a as WorkerSetupContext, B as BirpcOptions } from './chunks/worker.d.Dyxm8DEL.js';
-import { T as Traces } from './chunks/traces.d.402V_yFI.js';
-import { Awaitable } from '@vitest/utils';
-import { ModuleRunner } from 'vite/module-runner';
-import { R as RuntimeRPC } from './chunks/rpc.d.RH3apGEf.js';
-import '@vitest/runner';
-import './chunks/config.d.Cy95HiCx.js';
-import '@vitest/pretty-format';
-import '@vitest/snapshot';
-import '@vitest/utils/diff';
-import './chunks/environment.d.CrsxCzP1.js';
-
-/** @experimental */
-declare function setupEnvironment(context: WorkerSetupContext): Promise<() => Promise<void>>;
-/** @experimental */
-declare function runBaseTests(method: "run" | "collect", state: WorkerGlobalState, traces: Traces): Promise<void>;
-
-type WorkerRpcOptions = Pick<BirpcOptions<RuntimeRPC>, "on" | "off" | "post" | "serialize" | "deserialize">;
-interface VitestWorker extends WorkerRpcOptions {
- runTests: (state: WorkerGlobalState, traces: Traces) => Awaitable<unknown>;
- collectTests: (state: WorkerGlobalState, traces: Traces) => Awaitable<unknown>;
- onModuleRunner?: (moduleRunner: ModuleRunner) => Awaitable<unknown>;
- setup?: (context: WorkerSetupContext) => Promise<() => Promise<unknown>>;
-}
-
-interface Options extends VitestWorker {
- teardown?: () => void;
-}
-/** @experimental */
-declare function init(worker: Options): void;
-
-export { init, runBaseTests, setupEnvironment };
diff --git a/vanilla/node_modules/vitest/dist/worker.js b/vanilla/node_modules/vitest/dist/worker.js
deleted file mode 100644
index fe30578..0000000
--- a/vanilla/node_modules/vitest/dist/worker.js
+++ /dev/null
@@ -1,48 +0,0 @@
-export { r as runBaseTests, s as setupEnvironment } from './chunks/base.CJ0Y4ePK.js';
-export { i as init } from './chunks/init.B6MLFIaN.js';
-import 'node:vm';
-import '@vitest/spy';
-import './chunks/index.6Qv1eEA6.js';
-import '@vitest/expect';
-import './chunks/setup-common.Cm-kSBVi.js';
-import './chunks/coverage.D_JHT54q.js';
-import '@vitest/snapshot';
-import '@vitest/utils/timers';
-import './chunks/utils.DvEY5TfP.js';
-import './chunks/rpc.BoxB0q7B.js';
-import './chunks/index.Chj8NDwU.js';
-import './chunks/test.B8ej_ZHS.js';
-import '@vitest/runner';
-import '@vitest/utils/helpers';
-import './chunks/benchmark.B3N2zMcH.js';
-import '@vitest/runner/utils';
-import '@vitest/utils/error';
-import 'pathe';
-import './chunks/vi.2VT5v0um.js';
-import '@vitest/utils/offset';
-import '@vitest/utils/source-map';
-import './chunks/_commonjsHelpers.D26ty3Ew.js';
-import './chunks/date.Bq6ZW5rf.js';
-import './chunks/evaluatedModules.Dg1zASAC.js';
-import 'vite/module-runner';
-import './chunks/startModuleRunner.DEj0jb3e.js';
-import 'node:fs';
-import './chunks/modules.BJuCwlRJ.js';
-import 'node:module';
-import 'node:url';
-import './path.js';
-import 'node:path';
-import '@vitest/utils/serialize';
-import './module-evaluator.js';
-import './chunks/traces.CCmnQaNT.js';
-import '@vitest/mocker';
-import 'node:perf_hooks';
-import './chunks/inspector.CvyFGlXm.js';
-import 'node:timers';
-import 'node:timers/promises';
-import 'node:util';
-import '@vitest/utils/constants';
-import './chunks/index.Z5E_ObnR.js';
-import 'expect-type';
-import './chunks/index.CyBMJtT7.js';
-import 'node:console';
diff --git a/vanilla/node_modules/vitest/dist/workers/forks.js b/vanilla/node_modules/vitest/dist/workers/forks.js
deleted file mode 100644
index 676b2ce..0000000
--- a/vanilla/node_modules/vitest/dist/workers/forks.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import { r as runBaseTests, s as setupEnvironment } from '../chunks/base.CJ0Y4ePK.js';
-import { w as workerInit } from '../chunks/init-forks._y3TW739.js';
-import 'node:vm';
-import '@vitest/spy';
-import '../chunks/index.6Qv1eEA6.js';
-import '@vitest/expect';
-import '../chunks/setup-common.Cm-kSBVi.js';
-import '../chunks/coverage.D_JHT54q.js';
-import '@vitest/snapshot';
-import '@vitest/utils/timers';
-import '../chunks/utils.DvEY5TfP.js';
-import '../chunks/rpc.BoxB0q7B.js';
-import '../chunks/index.Chj8NDwU.js';
-import '../chunks/test.B8ej_ZHS.js';
-import '@vitest/runner';
-import '@vitest/utils/helpers';
-import '../chunks/benchmark.B3N2zMcH.js';
-import '@vitest/runner/utils';
-import '@vitest/utils/error';
-import 'pathe';
-import '../chunks/vi.2VT5v0um.js';
-import '@vitest/utils/offset';
-import '@vitest/utils/source-map';
-import '../chunks/_commonjsHelpers.D26ty3Ew.js';
-import '../chunks/date.Bq6ZW5rf.js';
-import '../chunks/init.B6MLFIaN.js';
-import 'node:fs';
-import 'node:module';
-import 'node:url';
-import 'vite/module-runner';
-import '../chunks/startModuleRunner.DEj0jb3e.js';
-import '../chunks/modules.BJuCwlRJ.js';
-import '../path.js';
-import 'node:path';
-import '@vitest/utils/serialize';
-import '../module-evaluator.js';
-import '../chunks/traces.CCmnQaNT.js';
-import '@vitest/mocker';
-import '../chunks/index.CyBMJtT7.js';
-import 'node:console';
-import '../chunks/inspector.CvyFGlXm.js';
-import '../chunks/evaluatedModules.Dg1zASAC.js';
-import 'node:perf_hooks';
-import 'node:timers';
-import 'node:timers/promises';
-import 'node:util';
-import '@vitest/utils/constants';
-import '../chunks/index.Z5E_ObnR.js';
-import 'expect-type';
-
-workerInit({
- runTests: runBaseTests,
- setup: setupEnvironment
-});
diff --git a/vanilla/node_modules/vitest/dist/workers/runVmTests.js b/vanilla/node_modules/vitest/dist/workers/runVmTests.js
deleted file mode 100644
index 84328b4..0000000
--- a/vanilla/node_modules/vitest/dist/workers/runVmTests.js
+++ /dev/null
@@ -1,95 +0,0 @@
-import { createRequire } from 'node:module';
-import { performance } from 'node:perf_hooks';
-import timers from 'node:timers';
-import timersPromises from 'node:timers/promises';
-import util from 'node:util';
-import { startTests, collectTests } from '@vitest/runner';
-import { KNOWN_ASSET_TYPES } from '@vitest/utils/constants';
-import { s as setupChaiConfig, r as resolveTestRunner, a as resolveSnapshotEnvironment } from '../chunks/index.6Qv1eEA6.js';
-import { c as setupCommonEnv, s as startCoverageInsideWorker, a as stopCoverageInsideWorker } from '../chunks/setup-common.Cm-kSBVi.js';
-import { i as index } from '../chunks/index.Z5E_ObnR.js';
-import { c as closeInspector } from '../chunks/inspector.CvyFGlXm.js';
-import { g as getWorkerState } from '../chunks/utils.DvEY5TfP.js';
-import { g as globalExpect } from '../chunks/vi.2VT5v0um.js';
-import '@vitest/expect';
-import '../chunks/rpc.BoxB0q7B.js';
-import '@vitest/utils/timers';
-import '../chunks/index.Chj8NDwU.js';
-import '../chunks/test.B8ej_ZHS.js';
-import '@vitest/utils/helpers';
-import '../chunks/benchmark.B3N2zMcH.js';
-import '@vitest/runner/utils';
-import '@vitest/utils/error';
-import 'pathe';
-import '../chunks/coverage.D_JHT54q.js';
-import '@vitest/snapshot';
-import '../chunks/evaluatedModules.Dg1zASAC.js';
-import 'vite/module-runner';
-import 'expect-type';
-import 'node:url';
-import '@vitest/spy';
-import '@vitest/utils/offset';
-import '@vitest/utils/source-map';
-import '../chunks/_commonjsHelpers.D26ty3Ew.js';
-import '../chunks/date.Bq6ZW5rf.js';
-
-async function run(method, files, config, moduleRunner, traces) {
- const workerState = getWorkerState();
- await traces.$("vitest.runtime.global_env", () => setupCommonEnv(config));
- Object.defineProperty(globalThis, "__vitest_index__", {
- value: index,
- enumerable: false
- });
- const viteEnvironment = workerState.environment.viteEnvironment || workerState.environment.name;
- globalExpect.setState({ environment: workerState.environment.name });
- if (viteEnvironment === "client") {
- const _require = createRequire(import.meta.url);
- // always mock "required" `css` files, because we cannot process them
- _require.extensions[".css"] = resolveCss;
- _require.extensions[".scss"] = resolveCss;
- _require.extensions[".sass"] = resolveCss;
- _require.extensions[".less"] = resolveCss;
- // since we are using Vite, we can assume how these will be resolved
- KNOWN_ASSET_TYPES.forEach((type) => {
- _require.extensions[`.${type}`] = resolveAsset;
- });
- process.env.SSR = "";
- } else process.env.SSR = "1";
- // @ts-expect-error not typed global for patched timers
- globalThis.__vitest_required__ = {
- util,
- timers,
- timersPromises
- };
- await traces.$("vitest.runtime.coverage.start", () => startCoverageInsideWorker(config.coverage, moduleRunner, { isolate: false }));
- if (config.chaiConfig) setupChaiConfig(config.chaiConfig);
- const [testRunner, snapshotEnvironment] = await Promise.all([traces.$("vitest.runtime.runner", () => resolveTestRunner(config, moduleRunner, traces)), traces.$("vitest.runtime.snapshot.environment", () => resolveSnapshotEnvironment(config, moduleRunner))]);
- config.snapshotOptions.snapshotEnvironment = snapshotEnvironment;
- testRunner.getWorkerContext = void 0;
- workerState.onCancel((reason) => {
- closeInspector(config);
- testRunner.cancel?.(reason);
- });
- workerState.durations.prepare = performance.now() - workerState.durations.prepare;
- const { vi } = index;
- await traces.$(`vitest.test.runner.${method}`, async () => {
- for (const file of files) {
- workerState.filepath = file.filepath;
- if (method === "run") await traces.$(`vitest.test.runner.${method}.module`, { attributes: { "code.file.path": file.filepath } }, () => startTests([file], testRunner));
- else await traces.$(`vitest.test.runner.${method}.module`, { attributes: { "code.file.path": file.filepath } }, () => collectTests([file], testRunner));
- // reset after tests, because user might call `vi.setConfig` in setupFile
- vi.resetConfig();
- // mocks should not affect different files
- vi.restoreAllMocks();
- }
- });
- await traces.$("vitest.runtime.coverage.stop", () => stopCoverageInsideWorker(config.coverage, moduleRunner, { isolate: false }));
-}
-function resolveCss(mod) {
- mod.exports = "";
-}
-function resolveAsset(mod, url) {
- mod.exports = url;
-}
-
-export { run };
diff --git a/vanilla/node_modules/vitest/dist/workers/threads.js b/vanilla/node_modules/vitest/dist/workers/threads.js
deleted file mode 100644
index 728087f..0000000
--- a/vanilla/node_modules/vitest/dist/workers/threads.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import { s as setupEnvironment, r as runBaseTests } from '../chunks/base.CJ0Y4ePK.js';
-import { w as workerInit } from '../chunks/init-threads.DBO2kn-p.js';
-import 'node:vm';
-import '@vitest/spy';
-import '../chunks/index.6Qv1eEA6.js';
-import '@vitest/expect';
-import '../chunks/setup-common.Cm-kSBVi.js';
-import '../chunks/coverage.D_JHT54q.js';
-import '@vitest/snapshot';
-import '@vitest/utils/timers';
-import '../chunks/utils.DvEY5TfP.js';
-import '../chunks/rpc.BoxB0q7B.js';
-import '../chunks/index.Chj8NDwU.js';
-import '../chunks/test.B8ej_ZHS.js';
-import '@vitest/runner';
-import '@vitest/utils/helpers';
-import '../chunks/benchmark.B3N2zMcH.js';
-import '@vitest/runner/utils';
-import '@vitest/utils/error';
-import 'pathe';
-import '../chunks/vi.2VT5v0um.js';
-import '@vitest/utils/offset';
-import '@vitest/utils/source-map';
-import '../chunks/_commonjsHelpers.D26ty3Ew.js';
-import '../chunks/date.Bq6ZW5rf.js';
-import '../chunks/init.B6MLFIaN.js';
-import 'node:fs';
-import 'node:module';
-import 'node:url';
-import 'vite/module-runner';
-import '../chunks/startModuleRunner.DEj0jb3e.js';
-import '../chunks/modules.BJuCwlRJ.js';
-import '../path.js';
-import 'node:path';
-import '@vitest/utils/serialize';
-import '../module-evaluator.js';
-import '../chunks/traces.CCmnQaNT.js';
-import '@vitest/mocker';
-import '../chunks/index.CyBMJtT7.js';
-import 'node:console';
-import '../chunks/inspector.CvyFGlXm.js';
-import '../chunks/evaluatedModules.Dg1zASAC.js';
-import 'node:perf_hooks';
-import 'node:timers';
-import 'node:timers/promises';
-import 'node:util';
-import '@vitest/utils/constants';
-import '../chunks/index.Z5E_ObnR.js';
-import 'expect-type';
-import 'node:worker_threads';
-
-workerInit({
- runTests: runBaseTests,
- setup: setupEnvironment
-});
diff --git a/vanilla/node_modules/vitest/dist/workers/vmForks.js b/vanilla/node_modules/vitest/dist/workers/vmForks.js
deleted file mode 100644
index ffb6ab1..0000000
--- a/vanilla/node_modules/vitest/dist/workers/vmForks.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import { w as workerInit } from '../chunks/init-forks._y3TW739.js';
-import { r as runVmTests } from '../chunks/vm.D3epNOPZ.js';
-import '../chunks/init.B6MLFIaN.js';
-import 'node:fs';
-import 'node:module';
-import 'node:url';
-import 'pathe';
-import 'vite/module-runner';
-import '../chunks/startModuleRunner.DEj0jb3e.js';
-import '@vitest/utils/helpers';
-import '../chunks/modules.BJuCwlRJ.js';
-import '../path.js';
-import 'node:path';
-import '@vitest/utils/serialize';
-import '../module-evaluator.js';
-import 'node:vm';
-import '../chunks/traces.CCmnQaNT.js';
-import '@vitest/mocker';
-import '../chunks/index.CyBMJtT7.js';
-import 'node:console';
-import '@vitest/utils/error';
-import '../chunks/rpc.BoxB0q7B.js';
-import '@vitest/utils/timers';
-import '../chunks/index.Chj8NDwU.js';
-import '../chunks/utils.DvEY5TfP.js';
-import '@vitest/utils/source-map';
-import '../chunks/inspector.CvyFGlXm.js';
-import '../chunks/evaluatedModules.Dg1zASAC.js';
-import '../chunks/console.Cf-YriPC.js';
-import 'node:stream';
-import 'tinyrainbow';
-import '../chunks/date.Bq6ZW5rf.js';
-import '@vitest/utils/resolver';
-import '@vitest/utils/constants';
-
-workerInit({ runTests: runVmTests });
diff --git a/vanilla/node_modules/vitest/dist/workers/vmThreads.js b/vanilla/node_modules/vitest/dist/workers/vmThreads.js
deleted file mode 100644
index 6a194e5..0000000
--- a/vanilla/node_modules/vitest/dist/workers/vmThreads.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import { w as workerInit } from '../chunks/init-threads.DBO2kn-p.js';
-import { r as runVmTests } from '../chunks/vm.D3epNOPZ.js';
-import 'node:worker_threads';
-import '../chunks/init.B6MLFIaN.js';
-import 'node:fs';
-import 'node:module';
-import 'node:url';
-import 'pathe';
-import 'vite/module-runner';
-import '../chunks/startModuleRunner.DEj0jb3e.js';
-import '@vitest/utils/helpers';
-import '../chunks/modules.BJuCwlRJ.js';
-import '../path.js';
-import 'node:path';
-import '@vitest/utils/serialize';
-import '../module-evaluator.js';
-import 'node:vm';
-import '../chunks/traces.CCmnQaNT.js';
-import '@vitest/mocker';
-import '../chunks/index.CyBMJtT7.js';
-import 'node:console';
-import '@vitest/utils/error';
-import '../chunks/rpc.BoxB0q7B.js';
-import '@vitest/utils/timers';
-import '../chunks/index.Chj8NDwU.js';
-import '../chunks/utils.DvEY5TfP.js';
-import '@vitest/utils/source-map';
-import '../chunks/inspector.CvyFGlXm.js';
-import '../chunks/evaluatedModules.Dg1zASAC.js';
-import '../chunks/console.Cf-YriPC.js';
-import 'node:stream';
-import 'tinyrainbow';
-import '../chunks/date.Bq6ZW5rf.js';
-import '@vitest/utils/resolver';
-import '@vitest/utils/constants';
-
-workerInit({ runTests: runVmTests });
diff --git a/vanilla/node_modules/vitest/environments.d.ts b/vanilla/node_modules/vitest/environments.d.ts
deleted file mode 100644
index 9758d6e..0000000
--- a/vanilla/node_modules/vitest/environments.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './dist/environments'
diff --git a/vanilla/node_modules/vitest/globals.d.ts b/vanilla/node_modules/vitest/globals.d.ts
deleted file mode 100644
index c55256a..0000000
--- a/vanilla/node_modules/vitest/globals.d.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-declare global {
- let suite: typeof import('vitest')['suite']
- let test: typeof import('vitest')['test']
- let chai: typeof import("vitest")["chai"]
- let describe: typeof import('vitest')['describe']
- let it: typeof import('vitest')['it']
- let expectTypeOf: typeof import('vitest')['expectTypeOf']
- let assertType: typeof import('vitest')['assertType']
- let expect: typeof import('vitest')['expect']
- let assert: typeof import('vitest')['assert']
- let vitest: typeof import('vitest')['vitest']
- let vi: typeof import('vitest')['vitest']
- let beforeAll: typeof import('vitest')['beforeAll']
- let afterAll: typeof import('vitest')['afterAll']
- let beforeEach: typeof import('vitest')['beforeEach']
- let afterEach: typeof import('vitest')['afterEach']
- let onTestFailed: typeof import('vitest')['onTestFailed']
- let onTestFinished: typeof import('vitest')['onTestFinished']
-}
-export {}
diff --git a/vanilla/node_modules/vitest/import-meta.d.ts b/vanilla/node_modules/vitest/import-meta.d.ts
deleted file mode 100644
index ee00ff5..0000000
--- a/vanilla/node_modules/vitest/import-meta.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-/// <reference path="./importMeta.d.ts" />
-
-// https://github.com/microsoft/TypeScript/issues/45096
-// TypeScript has a bug that makes <reference types="vite/types/importMeta" />
-// not possible in userland. This file provides a workaround for now.
diff --git a/vanilla/node_modules/vitest/importMeta.d.ts b/vanilla/node_modules/vitest/importMeta.d.ts
deleted file mode 100644
index 6892126..0000000
--- a/vanilla/node_modules/vitest/importMeta.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-interface ImportMeta {
- url: string
- readonly vitest?: typeof import('vitest')
-}
diff --git a/vanilla/node_modules/vitest/index.cjs b/vanilla/node_modules/vitest/index.cjs
deleted file mode 100644
index 85fc303..0000000
--- a/vanilla/node_modules/vitest/index.cjs
+++ /dev/null
@@ -1,5 +0,0 @@
-throw new Error(
- 'Vitest cannot be imported in a CommonJS module using require(). Please use "import" instead.'
- + '\n\nIf you are using "import" in your source code, then it\'s possible it was bundled into require() automatically by your bundler. '
- + 'In that case, do not bundle CommonJS output since it will never work with Vitest, or use dynamic import() which is available in all CommonJS modules.',
-)
diff --git a/vanilla/node_modules/vitest/index.d.cts b/vanilla/node_modules/vitest/index.d.cts
deleted file mode 100644
index 09e9c9b..0000000
--- a/vanilla/node_modules/vitest/index.d.cts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './dist/index.js'
diff --git a/vanilla/node_modules/vitest/jsdom.d.ts b/vanilla/node_modules/vitest/jsdom.d.ts
deleted file mode 100644
index 723af9d..0000000
--- a/vanilla/node_modules/vitest/jsdom.d.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import type { JSDOM } from 'jsdom'
-
-declare global {
- const jsdom: JSDOM
-}
-export {}
diff --git a/vanilla/node_modules/vitest/mocker.d.ts b/vanilla/node_modules/vitest/mocker.d.ts
deleted file mode 100644
index 38df3da..0000000
--- a/vanilla/node_modules/vitest/mocker.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './dist/mocker.js'
diff --git a/vanilla/node_modules/vitest/node.d.ts b/vanilla/node_modules/vitest/node.d.ts
deleted file mode 100644
index 18975f6..0000000
--- a/vanilla/node_modules/vitest/node.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './dist/node.js'
diff --git a/vanilla/node_modules/vitest/optional-types.d.ts b/vanilla/node_modules/vitest/optional-types.d.ts
deleted file mode 100644
index 49cdb4f..0000000
--- a/vanilla/node_modules/vitest/optional-types.d.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-/* eslint-disable ts/ban-ts-comment */
-
-// @ts-ignore optional peer dep
-export type * as jsdomTypes from 'jsdom'
-
-// @ts-ignore optional peer dep
-export type * as happyDomTypes from 'happy-dom'
diff --git a/vanilla/node_modules/vitest/package.json b/vanilla/node_modules/vitest/package.json
deleted file mode 100644
index 6c63cc6..0000000
--- a/vanilla/node_modules/vitest/package.json
+++ /dev/null
@@ -1,224 +0,0 @@
-{
- "name": "vitest",
- "type": "module",
- "version": "4.0.18",
- "description": "Next generation testing framework powered by Vite",
- "author": "Anthony Fu <anthonyfu117@hotmail.com>",
- "license": "MIT",
- "funding": "https://opencollective.com/vitest",
- "homepage": "https://vitest.dev",
- "repository": {
- "type": "git",
- "url": "git+https://github.com/vitest-dev/vitest.git",
- "directory": "packages/vitest"
- },
- "bugs": {
- "url": "https://github.com/vitest-dev/vitest/issues"
- },
- "keywords": [
- "vite",
- "vitest",
- "test",
- "jest"
- ],
- "sideEffects": false,
- "imports": {
- "#module-evaluator": {
- "types": "./dist/module-evaluator.d.ts",
- "default": "./dist/module-evaluator.js"
- }
- },
- "exports": {
- ".": {
- "import": {
- "types": "./dist/index.d.ts",
- "default": "./dist/index.js"
- },
- "require": {
- "types": "./index.d.cts",
- "default": "./index.cjs"
- }
- },
- "./browser": {
- "types": "./browser/context.d.ts",
- "default": "./browser/context.js"
- },
- "./package.json": "./package.json",
- "./optional-types.js": {
- "types": "./optional-types.d.ts"
- },
- "./src/*": "./src/*",
- "./globals": {
- "types": "./globals.d.ts"
- },
- "./jsdom": {
- "types": "./jsdom.d.ts"
- },
- "./importMeta": {
- "types": "./importMeta.d.ts"
- },
- "./import-meta": {
- "types": "./import-meta.d.ts"
- },
- "./node": {
- "types": "./dist/node.d.ts",
- "default": "./dist/node.js"
- },
- "./internal/browser": {
- "types": "./dist/browser.d.ts",
- "default": "./dist/browser.js"
- },
- "./internal/module-runner": {
- "types": "./dist/module-runner.d.ts",
- "default": "./dist/module-runner.js"
- },
- "./runners": {
- "types": "./dist/runners.d.ts",
- "default": "./dist/runners.js"
- },
- "./suite": {
- "types": "./dist/suite.d.ts",
- "default": "./dist/suite.js"
- },
- "./environments": {
- "types": "./dist/environments.d.ts",
- "default": "./dist/environments.js"
- },
- "./config": {
- "types": "./config.d.ts",
- "require": "./dist/config.cjs",
- "default": "./dist/config.js"
- },
- "./coverage": {
- "types": "./coverage.d.ts",
- "default": "./dist/coverage.js"
- },
- "./reporters": {
- "types": "./dist/reporters.d.ts",
- "default": "./dist/reporters.js"
- },
- "./snapshot": {
- "types": "./dist/snapshot.d.ts",
- "default": "./dist/snapshot.js"
- },
- "./mocker": {
- "types": "./dist/mocker.d.ts",
- "default": "./dist/mocker.js"
- },
- "./worker": {
- "types": "./worker.d.ts",
- "default": "./dist/worker.js"
- }
- },
- "main": "./dist/index.js",
- "module": "./dist/index.js",
- "types": "./dist/index.d.ts",
- "bin": {
- "vitest": "./vitest.mjs"
- },
- "files": [
- "*.cjs",
- "*.d.cts",
- "*.d.ts",
- "*.mjs",
- "bin",
- "browser",
- "dist"
- ],
- "engines": {
- "node": "^20.0.0 || ^22.0.0 || >=24.0.0"
- },
- "peerDependencies": {
- "@edge-runtime/vm": "*",
- "@opentelemetry/api": "^1.9.0",
- "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
- "happy-dom": "*",
- "jsdom": "*",
- "@vitest/browser-playwright": "4.0.18",
- "@vitest/browser-preview": "4.0.18",
- "@vitest/browser-webdriverio": "4.0.18",
- "@vitest/ui": "4.0.18"
- },
- "peerDependenciesMeta": {
- "@edge-runtime/vm": {
- "optional": true
- },
- "@opentelemetry/api": {
- "optional": true
- },
- "@types/node": {
- "optional": true
- },
- "@vitest/browser-playwright": {
- "optional": true
- },
- "@vitest/browser-preview": {
- "optional": true
- },
- "@vitest/browser-webdriverio": {
- "optional": true
- },
- "@vitest/ui": {
- "optional": true
- },
- "happy-dom": {
- "optional": true
- },
- "jsdom": {
- "optional": true
- }
- },
- "dependencies": {
- "es-module-lexer": "^1.7.0",
- "expect-type": "^1.2.2",
- "magic-string": "^0.30.21",
- "obug": "^2.1.1",
- "pathe": "^2.0.3",
- "picomatch": "^4.0.3",
- "std-env": "^3.10.0",
- "tinybench": "^2.9.0",
- "tinyexec": "^1.0.2",
- "tinyglobby": "^0.2.15",
- "tinyrainbow": "^3.0.3",
- "vite": "^6.0.0 || ^7.0.0",
- "why-is-node-running": "^2.3.0",
- "@vitest/mocker": "4.0.18",
- "@vitest/expect": "4.0.18",
- "@vitest/runner": "4.0.18",
- "@vitest/pretty-format": "4.0.18",
- "@vitest/snapshot": "4.0.18",
- "@vitest/spy": "4.0.18",
- "@vitest/utils": "4.0.18"
- },
- "devDependencies": {
- "@antfu/install-pkg": "^1.1.0",
- "@edge-runtime/vm": "^5.0.0",
- "@jridgewell/trace-mapping": "0.3.31",
- "@opentelemetry/api": "^1.9.0",
- "@sinonjs/fake-timers": "14.0.0",
- "@types/estree": "^1.0.8",
- "@types/istanbul-lib-coverage": "^2.0.6",
- "@types/istanbul-reports": "^3.0.4",
- "@types/jsdom": "^27.0.0",
- "@types/node": "^24.10.1",
- "@types/picomatch": "^4.0.2",
- "@types/prompts": "^2.4.9",
- "@types/sinonjs__fake-timers": "^8.1.5",
- "acorn-walk": "^8.3.4",
- "birpc": "^4.0.0",
- "cac": "^6.7.14",
- "empathic": "^2.0.0",
- "flatted": "^3.3.3",
- "happy-dom": "^20.0.11",
- "jsdom": "^27.2.0",
- "local-pkg": "^1.1.2",
- "mime": "^4.1.0",
- "prompts": "^2.4.2",
- "strip-literal": "^3.1.0",
- "ws": "^8.18.3"
- },
- "scripts": {
- "build": "premove dist && rollup -c",
- "dev": "NODE_OPTIONS=\"--max-old-space-size=8192\" rollup -c --watch -m inline"
- }
-} \ No newline at end of file
diff --git a/vanilla/node_modules/vitest/reporters.d.ts b/vanilla/node_modules/vitest/reporters.d.ts
deleted file mode 100644
index 5fe5fe7..0000000
--- a/vanilla/node_modules/vitest/reporters.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './dist/reporters.js'
diff --git a/vanilla/node_modules/vitest/runners.d.ts b/vanilla/node_modules/vitest/runners.d.ts
deleted file mode 100644
index 0477c34..0000000
--- a/vanilla/node_modules/vitest/runners.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './dist/runners.js'
diff --git a/vanilla/node_modules/vitest/snapshot.d.ts b/vanilla/node_modules/vitest/snapshot.d.ts
deleted file mode 100644
index e032fa7..0000000
--- a/vanilla/node_modules/vitest/snapshot.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './dist/snapshot.js'
diff --git a/vanilla/node_modules/vitest/suite.d.ts b/vanilla/node_modules/vitest/suite.d.ts
deleted file mode 100644
index 9465dc5..0000000
--- a/vanilla/node_modules/vitest/suite.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './dist/suite.js'
diff --git a/vanilla/node_modules/vitest/suppress-warnings.cjs b/vanilla/node_modules/vitest/suppress-warnings.cjs
deleted file mode 100644
index 65a3106..0000000
--- a/vanilla/node_modules/vitest/suppress-warnings.cjs
+++ /dev/null
@@ -1,21 +0,0 @@
-// borrowed from tsx implementation:
-// https://github.com/esbuild-kit/tsx
-
-const ignoreWarnings = new Set([
- '--experimental-loader is an experimental feature. This feature could change at any time',
- 'Custom ESM Loaders is an experimental feature. This feature could change at any time',
- 'Custom ESM Loaders is an experimental feature and might change at any time',
- 'VM Modules is an experimental feature and might change at any time',
- 'VM Modules is an experimental feature. This feature could change at any time',
-])
-
-const { emit } = process
-
-process.emit = function (event, warning) {
- if (event === 'warning' && ignoreWarnings.has(warning.message)) {
- return
- }
-
- // eslint-disable-next-line prefer-rest-params
- return Reflect.apply(emit, this, arguments)
-}
diff --git a/vanilla/node_modules/vitest/vitest.mjs b/vanilla/node_modules/vitest/vitest.mjs
deleted file mode 100755
index 02dd471..0000000
--- a/vanilla/node_modules/vitest/vitest.mjs
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/usr/bin/env node
-import './dist/cli.js'
diff --git a/vanilla/node_modules/vitest/worker.d.ts b/vanilla/node_modules/vitest/worker.d.ts
deleted file mode 100644
index 7dd1416..0000000
--- a/vanilla/node_modules/vitest/worker.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './dist/worker.js'