[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
12

Configure Feed

Select the types of activity you want to include in your feed.

feat!: move snapshot implementation into @vitest/snapshot (#3032)

authored by

Vladimir and committed by
GitHub
(Mar 29, 2023, 3:35 PM +0200) 6aff0176 446308da

+2064 -1949
+20 -6
pnpm-lock.yaml
··· 721 721 p-limit: 4.0.0 722 722 pathe: 1.1.0 723 723 724 + packages/snapshot: 725 + specifiers: 726 + '@types/natural-compare': ^1.4.1 727 + '@vitest/utils': workspace:* 728 + magic-string: ^0.27.0 729 + natural-compare: ^1.4.0 730 + pathe: ^1.1.0 731 + pretty-format: ^27.5.1 732 + dependencies: 733 + magic-string: 0.27.0 734 + pathe: 1.1.0 735 + pretty-format: 27.5.1 736 + devDependencies: 737 + '@types/natural-compare': 1.4.1 738 + '@vitest/utils': link:../utils 739 + natural-compare: 1.4.0 740 + 724 741 packages/spy: 725 742 specifiers: 726 743 tinyspy: ^2.1.0 ··· 846 863 '@types/istanbul-reports': ^3.0.1 847 864 '@types/jsdom': ^20.0.1 848 865 '@types/micromatch': ^4.0.2 849 - '@types/natural-compare': ^1.4.1 850 866 '@types/node': '*' 851 867 '@types/prompts': ^2.4.2 852 868 '@types/sinonjs__fake-timers': ^8.1.2 853 869 '@vitest/expect': workspace:* 854 870 '@vitest/runner': workspace:* 871 + '@vitest/snapshot': workspace:* 855 872 '@vitest/spy': workspace:* 856 873 '@vitest/utils': workspace:* 857 874 acorn: ^8.8.1 ··· 877 894 magic-string: ^0.27.0 878 895 micromatch: ^4.0.5 879 896 mlly: ^1.1.0 880 - natural-compare: ^1.4.0 881 897 p-limit: ^4.0.0 882 898 pathe: ^1.1.0 883 899 picocolors: ^1.0.0 ··· 906 922 '@types/node': 18.7.13 907 923 '@vitest/expect': link:../expect 908 924 '@vitest/runner': link:../runner 925 + '@vitest/snapshot': link:../snapshot 909 926 '@vitest/spy': link:../spy 910 927 '@vitest/utils': link:../utils 911 928 acorn: 8.8.1 ··· 915 932 concordance: 5.0.4 916 933 debug: 4.3.4 917 934 local-pkg: 0.4.2 935 + magic-string: 0.27.0 918 936 pathe: 1.1.0 919 937 picocolors: 1.0.0 920 938 source-map: 0.6.1 ··· 935 953 '@types/istanbul-reports': 3.0.1 936 954 '@types/jsdom': 20.0.1 937 955 '@types/micromatch': 4.0.2 938 - '@types/natural-compare': 1.4.1 939 956 '@types/prompts': 2.4.2 940 957 '@types/sinonjs__fake-timers': 8.1.2 941 958 birpc: 0.2.3 ··· 951 968 happy-dom: 8.3.2 952 969 jsdom: 21.1.0 953 970 log-update: 5.0.1 954 - magic-string: 0.27.0 955 971 micromatch: 4.0.5 956 972 mlly: 1.1.0 957 - natural-compare: 1.4.0 958 973 p-limit: 4.0.0 959 974 pkg-types: 1.0.1 960 975 playwright: 1.28.0 ··· 16436 16451 engines: {node: '>=12'} 16437 16452 dependencies: 16438 16453 '@jridgewell/sourcemap-codec': 1.4.14 16439 - dev: true 16440 16454 16441 16455 /make-dir/2.1.0: 16442 16456 resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==}
+2
tsconfig.json
··· 19 19 "@vitest/utils": ["./packages/utils/src/index.ts"], 20 20 "@vitest/utils/*": ["./packages/utils/src/*"], 21 21 "@vitest/spy": ["./packages/spy/src/index.ts"], 22 + "@vitest/snapshot": ["./packages/snapshot/src/index.ts"], 23 + "@vitest/snapshot/*": ["./packages/snapshot/src/*"], 22 24 "@vitest/expect": ["./packages/expect/src/index.ts"], 23 25 "@vitest/runner": ["./packages/runner/src/index.ts"], 24 26 "@vitest/runner/*": ["./packages/runner/src/*"],
+71
packages/snapshot/README.md
··· 1 + # @vitest/snapshot 2 + 3 + Lightweight implementation of Jest's snapshots. 4 + 5 + ## Usage 6 + 7 + ```js 8 + import { SnapshotClient } from '@vitest/snapshot' 9 + import { NodeSnapshotEnvironment } from '@vitest/snapshot/environment' 10 + import { SnapshotManager } from '@vitest/snapshot/manager' 11 + 12 + export class CustomSnapshotClient extends SnapshotClient { 13 + // by default, @vitest/snapshot checks equality with `!==` 14 + // you need to provide your own equality check implementation 15 + // this function is called when `.toMatchSnapshot({ property: 1 })` is called 16 + equalityCheck(received, expected) { 17 + return equals(received, expected, [iterableEquality, subsetEquality]) 18 + } 19 + } 20 + 21 + const client = new CustomSnapshotClient() 22 + // class that implements snapshot saving and reading 23 + // by default uses fs module, but you can provide your own implementation depending on the environment 24 + const environment = new NodeSnapshotEnvironment() 25 + 26 + const getCurrentFilepath = () => '/file.spec.ts' 27 + const getCurrentTestName = () => 'test1' 28 + 29 + const wrapper = (received) => { 30 + function __INLINE_SNAPSHOT__(inlineSnapshot, message) { 31 + client.assert({ 32 + received, 33 + message, 34 + isInline: true, 35 + inlineSnapshot, 36 + // you need to implement this yourselves, 37 + // this depends on your runner 38 + filepath: getCurrentFilepath(), 39 + name: getCurrentTestName(), 40 + }) 41 + } 42 + return { 43 + // the name is hard-coded, it should be inside another function, so Vitest can find the actual test file where it was called (parses call stack trace + 2) 44 + // you can override this behaviour in SnapshotState's `_inferInlineSnapshotStack` method by providing your own SnapshotState to SnapshotClient constructor 45 + toMatchInlineSnapshot: (...args) => __INLINE_SNAPSHOT__(...args), 46 + } 47 + } 48 + 49 + const options = { 50 + updateSnapshot: 'new', 51 + snapshotEnvironment: environment, 52 + } 53 + 54 + await client.setTest(getCurrentFilepath(), getCurrentTestName(), options) 55 + 56 + // uses "pretty-format", so it requires quotes 57 + // also naming is hard-coded when parsing test files 58 + wrapper('text 1').toMatchInlineSnapshot() 59 + wrapper('text 2').toMatchInlineSnapshot('"text 2"') 60 + 61 + const result = await client.resetCurrent() // this saves files and returns SnapshotResult 62 + 63 + // you can use manager to manage several clients 64 + const manager = new SnapshotManager(options) 65 + manager.add(result) 66 + 67 + // do something 68 + // and then read the summary 69 + 70 + console.log(manager.summary) 71 + ```
+50
packages/snapshot/package.json
··· 1 + { 2 + "name": "@vitest/snapshot", 3 + "type": "module", 4 + "version": "0.29.3", 5 + "description": "Vitest Snapshot Resolver", 6 + "license": "MIT", 7 + "repository": { 8 + "type": "git", 9 + "url": "git+https://github.com/vitest-dev/vitest.git", 10 + "directory": "packages/snapshot" 11 + }, 12 + "sideEffects": false, 13 + "exports": { 14 + ".": { 15 + "types": "./dist/index.d.ts", 16 + "import": "./dist/index.js" 17 + }, 18 + "./environment": { 19 + "types": "./dist/environment.d.ts", 20 + "import": "./dist/environment.js" 21 + }, 22 + "./manager": { 23 + "types": "./dist/manager.d.ts", 24 + "import": "./dist/manager.js" 25 + }, 26 + "./*": "./*" 27 + }, 28 + "main": "./dist/index.js", 29 + "module": "./dist/index.js", 30 + "types": "./dist/index.d.ts", 31 + "files": [ 32 + "dist", 33 + "*.d.ts" 34 + ], 35 + "scripts": { 36 + "build": "rimraf dist && rollup -c", 37 + "dev": "rollup -c --watch", 38 + "prepublishOnly": "pnpm build" 39 + }, 40 + "dependencies": { 41 + "magic-string": "^0.27.0", 42 + "pathe": "^1.1.0", 43 + "pretty-format": "^27.5.1" 44 + }, 45 + "devDependencies": { 46 + "@types/natural-compare": "^1.4.1", 47 + "@vitest/utils": "workspace:*", 48 + "natural-compare": "^1.4.0" 49 + } 50 + }
+63
packages/snapshot/rollup.config.js
··· 1 + import { builtinModules } from 'module' 2 + import esbuild from 'rollup-plugin-esbuild' 3 + import nodeResolve from '@rollup/plugin-node-resolve' 4 + import dts from 'rollup-plugin-dts' 5 + import commonjs from '@rollup/plugin-commonjs' 6 + import { defineConfig } from 'rollup' 7 + import pkg from './package.json' 8 + 9 + const external = [ 10 + ...builtinModules, 11 + ...Object.keys(pkg.dependencies || {}), 12 + ...Object.keys(pkg.peerDependencies || {}), 13 + ] 14 + 15 + const entries = { 16 + index: 'src/index.ts', 17 + environment: 'src/environment.ts', 18 + manager: 'src/manager.ts', 19 + } 20 + 21 + const plugins = [ 22 + nodeResolve({ 23 + preferBuiltins: true, 24 + }), 25 + commonjs(), 26 + esbuild({ 27 + target: 'node14', 28 + }), 29 + ] 30 + 31 + export default defineConfig([ 32 + { 33 + input: entries, 34 + output: { 35 + dir: 'dist', 36 + format: 'esm', 37 + entryFileNames: '[name].js', 38 + chunkFileNames: 'chunk-[name].js', 39 + }, 40 + external, 41 + plugins, 42 + onwarn, 43 + }, 44 + { 45 + input: entries, 46 + output: { 47 + dir: 'dist', 48 + entryFileNames: '[name].d.ts', 49 + format: 'esm', 50 + }, 51 + external, 52 + plugins: [ 53 + dts({ respectExternal: true }), 54 + ], 55 + onwarn, 56 + }, 57 + ]) 58 + 59 + function onwarn(message) { 60 + if (['EMPTY_BUNDLE', 'CIRCULAR_DEPENDENCY'].includes(message.code)) 61 + return 62 + console.error(message) 63 + }
+356 -572
packages/vitest/LICENSE.md
··· 37 37 > Apache License 38 38 > Version 2.0, January 2004 39 39 > http://www.apache.org/licenses/ 40 - > 40 + > 41 41 > TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 42 - > 42 + > 43 43 > 1. Definitions. 44 - > 44 + > 45 45 > "License" shall mean the terms and conditions for use, reproduction, 46 46 > and distribution as defined by Sections 1 through 9 of this document. 47 - > 47 + > 48 48 > "Licensor" shall mean the copyright owner or entity authorized by 49 49 > the copyright owner that is granting the License. 50 - > 50 + > 51 51 > "Legal Entity" shall mean the union of the acting entity and all 52 52 > other entities that control, are controlled by, or are under common 53 53 > control with that entity. For the purposes of this definition, ··· 55 55 > direction or management of such entity, whether by contract or 56 56 > otherwise, or (ii) ownership of fifty percent (50%) or more of the 57 57 > outstanding shares, or (iii) beneficial ownership of such entity. 58 - > 58 + > 59 59 > "You" (or "Your") shall mean an individual or Legal Entity 60 60 > exercising permissions granted by this License. 61 - > 61 + > 62 62 > "Source" form shall mean the preferred form for making modifications, 63 63 > including but not limited to software source code, documentation 64 64 > source, and configuration files. 65 - > 65 + > 66 66 > "Object" form shall mean any form resulting from mechanical 67 67 > transformation or translation of a Source form, including but 68 68 > not limited to compiled object code, generated documentation, 69 69 > and conversions to other media types. 70 - > 70 + > 71 71 > "Work" shall mean the work of authorship, whether in Source or 72 72 > Object form, made available under the License, as indicated by a 73 73 > copyright notice that is included in or attached to the work 74 74 > (an example is provided in the Appendix below). 75 - > 75 + > 76 76 > "Derivative Works" shall mean any work, whether in Source or Object 77 77 > form, that is based on (or derived from) the Work and for which the 78 78 > editorial revisions, annotations, elaborations, or other modifications ··· 80 80 > of this License, Derivative Works shall not include works that remain 81 81 > separable from, or merely link (or bind by name) to the interfaces of, 82 82 > the Work and Derivative Works thereof. 83 - > 83 + > 84 84 > "Contribution" shall mean any work of authorship, including 85 85 > the original version of the Work and any modifications or additions 86 86 > to that Work or Derivative Works thereof, that is intentionally ··· 94 94 > Licensor for the purpose of discussing and improving the Work, but 95 95 > excluding communication that is conspicuously marked or otherwise 96 96 > designated in writing by the copyright owner as "Not a Contribution." 97 - > 97 + > 98 98 > "Contributor" shall mean Licensor and any individual or Legal Entity 99 99 > on behalf of whom a Contribution has been received by Licensor and 100 100 > subsequently incorporated within the Work. 101 - > 101 + > 102 102 > 2. Grant of Copyright License. Subject to the terms and conditions of 103 103 > this License, each Contributor hereby grants to You a perpetual, 104 104 > worldwide, non-exclusive, no-charge, royalty-free, irrevocable 105 105 > copyright license to reproduce, prepare Derivative Works of, 106 106 > publicly display, publicly perform, sublicense, and distribute the 107 107 > Work and such Derivative Works in Source or Object form. 108 - > 108 + > 109 109 > 3. Grant of Patent License. Subject to the terms and conditions of 110 110 > this License, each Contributor hereby grants to You a perpetual, 111 111 > worldwide, non-exclusive, no-charge, royalty-free, irrevocable ··· 121 121 > or contributory patent infringement, then any patent licenses 122 122 > granted to You under this License for that Work shall terminate 123 123 > as of the date such litigation is filed. 124 - > 124 + > 125 125 > 4. Redistribution. You may reproduce and distribute copies of the 126 126 > Work or Derivative Works thereof in any medium, with or without 127 127 > modifications, and in Source or Object form, provided that You 128 128 > meet the following conditions: 129 - > 129 + > 130 130 > (a) You must give any other recipients of the Work or 131 131 > Derivative Works a copy of this License; and 132 - > 132 + > 133 133 > (b) You must cause any modified files to carry prominent notices 134 134 > stating that You changed the files; and 135 - > 135 + > 136 136 > (c) You must retain, in the Source form of any Derivative Works 137 137 > that You distribute, all copyright, patent, trademark, and 138 138 > attribution notices from the Source form of the Work, 139 139 > excluding those notices that do not pertain to any part of 140 140 > the Derivative Works; and 141 - > 141 + > 142 142 > (d) If the Work includes a "NOTICE" text file as part of its 143 143 > distribution, then any Derivative Works that You distribute must 144 144 > include a readable copy of the attribution notices contained ··· 155 155 > or as an addendum to the NOTICE text from the Work, provided 156 156 > that such additional attribution notices cannot be construed 157 157 > as modifying the License. 158 - > 158 + > 159 159 > You may add Your own copyright statement to Your modifications and 160 160 > may provide additional or different license terms and conditions 161 161 > for use, reproduction, or distribution of Your modifications, or 162 162 > for any such Derivative Works as a whole, provided Your use, 163 163 > reproduction, and distribution of the Work otherwise complies with 164 164 > the conditions stated in this License. 165 - > 165 + > 166 166 > 5. Submission of Contributions. Unless You explicitly state otherwise, 167 167 > any Contribution intentionally submitted for inclusion in the Work 168 168 > by You to the Licensor shall be under the terms and conditions of ··· 170 170 > Notwithstanding the above, nothing herein shall supersede or modify 171 171 > the terms of any separate license agreement you may have executed 172 172 > with Licensor regarding such Contributions. 173 - > 173 + > 174 174 > 6. Trademarks. This License does not grant permission to use the trade 175 175 > names, trademarks, service marks, or product names of the Licensor, 176 176 > except as required for reasonable and customary use in describing the 177 177 > origin of the Work and reproducing the content of the NOTICE file. 178 - > 178 + > 179 179 > 7. Disclaimer of Warranty. Unless required by applicable law or 180 180 > agreed to in writing, Licensor provides the Work (and each 181 181 > Contributor provides its Contributions) on an "AS IS" BASIS, ··· 185 185 > PARTICULAR PURPOSE. You are solely responsible for determining the 186 186 > appropriateness of using or redistributing the Work and assume any 187 187 > risks associated with Your exercise of permissions under this License. 188 - > 188 + > 189 189 > 8. Limitation of Liability. In no event and under no legal theory, 190 190 > whether in tort (including negligence), contract, or otherwise, 191 191 > unless required by applicable law (such as deliberate and grossly ··· 197 197 > work stoppage, computer failure or malfunction, or any and all 198 198 > other commercial damages or losses), even if such Contributor 199 199 > has been advised of the possibility of such damages. 200 - > 200 + > 201 201 > 9. Accepting Warranty or Additional Liability. While redistributing 202 202 > the Work or Derivative Works thereof, You may choose to offer, 203 203 > and charge a fee for, acceptance of support, warranty, indemnity, ··· 208 208 > defend, and hold each Contributor harmless for any liability 209 209 > incurred by, or claims asserted against, such Contributor by reason 210 210 > of your accepting any such warranty or additional liability. 211 - > 211 + > 212 212 > END OF TERMS AND CONDITIONS 213 - > 213 + > 214 214 > APPENDIX: How to apply the Apache License to your work. 215 - > 215 + > 216 216 > To apply the Apache License to your work, attach the following 217 217 > boilerplate notice, with the fields enclosed by brackets "[]" 218 218 > replaced with your own identifying information. (Don't include ··· 221 221 > file or class name and description of purpose be included on the 222 222 > same "printed page" as the copyright notice for easier 223 223 > identification within third-party archives. 224 - > 224 + > 225 225 > Copyright 2019 Google LLC 226 - > 226 + > 227 227 > Licensed under the Apache License, Version 2.0 (the "License"); 228 228 > you may not use this file except in compliance with the License. 229 229 > You may obtain a copy of the License at 230 - > 230 + > 231 231 > http://www.apache.org/licenses/LICENSE-2.0 232 - > 232 + > 233 233 > Unless required by applicable law or agreed to in writing, software 234 234 > distributed under the License is distributed on an "AS IS" BASIS, 235 235 > WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ··· 244 244 Repository: git+https://github.com/antfu/install-pkg.git 245 245 246 246 > MIT License 247 - > 247 + > 248 248 > Copyright (c) 2021 Anthony Fu <https://github.com/antfu> 249 - > 249 + > 250 250 > Permission is hereby granted, free of charge, to any person obtaining a copy 251 251 > of this software and associated documentation files (the "Software"), to deal 252 252 > in the Software without restriction, including without limitation the rights 253 253 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 254 254 > copies of the Software, and to permit persons to whom the Software is 255 255 > furnished to do so, subject to the following conditions: 256 - > 256 + > 257 257 > The above copyright notice and this permission notice shall be included in all 258 258 > copies or substantial portions of the Software. 259 - > 260 - > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 261 - > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 262 - > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 263 - > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 264 - > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 265 - > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 266 - > SOFTWARE. 267 - 268 - --------------------------------------- 269 - 270 - ## @jridgewell/gen-mapping 271 - License: MIT 272 - By: Justin Ridgewell 273 - Repository: https://github.com/jridgewell/gen-mapping 274 - 275 - > Copyright 2022 Justin Ridgewell <jridgewell@google.com> 276 - > 277 - > Permission is hereby granted, free of charge, to any person obtaining a copy 278 - > of this software and associated documentation files (the "Software"), to deal 279 - > in the Software without restriction, including without limitation the rights 280 - > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 281 - > copies of the Software, and to permit persons to whom the Software is 282 - > furnished to do so, subject to the following conditions: 283 - > 284 - > The above copyright notice and this permission notice shall be included in 285 - > all copies or substantial portions of the Software. 286 - > 287 - > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 288 - > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 289 - > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 290 - > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 291 - > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 292 - > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 293 - > SOFTWARE. 294 - 295 - --------------------------------------- 296 - 297 - ## @jridgewell/resolve-uri 298 - License: MIT 299 - By: Justin Ridgewell 300 - Repository: https://github.com/jridgewell/resolve-uri 301 - 302 - > Copyright 2019 Justin Ridgewell <jridgewell@google.com> 303 - > 304 - > Permission is hereby granted, free of charge, to any person obtaining a copy 305 - > of this software and associated documentation files (the "Software"), to deal 306 - > in the Software without restriction, including without limitation the rights 307 - > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 308 - > copies of the Software, and to permit persons to whom the Software is 309 - > furnished to do so, subject to the following conditions: 310 - > 311 - > The above copyright notice and this permission notice shall be included in 312 - > all copies or substantial portions of the Software. 313 - > 314 - > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 315 - > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 316 - > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 317 - > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 318 - > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 319 - > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 320 - > SOFTWARE. 321 - 322 - --------------------------------------- 323 - 324 - ## @jridgewell/set-array 325 - License: MIT 326 - By: Justin Ridgewell 327 - Repository: https://github.com/jridgewell/set-array 328 - 329 - > Copyright 2022 Justin Ridgewell <jridgewell@google.com> 330 - > 331 - > Permission is hereby granted, free of charge, to any person obtaining a copy 332 - > of this software and associated documentation files (the "Software"), to deal 333 - > in the Software without restriction, including without limitation the rights 334 - > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 335 - > copies of the Software, and to permit persons to whom the Software is 336 - > furnished to do so, subject to the following conditions: 337 - > 338 - > The above copyright notice and this permission notice shall be included in 339 - > all copies or substantial portions of the Software. 340 - > 341 - > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 342 - > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 343 - > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 344 - > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 345 - > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 346 - > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 347 - > SOFTWARE. 348 - 349 - --------------------------------------- 350 - 351 - ## @jridgewell/sourcemap-codec 352 - License: MIT 353 - By: Rich Harris 354 - Repository: git+https://github.com/jridgewell/sourcemap-codec.git 355 - 356 - > The MIT License 357 - > 358 - > Copyright (c) 2015 Rich Harris 359 - > 360 - > Permission is hereby granted, free of charge, to any person obtaining a copy 361 - > of this software and associated documentation files (the "Software"), to deal 362 - > in the Software without restriction, including without limitation the rights 363 - > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 364 - > copies of the Software, and to permit persons to whom the Software is 365 - > furnished to do so, subject to the following conditions: 366 - > 367 - > The above copyright notice and this permission notice shall be included in 368 - > all copies or substantial portions of the Software. 369 - > 370 - > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 371 - > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 372 - > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 373 - > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 374 - > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 375 - > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 376 - > THE SOFTWARE. 377 - 378 - --------------------------------------- 379 - 380 - ## @jridgewell/trace-mapping 381 - License: MIT 382 - By: Justin Ridgewell 383 - Repository: git+https://github.com/jridgewell/trace-mapping.git 384 - 385 - > Copyright 2022 Justin Ridgewell <justin@ridgewell.name> 386 - > 387 - > Permission is hereby granted, free of charge, to any person obtaining a copy 388 - > of this software and associated documentation files (the "Software"), to deal 389 - > in the Software without restriction, including without limitation the rights 390 - > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 391 - > copies of the Software, and to permit persons to whom the Software is 392 - > furnished to do so, subject to the following conditions: 393 - > 394 - > The above copyright notice and this permission notice shall be included in 395 - > all copies or substantial portions of the Software. 396 - > 259 + > 397 260 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 398 261 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 399 262 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 409 272 Repository: https://github.com/nodelib/nodelib/tree/master/packages/fs/fs.scandir 410 273 411 274 > The MIT License (MIT) 412 - > 275 + > 413 276 > Copyright (c) Denis Malinochkin 414 - > 277 + > 415 278 > Permission is hereby granted, free of charge, to any person obtaining a copy 416 279 > of this software and associated documentation files (the "Software"), to deal 417 280 > in the Software without restriction, including without limitation the rights 418 281 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 419 282 > copies of the Software, and to permit persons to whom the Software is 420 283 > furnished to do so, subject to the following conditions: 421 - > 284 + > 422 285 > The above copyright notice and this permission notice shall be included in all 423 286 > copies or substantial portions of the Software. 424 - > 287 + > 425 288 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 426 289 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 427 290 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 437 300 Repository: https://github.com/nodelib/nodelib/tree/master/packages/fs/fs.stat 438 301 439 302 > The MIT License (MIT) 440 - > 303 + > 441 304 > Copyright (c) Denis Malinochkin 442 - > 305 + > 443 306 > Permission is hereby granted, free of charge, to any person obtaining a copy 444 307 > of this software and associated documentation files (the "Software"), to deal 445 308 > in the Software without restriction, including without limitation the rights 446 309 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 447 310 > copies of the Software, and to permit persons to whom the Software is 448 311 > furnished to do so, subject to the following conditions: 449 - > 312 + > 450 313 > The above copyright notice and this permission notice shall be included in all 451 314 > copies or substantial portions of the Software. 452 - > 315 + > 453 316 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 454 317 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 455 318 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 465 328 Repository: https://github.com/nodelib/nodelib/tree/master/packages/fs/fs.walk 466 329 467 330 > The MIT License (MIT) 468 - > 331 + > 469 332 > Copyright (c) Denis Malinochkin 470 - > 333 + > 471 334 > Permission is hereby granted, free of charge, to any person obtaining a copy 472 335 > of this software and associated documentation files (the "Software"), to deal 473 336 > in the Software without restriction, including without limitation the rights 474 337 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 475 338 > copies of the Software, and to permit persons to whom the Software is 476 339 > furnished to do so, subject to the following conditions: 477 - > 340 + > 478 341 > The above copyright notice and this permission notice shall be included in all 479 342 > copies or substantial portions of the Software. 480 - > 343 + > 481 344 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 482 345 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 483 346 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 493 356 Repository: git+https://github.com/sinonjs/commons.git 494 357 495 358 > BSD 3-Clause License 496 - > 359 + > 497 360 > Copyright (c) 2018, Sinon.JS 498 361 > All rights reserved. 499 - > 362 + > 500 363 > Redistribution and use in source and binary forms, with or without 501 364 > modification, are permitted provided that the following conditions are met: 502 - > 365 + > 503 366 > * Redistributions of source code must retain the above copyright notice, this 504 367 > list of conditions and the following disclaimer. 505 - > 368 + > 506 369 > * Redistributions in binary form must reproduce the above copyright notice, 507 370 > this list of conditions and the following disclaimer in the documentation 508 371 > and/or other materials provided with the distribution. 509 - > 372 + > 510 373 > * Neither the name of the copyright holder nor the names of its 511 374 > contributors may be used to endorse or promote products derived from 512 375 > this software without specific prior written permission. 513 - > 376 + > 514 377 > THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 515 378 > AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 516 379 > IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ··· 530 393 Repository: https://github.com/sinonjs/fake-timers.git 531 394 532 395 > Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no. All rights reserved. 533 - > 396 + > 534 397 > Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 535 - > 398 + > 536 399 > 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 537 - > 400 + > 538 401 > 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. 539 - > 402 + > 540 403 > 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. 541 - > 404 + > 542 405 > 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. 543 406 544 407 --------------------------------------- ··· 549 412 Repository: sindresorhus/ansi-escapes 550 413 551 414 > MIT License 552 - > 415 + > 553 416 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 554 - > 417 + > 555 418 > 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: 556 - > 419 + > 557 420 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 558 - > 421 + > 559 422 > 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. 560 423 561 424 --------------------------------------- ··· 566 429 Repository: chalk/ansi-regex 567 430 568 431 > MIT License 569 - > 570 - > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com) 571 - > 432 + > 433 + > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 434 + > 572 435 > 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: 573 - > 436 + > 574 437 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 575 - > 438 + > 576 439 > 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. 577 440 578 441 --------------------------------------- ··· 583 446 Repository: chalk/ansi-styles 584 447 585 448 > MIT License 586 - > 587 - > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com) 588 - > 449 + > 450 + > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 451 + > 589 452 > 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: 590 - > 453 + > 591 454 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 592 - > 455 + > 593 456 > 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. 594 457 595 458 --------------------------------------- ··· 600 463 Repository: git+https://github.com/antfu/birpc.git 601 464 602 465 > MIT License 603 - > 466 + > 604 467 > Copyright (c) 2021 Anthony Fu <https://github.com/antfu> 605 - > 468 + > 606 469 > Permission is hereby granted, free of charge, to any person obtaining a copy 607 470 > of this software and associated documentation files (the "Software"), to deal 608 471 > in the Software without restriction, including without limitation the rights 609 472 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 610 473 > copies of the Software, and to permit persons to whom the Software is 611 474 > furnished to do so, subject to the following conditions: 612 - > 475 + > 613 476 > The above copyright notice and this permission notice shall be included in all 614 477 > copies or substantial portions of the Software. 615 - > 478 + > 616 479 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 617 480 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 618 481 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 629 492 Repository: micromatch/braces 630 493 631 494 > The MIT License (MIT) 632 - > 495 + > 633 496 > Copyright (c) 2014-2018, Jon Schlinkert. 634 - > 497 + > 635 498 > Permission is hereby granted, free of charge, to any person obtaining a copy 636 499 > of this software and associated documentation files (the "Software"), to deal 637 500 > in the Software without restriction, including without limitation the rights 638 501 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 639 502 > copies of the Software, and to permit persons to whom the Software is 640 503 > furnished to do so, subject to the following conditions: 641 - > 504 + > 642 505 > The above copyright notice and this permission notice shall be included in 643 506 > all copies or substantial portions of the Software. 644 - > 507 + > 645 508 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 646 509 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 647 510 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 658 521 Repository: https://github.com/debitoor/chai-subset.git 659 522 660 523 > The MIT License (MIT) 661 - > 662 - > Copyright (c) 2014 663 - > 524 + > 525 + > Copyright (c) 2014 526 + > 664 527 > Permission is hereby granted, free of charge, to any person obtaining a copy 665 528 > of this software and associated documentation files (the "Software"), to deal 666 529 > in the Software without restriction, including without limitation the rights 667 530 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 668 531 > copies of the Software, and to permit persons to whom the Software is 669 532 > furnished to do so, subject to the following conditions: 670 - > 533 + > 671 534 > The above copyright notice and this permission notice shall be included in all 672 535 > copies or substantial portions of the Software. 673 - > 536 + > 674 537 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 675 538 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 676 539 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 687 550 Repository: sindresorhus/cli-cursor 688 551 689 552 > MIT License 690 - > 553 + > 691 554 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 692 - > 555 + > 693 556 > 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: 694 - > 557 + > 695 558 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 696 - > 559 + > 697 560 > 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. 698 561 699 562 --------------------------------------- ··· 704 567 Repository: sindresorhus/cli-truncate 705 568 706 569 > MIT License 707 - > 570 + > 708 571 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 709 - > 572 + > 710 573 > 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: 711 - > 574 + > 712 575 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 713 - > 576 + > 714 577 > 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. 715 578 716 579 --------------------------------------- ··· 721 584 Repository: git@github.com:moxystudio/node-cross-spawn.git 722 585 723 586 > The MIT License (MIT) 724 - > 587 + > 725 588 > Copyright (c) 2018 Made With MOXY Lda <hello@moxy.studio> 726 - > 589 + > 727 590 > Permission is hereby granted, free of charge, to any person obtaining a copy 728 591 > of this software and associated documentation files (the "Software"), to deal 729 592 > in the Software without restriction, including without limitation the rights 730 593 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 731 594 > copies of the Software, and to permit persons to whom the Software is 732 595 > furnished to do so, subject to the following conditions: 733 - > 596 + > 734 597 > The above copyright notice and this permission notice shall be included in 735 598 > all copies or substantial portions of the Software. 736 - > 599 + > 737 600 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 738 601 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 739 602 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 757 620 Repository: https://github.com/mathiasbynens/emoji-regex.git 758 621 759 622 > Copyright Mathias Bynens <https://mathiasbynens.be/> 760 - > 623 + > 761 624 > Permission is hereby granted, free of charge, to any person obtaining 762 625 > a copy of this software and associated documentation files (the 763 626 > "Software"), to deal in the Software without restriction, including ··· 765 628 > distribute, sublicense, and/or sell copies of the Software, and to 766 629 > permit persons to whom the Software is furnished to do so, subject to 767 630 > the following conditions: 768 - > 631 + > 769 632 > The above copyright notice and this permission notice shall be 770 633 > included in all copies or substantial portions of the Software. 771 - > 634 + > 772 635 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 773 636 > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 774 637 > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ··· 785 648 Repository: git+https://github.com/benlesh/event-target-polyfill.git 786 649 787 650 > MIT License 788 - > 651 + > 789 652 > Copyright (c) 2020 Ben Lesh 790 - > 653 + > 791 654 > Permission is hereby granted, free of charge, to any person obtaining a copy 792 655 > of this software and associated documentation files (the "Software"), to deal 793 656 > in the Software without restriction, including without limitation the rights 794 657 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 795 658 > copies of the Software, and to permit persons to whom the Software is 796 659 > furnished to do so, subject to the following conditions: 797 - > 660 + > 798 661 > The above copyright notice and this permission notice shall be included in all 799 662 > copies or substantial portions of the Software. 800 - > 663 + > 801 664 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 802 665 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 803 666 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 814 677 Repository: sindresorhus/execa 815 678 816 679 > MIT License 817 - > 680 + > 818 681 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 819 - > 682 + > 820 683 > 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: 821 - > 684 + > 822 685 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 823 - > 686 + > 824 687 > 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. 825 688 826 689 --------------------------------------- ··· 832 695 > Apache License 833 696 > Version 2.0, January 2004 834 697 > http://www.apache.org/licenses/ 835 - > 698 + > 836 699 > TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 837 - > 700 + > 838 701 > 1. Definitions. 839 - > 702 + > 840 703 > "License" shall mean the terms and conditions for use, reproduction, 841 704 > and distribution as defined by Sections 1 through 9 of this document. 842 - > 705 + > 843 706 > "Licensor" shall mean the copyright owner or entity authorized by 844 707 > the copyright owner that is granting the License. 845 - > 708 + > 846 709 > "Legal Entity" shall mean the union of the acting entity and all 847 710 > other entities that control, are controlled by, or are under common 848 711 > control with that entity. For the purposes of this definition, ··· 850 713 > direction or management of such entity, whether by contract or 851 714 > otherwise, or (ii) ownership of fifty percent (50%) or more of the 852 715 > outstanding shares, or (iii) beneficial ownership of such entity. 853 - > 716 + > 854 717 > "You" (or "Your") shall mean an individual or Legal Entity 855 718 > exercising permissions granted by this License. 856 - > 719 + > 857 720 > "Source" form shall mean the preferred form for making modifications, 858 721 > including but not limited to software source code, documentation 859 722 > source, and configuration files. 860 - > 723 + > 861 724 > "Object" form shall mean any form resulting from mechanical 862 725 > transformation or translation of a Source form, including but 863 726 > not limited to compiled object code, generated documentation, 864 727 > and conversions to other media types. 865 - > 728 + > 866 729 > "Work" shall mean the work of authorship, whether in Source or 867 730 > Object form, made available under the License, as indicated by a 868 731 > copyright notice that is included in or attached to the work 869 732 > (an example is provided in the Appendix below). 870 - > 733 + > 871 734 > "Derivative Works" shall mean any work, whether in Source or Object 872 735 > form, that is based on (or derived from) the Work and for which the 873 736 > editorial revisions, annotations, elaborations, or other modifications ··· 875 738 > of this License, Derivative Works shall not include works that remain 876 739 > separable from, or merely link (or bind by name) to the interfaces of, 877 740 > the Work and Derivative Works thereof. 878 - > 741 + > 879 742 > "Contribution" shall mean any work of authorship, including 880 743 > the original version of the Work and any modifications or additions 881 744 > to that Work or Derivative Works thereof, that is intentionally ··· 889 752 > Licensor for the purpose of discussing and improving the Work, but 890 753 > excluding communication that is conspicuously marked or otherwise 891 754 > designated in writing by the copyright owner as "Not a Contribution." 892 - > 755 + > 893 756 > "Contributor" shall mean Licensor and any individual or Legal Entity 894 757 > on behalf of whom a Contribution has been received by Licensor and 895 758 > subsequently incorporated within the Work. 896 - > 759 + > 897 760 > 2. Grant of Copyright License. Subject to the terms and conditions of 898 761 > this License, each Contributor hereby grants to You a perpetual, 899 762 > worldwide, non-exclusive, no-charge, royalty-free, irrevocable 900 763 > copyright license to reproduce, prepare Derivative Works of, 901 764 > publicly display, publicly perform, sublicense, and distribute the 902 765 > Work and such Derivative Works in Source or Object form. 903 - > 766 + > 904 767 > 3. Grant of Patent License. Subject to the terms and conditions of 905 768 > this License, each Contributor hereby grants to You a perpetual, 906 769 > worldwide, non-exclusive, no-charge, royalty-free, irrevocable ··· 916 779 > or contributory patent infringement, then any patent licenses 917 780 > granted to You under this License for that Work shall terminate 918 781 > as of the date such litigation is filed. 919 - > 782 + > 920 783 > 4. Redistribution. You may reproduce and distribute copies of the 921 784 > Work or Derivative Works thereof in any medium, with or without 922 785 > modifications, and in Source or Object form, provided that You 923 786 > meet the following conditions: 924 - > 787 + > 925 788 > (a) You must give any other recipients of the Work or 926 789 > Derivative Works a copy of this License; and 927 - > 790 + > 928 791 > (b) You must cause any modified files to carry prominent notices 929 792 > stating that You changed the files; and 930 - > 793 + > 931 794 > (c) You must retain, in the Source form of any Derivative Works 932 795 > that You distribute, all copyright, patent, trademark, and 933 796 > attribution notices from the Source form of the Work, 934 797 > excluding those notices that do not pertain to any part of 935 798 > the Derivative Works; and 936 - > 799 + > 937 800 > (d) If the Work includes a "NOTICE" text file as part of its 938 801 > distribution, then any Derivative Works that You distribute must 939 802 > include a readable copy of the attribution notices contained ··· 950 813 > or as an addendum to the NOTICE text from the Work, provided 951 814 > that such additional attribution notices cannot be construed 952 815 > as modifying the License. 953 - > 816 + > 954 817 > You may add Your own copyright statement to Your modifications and 955 818 > may provide additional or different license terms and conditions 956 819 > for use, reproduction, or distribution of Your modifications, or 957 820 > for any such Derivative Works as a whole, provided Your use, 958 821 > reproduction, and distribution of the Work otherwise complies with 959 822 > the conditions stated in this License. 960 - > 823 + > 961 824 > 5. Submission of Contributions. Unless You explicitly state otherwise, 962 825 > any Contribution intentionally submitted for inclusion in the Work 963 826 > by You to the Licensor shall be under the terms and conditions of ··· 965 828 > Notwithstanding the above, nothing herein shall supersede or modify 966 829 > the terms of any separate license agreement you may have executed 967 830 > with Licensor regarding such Contributions. 968 - > 831 + > 969 832 > 6. Trademarks. This License does not grant permission to use the trade 970 833 > names, trademarks, service marks, or product names of the Licensor, 971 834 > except as required for reasonable and customary use in describing the 972 835 > origin of the Work and reproducing the content of the NOTICE file. 973 - > 836 + > 974 837 > 7. Disclaimer of Warranty. Unless required by applicable law or 975 838 > agreed to in writing, Licensor provides the Work (and each 976 839 > Contributor provides its Contributions) on an "AS IS" BASIS, ··· 980 843 > PARTICULAR PURPOSE. You are solely responsible for determining the 981 844 > appropriateness of using or redistributing the Work and assume any 982 845 > risks associated with Your exercise of permissions under this License. 983 - > 846 + > 984 847 > 8. Limitation of Liability. In no event and under no legal theory, 985 848 > whether in tort (including negligence), contract, or otherwise, 986 849 > unless required by applicable law (such as deliberate and grossly ··· 992 855 > work stoppage, computer failure or malfunction, or any and all 993 856 > other commercial damages or losses), even if such Contributor 994 857 > has been advised of the possibility of such damages. 995 - > 858 + > 996 859 > 9. Accepting Warranty or Additional Liability. While redistributing 997 860 > the Work or Derivative Works thereof, You may choose to offer, 998 861 > and charge a fee for, acceptance of support, warranty, indemnity, ··· 1003 866 > defend, and hold each Contributor harmless for any liability 1004 867 > incurred by, or claims asserted against, such Contributor by reason 1005 868 > of your accepting any such warranty or additional liability. 1006 - > 869 + > 1007 870 > END OF TERMS AND CONDITIONS 1008 - > 871 + > 1009 872 > APPENDIX: How to apply the Apache License to your work. 1010 - > 873 + > 1011 874 > To apply the Apache License to your work, attach the following 1012 875 > boilerplate notice, with the fields enclosed by brackets "[]" 1013 876 > replaced with your own identifying information. (Don't include ··· 1016 879 > file or class name and description of purpose be included on the 1017 880 > same "printed page" as the copyright notice for easier 1018 881 > identification within third-party archives. 1019 - > 882 + > 1020 883 > Copyright [yyyy] [name of copyright owner] 1021 - > 884 + > 1022 885 > Licensed under the Apache License, Version 2.0 (the "License"); 1023 886 > you may not use this file except in compliance with the License. 1024 887 > You may obtain a copy of the License at 1025 - > 888 + > 1026 889 > http://www.apache.org/licenses/LICENSE-2.0 1027 - > 890 + > 1028 891 > Unless required by applicable law or agreed to in writing, software 1029 892 > distributed under the License is distributed on an "AS IS" BASIS, 1030 893 > WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ··· 1039 902 Repository: mrmlnc/fast-glob 1040 903 1041 904 > The MIT License (MIT) 1042 - > 905 + > 1043 906 > Copyright (c) Denis Malinochkin 1044 - > 907 + > 1045 908 > Permission is hereby granted, free of charge, to any person obtaining a copy 1046 909 > of this software and associated documentation files (the "Software"), to deal 1047 910 > in the Software without restriction, including without limitation the rights 1048 911 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1049 912 > copies of the Software, and to permit persons to whom the Software is 1050 913 > furnished to do so, subject to the following conditions: 1051 - > 914 + > 1052 915 > The above copyright notice and this permission notice shall be included in all 1053 916 > copies or substantial portions of the Software. 1054 - > 917 + > 1055 918 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1056 919 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1057 920 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 1068 931 Repository: git+https://github.com/mcollina/fastq.git 1069 932 1070 933 > Copyright (c) 2015-2020, Matteo Collina <matteo.collina@gmail.com> 1071 - > 934 + > 1072 935 > Permission to use, copy, modify, and/or distribute this software for any 1073 936 > purpose with or without fee is hereby granted, provided that the above 1074 937 > copyright notice and this permission notice appear in all copies. 1075 - > 938 + > 1076 939 > THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1077 940 > WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1078 941 > MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ··· 1089 952 Repository: jonschlinkert/fill-range 1090 953 1091 954 > The MIT License (MIT) 1092 - > 955 + > 1093 956 > Copyright (c) 2014-present, Jon Schlinkert. 1094 - > 957 + > 1095 958 > Permission is hereby granted, free of charge, to any person obtaining a copy 1096 959 > of this software and associated documentation files (the "Software"), to deal 1097 960 > in the Software without restriction, including without limitation the rights 1098 961 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1099 962 > copies of the Software, and to permit persons to whom the Software is 1100 963 > furnished to do so, subject to the following conditions: 1101 - > 964 + > 1102 965 > The above copyright notice and this permission notice shall be included in 1103 966 > all copies or substantial portions of the Software. 1104 - > 967 + > 1105 968 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1106 969 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1107 970 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 1118 981 Repository: sindresorhus/find-up 1119 982 1120 983 > MIT License 1121 - > 984 + > 1122 985 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 1123 - > 986 + > 1124 987 > 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: 1125 - > 988 + > 1126 989 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 1127 - > 990 + > 1128 991 > 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. 1129 992 1130 993 --------------------------------------- ··· 1135 998 Repository: git+https://github.com/WebReflection/flatted.git 1136 999 1137 1000 > ISC License 1138 - > 1001 + > 1139 1002 > Copyright (c) 2018-2020, Andrea Giammarchi, @WebReflection 1140 - > 1003 + > 1141 1004 > Permission to use, copy, modify, and/or distribute this software for any 1142 1005 > purpose with or without fee is hereby granted, provided that the above 1143 1006 > copyright notice and this permission notice appear in all copies. 1144 - > 1007 + > 1145 1008 > THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 1146 1009 > REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 1147 1010 > AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, ··· 1158 1021 Repository: sindresorhus/get-stream 1159 1022 1160 1023 > MIT License 1161 - > 1024 + > 1162 1025 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 1163 - > 1026 + > 1164 1027 > 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: 1165 - > 1028 + > 1166 1029 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 1167 - > 1030 + > 1168 1031 > 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. 1169 1032 1170 1033 --------------------------------------- ··· 1175 1038 Repository: privatenumber/get-tsconfig 1176 1039 1177 1040 > MIT License 1178 - > 1041 + > 1179 1042 > Copyright (c) Hiroki Osame <hiroki.osame@gmail.com> 1180 - > 1043 + > 1181 1044 > Permission is hereby granted, free of charge, to any person obtaining a copy 1182 1045 > of this software and associated documentation files (the "Software"), to deal 1183 1046 > in the Software without restriction, including without limitation the rights 1184 1047 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1185 1048 > copies of the Software, and to permit persons to whom the Software is 1186 1049 > furnished to do so, subject to the following conditions: 1187 - > 1050 + > 1188 1051 > The above copyright notice and this permission notice shall be included in all 1189 1052 > copies or substantial portions of the Software. 1190 - > 1053 + > 1191 1054 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1192 1055 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1193 1056 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 1204 1067 Repository: gulpjs/glob-parent 1205 1068 1206 1069 > The ISC License 1207 - > 1070 + > 1208 1071 > Copyright (c) 2015, 2019 Elan Shanker 1209 - > 1072 + > 1210 1073 > Permission to use, copy, modify, and/or distribute this software for any 1211 1074 > purpose with or without fee is hereby granted, provided that the above 1212 1075 > copyright notice and this permission notice appear in all copies. 1213 - > 1076 + > 1214 1077 > THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1215 1078 > WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1216 1079 > MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ··· 1229 1092 > Apache License 1230 1093 > Version 2.0, January 2004 1231 1094 > http://www.apache.org/licenses/ 1232 - > 1095 + > 1233 1096 > TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1234 - > 1097 + > 1235 1098 > 1. Definitions. 1236 - > 1099 + > 1237 1100 > "License" shall mean the terms and conditions for use, reproduction, 1238 1101 > and distribution as defined by Sections 1 through 9 of this document. 1239 - > 1102 + > 1240 1103 > "Licensor" shall mean the copyright owner or entity authorized by 1241 1104 > the copyright owner that is granting the License. 1242 - > 1105 + > 1243 1106 > "Legal Entity" shall mean the union of the acting entity and all 1244 1107 > other entities that control, are controlled by, or are under common 1245 1108 > control with that entity. For the purposes of this definition, ··· 1247 1110 > direction or management of such entity, whether by contract or 1248 1111 > otherwise, or (ii) ownership of fifty percent (50%) or more of the 1249 1112 > outstanding shares, or (iii) beneficial ownership of such entity. 1250 - > 1113 + > 1251 1114 > "You" (or "Your") shall mean an individual or Legal Entity 1252 1115 > exercising permissions granted by this License. 1253 - > 1116 + > 1254 1117 > "Source" form shall mean the preferred form for making modifications, 1255 1118 > including but not limited to software source code, documentation 1256 1119 > source, and configuration files. 1257 - > 1120 + > 1258 1121 > "Object" form shall mean any form resulting from mechanical 1259 1122 > transformation or translation of a Source form, including but 1260 1123 > not limited to compiled object code, generated documentation, 1261 1124 > and conversions to other media types. 1262 - > 1125 + > 1263 1126 > "Work" shall mean the work of authorship, whether in Source or 1264 1127 > Object form, made available under the License, as indicated by a 1265 1128 > copyright notice that is included in or attached to the work 1266 1129 > (an example is provided in the Appendix below). 1267 - > 1130 + > 1268 1131 > "Derivative Works" shall mean any work, whether in Source or Object 1269 1132 > form, that is based on (or derived from) the Work and for which the 1270 1133 > editorial revisions, annotations, elaborations, or other modifications ··· 1272 1135 > of this License, Derivative Works shall not include works that remain 1273 1136 > separable from, or merely link (or bind by name) to the interfaces of, 1274 1137 > the Work and Derivative Works thereof. 1275 - > 1138 + > 1276 1139 > "Contribution" shall mean any work of authorship, including 1277 1140 > the original version of the Work and any modifications or additions 1278 1141 > to that Work or Derivative Works thereof, that is intentionally ··· 1286 1149 > Licensor for the purpose of discussing and improving the Work, but 1287 1150 > excluding communication that is conspicuously marked or otherwise 1288 1151 > designated in writing by the copyright owner as "Not a Contribution." 1289 - > 1152 + > 1290 1153 > "Contributor" shall mean Licensor and any individual or Legal Entity 1291 1154 > on behalf of whom a Contribution has been received by Licensor and 1292 1155 > subsequently incorporated within the Work. 1293 - > 1156 + > 1294 1157 > 2. Grant of Copyright License. Subject to the terms and conditions of 1295 1158 > this License, each Contributor hereby grants to You a perpetual, 1296 1159 > worldwide, non-exclusive, no-charge, royalty-free, irrevocable 1297 1160 > copyright license to reproduce, prepare Derivative Works of, 1298 1161 > publicly display, publicly perform, sublicense, and distribute the 1299 1162 > Work and such Derivative Works in Source or Object form. 1300 - > 1163 + > 1301 1164 > 3. Grant of Patent License. Subject to the terms and conditions of 1302 1165 > this License, each Contributor hereby grants to You a perpetual, 1303 1166 > worldwide, non-exclusive, no-charge, royalty-free, irrevocable ··· 1313 1176 > or contributory patent infringement, then any patent licenses 1314 1177 > granted to You under this License for that Work shall terminate 1315 1178 > as of the date such litigation is filed. 1316 - > 1179 + > 1317 1180 > 4. Redistribution. You may reproduce and distribute copies of the 1318 1181 > Work or Derivative Works thereof in any medium, with or without 1319 1182 > modifications, and in Source or Object form, provided that You 1320 1183 > meet the following conditions: 1321 - > 1184 + > 1322 1185 > (a) You must give any other recipients of the Work or 1323 1186 > Derivative Works a copy of this License; and 1324 - > 1187 + > 1325 1188 > (b) You must cause any modified files to carry prominent notices 1326 1189 > stating that You changed the files; and 1327 - > 1190 + > 1328 1191 > (c) You must retain, in the Source form of any Derivative Works 1329 1192 > that You distribute, all copyright, patent, trademark, and 1330 1193 > attribution notices from the Source form of the Work, 1331 1194 > excluding those notices that do not pertain to any part of 1332 1195 > the Derivative Works; and 1333 - > 1196 + > 1334 1197 > (d) If the Work includes a "NOTICE" text file as part of its 1335 1198 > distribution, then any Derivative Works that You distribute must 1336 1199 > include a readable copy of the attribution notices contained ··· 1347 1210 > or as an addendum to the NOTICE text from the Work, provided 1348 1211 > that such additional attribution notices cannot be construed 1349 1212 > as modifying the License. 1350 - > 1213 + > 1351 1214 > You may add Your own copyright statement to Your modifications and 1352 1215 > may provide additional or different license terms and conditions 1353 1216 > for use, reproduction, or distribution of Your modifications, or 1354 1217 > for any such Derivative Works as a whole, provided Your use, 1355 1218 > reproduction, and distribution of the Work otherwise complies with 1356 1219 > the conditions stated in this License. 1357 - > 1220 + > 1358 1221 > 5. Submission of Contributions. Unless You explicitly state otherwise, 1359 1222 > any Contribution intentionally submitted for inclusion in the Work 1360 1223 > by You to the Licensor shall be under the terms and conditions of ··· 1362 1225 > Notwithstanding the above, nothing herein shall supersede or modify 1363 1226 > the terms of any separate license agreement you may have executed 1364 1227 > with Licensor regarding such Contributions. 1365 - > 1228 + > 1366 1229 > 6. Trademarks. This License does not grant permission to use the trade 1367 1230 > names, trademarks, service marks, or product names of the Licensor, 1368 1231 > except as required for reasonable and customary use in describing the 1369 1232 > origin of the Work and reproducing the content of the NOTICE file. 1370 - > 1233 + > 1371 1234 > 7. Disclaimer of Warranty. Unless required by applicable law or 1372 1235 > agreed to in writing, Licensor provides the Work (and each 1373 1236 > Contributor provides its Contributions) on an "AS IS" BASIS, ··· 1377 1240 > PARTICULAR PURPOSE. You are solely responsible for determining the 1378 1241 > appropriateness of using or redistributing the Work and assume any 1379 1242 > risks associated with Your exercise of permissions under this License. 1380 - > 1243 + > 1381 1244 > 8. Limitation of Liability. In no event and under no legal theory, 1382 1245 > whether in tort (including negligence), contract, or otherwise, 1383 1246 > unless required by applicable law (such as deliberate and grossly ··· 1389 1252 > work stoppage, computer failure or malfunction, or any and all 1390 1253 > other commercial damages or losses), even if such Contributor 1391 1254 > has been advised of the possibility of such damages. 1392 - > 1255 + > 1393 1256 > 9. Accepting Warranty or Additional Liability. While redistributing 1394 1257 > the Work or Derivative Works thereof, You may choose to offer, 1395 1258 > and charge a fee for, acceptance of support, warranty, indemnity, ··· 1400 1263 > defend, and hold each Contributor harmless for any liability 1401 1264 > incurred by, or claims asserted against, such Contributor by reason 1402 1265 > of your accepting any such warranty or additional liability. 1403 - > 1266 + > 1404 1267 > END OF TERMS AND CONDITIONS 1405 - > 1268 + > 1406 1269 > APPENDIX: How to apply the Apache License to your work. 1407 - > 1270 + > 1408 1271 > To apply the Apache License to your work, attach the following 1409 1272 > boilerplate notice, with the fields enclosed by brackets "[]" 1410 1273 > replaced with your own identifying information. (Don't include ··· 1413 1276 > file or class name and description of purpose be included on the 1414 1277 > same "printed page" as the copyright notice for easier 1415 1278 > identification within third-party archives. 1416 - > 1279 + > 1417 1280 > Copyright 2022 ehmicky <ehmicky@gmail.com> 1418 - > 1281 + > 1419 1282 > Licensed under the Apache License, Version 2.0 (the "License"); 1420 1283 > you may not use this file except in compliance with the License. 1421 1284 > You may obtain a copy of the License at 1422 - > 1285 + > 1423 1286 > http://www.apache.org/licenses/LICENSE-2.0 1424 - > 1287 + > 1425 1288 > Unless required by applicable law or agreed to in writing, software 1426 1289 > distributed under the License is distributed on an "AS IS" BASIS, 1427 1290 > WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ··· 1436 1299 Repository: jonschlinkert/is-extglob 1437 1300 1438 1301 > The MIT License (MIT) 1439 - > 1302 + > 1440 1303 > Copyright (c) 2014-2016, Jon Schlinkert 1441 - > 1304 + > 1442 1305 > Permission is hereby granted, free of charge, to any person obtaining a copy 1443 1306 > of this software and associated documentation files (the "Software"), to deal 1444 1307 > in the Software without restriction, including without limitation the rights 1445 1308 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1446 1309 > copies of the Software, and to permit persons to whom the Software is 1447 1310 > furnished to do so, subject to the following conditions: 1448 - > 1311 + > 1449 1312 > The above copyright notice and this permission notice shall be included in 1450 1313 > all copies or substantial portions of the Software. 1451 - > 1314 + > 1452 1315 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1453 1316 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1454 1317 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 1465 1328 Repository: sindresorhus/is-fullwidth-code-point 1466 1329 1467 1330 > MIT License 1468 - > 1331 + > 1469 1332 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 1470 - > 1333 + > 1471 1334 > 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: 1472 - > 1335 + > 1473 1336 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 1474 - > 1337 + > 1475 1338 > 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. 1476 1339 1477 1340 --------------------------------------- ··· 1482 1345 Repository: micromatch/is-glob 1483 1346 1484 1347 > The MIT License (MIT) 1485 - > 1348 + > 1486 1349 > Copyright (c) 2014-2017, Jon Schlinkert. 1487 - > 1350 + > 1488 1351 > Permission is hereby granted, free of charge, to any person obtaining a copy 1489 1352 > of this software and associated documentation files (the "Software"), to deal 1490 1353 > in the Software without restriction, including without limitation the rights 1491 1354 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1492 1355 > copies of the Software, and to permit persons to whom the Software is 1493 1356 > furnished to do so, subject to the following conditions: 1494 - > 1357 + > 1495 1358 > The above copyright notice and this permission notice shall be included in 1496 1359 > all copies or substantial portions of the Software. 1497 - > 1360 + > 1498 1361 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1499 1362 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1500 1363 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 1511 1374 Repository: jonschlinkert/is-number 1512 1375 1513 1376 > The MIT License (MIT) 1514 - > 1377 + > 1515 1378 > Copyright (c) 2014-present, Jon Schlinkert. 1516 - > 1379 + > 1517 1380 > Permission is hereby granted, free of charge, to any person obtaining a copy 1518 1381 > of this software and associated documentation files (the "Software"), to deal 1519 1382 > in the Software without restriction, including without limitation the rights 1520 1383 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1521 1384 > copies of the Software, and to permit persons to whom the Software is 1522 1385 > furnished to do so, subject to the following conditions: 1523 - > 1386 + > 1524 1387 > The above copyright notice and this permission notice shall be included in 1525 1388 > all copies or substantial portions of the Software. 1526 - > 1389 + > 1527 1390 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1528 1391 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1529 1392 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 1540 1403 Repository: sindresorhus/is-stream 1541 1404 1542 1405 > MIT License 1543 - > 1406 + > 1544 1407 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 1545 - > 1408 + > 1546 1409 > 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: 1547 - > 1410 + > 1548 1411 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 1549 - > 1412 + > 1550 1413 > 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. 1551 1414 1552 1415 --------------------------------------- ··· 1557 1420 Repository: git+https://github.com/isaacs/isexe.git 1558 1421 1559 1422 > The ISC License 1560 - > 1423 + > 1561 1424 > Copyright (c) Isaac Z. Schlueter and Contributors 1562 - > 1425 + > 1563 1426 > Permission to use, copy, modify, and/or distribute this software for any 1564 1427 > purpose with or without fee is hereby granted, provided that the above 1565 1428 > copyright notice and this permission notice appear in all copies. 1566 - > 1429 + > 1567 1430 > THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1568 1431 > WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1569 1432 > MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ··· 1580 1443 Repository: lukeed/kleur 1581 1444 1582 1445 > The MIT License (MIT) 1583 - > 1446 + > 1584 1447 > Copyright (c) Luke Edwards <luke.edwards05@gmail.com> (lukeed.com) 1585 - > 1448 + > 1586 1449 > Permission is hereby granted, free of charge, to any person obtaining a copy 1587 1450 > of this software and associated documentation files (the "Software"), to deal 1588 1451 > in the Software without restriction, including without limitation the rights 1589 1452 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1590 1453 > copies of the Software, and to permit persons to whom the Software is 1591 1454 > furnished to do so, subject to the following conditions: 1592 - > 1455 + > 1593 1456 > The above copyright notice and this permission notice shall be included in 1594 1457 > all copies or substantial portions of the Software. 1595 - > 1458 + > 1596 1459 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1597 1460 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1598 1461 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 1609 1472 Repository: sindresorhus/locate-path 1610 1473 1611 1474 > MIT License 1612 - > 1475 + > 1613 1476 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 1614 - > 1477 + > 1615 1478 > 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: 1616 - > 1479 + > 1617 1480 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 1618 - > 1481 + > 1619 1482 > 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. 1620 1483 1621 1484 --------------------------------------- ··· 1626 1489 Repository: sindresorhus/log-update 1627 1490 1628 1491 > MIT License 1629 - > 1492 + > 1630 1493 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 1631 - > 1494 + > 1632 1495 > 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: 1633 - > 1496 + > 1634 1497 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 1635 - > 1636 - > 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. 1637 - 1638 - --------------------------------------- 1639 - 1640 - ## magic-string 1641 - License: MIT 1642 - By: Rich Harris 1643 - Repository: https://github.com/rich-harris/magic-string 1644 - 1645 - > Copyright 2018 Rich Harris 1646 - > 1647 - > 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: 1648 - > 1649 - > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 1650 - > 1498 + > 1651 1499 > 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. 1652 1500 1653 1501 --------------------------------------- ··· 1658 1506 Repository: grncdr/merge-stream 1659 1507 1660 1508 > The MIT License (MIT) 1661 - > 1509 + > 1662 1510 > Copyright (c) Stephen Sugden <me@stephensugden.com> (stephensugden.com) 1663 - > 1511 + > 1664 1512 > Permission is hereby granted, free of charge, to any person obtaining a copy 1665 1513 > of this software and associated documentation files (the "Software"), to deal 1666 1514 > in the Software without restriction, including without limitation the rights 1667 1515 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1668 1516 > copies of the Software, and to permit persons to whom the Software is 1669 1517 > furnished to do so, subject to the following conditions: 1670 - > 1518 + > 1671 1519 > The above copyright notice and this permission notice shall be included in 1672 1520 > all copies or substantial portions of the Software. 1673 - > 1521 + > 1674 1522 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1675 1523 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1676 1524 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 1686 1534 Repository: git@github.com:teambition/merge2.git 1687 1535 1688 1536 > The MIT License (MIT) 1689 - > 1537 + > 1690 1538 > Copyright (c) 2014-2020 Teambition 1691 - > 1539 + > 1692 1540 > Permission is hereby granted, free of charge, to any person obtaining a copy 1693 1541 > of this software and associated documentation files (the "Software"), to deal 1694 1542 > in the Software without restriction, including without limitation the rights 1695 1543 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1696 1544 > copies of the Software, and to permit persons to whom the Software is 1697 1545 > furnished to do so, subject to the following conditions: 1698 - > 1546 + > 1699 1547 > The above copyright notice and this permission notice shall be included in all 1700 1548 > copies or substantial portions of the Software. 1701 - > 1549 + > 1702 1550 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1703 1551 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1704 1552 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 1715 1563 Repository: micromatch/micromatch 1716 1564 1717 1565 > The MIT License (MIT) 1718 - > 1566 + > 1719 1567 > Copyright (c) 2014-present, Jon Schlinkert. 1720 - > 1568 + > 1721 1569 > Permission is hereby granted, free of charge, to any person obtaining a copy 1722 1570 > of this software and associated documentation files (the "Software"), to deal 1723 1571 > in the Software without restriction, including without limitation the rights 1724 1572 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1725 1573 > copies of the Software, and to permit persons to whom the Software is 1726 1574 > furnished to do so, subject to the following conditions: 1727 - > 1575 + > 1728 1576 > The above copyright notice and this permission notice shall be included in 1729 1577 > all copies or substantial portions of the Software. 1730 - > 1578 + > 1731 1579 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1732 1580 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1733 1581 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 1744 1592 Repository: sindresorhus/mimic-fn 1745 1593 1746 1594 > MIT License 1747 - > 1595 + > 1748 1596 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com) 1749 - > 1597 + > 1750 1598 > 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: 1751 - > 1599 + > 1752 1600 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 1753 - > 1601 + > 1754 1602 > 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. 1755 1603 1756 1604 --------------------------------------- ··· 1760 1608 Repository: unjs/mlly 1761 1609 1762 1610 > MIT License 1763 - > 1611 + > 1764 1612 > Copyright (c) Pooya Parsa <pooya@pi0.io> 1765 - > 1613 + > 1766 1614 > Permission is hereby granted, free of charge, to any person obtaining a copy 1767 1615 > of this software and associated documentation files (the "Software"), to deal 1768 1616 > in the Software without restriction, including without limitation the rights 1769 1617 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1770 1618 > copies of the Software, and to permit persons to whom the Software is 1771 1619 > furnished to do so, subject to the following conditions: 1772 - > 1620 + > 1773 1621 > The above copyright notice and this permission notice shall be included in all 1774 1622 > copies or substantial portions of the Software. 1775 - > 1623 + > 1776 1624 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1777 1625 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1778 1626 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 1783 1631 1784 1632 --------------------------------------- 1785 1633 1786 - ## natural-compare 1787 - License: MIT 1788 - By: Lauri Rooden 1789 - Repository: git://github.com/litejs/natural-compare-lite.git 1790 - 1791 - --------------------------------------- 1792 - 1793 1634 ## npm-run-path 1794 1635 License: MIT 1795 1636 By: Sindre Sorhus 1796 1637 Repository: sindresorhus/npm-run-path 1797 1638 1798 1639 > MIT License 1799 - > 1640 + > 1800 1641 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 1801 - > 1642 + > 1802 1643 > 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: 1803 - > 1644 + > 1804 1645 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 1805 - > 1646 + > 1806 1647 > 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. 1807 1648 1808 1649 --------------------------------------- ··· 1813 1654 Repository: sindresorhus/onetime 1814 1655 1815 1656 > MIT License 1816 - > 1657 + > 1817 1658 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 1818 - > 1659 + > 1819 1660 > 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: 1820 - > 1661 + > 1821 1662 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 1822 - > 1663 + > 1823 1664 > 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. 1824 1665 1825 1666 --------------------------------------- ··· 1830 1671 Repository: sindresorhus/p-limit 1831 1672 1832 1673 > MIT License 1833 - > 1674 + > 1834 1675 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 1835 - > 1676 + > 1836 1677 > 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: 1837 - > 1678 + > 1838 1679 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 1839 - > 1680 + > 1840 1681 > 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. 1841 1682 1842 1683 --------------------------------------- ··· 1847 1688 Repository: sindresorhus/p-locate 1848 1689 1849 1690 > MIT License 1850 - > 1691 + > 1851 1692 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 1852 - > 1693 + > 1853 1694 > 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: 1854 - > 1695 + > 1855 1696 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 1856 - > 1697 + > 1857 1698 > 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. 1858 1699 1859 1700 --------------------------------------- ··· 1864 1705 Repository: sindresorhus/path-exists 1865 1706 1866 1707 > MIT License 1867 - > 1708 + > 1868 1709 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com) 1869 - > 1710 + > 1870 1711 > 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: 1871 - > 1712 + > 1872 1713 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 1873 - > 1714 + > 1874 1715 > 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. 1875 1716 1876 1717 --------------------------------------- ··· 1881 1722 Repository: sindresorhus/path-key 1882 1723 1883 1724 > MIT License 1884 - > 1725 + > 1885 1726 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com) 1886 - > 1727 + > 1887 1728 > 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: 1888 - > 1729 + > 1889 1730 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 1890 - > 1731 + > 1891 1732 > 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. 1892 1733 1893 1734 --------------------------------------- ··· 1898 1739 Repository: micromatch/picomatch 1899 1740 1900 1741 > The MIT License (MIT) 1901 - > 1742 + > 1902 1743 > Copyright (c) 2017-present, Jon Schlinkert. 1903 - > 1744 + > 1904 1745 > Permission is hereby granted, free of charge, to any person obtaining a copy 1905 1746 > of this software and associated documentation files (the "Software"), to deal 1906 1747 > in the Software without restriction, including without limitation the rights 1907 1748 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1908 1749 > copies of the Software, and to permit persons to whom the Software is 1909 1750 > furnished to do so, subject to the following conditions: 1910 - > 1751 + > 1911 1752 > The above copyright notice and this permission notice shall be included in 1912 1753 > all copies or substantial portions of the Software. 1913 - > 1754 + > 1914 1755 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1915 1756 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1916 1757 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 1921 1762 1922 1763 --------------------------------------- 1923 1764 1924 - ## pretty-format 1925 - License: MIT 1926 - By: James Kyle 1927 - Repository: https://github.com/facebook/jest.git 1928 - 1929 - > MIT License 1930 - > 1931 - > Copyright (c) Facebook, Inc. and its affiliates. 1932 - > 1933 - > Permission is hereby granted, free of charge, to any person obtaining a copy 1934 - > of this software and associated documentation files (the "Software"), to deal 1935 - > in the Software without restriction, including without limitation the rights 1936 - > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1937 - > copies of the Software, and to permit persons to whom the Software is 1938 - > furnished to do so, subject to the following conditions: 1939 - > 1940 - > The above copyright notice and this permission notice shall be included in all 1941 - > copies or substantial portions of the Software. 1942 - > 1943 - > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1944 - > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1945 - > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1946 - > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1947 - > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1948 - > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 1949 - > SOFTWARE. 1950 - 1951 - --------------------------------------- 1952 - 1953 1765 ## prompts 1954 1766 License: MIT 1955 1767 By: Terkel Gjervig 1956 1768 Repository: terkelg/prompts 1957 1769 1958 1770 > MIT License 1959 - > 1771 + > 1960 1772 > Copyright (c) 2018 Terkel Gjervig Nielsen 1961 - > 1773 + > 1962 1774 > Permission is hereby granted, free of charge, to any person obtaining a copy 1963 1775 > of this software and associated documentation files (the "Software"), to deal 1964 1776 > in the Software without restriction, including without limitation the rights 1965 1777 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1966 1778 > copies of the Software, and to permit persons to whom the Software is 1967 1779 > furnished to do so, subject to the following conditions: 1968 - > 1780 + > 1969 1781 > The above copyright notice and this permission notice shall be included in all 1970 1782 > copies or substantial portions of the Software. 1971 - > 1783 + > 1972 1784 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1973 1785 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1974 1786 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 1985 1797 Repository: git://github.com/feross/queue-microtask.git 1986 1798 1987 1799 > The MIT License (MIT) 1988 - > 1800 + > 1989 1801 > Copyright (c) Feross Aboukhadijeh 1990 - > 1802 + > 1991 1803 > Permission is hereby granted, free of charge, to any person obtaining a copy of 1992 1804 > this software and associated documentation files (the "Software"), to deal in 1993 1805 > the Software without restriction, including without limitation the rights to 1994 1806 > use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 1995 1807 > the Software, and to permit persons to whom the Software is furnished to do so, 1996 1808 > subject to the following conditions: 1997 - > 1809 + > 1998 1810 > The above copyright notice and this permission notice shall be included in all 1999 1811 > copies or substantial portions of the Software. 2000 - > 1812 + > 2001 1813 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2002 1814 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 2003 1815 > FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR ··· 2007 1819 2008 1820 --------------------------------------- 2009 1821 2010 - ## react-is 2011 - License: MIT 2012 - Repository: https://github.com/facebook/react.git 2013 - 2014 - > MIT License 2015 - > 2016 - > Copyright (c) Facebook, Inc. and its affiliates. 2017 - > 2018 - > Permission is hereby granted, free of charge, to any person obtaining a copy 2019 - > of this software and associated documentation files (the "Software"), to deal 2020 - > in the Software without restriction, including without limitation the rights 2021 - > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 2022 - > copies of the Software, and to permit persons to whom the Software is 2023 - > furnished to do so, subject to the following conditions: 2024 - > 2025 - > The above copyright notice and this permission notice shall be included in all 2026 - > copies or substantial portions of the Software. 2027 - > 2028 - > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2029 - > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2030 - > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2031 - > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2032 - > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2033 - > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2034 - > SOFTWARE. 2035 - 2036 - --------------------------------------- 2037 - 2038 1822 ## restore-cursor 2039 1823 License: MIT 2040 1824 By: Sindre Sorhus 2041 1825 Repository: sindresorhus/restore-cursor 2042 1826 2043 1827 > MIT License 2044 - > 1828 + > 2045 1829 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 2046 - > 1830 + > 2047 1831 > 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: 2048 - > 1832 + > 2049 1833 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 2050 - > 1834 + > 2051 1835 > 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. 2052 1836 2053 1837 --------------------------------------- ··· 2058 1842 Repository: git+https://github.com/mcollina/reusify.git 2059 1843 2060 1844 > The MIT License (MIT) 2061 - > 1845 + > 2062 1846 > Copyright (c) 2015 Matteo Collina 2063 - > 1847 + > 2064 1848 > Permission is hereby granted, free of charge, to any person obtaining a copy 2065 1849 > of this software and associated documentation files (the "Software"), to deal 2066 1850 > in the Software without restriction, including without limitation the rights 2067 1851 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 2068 1852 > copies of the Software, and to permit persons to whom the Software is 2069 1853 > furnished to do so, subject to the following conditions: 2070 - > 1854 + > 2071 1855 > The above copyright notice and this permission notice shall be included in all 2072 1856 > copies or substantial portions of the Software. 2073 - > 1857 + > 2074 1858 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2075 1859 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2076 1860 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 2087 1871 Repository: git://github.com/feross/run-parallel.git 2088 1872 2089 1873 > The MIT License (MIT) 2090 - > 1874 + > 2091 1875 > Copyright (c) Feross Aboukhadijeh 2092 - > 1876 + > 2093 1877 > Permission is hereby granted, free of charge, to any person obtaining a copy of 2094 1878 > this software and associated documentation files (the "Software"), to deal in 2095 1879 > the Software without restriction, including without limitation the rights to 2096 1880 > use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 2097 1881 > the Software, and to permit persons to whom the Software is furnished to do so, 2098 1882 > subject to the following conditions: 2099 - > 1883 + > 2100 1884 > The above copyright notice and this permission notice shall be included in all 2101 1885 > copies or substantial portions of the Software. 2102 - > 1886 + > 2103 1887 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2104 1888 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 2105 1889 > FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR ··· 2115 1899 Repository: kevva/shebang-command 2116 1900 2117 1901 > MIT License 2118 - > 1902 + > 2119 1903 > Copyright (c) Kevin Mårtensson <kevinmartensson@gmail.com> (github.com/kevva) 2120 - > 1904 + > 2121 1905 > 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: 2122 - > 1906 + > 2123 1907 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 2124 - > 1908 + > 2125 1909 > 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. 2126 1910 2127 1911 --------------------------------------- ··· 2132 1916 Repository: sindresorhus/shebang-regex 2133 1917 2134 1918 > MIT License 2135 - > 1919 + > 2136 1920 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com) 2137 - > 1921 + > 2138 1922 > 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: 2139 - > 1923 + > 2140 1924 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 2141 - > 1925 + > 2142 1926 > 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. 2143 1927 2144 1928 --------------------------------------- ··· 2149 1933 Repository: https://github.com/tapjs/signal-exit.git 2150 1934 2151 1935 > The ISC License 2152 - > 1936 + > 2153 1937 > Copyright (c) 2015, Contributors 2154 - > 1938 + > 2155 1939 > Permission to use, copy, modify, and/or distribute this software 2156 1940 > for any purpose with or without fee is hereby granted, provided 2157 1941 > that the above copyright notice and this permission notice 2158 1942 > appear in all copies. 2159 - > 1943 + > 2160 1944 > THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 2161 1945 > WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 2162 1946 > OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE ··· 2173 1957 Repository: https://github.com/terkelg/sisteransi 2174 1958 2175 1959 > MIT License 2176 - > 1960 + > 2177 1961 > Copyright (c) 2018 Terkel Gjervig Nielsen 2178 - > 1962 + > 2179 1963 > Permission is hereby granted, free of charge, to any person obtaining a copy 2180 1964 > of this software and associated documentation files (the "Software"), to deal 2181 1965 > in the Software without restriction, including without limitation the rights 2182 1966 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 2183 1967 > copies of the Software, and to permit persons to whom the Software is 2184 1968 > furnished to do so, subject to the following conditions: 2185 - > 1969 + > 2186 1970 > The above copyright notice and this permission notice shall be included in all 2187 1971 > copies or substantial portions of the Software. 2188 - > 1972 + > 2189 1973 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2190 1974 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2191 1975 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 2201 1985 Repository: chalk/slice-ansi 2202 1986 2203 1987 > MIT License 2204 - > 1988 + > 2205 1989 > Copyright (c) DC <threedeecee@gmail.com> 2206 1990 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 2207 - > 1991 + > 2208 1992 > 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: 2209 - > 1993 + > 2210 1994 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 2211 - > 1995 + > 2212 1996 > 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. 2213 1997 2214 1998 --------------------------------------- ··· 2219 2003 Repository: sindresorhus/string-width 2220 2004 2221 2005 > MIT License 2222 - > 2006 + > 2223 2007 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 2224 - > 2008 + > 2225 2009 > 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: 2226 - > 2010 + > 2227 2011 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 2228 - > 2012 + > 2229 2013 > 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. 2230 2014 2231 2015 --------------------------------------- ··· 2236 2020 Repository: chalk/strip-ansi 2237 2021 2238 2022 > MIT License 2239 - > 2023 + > 2240 2024 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 2241 - > 2025 + > 2242 2026 > 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: 2243 - > 2027 + > 2244 2028 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 2245 - > 2029 + > 2246 2030 > 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. 2247 2031 2248 2032 --------------------------------------- ··· 2253 2037 Repository: sindresorhus/strip-final-newline 2254 2038 2255 2039 > MIT License 2256 - > 2040 + > 2257 2041 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 2258 - > 2042 + > 2259 2043 > 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: 2260 - > 2044 + > 2261 2045 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 2262 - > 2046 + > 2263 2047 > 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. 2264 2048 2265 2049 --------------------------------------- ··· 2270 2054 Repository: micromatch/to-regex-range 2271 2055 2272 2056 > The MIT License (MIT) 2273 - > 2057 + > 2274 2058 > Copyright (c) 2015-present, Jon Schlinkert. 2275 - > 2059 + > 2276 2060 > Permission is hereby granted, free of charge, to any person obtaining a copy 2277 2061 > of this software and associated documentation files (the "Software"), to deal 2278 2062 > in the Software without restriction, including without limitation the rights 2279 2063 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 2280 2064 > copies of the Software, and to permit persons to whom the Software is 2281 2065 > furnished to do so, subject to the following conditions: 2282 - > 2066 + > 2283 2067 > The above copyright notice and this permission notice shall be included in 2284 2068 > all copies or substantial portions of the Software. 2285 - > 2069 + > 2286 2070 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2287 2071 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2288 2072 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 2299 2083 Repository: git+ssh://git@github.com/chaijs/type-detect.git 2300 2084 2301 2085 > Copyright (c) 2013 Jake Luer <jake@alogicalparadox.com> (http://alogicalparadox.com) 2302 - > 2086 + > 2303 2087 > Permission is hereby granted, free of charge, to any person obtaining a copy 2304 2088 > of this software and associated documentation files (the "Software"), to deal 2305 2089 > in the Software without restriction, including without limitation the rights 2306 2090 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 2307 2091 > copies of the Software, and to permit persons to whom the Software is 2308 2092 > furnished to do so, subject to the following conditions: 2309 - > 2093 + > 2310 2094 > The above copyright notice and this permission notice shall be included in 2311 2095 > all copies or substantial portions of the Software. 2312 - > 2096 + > 2313 2097 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2314 2098 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2315 2099 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ··· 2326 2110 Repository: git://github.com/isaacs/node-which.git 2327 2111 2328 2112 > The ISC License 2329 - > 2113 + > 2330 2114 > Copyright (c) Isaac Z. Schlueter and Contributors 2331 - > 2115 + > 2332 2116 > Permission to use, copy, modify, and/or distribute this software for any 2333 2117 > purpose with or without fee is hereby granted, provided that the above 2334 2118 > copyright notice and this permission notice appear in all copies. 2335 - > 2119 + > 2336 2120 > THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 2337 2121 > WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 2338 2122 > MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ··· 2349 2133 Repository: chalk/wrap-ansi 2350 2134 2351 2135 > MIT License 2352 - > 2136 + > 2353 2137 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 2354 - > 2138 + > 2355 2139 > 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: 2356 - > 2140 + > 2357 2141 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 2358 - > 2142 + > 2359 2143 > 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. 2360 2144 2361 2145 --------------------------------------- ··· 2368 2152 > Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com> 2369 2153 > Copyright (c) 2013 Arnout Kazemier and contributors 2370 2154 > Copyright (c) 2016 Luigi Pinca and contributors 2371 - > 2155 + > 2372 2156 > Permission is hereby granted, free of charge, to any person obtaining a copy of 2373 2157 > this software and associated documentation files (the "Software"), to deal in 2374 2158 > the Software without restriction, including without limitation the rights to 2375 2159 > use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 2376 2160 > the Software, and to permit persons to whom the Software is furnished to do so, 2377 2161 > subject to the following conditions: 2378 - > 2162 + > 2379 2163 > The above copyright notice and this permission notice shall be included in all 2380 2164 > copies or substantial portions of the Software. 2381 - > 2165 + > 2382 2166 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2383 2167 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 2384 2168 > FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR ··· 2394 2178 Repository: sindresorhus/yocto-queue 2395 2179 2396 2180 > MIT License 2397 - > 2181 + > 2398 2182 > Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) 2399 - > 2183 + > 2400 2184 > 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: 2401 - > 2185 + > 2402 2186 > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 2403 - > 2187 + > 2404 2188 > 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.
+2 -3
packages/vitest/package.json
··· 139 139 "@types/node": "*", 140 140 "@vitest/expect": "workspace:*", 141 141 "@vitest/runner": "workspace:*", 142 + "@vitest/snapshot": "workspace:*", 142 143 "@vitest/spy": "workspace:*", 143 144 "@vitest/utils": "workspace:*", 144 145 "acorn": "^8.8.1", ··· 148 149 "concordance": "^5.0.4", 149 150 "debug": "^4.3.4", 150 151 "local-pkg": "^0.4.2", 152 + "magic-string": "^0.27.0", 151 153 "pathe": "^1.1.0", 152 154 "picocolors": "^1.0.0", 153 155 "source-map": "^0.6.1", ··· 169 171 "@types/istanbul-reports": "^3.0.1", 170 172 "@types/jsdom": "^20.0.1", 171 173 "@types/micromatch": "^4.0.2", 172 - "@types/natural-compare": "^1.4.1", 173 174 "@types/prompts": "^2.4.2", 174 175 "@types/sinonjs__fake-timers": "^8.1.2", 175 176 "birpc": "^0.2.3", ··· 185 186 "happy-dom": "^8.3.2", 186 187 "jsdom": "^21.1.0", 187 188 "log-update": "^5.0.1", 188 - "magic-string": "^0.27.0", 189 189 "micromatch": "^4.0.5", 190 190 "mlly": "^1.1.0", 191 - "natural-compare": "^1.4.0", 192 191 "p-limit": "^4.0.0", 193 192 "pkg-types": "^1.0.1", 194 193 "playwright": "^1.28.0",
+2
packages/vitest/rollup.config.js
··· 61 61 '@vitest/utils/diff', 62 62 '@vitest/runner/utils', 63 63 '@vitest/runner/types', 64 + '@vitest/snapshot/environment', 65 + '@vitest/snapshot/manager', 64 66 ] 65 67 66 68 const plugins = [
+2
packages/ws-client/rollup.config.js
··· 18 18 'node:fs', 19 19 'vitest', 20 20 'inspector', 21 + '@vitest/snapshot/environment', 22 + '@vitest/snapshot/manager', 21 23 ] 22 24 23 25 export default () => [
+7
test/config/vitest.config.ts
··· 1 + import { defineConfig } from 'vitest/config' 2 + 3 + export default defineConfig({ 4 + test: { 5 + testTimeout: 60_000, 6 + }, 7 + })
+155
packages/snapshot/src/client.ts
··· 1 + import { deepMergeSnapshot } from './port/utils' 2 + import SnapshotState from './port/state' 3 + import type { SnapshotStateOptions } from './types' 4 + 5 + const createMismatchError = (message: string, actual: unknown, expected: unknown) => { 6 + const error = new Error(message) 7 + Object.defineProperty(error, 'actual', { 8 + value: actual, 9 + enumerable: true, 10 + configurable: true, 11 + writable: true, 12 + }) 13 + Object.defineProperty(error, 'expected', { 14 + value: expected, 15 + enumerable: true, 16 + configurable: true, 17 + writable: true, 18 + }) 19 + return error 20 + } 21 + 22 + export interface Context { 23 + file: string 24 + title?: string 25 + fullTitle?: string 26 + } 27 + 28 + interface AssertOptions { 29 + received: unknown 30 + filepath?: string 31 + name?: string 32 + message?: string 33 + isInline?: boolean 34 + properties?: object 35 + inlineSnapshot?: string 36 + error?: Error 37 + errorMessage?: string 38 + } 39 + 40 + export class SnapshotClient { 41 + filepath?: string 42 + name?: string 43 + snapshotState: SnapshotState | undefined 44 + snapshotStateMap = new Map<string, SnapshotState>() 45 + 46 + constructor(private Service = SnapshotState) {} 47 + 48 + async setTest(filepath: string, name: string, options: SnapshotStateOptions) { 49 + this.filepath = filepath 50 + this.name = name 51 + 52 + if (this.snapshotState?.testFilePath !== filepath) { 53 + this.resetCurrent() 54 + 55 + if (!this.getSnapshotState(filepath)) { 56 + this.snapshotStateMap.set( 57 + filepath, 58 + await this.Service.create( 59 + filepath, 60 + options, 61 + ), 62 + ) 63 + } 64 + this.snapshotState = this.getSnapshotState(filepath) 65 + } 66 + } 67 + 68 + getSnapshotState(filepath: string) { 69 + return this.snapshotStateMap.get(filepath)! 70 + } 71 + 72 + clearTest() { 73 + this.filepath = undefined 74 + this.name = undefined 75 + } 76 + 77 + skipTestSnapshots(name: string) { 78 + this.snapshotState?.markSnapshotsAsCheckedForTest(name) 79 + } 80 + 81 + /** 82 + * Should be overriden by the consumer. 83 + * 84 + * Vitest checks equality with @vitest/expect. 85 + */ 86 + equalityCheck(received: unknown, expected: unknown) { 87 + return received === expected 88 + } 89 + 90 + assert(options: AssertOptions): void { 91 + const { 92 + filepath = this.filepath, 93 + name = this.name, 94 + message, 95 + isInline = false, 96 + properties, 97 + inlineSnapshot, 98 + error, 99 + errorMessage, 100 + } = options 101 + let { received } = options 102 + 103 + if (!filepath) 104 + throw new Error('Snapshot cannot be used outside of test') 105 + 106 + if (typeof properties === 'object') { 107 + if (typeof received !== 'object' || !received) 108 + throw new Error('Received value must be an object when the matcher has properties') 109 + 110 + try { 111 + const pass = this.equalityCheck(received, properties) 112 + // const pass = equals(received, properties, [iterableEquality, subsetEquality]) 113 + if (!pass) 114 + throw createMismatchError('Snapshot properties mismatched', received, properties) 115 + else 116 + received = deepMergeSnapshot(received, properties) 117 + } 118 + catch (err: any) { 119 + err.message = errorMessage || 'Snapshot mismatched' 120 + throw err 121 + } 122 + } 123 + 124 + const testName = [ 125 + name, 126 + ...(message ? [message] : []), 127 + ].join(' > ') 128 + 129 + const snapshotState = this.getSnapshotState(filepath) 130 + 131 + const { actual, expected, key, pass } = snapshotState.match({ 132 + testName, 133 + received, 134 + isInline, 135 + error, 136 + inlineSnapshot, 137 + }) 138 + 139 + if (!pass) 140 + throw createMismatchError(`Snapshot \`${key || 'unknown'}\` mismatched`, actual?.trim(), expected?.trim()) 141 + } 142 + 143 + async resetCurrent() { 144 + if (!this.snapshotState) 145 + return null 146 + const result = await this.snapshotState.pack() 147 + 148 + this.snapshotState = undefined 149 + return result 150 + } 151 + 152 + clear() { 153 + this.snapshotStateMap.clear() 154 + } 155 + }
+2
packages/snapshot/src/environment.ts
··· 1 + export { NodeSnapshotEnvironment } from './env/node' 2 + export type { SnapshotEnvironment } from './types/environment'
+15
packages/snapshot/src/index.ts
··· 1 + export { SnapshotClient } from './client' 2 + 3 + export { default as SnapshotState } from './port/state' 4 + export { addSerializer, getSerializers } from './port/plugins' 5 + export { stripSnapshotIndentation } from './port/inlineSnapshot' 6 + 7 + export type { 8 + SnapshotData, 9 + SnapshotUpdateState, 10 + SnapshotStateOptions, 11 + SnapshotMatchOptions, 12 + SnapshotResult, 13 + UncheckedSnapshot, 14 + SnapshotSummary, 15 + } from './types'
+76
packages/snapshot/src/manager.ts
··· 1 + import { basename, dirname, join } from 'pathe' 2 + import type { SnapshotResult, SnapshotStateOptions, SnapshotSummary } from './types' 3 + 4 + export class SnapshotManager { 5 + summary: SnapshotSummary = undefined! 6 + extension = '.snap' 7 + 8 + constructor(public options: Omit<SnapshotStateOptions, 'snapshotEnvironment'>) { 9 + this.clear() 10 + } 11 + 12 + clear() { 13 + this.summary = emptySummary(this.options) 14 + } 15 + 16 + add(result: SnapshotResult) { 17 + addSnapshotResult(this.summary, result) 18 + } 19 + 20 + resolvePath(testPath: string) { 21 + const resolver = this.options.resolveSnapshotPath || (() => { 22 + return join( 23 + join( 24 + dirname(testPath), '__snapshots__'), 25 + `${basename(testPath)}${this.extension}`, 26 + ) 27 + }) 28 + 29 + return resolver(testPath, this.extension) 30 + } 31 + } 32 + 33 + export function emptySummary(options: Omit<SnapshotStateOptions, 'snapshotEnvironment'>): SnapshotSummary { 34 + const summary = { 35 + added: 0, 36 + failure: false, 37 + filesAdded: 0, 38 + filesRemoved: 0, 39 + filesRemovedList: [], 40 + filesUnmatched: 0, 41 + filesUpdated: 0, 42 + matched: 0, 43 + total: 0, 44 + unchecked: 0, 45 + uncheckedKeysByFile: [], 46 + unmatched: 0, 47 + updated: 0, 48 + didUpdate: options.updateSnapshot === 'all', 49 + } 50 + return summary 51 + } 52 + 53 + export function addSnapshotResult(summary: SnapshotSummary, result: SnapshotResult): void { 54 + if (result.added) 55 + summary.filesAdded++ 56 + if (result.fileDeleted) 57 + summary.filesRemoved++ 58 + if (result.unmatched) 59 + summary.filesUnmatched++ 60 + if (result.updated) 61 + summary.filesUpdated++ 62 + 63 + summary.added += result.added 64 + summary.matched += result.matched 65 + summary.unchecked += result.unchecked 66 + if (result.uncheckedKeys && result.uncheckedKeys.length > 0) { 67 + summary.uncheckedKeysByFile.push({ 68 + filePath: result.filepath, 69 + keys: result.uncheckedKeys, 70 + }) 71 + } 72 + 73 + summary.unmatched += result.unmatched 74 + summary.updated += result.updated 75 + summary.total += result.added + result.matched + result.unmatched + result.updated 76 + }
+1 -1
packages/utils/src/colors.ts
··· 47 47 string.open = '' 48 48 string.close = '' 49 49 50 - const defaultColors = colorsEntries.reduce((acc, [key]) => { 50 + const defaultColors = /* #__PURE__ */ colorsEntries.reduce((acc, [key]) => { 51 51 acc[key as ColorName] = string 52 52 return acc 53 53 }, { isColorSupported: false } as Colors)
+2
packages/utils/src/diff.ts
··· 1 1 import { getColors } from './colors' 2 2 import { diffDescriptors, getConcordanceTheme } from './descriptors' 3 3 4 + export * from './descriptors' 5 + 4 6 export interface DiffOptions { 5 7 showLegend?: boolean 6 8 outputDiffLines?: number
+50
packages/utils/src/helpers.ts
··· 1 1 import type { Arrayable, Nullable } from './types' 2 2 3 + export function notNullish<T>(v: T | null | undefined): v is NonNullable<T> { 4 + return v != null 5 + } 6 + 3 7 export function assertTypes(value: unknown, name: string, types: string[]): void { 4 8 const receivedType = typeof value 5 9 const pass = types.includes(receivedType) 6 10 if (!pass) 7 11 throw new TypeError(`${name} value must be ${types.join(' or ')}, received "${receivedType}"`) 12 + } 13 + 14 + export function isPrimitive(value: unknown) { 15 + return value === null || (typeof value !== 'function' && typeof value !== 'object') 8 16 } 9 17 10 18 export function slash(path: string) { ··· 143 151 p.resolve = resolve! 144 152 p.reject = reject! 145 153 return p 154 + } 155 + 156 + /** 157 + * If code starts with a function call, will return its last index, respecting arguments. 158 + * This will return 25 - last ending character of toMatch ")" 159 + * Also works with callbacks 160 + * ``` 161 + * toMatch({ test: '123' }); 162 + * toBeAliased('123') 163 + * ``` 164 + */ 165 + export function getCallLastIndex(code: string) { 166 + let charIndex = -1 167 + let inString: string | null = null 168 + let startedBracers = 0 169 + let endedBracers = 0 170 + let beforeChar: string | null = null 171 + while (charIndex <= code.length) { 172 + beforeChar = code[charIndex] 173 + charIndex++ 174 + const char = code[charIndex] 175 + 176 + const isCharString = char === '"' || char === '\'' || char === '`' 177 + 178 + if (isCharString && beforeChar !== '\\') { 179 + if (inString === char) 180 + inString = null 181 + else if (!inString) 182 + inString = char 183 + } 184 + 185 + if (!inString) { 186 + if (char === '(') 187 + startedBracers++ 188 + if (char === ')') 189 + endedBracers++ 190 + } 191 + 192 + if (startedBracers && endedBracers && startedBracers === endedBracers) 193 + return charIndex 194 + } 195 + return null 146 196 }
+1 -1
packages/utils/src/index.ts
··· 7 7 export * from './constants' 8 8 export * from './colors' 9 9 export * from './error' 10 - export * from './descriptors' 10 + export * from './source-map'
+147
packages/utils/src/source-map.ts
··· 1 + import { resolve } from 'pathe' 2 + import type { ErrorWithDiff, ParsedStack } from './types' 3 + import { isPrimitive, notNullish } from './helpers' 4 + 5 + export const lineSplitRE = /\r?\n/ 6 + 7 + const stackIgnorePatterns = [ 8 + 'node:internal', 9 + /\/packages\/\w+\/dist\//, 10 + /\/@vitest\/\w+\/dist\//, 11 + '/vitest/dist/', 12 + '/vitest/src/', 13 + '/vite-node/dist/', 14 + '/vite-node/src/', 15 + '/node_modules/chai/', 16 + '/node_modules/tinypool/', 17 + '/node_modules/tinyspy/', 18 + ] 19 + 20 + function extractLocation(urlLike: string) { 21 + // Fail-fast but return locations like "(native)" 22 + if (!urlLike.includes(':')) 23 + return [urlLike] 24 + 25 + const regExp = /(.+?)(?::(\d+))?(?::(\d+))?$/ 26 + const parts = regExp.exec(urlLike.replace(/[()]/g, '')) 27 + if (!parts) 28 + return [urlLike] 29 + return [parts[1], parts[2] || undefined, parts[3] || undefined] 30 + } 31 + 32 + // Based on https://github.com/stacktracejs/error-stack-parser 33 + // Credit to stacktracejs 34 + export function parseSingleStack(raw: string): ParsedStack | null { 35 + let line = raw.trim() 36 + 37 + if (line.includes('(eval ')) 38 + line = line.replace(/eval code/g, 'eval').replace(/(\(eval at [^()]*)|(,.*$)/g, '') 39 + 40 + let sanitizedLine = line 41 + .replace(/^\s+/, '') 42 + .replace(/\(eval code/g, '(') 43 + .replace(/^.*?\s+/, '') 44 + 45 + // capture and preserve the parenthesized location "(/foo/my bar.js:12:87)" in 46 + // case it has spaces in it, as the string is split on \s+ later on 47 + const location = sanitizedLine.match(/ (\(.+\)$)/) 48 + 49 + // remove the parenthesized location from the line, if it was matched 50 + sanitizedLine = location ? sanitizedLine.replace(location[0], '') : sanitizedLine 51 + 52 + // if a location was matched, pass it to extractLocation() otherwise pass all sanitizedLine 53 + // because this line doesn't have function name 54 + const [url, lineNumber, columnNumber] = extractLocation(location ? location[1] : sanitizedLine) 55 + let method = (location && sanitizedLine) || '' 56 + let file = url && ['eval', '<anonymous>'].includes(url) ? undefined : url 57 + 58 + if (!file || !lineNumber || !columnNumber) 59 + return null 60 + 61 + if (method.startsWith('async ')) 62 + method = method.slice(6) 63 + 64 + if (file.startsWith('file://')) 65 + file = file.slice(7) 66 + 67 + // normalize Windows path (\ -> /) 68 + file = resolve(file) 69 + 70 + return { 71 + method, 72 + file, 73 + line: parseInt(lineNumber), 74 + column: parseInt(columnNumber), 75 + } 76 + } 77 + 78 + export function parseStacktrace(stack: string, ignore = stackIgnorePatterns): ParsedStack[] { 79 + const stackFrames = stack 80 + .split('\n') 81 + .map((raw): ParsedStack | null => { 82 + const stack = parseSingleStack(raw) 83 + 84 + if (!stack || (ignore.length && ignore.some(p => stack.file.match(p)))) 85 + return null 86 + 87 + return stack 88 + }) 89 + .filter(notNullish) 90 + 91 + return stackFrames 92 + } 93 + 94 + export function parseErrorStacktrace(e: ErrorWithDiff, ignore = stackIgnorePatterns): ParsedStack[] { 95 + if (!e || isPrimitive(e)) 96 + return [] 97 + 98 + if (e.stacks) 99 + return e.stacks 100 + 101 + const stackStr = e.stack || e.stackStr || '' 102 + const stackFrames = parseStacktrace(stackStr, ignore) 103 + 104 + e.stacks = stackFrames 105 + return stackFrames 106 + } 107 + 108 + export function positionToOffset( 109 + source: string, 110 + lineNumber: number, 111 + columnNumber: number, 112 + ): number { 113 + const lines = source.split(lineSplitRE) 114 + const nl = /\r\n/.test(source) ? 2 : 1 115 + let start = 0 116 + 117 + if (lineNumber > lines.length) 118 + return source.length 119 + 120 + for (let i = 0; i < lineNumber - 1; i++) 121 + start += lines[i].length + nl 122 + 123 + return start + columnNumber 124 + } 125 + 126 + export function offsetToLineNumber( 127 + source: string, 128 + offset: number, 129 + ): number { 130 + if (offset > source.length) { 131 + throw new Error( 132 + `offset is longer than source length! offset ${offset} > length ${source.length}`, 133 + ) 134 + } 135 + const lines = source.split(lineSplitRE) 136 + const nl = /\r\n/.test(source) ? 2 : 1 137 + let counted = 0 138 + let line = 0 139 + for (; line < lines.length; line++) { 140 + const lineLength = lines[line].length + nl 141 + if (counted + lineLength >= offset) 142 + break 143 + 144 + counted += lineLength 145 + } 146 + return line + 1 147 + }
+22
packages/utils/src/types.ts
··· 23 23 export interface Constructable { 24 24 new (...args: any[]): any 25 25 } 26 + 27 + export interface ParsedStack { 28 + method: string 29 + file: string 30 + line: number 31 + column: number 32 + } 33 + 34 + export interface ErrorWithDiff extends Error { 35 + name: string 36 + nameStr?: string 37 + stack?: string 38 + stackStr?: string 39 + stacks?: ParsedStack[] 40 + showDiff?: boolean 41 + actual?: any 42 + expected?: any 43 + operator?: string 44 + type?: string 45 + frame?: string 46 + diff?: string 47 + }
-1
packages/vitest/src/browser.ts
··· 1 1 export { startTests } from '@vitest/runner' 2 2 export { setupCommonEnv } from './runtime/setup.common' 3 - export { setupSnapshotEnvironment } from './integrations/snapshot/env' 4 3 export { takeCoverageInsideWorker, stopCoverageInsideWorker, getCoverageProvider, startCoverageInsideWorker } from './integrations/coverage'
+1 -1
packages/vitest/src/index.ts
··· 15 15 export * from './integrations/chai' 16 16 export * from './integrations/vi' 17 17 export * from './integrations/utils' 18 - export type { SnapshotEnvironment } from './integrations/snapshot/env' 18 + export type { SnapshotEnvironment } from '@vitest/snapshot/environment' 19 19 20 20 export * from './types' 21 21 export * from './api/types'
+1 -1
test/core/test/inline-snap.test.ts
··· 1 1 import MagicString from 'magic-string' 2 2 import { describe, expect, it } from 'vitest' 3 - import { replaceInlineSnap } from '../../../packages/vitest/src/integrations/snapshot/port/inlineSnapshot' 3 + import { replaceInlineSnap } from '../../../packages/snapshot/src/port/inlineSnapshot' 4 4 5 5 describe('inline-snap utils', () => { 6 6 it('replaceInlineSnap', async () => {
+1 -1
test/core/test/utils.spec.ts
··· 1 1 import { beforeAll, describe, expect, test } from 'vitest' 2 2 import { assertTypes, deepClone, objectAttr, toArray } from '@vitest/utils' 3 3 import { deepMerge, resetModules } from '../../../packages/vitest/src/utils' 4 - import { deepMergeSnapshot } from '../../../packages/vitest/src/integrations/snapshot/port/utils' 4 + import { deepMergeSnapshot } from '../../../packages/snapshot/src/port/utils' 5 5 import type { EncodedSourceMap } from '../../../packages/vite-node/src/types' 6 6 import { ModuleCacheMap } from '../../../packages/vite-node/dist/client' 7 7
+13
test/snapshots/test/snapshot-async.test.ts
··· 1 + import { expect, test } from 'vitest' 2 + 3 + const resolve = () => Promise.resolve('foo') 4 + const reject = () => Promise.reject(new Error('foo')) 5 + 6 + test('resolved inline', async () => { 7 + await expect(resolve()).resolves.toMatchInlineSnapshot('"foo"') 8 + }) 9 + 10 + test('rejected inline', async () => { 11 + await expect(reject()).rejects.toMatchInlineSnapshot('[Error: foo]') 12 + await expect(reject()).rejects.toThrowErrorMatchingInlineSnapshot('"foo"') 13 + })
+5 -9
packages/browser/src/client/main.ts
··· 3 3 import type { ResolvedConfig } from 'vitest' 4 4 import type { VitestRunner } from '@vitest/runner' 5 5 import { createBrowserRunner } from './runner' 6 - import { BrowserSnapshotEnvironment } from './snapshot' 7 6 import { importId } from './utils' 8 7 import { setupConsoleLogSpy } from './logger' 9 8 import { createSafeRpc, rpc, rpcDone } from './rpc' 10 9 import { setupDialogsSpy } from './dialog' 10 + import { BrowserSnapshotEnvironment } from './snapshot' 11 11 12 12 // @ts-expect-error mocking some node apis 13 13 globalThis.process = { env: {}, argv: [], cwd: () => '/', stdout: { write: () => {} }, nextTick: cb => cb() } ··· 75 75 76 76 await setupConsoleLogSpy() 77 77 setupDialogsSpy() 78 - await runTests(paths, config) 78 + await runTests(paths, config!) 79 79 }) 80 80 81 - let hasSnapshot = false 82 - async function runTests(paths: string[], config: any) { 81 + async function runTests(paths: string[], config: ResolvedConfig) { 83 82 // need to import it before any other import, otherwise Vite optimizer will hang 84 83 const viteClientPath = '/@vite/client' 85 84 await import(viteClientPath) ··· 87 86 const { 88 87 startTests, 89 88 setupCommonEnv, 90 - setupSnapshotEnvironment, 91 89 takeCoverageInsideWorker, 92 90 } = await importId('vitest/browser') as typeof import('vitest/browser') 93 91 ··· 101 99 runner = new BrowserRunner({ config, browserHashMap }) 102 100 } 103 101 104 - if (!hasSnapshot) { 105 - setupSnapshotEnvironment(new BrowserSnapshotEnvironment()) 106 - hasSnapshot = true 107 - } 102 + if (!config.snapshotOptions.snapshotEnvironment) 103 + config.snapshotOptions.snapshotEnvironment = new BrowserSnapshotEnvironment() 108 104 109 105 try { 110 106 await setupCommonEnv(config)
+8
packages/browser/src/client/snapshot.ts
··· 2 2 import type { SnapshotEnvironment } from '#types' 3 3 4 4 export class BrowserSnapshotEnvironment implements SnapshotEnvironment { 5 + getVersion(): string { 6 + return '1' 7 + } 8 + 9 + getHeader(): string { 10 + return `// Vitest Snapshot v${this.getVersion()}, https://vitest.dev/guide/snapshot.html` 11 + } 12 + 5 13 readSnapshotFile(filepath: string): Promise<string | null> { 6 14 return rpc().readFile(filepath) 7 15 }
+1 -21
packages/runner/src/utils/error.ts
··· 2 2 import type { DiffOptions } from '@vitest/utils/diff' 3 3 import { unifiedDiff } from '@vitest/utils/diff' 4 4 5 - export interface ParsedStack { 6 - method: string 7 - file: string 8 - line: number 9 - column: number 10 - } 11 - 12 - export interface ErrorWithDiff extends Error { 13 - name: string 14 - nameStr?: string 15 - stack?: string 16 - stackStr?: string 17 - stacks?: ParsedStack[] 18 - showDiff?: boolean 19 - diff?: string 20 - actual?: any 21 - expected?: any 22 - operator?: string 23 - type?: string 24 - frame?: string 25 - } 5 + export type { ParsedStack, ErrorWithDiff } from '@vitest/utils' 26 6 27 7 const IS_RECORD_SYMBOL = '@@__IMMUTABLE_RECORD__@@' 28 8 const IS_COLLECTION_SYMBOL = '@@__IMMUTABLE_ITERABLE__@@'
+40
packages/snapshot/src/env/node.ts
··· 1 + import { existsSync, promises as fs } from 'node:fs' 2 + import { basename, dirname, join } from 'pathe' 3 + import type { SnapshotEnvironment } from '../types' 4 + 5 + export class NodeSnapshotEnvironment implements SnapshotEnvironment { 6 + getVersion(): string { 7 + return '1' 8 + } 9 + 10 + getHeader(): string { 11 + return `// Snapshot v${this.getVersion()}` 12 + } 13 + 14 + async resolvePath(filepath: string): Promise<string> { 15 + return join( 16 + join( 17 + dirname(filepath), '__snapshots__'), 18 + `${basename(filepath)}.snap`, 19 + ) 20 + } 21 + 22 + async prepareDirectory(filepath: string): Promise<void> { 23 + await fs.mkdir(filepath, { recursive: true }) 24 + } 25 + 26 + async saveSnapshotFile(filepath: string, snapshot: string): Promise<void> { 27 + await fs.writeFile(filepath, snapshot, 'utf-8') 28 + } 29 + 30 + async readSnapshotFile(filepath: string): Promise<string | null> { 31 + if (!existsSync(filepath)) 32 + return null 33 + return fs.readFile(filepath, 'utf-8') 34 + } 35 + 36 + async removeSnapshotFile(filepath: string): Promise<void> { 37 + if (existsSync(filepath)) 38 + await fs.unlink(filepath) 39 + } 40 + }
+137
packages/snapshot/src/port/inlineSnapshot.ts
··· 1 + import type MagicString from 'magic-string' 2 + import { getCallLastIndex, lineSplitRE, offsetToLineNumber, positionToOffset } from '@vitest/utils' 3 + import type { SnapshotEnvironment } from '../types' 4 + 5 + export interface InlineSnapshot { 6 + snapshot: string 7 + file: string 8 + line: number 9 + column: number 10 + } 11 + 12 + export async function saveInlineSnapshots( 13 + environment: SnapshotEnvironment, 14 + snapshots: Array<InlineSnapshot>, 15 + ) { 16 + const MagicString = (await import('magic-string')).default 17 + const files = new Set(snapshots.map(i => i.file)) 18 + await Promise.all(Array.from(files).map(async (file) => { 19 + const snaps = snapshots.filter(i => i.file === file) 20 + const code = await environment.readSnapshotFile(file) as string 21 + const s = new MagicString(code) 22 + 23 + for (const snap of snaps) { 24 + const index = positionToOffset(code, snap.line, snap.column) 25 + replaceInlineSnap(code, s, index, snap.snapshot) 26 + } 27 + 28 + const transformed = s.toString() 29 + if (transformed !== code) 30 + await environment.saveSnapshotFile(file, transformed) 31 + })) 32 + } 33 + 34 + const startObjectRegex = /(?:toMatchInlineSnapshot|toThrowErrorMatchingInlineSnapshot)\s*\(\s*(?:\/\*[\S\s]*\*\/\s*|\/\/.*\s+)*\s*({)/m 35 + 36 + function replaceObjectSnap(code: string, s: MagicString, index: number, newSnap: string) { 37 + code = code.slice(index) 38 + const startMatch = startObjectRegex.exec(code) 39 + if (!startMatch) 40 + return false 41 + 42 + code = code.slice(startMatch.index) 43 + const charIndex = getCallLastIndex(code) 44 + if (charIndex === null) 45 + return false 46 + 47 + s.appendLeft(index + startMatch.index + charIndex, `, ${prepareSnapString(newSnap, code, index)}`) 48 + 49 + return true 50 + } 51 + 52 + function prepareSnapString(snap: string, source: string, index: number) { 53 + const lineNumber = offsetToLineNumber(source, index) 54 + const line = source.split(lineSplitRE)[lineNumber - 1] 55 + const indent = line.match(/^\s*/)![0] || '' 56 + const indentNext = indent.includes('\t') ? `${indent}\t` : `${indent} ` 57 + 58 + const lines = snap 59 + .trim() 60 + .replace(/\\/g, '\\\\') 61 + .split(/\n/g) 62 + 63 + const isOneline = lines.length <= 1 64 + const quote = isOneline ? '\'' : '`' 65 + if (isOneline) 66 + return `'${lines.join('\n').replace(/'/g, '\\\'')}'` 67 + else 68 + return `${quote}\n${lines.map(i => i ? indentNext + i : '').join('\n').replace(/`/g, '\\`').replace(/\${/g, '\\${')}\n${indent}${quote}` 69 + } 70 + 71 + const startRegex = /(?:toMatchInlineSnapshot|toThrowErrorMatchingInlineSnapshot)\s*\(\s*(?:\/\*[\S\s]*\*\/\s*|\/\/.*\s+)*\s*[\w_$]*(['"`\)])/m 72 + export function replaceInlineSnap(code: string, s: MagicString, index: number, newSnap: string) { 73 + const startMatch = startRegex.exec(code.slice(index)) 74 + if (!startMatch) 75 + return replaceObjectSnap(code, s, index, newSnap) 76 + 77 + const quote = startMatch[1] 78 + const startIndex = index + startMatch.index! + startMatch[0].length 79 + const snapString = prepareSnapString(newSnap, code, index) 80 + 81 + if (quote === ')') { 82 + s.appendRight(startIndex - 1, snapString) 83 + return true 84 + } 85 + 86 + const quoteEndRE = new RegExp(`(?:^|[^\\\\])${quote}`) 87 + const endMatch = quoteEndRE.exec(code.slice(startIndex)) 88 + if (!endMatch) 89 + return false 90 + const endIndex = startIndex + endMatch.index! + endMatch[0].length 91 + s.overwrite(startIndex - 1, endIndex, snapString) 92 + 93 + return true 94 + } 95 + 96 + const INDENTATION_REGEX = /^([^\S\n]*)\S/m 97 + export function stripSnapshotIndentation(inlineSnapshot: string) { 98 + // Find indentation if exists. 99 + const match = inlineSnapshot.match(INDENTATION_REGEX) 100 + if (!match || !match[1]) { 101 + // No indentation. 102 + return inlineSnapshot 103 + } 104 + 105 + const indentation = match[1] 106 + const lines = inlineSnapshot.split(/\n/g) 107 + if (lines.length <= 2) { 108 + // Must be at least 3 lines. 109 + return inlineSnapshot 110 + } 111 + 112 + if (lines[0].trim() !== '' || lines[lines.length - 1].trim() !== '') { 113 + // If not blank first and last lines, abort. 114 + return inlineSnapshot 115 + } 116 + 117 + for (let i = 1; i < lines.length - 1; i++) { 118 + if (lines[i] !== '') { 119 + if (lines[i].indexOf(indentation) !== 0) { 120 + // All lines except first and last should either be blank or have the same 121 + // indent as the first line (or more). If this isn't the case we don't 122 + // want to touch the snapshot at all. 123 + return inlineSnapshot 124 + } 125 + 126 + lines[i] = lines[i].substring(indentation.length) 127 + } 128 + } 129 + 130 + // Last line is a special case because it won't have the same indent as others 131 + // but may still have been given some indent to line up. 132 + lines[lines.length - 1] = '' 133 + 134 + // Return inline snapshot, now at indent 0. 135 + inlineSnapshot = lines.join('\n') 136 + return inlineSnapshot 137 + }
+51
packages/snapshot/src/port/mockSerializer.ts
··· 1 + /** 2 + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 3 + * 4 + * This source code is licensed under the MIT license found in the 5 + * LICENSE file in the root directory of this source tree. 6 + * 7 + * https://github.com/facebook/jest/blob/4eb4f6a59b6eae0e05b8e51dd8cd3fdca1c7aff1/packages/jest-snapshot/src/mockSerializer.ts#L4 8 + */ 9 + 10 + import type { NewPlugin } from 'pretty-format' 11 + 12 + export const serialize: NewPlugin['serialize'] = ( 13 + val, 14 + config, 15 + indentation, 16 + depth, 17 + refs, 18 + printer, 19 + ): string => { 20 + // Serialize a non-default name, even if config.printFunctionName is false. 21 + const name = val.getMockName() 22 + const nameString = name === 'vi.fn()' ? '' : ` ${name}` 23 + 24 + let callsString = '' 25 + if (val.mock.calls.length !== 0) { 26 + const indentationNext = indentation + config.indent 27 + callsString 28 + = ` {${ 29 + config.spacingOuter 30 + }${indentationNext 31 + }"calls": ${ 32 + printer(val.mock.calls, config, indentationNext, depth, refs) 33 + }${config.min ? ', ' : ',' 34 + }${config.spacingOuter 35 + }${indentationNext 36 + }"results": ${ 37 + printer(val.mock.results, config, indentationNext, depth, refs) 38 + }${config.min ? '' : ',' 39 + }${config.spacingOuter 40 + }${indentation 41 + }}` 42 + } 43 + 44 + return `[MockFunction${nameString}]${callsString}` 45 + } 46 + 47 + export const test: NewPlugin['test'] = val => val && !!val._isMockFunction 48 + 49 + const plugin: NewPlugin = { serialize, test } 50 + 51 + export default plugin
+41
packages/snapshot/src/port/plugins.ts
··· 1 + /** 2 + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 3 + * 4 + * This source code is licensed under the MIT license found in the 5 + * LICENSE file in the root directory of this source tree. 6 + */ 7 + 8 + import type { 9 + Plugin as PrettyFormatPlugin, 10 + Plugins as PrettyFormatPlugins, 11 + } from 'pretty-format' 12 + import { 13 + plugins as prettyFormatPlugins, 14 + } from 'pretty-format' 15 + 16 + import MockSerializer from './mockSerializer' 17 + 18 + const { 19 + DOMCollection, 20 + DOMElement, 21 + Immutable, 22 + ReactElement, 23 + ReactTestComponent, 24 + AsymmetricMatcher, 25 + } = prettyFormatPlugins 26 + 27 + let PLUGINS: PrettyFormatPlugins = [ 28 + ReactTestComponent, 29 + ReactElement, 30 + DOMElement, 31 + DOMCollection, 32 + Immutable, 33 + AsymmetricMatcher, 34 + MockSerializer, 35 + ] 36 + 37 + export const addSerializer = (plugin: PrettyFormatPlugin): void => { 38 + PLUGINS = [plugin].concat(PLUGINS) 39 + } 40 + 41 + export const getSerializers = (): PrettyFormatPlugins => PLUGINS
+331
packages/snapshot/src/port/state.ts
··· 1 + /** 2 + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 3 + * 4 + * This source code is licensed under the MIT license found in the 5 + * LICENSE file in the root directory of this source tree. 6 + */ 7 + 8 + import type { ParsedStack } from '@vitest/utils' 9 + import { parseErrorStacktrace } from '@vitest/utils' 10 + import type { OptionsReceived as PrettyFormatOptions } from 'pretty-format' 11 + import type { SnapshotData, SnapshotEnvironment, SnapshotMatchOptions, SnapshotResult, SnapshotStateOptions, SnapshotUpdateState } from '../types' 12 + import type { InlineSnapshot } from './inlineSnapshot' 13 + import { saveInlineSnapshots } from './inlineSnapshot' 14 + 15 + import { 16 + addExtraLineBreaks, 17 + getSnapshotData, 18 + keyToTestName, 19 + prepareExpected, 20 + removeExtraLineBreaks, 21 + saveSnapshotFile, 22 + serialize, 23 + testNameToKey, 24 + } from './utils' 25 + 26 + interface SnapshotReturnOptions { 27 + actual: string 28 + count: number 29 + expected?: string 30 + key: string 31 + pass: boolean 32 + } 33 + 34 + interface SaveStatus { 35 + deleted: boolean 36 + saved: boolean 37 + } 38 + 39 + export default class SnapshotState { 40 + private _counters: Map<string, number> 41 + private _dirty: boolean 42 + private _updateSnapshot: SnapshotUpdateState 43 + private _snapshotData: SnapshotData 44 + private _initialData: SnapshotData 45 + private _inlineSnapshots: Array<InlineSnapshot> 46 + private _uncheckedKeys: Set<string> 47 + private _snapshotFormat: PrettyFormatOptions 48 + private _environment: SnapshotEnvironment 49 + private _fileExists: boolean 50 + 51 + added: number 52 + expand: boolean 53 + matched: number 54 + unmatched: number 55 + updated: number 56 + 57 + private constructor( 58 + public testFilePath: string, 59 + public snapshotPath: string, 60 + snapshotContent: string | null, 61 + options: SnapshotStateOptions, 62 + ) { 63 + const { data, dirty } = getSnapshotData( 64 + snapshotContent, 65 + options, 66 + ) 67 + this._fileExists = snapshotContent != null // TODO: update on watch? 68 + this._initialData = data 69 + this._snapshotData = data 70 + this._dirty = dirty 71 + this._inlineSnapshots = [] 72 + this._uncheckedKeys = new Set(Object.keys(this._snapshotData)) 73 + this._counters = new Map() 74 + this.expand = options.expand || false 75 + this.added = 0 76 + this.matched = 0 77 + this.unmatched = 0 78 + this._updateSnapshot = options.updateSnapshot 79 + this.updated = 0 80 + this._snapshotFormat = { 81 + printBasicPrototype: false, 82 + ...options.snapshotFormat, 83 + } 84 + this._environment = options.snapshotEnvironment 85 + } 86 + 87 + static async create( 88 + testFilePath: string, 89 + options: SnapshotStateOptions, 90 + ) { 91 + const snapshotPath = await options.snapshotEnvironment.resolvePath(testFilePath) 92 + const content = await options.snapshotEnvironment.readSnapshotFile(snapshotPath) 93 + return new SnapshotState(testFilePath, snapshotPath, content, options) 94 + } 95 + 96 + markSnapshotsAsCheckedForTest(testName: string): void { 97 + this._uncheckedKeys.forEach((uncheckedKey) => { 98 + if (keyToTestName(uncheckedKey) === testName) 99 + this._uncheckedKeys.delete(uncheckedKey) 100 + }) 101 + } 102 + 103 + protected _inferInlineSnapshotStack(stacks: ParsedStack[]) { 104 + // if called inside resolves/rejects, stacktrace is different 105 + const promiseIndex = stacks.findIndex(i => i.method.match(/__VITEST_(RESOLVES|REJECTS)__/)) 106 + if (promiseIndex !== -1) 107 + return stacks[promiseIndex + 3] 108 + 109 + // inline snapshot function is called __INLINE_SNAPSHOT__ 110 + // in integrations/snapshot/chai.ts 111 + const stackIndex = stacks.findIndex(i => i.method.includes('__INLINE_SNAPSHOT__')) 112 + return stackIndex !== -1 ? stacks[stackIndex + 2] : null 113 + } 114 + 115 + private _addSnapshot( 116 + key: string, 117 + receivedSerialized: string, 118 + options: { isInline: boolean; error?: Error }, 119 + ): void { 120 + this._dirty = true 121 + if (options.isInline) { 122 + const stacks = parseErrorStacktrace(options.error || new Error('snapshot'), []) 123 + const stack = this._inferInlineSnapshotStack(stacks) 124 + if (!stack) { 125 + throw new Error( 126 + `@vitest/snapshot: Couldn't infer stack frame for inline snapshot.\n${JSON.stringify(stacks)}`, 127 + ) 128 + } 129 + // removing 1 column, because source map points to the wrong 130 + // location for js files, but `column-1` points to the same in both js/ts 131 + // https://github.com/vitejs/vite/issues/8657 132 + stack.column-- 133 + this._inlineSnapshots.push({ 134 + snapshot: receivedSerialized, 135 + ...stack, 136 + }) 137 + } 138 + else { 139 + this._snapshotData[key] = receivedSerialized 140 + } 141 + } 142 + 143 + clear(): void { 144 + this._snapshotData = this._initialData 145 + // this._inlineSnapshots = [] 146 + this._counters = new Map() 147 + this.added = 0 148 + this.matched = 0 149 + this.unmatched = 0 150 + this.updated = 0 151 + this._dirty = false 152 + } 153 + 154 + async save(): Promise<SaveStatus> { 155 + const hasExternalSnapshots = Object.keys(this._snapshotData).length 156 + const hasInlineSnapshots = this._inlineSnapshots.length 157 + const isEmpty = !hasExternalSnapshots && !hasInlineSnapshots 158 + 159 + const status: SaveStatus = { 160 + deleted: false, 161 + saved: false, 162 + } 163 + 164 + if ((this._dirty || this._uncheckedKeys.size) && !isEmpty) { 165 + if (hasExternalSnapshots) { 166 + await saveSnapshotFile(this._environment, this._snapshotData, this.snapshotPath) 167 + this._fileExists = true 168 + } 169 + if (hasInlineSnapshots) 170 + await saveInlineSnapshots(this._environment, this._inlineSnapshots) 171 + 172 + status.saved = true 173 + } 174 + else if (!hasExternalSnapshots && this._fileExists) { 175 + if (this._updateSnapshot === 'all') { 176 + await this._environment.removeSnapshotFile(this.snapshotPath) 177 + this._fileExists = false 178 + } 179 + 180 + status.deleted = true 181 + } 182 + 183 + return status 184 + } 185 + 186 + getUncheckedCount(): number { 187 + return this._uncheckedKeys.size || 0 188 + } 189 + 190 + getUncheckedKeys(): Array<string> { 191 + return Array.from(this._uncheckedKeys) 192 + } 193 + 194 + removeUncheckedKeys(): void { 195 + if (this._updateSnapshot === 'all' && this._uncheckedKeys.size) { 196 + this._dirty = true 197 + this._uncheckedKeys.forEach(key => delete this._snapshotData[key]) 198 + this._uncheckedKeys.clear() 199 + } 200 + } 201 + 202 + match({ 203 + testName, 204 + received, 205 + key, 206 + inlineSnapshot, 207 + isInline, 208 + error, 209 + }: SnapshotMatchOptions): SnapshotReturnOptions { 210 + this._counters.set(testName, (this._counters.get(testName) || 0) + 1) 211 + const count = Number(this._counters.get(testName)) 212 + 213 + if (!key) 214 + key = testNameToKey(testName, count) 215 + 216 + // Do not mark the snapshot as "checked" if the snapshot is inline and 217 + // there's an external snapshot. This way the external snapshot can be 218 + // removed with `--updateSnapshot`. 219 + if (!(isInline && this._snapshotData[key] !== undefined)) 220 + this._uncheckedKeys.delete(key) 221 + 222 + const receivedSerialized = addExtraLineBreaks(serialize(received, undefined, this._snapshotFormat)) 223 + const expected = isInline ? inlineSnapshot : this._snapshotData[key] 224 + const expectedTrimmed = prepareExpected(expected) 225 + const pass = expectedTrimmed === prepareExpected(receivedSerialized) 226 + const hasSnapshot = expected !== undefined 227 + const snapshotIsPersisted = isInline || this._fileExists 228 + 229 + if (pass && !isInline) { 230 + // Executing a snapshot file as JavaScript and writing the strings back 231 + // when other snapshots have changed loses the proper escaping for some 232 + // characters. Since we check every snapshot in every test, use the newly 233 + // generated formatted string. 234 + // Note that this is only relevant when a snapshot is added and the dirty 235 + // flag is set. 236 + this._snapshotData[key] = receivedSerialized 237 + } 238 + 239 + // These are the conditions on when to write snapshots: 240 + // * There's no snapshot file in a non-CI environment. 241 + // * There is a snapshot file and we decided to update the snapshot. 242 + // * There is a snapshot file, but it doesn't have this snapshot. 243 + // These are the conditions on when not to write snapshots: 244 + // * The update flag is set to 'none'. 245 + // * There's no snapshot file or a file without this snapshot on a CI environment. 246 + if ( 247 + (hasSnapshot && this._updateSnapshot === 'all') 248 + || ((!hasSnapshot || !snapshotIsPersisted) 249 + && (this._updateSnapshot === 'new' || this._updateSnapshot === 'all')) 250 + ) { 251 + if (this._updateSnapshot === 'all') { 252 + if (!pass) { 253 + if (hasSnapshot) 254 + this.updated++ 255 + else 256 + this.added++ 257 + 258 + this._addSnapshot(key, receivedSerialized, { error, isInline }) 259 + } 260 + else { 261 + this.matched++ 262 + } 263 + } 264 + else { 265 + this._addSnapshot(key, receivedSerialized, { error, isInline }) 266 + this.added++ 267 + } 268 + 269 + return { 270 + actual: '', 271 + count, 272 + expected: '', 273 + key, 274 + pass: true, 275 + } 276 + } 277 + else { 278 + if (!pass) { 279 + this.unmatched++ 280 + return { 281 + actual: removeExtraLineBreaks(receivedSerialized), 282 + count, 283 + expected: 284 + expectedTrimmed !== undefined 285 + ? removeExtraLineBreaks(expectedTrimmed) 286 + : undefined, 287 + key, 288 + pass: false, 289 + } 290 + } 291 + else { 292 + this.matched++ 293 + return { 294 + actual: '', 295 + count, 296 + expected: '', 297 + key, 298 + pass: true, 299 + } 300 + } 301 + } 302 + } 303 + 304 + async pack(): Promise<SnapshotResult> { 305 + const snapshot: SnapshotResult = { 306 + filepath: this.testFilePath, 307 + added: 0, 308 + fileDeleted: false, 309 + matched: 0, 310 + unchecked: 0, 311 + uncheckedKeys: [], 312 + unmatched: 0, 313 + updated: 0, 314 + } 315 + const uncheckedCount = this.getUncheckedCount() 316 + const uncheckedKeys = this.getUncheckedKeys() 317 + if (uncheckedCount) 318 + this.removeUncheckedKeys() 319 + 320 + const status = await this.save() 321 + snapshot.fileDeleted = status.deleted 322 + snapshot.added = this.added 323 + snapshot.matched = this.matched 324 + snapshot.unmatched = this.unmatched 325 + snapshot.updated = this.updated 326 + snapshot.unchecked = !status.deleted ? uncheckedCount : 0 327 + snapshot.uncheckedKeys = Array.from(uncheckedKeys) 328 + 329 + return snapshot 330 + } 331 + }
+250
packages/snapshot/src/port/utils.ts
··· 1 + /** 2 + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 3 + * 4 + * This source code is licensed under the MIT license found in the 5 + * LICENSE file in the root directory of this source tree. 6 + */ 7 + 8 + import { dirname, join } from 'pathe' 9 + import naturalCompare from 'natural-compare' 10 + import type { OptionsReceived as PrettyFormatOptions } from 'pretty-format' 11 + import { 12 + format as prettyFormat, 13 + } from 'pretty-format' 14 + import { isObject } from '@vitest/utils' 15 + import type { SnapshotData, SnapshotStateOptions } from '../types' 16 + import type { SnapshotEnvironment } from '../types/environment' 17 + import { getSerializers } from './plugins' 18 + 19 + // TODO: rewrite and clean up 20 + 21 + export const testNameToKey = (testName: string, count: number): string => 22 + `${testName} ${count}` 23 + 24 + export const keyToTestName = (key: string): string => { 25 + if (!/ \d+$/.test(key)) 26 + throw new Error('Snapshot keys must end with a number.') 27 + 28 + return key.replace(/ \d+$/, '') 29 + } 30 + 31 + export const getSnapshotData = ( 32 + content: string | null, 33 + options: SnapshotStateOptions, 34 + ): { 35 + data: SnapshotData 36 + dirty: boolean 37 + } => { 38 + const update = options.updateSnapshot 39 + const data = Object.create(null) 40 + let snapshotContents = '' 41 + let dirty = false 42 + 43 + if (content != null) { 44 + try { 45 + snapshotContents = content 46 + // eslint-disable-next-line no-new-func 47 + const populate = new Function('exports', snapshotContents) 48 + populate(data) 49 + } 50 + catch {} 51 + } 52 + 53 + // const validationResult = validateSnapshotVersion(snapshotContents) 54 + const isInvalid = snapshotContents // && validationResult 55 + 56 + // if (update === 'none' && isInvalid) 57 + // throw validationResult 58 + 59 + if ((update === 'all' || update === 'new') && isInvalid) 60 + dirty = true 61 + 62 + return { data, dirty } 63 + } 64 + 65 + // Add extra line breaks at beginning and end of multiline snapshot 66 + // to make the content easier to read. 67 + export const addExtraLineBreaks = (string: string): string => 68 + string.includes('\n') ? `\n${string}\n` : string 69 + 70 + // Remove extra line breaks at beginning and end of multiline snapshot. 71 + // Instead of trim, which can remove additional newlines or spaces 72 + // at beginning or end of the content from a custom serializer. 73 + export const removeExtraLineBreaks = (string: string): string => 74 + string.length > 2 && string.startsWith('\n') && string.endsWith('\n') 75 + ? string.slice(1, -1) 76 + : string 77 + 78 + // export const removeLinesBeforeExternalMatcherTrap = (stack: string): string => { 79 + // const lines = stack.split('\n') 80 + 81 + // for (let i = 0; i < lines.length; i += 1) { 82 + // // It's a function name specified in `packages/expect/src/index.ts` 83 + // // for external custom matchers. 84 + // if (lines[i].includes('__EXTERNAL_MATCHER_TRAP__')) 85 + // return lines.slice(i + 1).join('\n') 86 + // } 87 + 88 + // return stack 89 + // } 90 + 91 + const escapeRegex = true 92 + const printFunctionName = false 93 + 94 + export function serialize(val: unknown, 95 + indent = 2, 96 + formatOverrides: PrettyFormatOptions = {}): string { 97 + return normalizeNewlines( 98 + prettyFormat(val, { 99 + escapeRegex, 100 + indent, 101 + plugins: getSerializers(), 102 + printFunctionName, 103 + ...formatOverrides, 104 + }), 105 + ) 106 + } 107 + 108 + export function minify(val: unknown): string { 109 + return prettyFormat(val, { 110 + escapeRegex, 111 + min: true, 112 + plugins: getSerializers(), 113 + printFunctionName, 114 + }) 115 + } 116 + 117 + // Remove double quote marks and unescape double quotes and backslashes. 118 + export function deserializeString(stringified: string): string { 119 + return stringified.slice(1, -1).replace(/\\("|\\)/g, '$1') 120 + } 121 + 122 + export function escapeBacktickString(str: string): string { 123 + return str.replace(/`|\\|\${/g, '\\$&') 124 + } 125 + 126 + function printBacktickString(str: string): string { 127 + return `\`${escapeBacktickString(str)}\`` 128 + } 129 + 130 + export async function ensureDirectoryExists(environment: SnapshotEnvironment, filePath: string) { 131 + try { 132 + await environment.prepareDirectory(join(dirname(filePath))) 133 + } 134 + catch { } 135 + } 136 + 137 + function normalizeNewlines(string: string) { 138 + return string.replace(/\r\n|\r/g, '\n') 139 + } 140 + 141 + export async function saveSnapshotFile( 142 + environment: SnapshotEnvironment, 143 + snapshotData: SnapshotData, 144 + snapshotPath: string, 145 + ) { 146 + const snapshots = Object.keys(snapshotData) 147 + .sort(naturalCompare) 148 + .map( 149 + key => `exports[${printBacktickString(key)}] = ${printBacktickString(normalizeNewlines(snapshotData[key]))};`, 150 + ) 151 + 152 + const content = `${environment.getHeader()}\n\n${snapshots.join('\n\n')}\n` 153 + const oldContent = await environment.readSnapshotFile(snapshotPath) 154 + const skipWriting = oldContent && oldContent === content 155 + 156 + if (skipWriting) 157 + return 158 + 159 + await ensureDirectoryExists(environment, snapshotPath) 160 + await environment.saveSnapshotFile( 161 + snapshotPath, 162 + content, 163 + ) 164 + } 165 + 166 + export function prepareExpected(expected?: string) { 167 + function findStartIndent() { 168 + // Attempts to find indentation for objects. 169 + // Matches the ending tag of the object. 170 + const matchObject = /^( +)}\s+$/m.exec(expected || '') 171 + const objectIndent = matchObject?.[1]?.length 172 + 173 + if (objectIndent) 174 + return objectIndent 175 + 176 + // Attempts to find indentation for texts. 177 + // Matches the quote of first line. 178 + const matchText = /^\n( +)"/.exec(expected || '') 179 + return matchText?.[1]?.length || 0 180 + } 181 + 182 + const startIndent = findStartIndent() 183 + 184 + let expectedTrimmed = expected?.trim() 185 + 186 + if (startIndent) { 187 + expectedTrimmed = expectedTrimmed 188 + ?.replace(new RegExp(`^${' '.repeat(startIndent)}`, 'gm'), '').replace(/ +}$/, '}') 189 + } 190 + 191 + return expectedTrimmed 192 + } 193 + 194 + function deepMergeArray(target: any[] = [], source: any[] = []) { 195 + const mergedOutput = Array.from(target) 196 + 197 + source.forEach((sourceElement, index) => { 198 + const targetElement = mergedOutput[index] 199 + 200 + if (Array.isArray(target[index])) { 201 + mergedOutput[index] = deepMergeArray(target[index], sourceElement) 202 + } 203 + else if (isObject(targetElement)) { 204 + mergedOutput[index] = deepMergeSnapshot(target[index], sourceElement) 205 + } 206 + else { 207 + // Source does not exist in target or target is primitive and cannot be deep merged 208 + mergedOutput[index] = sourceElement 209 + } 210 + }) 211 + 212 + return mergedOutput 213 + } 214 + 215 + /** 216 + * Deep merge, but considers asymmetric matchers. Unlike base util's deep merge, 217 + * will merge any object-like instance. 218 + * Compatible with Jest's snapshot matcher. Should not be used outside of snapshot. 219 + * 220 + * @example 221 + * ```ts 222 + * toMatchSnapshot({ 223 + * name: expect.stringContaining('text') 224 + * }) 225 + * ``` 226 + */ 227 + export function deepMergeSnapshot(target: any, source: any): any { 228 + if (isObject(target) && isObject(source)) { 229 + const mergedOutput = { ...target } 230 + Object.keys(source).forEach((key) => { 231 + if (isObject(source[key]) && !source[key].$$typeof) { 232 + if (!(key in target)) 233 + Object.assign(mergedOutput, { [key]: source[key] }) 234 + else mergedOutput[key] = deepMergeSnapshot(target[key], source[key]) 235 + } 236 + else if (Array.isArray(source[key])) { 237 + mergedOutput[key] = deepMergeArray(target[key], source[key]) 238 + } 239 + else { 240 + Object.assign(mergedOutput, { [key]: source[key] }) 241 + } 242 + }) 243 + 244 + return mergedOutput 245 + } 246 + else if (Array.isArray(target) && Array.isArray(source)) { 247 + return deepMergeArray(target, source) 248 + } 249 + return target 250 + }
+9
packages/snapshot/src/types/environment.ts
··· 1 + export interface SnapshotEnvironment { 2 + getVersion(): string 3 + getHeader(): string 4 + resolvePath(filepath: string): Promise<string> 5 + prepareDirectory(filepath: string): Promise<void> 6 + saveSnapshotFile(filepath: string, snapshot: string): Promise<void> 7 + readSnapshotFile(filepath: string): Promise<string | null> 8 + removeSnapshotFile(filepath: string): Promise<void> 9 + }
+57
packages/snapshot/src/types/index.ts
··· 1 + import type { OptionsReceived as PrettyFormatOptions } from 'pretty-format' 2 + import type { SnapshotEnvironment } from './environment' 3 + 4 + export type { SnapshotEnvironment } 5 + export type SnapshotData = Record<string, string> 6 + 7 + export type SnapshotUpdateState = 'all' | 'new' | 'none' 8 + 9 + export interface SnapshotStateOptions { 10 + updateSnapshot: SnapshotUpdateState 11 + snapshotEnvironment: SnapshotEnvironment 12 + expand?: boolean 13 + snapshotFormat?: PrettyFormatOptions 14 + resolveSnapshotPath?: (path: string, extension: string) => string 15 + } 16 + 17 + export interface SnapshotMatchOptions { 18 + testName: string 19 + received: unknown 20 + key?: string 21 + inlineSnapshot?: string 22 + isInline: boolean 23 + error?: Error 24 + } 25 + 26 + export interface SnapshotResult { 27 + filepath: string 28 + added: number 29 + fileDeleted: boolean 30 + matched: number 31 + unchecked: number 32 + uncheckedKeys: Array<string> 33 + unmatched: number 34 + updated: number 35 + } 36 + 37 + export interface UncheckedSnapshot { 38 + filePath: string 39 + keys: Array<string> 40 + } 41 + 42 + export interface SnapshotSummary { 43 + added: number 44 + didUpdate: boolean 45 + failure: boolean 46 + filesAdded: number 47 + filesRemoved: number 48 + filesRemovedList: Array<string> 49 + filesUnmatched: number 50 + filesUpdated: number 51 + matched: number 52 + total: number 53 + unchecked: number 54 + uncheckedKeysByFile: Array<UncheckedSnapshot> 55 + unmatched: number 56 + updated: number 57 + }
+2
packages/vitest/src/node/config.ts
··· 157 157 ? 'all' 158 158 : 'new', 159 159 resolveSnapshotPath: options.resolveSnapshotPath, 160 + // resolved inside the worker 161 + snapshotEnvironment: null as any, 160 162 } 161 163 162 164 if (options.resolveSnapshotPath)
+3 -1
packages/vitest/src/node/core.ts
··· 6 6 import c from 'picocolors' 7 7 import { normalizeRequestId } from 'vite-node/utils' 8 8 import { ViteNodeRunner } from 'vite-node/client' 9 + import { SnapshotManager } from '@vitest/snapshot/manager' 9 10 import type { ArgumentsType, CoverageProvider, OnServerRestartHandler, Reporter, ResolvedConfig, UserConfig, VitestRunMode } from '../types' 10 - import { SnapshotManager } from '../integrations/snapshot/manager' 11 11 import { deepMerge, hasFailed, noop, slash, toArray } from '../utils' 12 12 import { getCoverageProvider } from '../integrations/coverage' 13 13 import { Typechecker } from '../typecheck/typechecker' ··· 442 442 this.configOverride = { 443 443 snapshotOptions: { 444 444 updateSnapshot: 'all', 445 + // environment is resolved inside a worker thread 446 + snapshotEnvironment: null as any, 445 447 }, 446 448 } 447 449
+1 -1
packages/vitest/src/node/error.ts
··· 42 42 if (!ctx.config) 43 43 return printErrorMessage(e, ctx.logger) 44 44 45 - const stacks = parseErrorStacktrace(e, fullStack) 45 + const stacks = parseErrorStacktrace(e, fullStack ? [] : undefined) 46 46 47 47 const nearest = error instanceof TypeCheckError 48 48 ? error.stacks[0]
+6 -5
packages/vitest/src/runtime/setup.node.ts
··· 4 4 import { createColors, setupColors } from '@vitest/utils' 5 5 import { environments } from '../integrations/env' 6 6 import type { Environment, ResolvedConfig } from '../types' 7 + import { VitestSnapshotEnvironment } from '../integrations/snapshot/environments/node' 7 8 import { getSafeTimers, getWorkerState } from '../utils' 8 9 import * as VitestIndex from '../index' 9 10 import { RealDate } from '../integrations/mock/date' 10 11 import { expect } from '../integrations/chai' 11 - import { setupSnapshotEnvironment } from '../integrations/snapshot/env' 12 - import { NodeSnapshotEnvironment } from '../integrations/snapshot/environments/node' 13 12 import { rpc } from './rpc' 14 13 import { setupCommonEnv } from './setup.common' 15 14 import type { VitestExecutor } from './execute' ··· 24 23 enumerable: false, 25 24 }) 26 25 26 + const state = getWorkerState() 27 + 28 + if (!state.config.snapshotOptions.snapshotEnvironment) 29 + state.config.snapshotOptions.snapshotEnvironment = new VitestSnapshotEnvironment() 30 + 27 31 if (globalSetup) 28 32 return 29 33 30 34 globalSetup = true 31 - setupSnapshotEnvironment(new NodeSnapshotEnvironment()) 32 35 setupColors(createColors(isatty(1))) 33 36 34 37 const _require = createRequire(import.meta.url) ··· 36 39 _require.extensions['.css'] = () => ({}) 37 40 _require.extensions['.scss'] = () => ({}) 38 41 _require.extensions['.sass'] = () => ({}) 39 - 40 - const state = getWorkerState() 41 42 42 43 installSourcemapsSupport({ 43 44 getSourceMap: source => state.moduleCache.getSourceMap(source),
+1 -1
packages/vitest/src/types/global.ts
··· 1 1 import type { Plugin as PrettyFormatPlugin } from 'pretty-format' 2 2 import type { MatchersObject } from '@vitest/expect' 3 - import type SnapshotState from '../integrations/snapshot/port/state' 3 + import type { SnapshotState } from '@vitest/snapshot' 4 4 import type { MatcherState } from './chai' 5 5 import type { Constructable, UserConsoleLog } from './general' 6 6 import type { VitestEnvironment } from './config'
+9 -54
packages/vitest/src/types/snapshot.ts
··· 1 - import type { OptionsReceived as PrettyFormatOptions } from 'pretty-format' 2 - 3 - export type SnapshotData = Record<string, string> 4 - 5 - export type SnapshotUpdateState = 'all' | 'new' | 'none' 6 - 7 - export interface SnapshotStateOptions { 8 - updateSnapshot: SnapshotUpdateState 9 - expand?: boolean 10 - snapshotFormat?: PrettyFormatOptions 11 - resolveSnapshotPath?: (path: string, extension: string) => string 12 - } 13 - 14 - export interface SnapshotMatchOptions { 15 - testName: string 16 - received: unknown 17 - key?: string 18 - inlineSnapshot?: string 19 - isInline: boolean 20 - error?: Error 21 - } 22 - 23 - export interface SnapshotResult { 24 - filepath: string 25 - added: number 26 - fileDeleted: boolean 27 - matched: number 28 - unchecked: number 29 - uncheckedKeys: Array<string> 30 - unmatched: number 31 - updated: number 32 - } 33 - 34 - export interface UncheckedSnapshot { 35 - filePath: string 36 - keys: Array<string> 37 - } 38 - 39 - export interface SnapshotSummary { 40 - added: number 41 - didUpdate: boolean 42 - failure: boolean 43 - filesAdded: number 44 - filesRemoved: number 45 - filesRemovedList: Array<string> 46 - filesUnmatched: number 47 - filesUpdated: number 48 - matched: number 49 - total: number 50 - unchecked: number 51 - uncheckedKeysByFile: Array<UncheckedSnapshot> 52 - unmatched: number 53 - updated: number 54 - } 1 + export type { 2 + SnapshotData, 3 + SnapshotUpdateState, 4 + SnapshotStateOptions, 5 + SnapshotMatchOptions, 6 + SnapshotResult, 7 + UncheckedSnapshot, 8 + SnapshotSummary, 9 + } from '@vitest/snapshot'
+2 -4
packages/vitest/src/utils/base.ts
··· 1 1 import type { Arrayable, Nullable, ResolvedConfig, VitestEnvironment } from '../types' 2 2 3 + export { notNullish, getCallLastIndex } from '@vitest/utils' 4 + 3 5 function isFinalObj(obj: any) { 4 6 return obj === Object.prototype || obj === Function.prototype || obj === RegExp.prototype 5 7 } ··· 45 47 allProps.set('default', { key: 'default', descriptor }) 46 48 } 47 49 return Array.from(allProps.values()) 48 - } 49 - 50 - export function notNullish<T>(v: T | null | undefined): v is NonNullable<T> { 51 - return v != null 52 50 } 53 51 54 52 export function slash(str: string) {
-42
packages/vitest/src/utils/index.ts
··· 46 46 return obj 47 47 } 48 48 49 - /** 50 - * If code starts with a function call, will return its last index, respecting arguments. 51 - * This will return 25 - last ending character of toMatch ")" 52 - * Also works with callbacks 53 - * ``` 54 - * toMatch({ test: '123' }); 55 - * toBeAliased('123') 56 - * ``` 57 - */ 58 - export function getCallLastIndex(code: string) { 59 - let charIndex = -1 60 - let inString: string | null = null 61 - let startedBracers = 0 62 - let endedBracers = 0 63 - let beforeChar: string | null = null 64 - while (charIndex <= code.length) { 65 - beforeChar = code[charIndex] 66 - charIndex++ 67 - const char = code[charIndex] 68 - 69 - const isCharString = char === '"' || char === '\'' || char === '`' 70 - 71 - if (isCharString && beforeChar !== '\\') { 72 - if (inString === char) 73 - inString = null 74 - else if (!inString) 75 - inString = char 76 - } 77 - 78 - if (!inString) { 79 - if (char === '(') 80 - startedBracers++ 81 - if (char === ')') 82 - endedBracers++ 83 - } 84 - 85 - if (startedBracers && endedBracers && startedBracers === endedBracers) 86 - return charIndex 87 - } 88 - return null 89 - } 90 - 91 49 // AggregateError is supported in Node.js 15.0.0+ 92 50 class AggregateErrorPonyfill extends Error { 93 51 errors: unknown[]
+8 -145
packages/vitest/src/utils/source-map.ts
··· 1 - import { resolve } from 'pathe' 2 - import type { ErrorWithDiff, ParsedStack } from '../types' 3 - import { isPrimitive, notNullish } from './base' 4 - 5 - export const lineSplitRE = /\r?\n/ 6 - 7 - const stackIgnorePatterns = [ 8 - 'node:internal', 9 - /\/packages\/\w+\/dist\//, 10 - /\/@vitest\/\w+\/dist\//, 11 - '/vitest/dist/', 12 - '/vitest/src/', 13 - '/vite-node/dist/', 14 - '/vite-node/src/', 15 - '/node_modules/chai/', 16 - '/node_modules/tinypool/', 17 - '/node_modules/tinyspy/', 18 - ] 19 - 20 - function extractLocation(urlLike: string) { 21 - // Fail-fast but return locations like "(native)" 22 - if (!urlLike.includes(':')) 23 - return [urlLike] 24 - 25 - const regExp = /(.+?)(?::(\d+))?(?::(\d+))?$/ 26 - const parts = regExp.exec(urlLike.replace(/[()]/g, '')) 27 - if (!parts) 28 - return [urlLike] 29 - return [parts[1], parts[2] || undefined, parts[3] || undefined] 30 - } 31 - 32 - // Based on https://github.com/stacktracejs/error-stack-parser 33 - // Credit to stacktracejs 34 - export function parseSingleStack(raw: string): ParsedStack | null { 35 - let line = raw.trim() 36 - 37 - if (line.includes('(eval ')) 38 - line = line.replace(/eval code/g, 'eval').replace(/(\(eval at [^()]*)|(,.*$)/g, '') 39 - 40 - let sanitizedLine = line 41 - .replace(/^\s+/, '') 42 - .replace(/\(eval code/g, '(') 43 - .replace(/^.*?\s+/, '') 44 - 45 - // capture and preserve the parenthesized location "(/foo/my bar.js:12:87)" in 46 - // case it has spaces in it, as the string is split on \s+ later on 47 - const location = sanitizedLine.match(/ (\(.+\)$)/) 48 - 49 - // remove the parenthesized location from the line, if it was matched 50 - sanitizedLine = location ? sanitizedLine.replace(location[0], '') : sanitizedLine 51 - 52 - // if a location was matched, pass it to extractLocation() otherwise pass all sanitizedLine 53 - // because this line doesn't have function name 54 - const [url, lineNumber, columnNumber] = extractLocation(location ? location[1] : sanitizedLine) 55 - let method = (location && sanitizedLine) || '' 56 - let file = url && ['eval', '<anonymous>'].includes(url) ? undefined : url 57 - 58 - if (!file || !lineNumber || !columnNumber) 59 - return null 60 - 61 - if (method.startsWith('async ')) 62 - method = method.slice(6) 63 - 64 - if (file.startsWith('file://')) 65 - file = file.slice(7) 66 - 67 - // normalize Windows path (\ -> /) 68 - file = resolve(file) 69 - 70 - return { 71 - method, 72 - file, 73 - line: parseInt(lineNumber), 74 - column: parseInt(columnNumber), 75 - } 76 - } 77 - 78 - export function parseStacktrace(stack: string, full = false): ParsedStack[] { 79 - const stackFrames = stack 80 - .split('\n') 81 - .map((raw): ParsedStack | null => { 82 - const stack = parseSingleStack(raw) 83 - 84 - if (!stack || (!full && stackIgnorePatterns.some(p => stack.file.match(p)))) 85 - return null 86 - 87 - return stack 88 - }) 89 - .filter(notNullish) 90 - 91 - return stackFrames 92 - } 93 - 94 - export function parseErrorStacktrace(e: ErrorWithDiff, full = false): ParsedStack[] { 95 - if (!e || isPrimitive(e)) 96 - return [] 97 - 98 - if (e.stacks) 99 - return e.stacks 100 - 101 - const stackStr = e.stack || e.stackStr || '' 102 - const stackFrames = parseStacktrace(stackStr, full) 103 - 104 - e.stacks = stackFrames 105 - return stackFrames 106 - } 107 - 108 - export function positionToOffset( 109 - source: string, 110 - lineNumber: number, 111 - columnNumber: number, 112 - ): number { 113 - const lines = source.split(lineSplitRE) 114 - let start = 0 115 - 116 - if (lineNumber > lines.length) 117 - return source.length 118 - 119 - for (let i = 0; i < lineNumber - 1; i++) 120 - start += lines[i].length + 1 121 - 122 - return start + columnNumber 123 - } 124 - 125 - export function offsetToLineNumber( 126 - source: string, 127 - offset: number, 128 - ): number { 129 - if (offset > source.length) { 130 - throw new Error( 131 - `offset is longer than source length! offset ${offset} > length ${source.length}`, 132 - ) 133 - } 134 - const lines = source.split(lineSplitRE) 135 - let counted = 0 136 - let line = 0 137 - for (; line < lines.length; line++) { 138 - const lineLength = lines[line].length + 1 139 - if (counted + lineLength >= offset) 140 - break 141 - 142 - counted += lineLength 143 - } 144 - return line + 1 145 - } 1 + export { 2 + lineSplitRE, 3 + parseSingleStack, 4 + parseStacktrace, 5 + parseErrorStacktrace, 6 + positionToOffset, 7 + offsetToLineNumber, 8 + } from '@vitest/utils'
+21 -10
packages/vitest/src/integrations/snapshot/chai.ts
··· 1 1 import type { ChaiPlugin } from '@vitest/expect' 2 - import { SnapshotClient } from './client' 3 - import { stripSnapshotIndentation } from './port/inlineSnapshot' 4 - import { addSerializer } from './port/plugins' 2 + import type { Test } from '@vitest/runner' 3 + import { getNames } from '@vitest/runner/utils' 4 + import type { SnapshotClient } from '@vitest/snapshot' 5 + import { addSerializer, stripSnapshotIndentation } from '@vitest/snapshot' 6 + import { VitestSnapshotClient } from './client' 5 7 6 8 let _client: SnapshotClient 7 9 8 10 export function getSnapshotClient(): SnapshotClient { 9 11 if (!_client) 10 - _client = new SnapshotClient() 12 + _client = new VitestSnapshotClient() 11 13 return _client 12 14 } 13 15 ··· 38 40 } 39 41 40 42 export const SnapshotPlugin: ChaiPlugin = (chai, utils) => { 43 + const getTestNames = (test?: Test) => { 44 + if (!test) 45 + return {} 46 + return { 47 + filepath: test.file?.filepath, 48 + name: getNames(test).slice(1).join(' > '), 49 + } 50 + } 51 + 41 52 for (const key of ['matchSnapshot', 'toMatchSnapshot']) { 42 53 utils.addMethod( 43 54 chai.Assertion.prototype, ··· 52 63 const errorMessage = utils.flag(this, 'message') 53 64 getSnapshotClient().assert({ 54 65 received: expected, 55 - test, 56 66 message, 57 67 isInline: false, 58 68 properties, 59 69 errorMessage, 70 + ...getTestNames(test), 60 71 }) 61 72 }, 62 73 ) ··· 64 75 utils.addMethod( 65 76 chai.Assertion.prototype, 66 77 'toMatchInlineSnapshot', 67 - function __VITEST_INLINE_SNAPSHOT__(this: Record<string, unknown>, properties?: object, inlineSnapshot?: string, message?: string) { 78 + function __INLINE_SNAPSHOT__(this: Record<string, unknown>, properties?: object, inlineSnapshot?: string, message?: string) { 68 79 const expected = utils.flag(this, 'object') 69 80 const error = utils.flag(this, 'error') 70 81 const test = utils.flag(this, 'vitest-test') ··· 78 89 const errorMessage = utils.flag(this, 'message') 79 90 getSnapshotClient().assert({ 80 91 received: expected, 81 - test, 82 92 message, 83 93 isInline: true, 84 94 properties, 85 95 inlineSnapshot, 86 96 error, 87 97 errorMessage, 98 + ...getTestNames(test), 88 99 }) 89 100 }, 90 101 ) ··· 98 109 const errorMessage = utils.flag(this, 'message') 99 110 getSnapshotClient().assert({ 100 111 received: getErrorString(expected, promise), 101 - test, 102 112 message, 103 113 errorMessage, 114 + ...getTestNames(test), 104 115 }) 105 116 }, 106 117 ) 107 118 utils.addMethod( 108 119 chai.Assertion.prototype, 109 120 'toThrowErrorMatchingInlineSnapshot', 110 - function __VITEST_INLINE_SNAPSHOT__(this: Record<string, unknown>, inlineSnapshot: string, message: string) { 121 + function __INLINE_SNAPSHOT__(this: Record<string, unknown>, inlineSnapshot: string, message: string) { 111 122 const expected = utils.flag(this, 'object') 112 123 const error = utils.flag(this, 'error') 113 124 const test = utils.flag(this, 'vitest-test') ··· 115 126 const errorMessage = utils.flag(this, 'message') 116 127 getSnapshotClient().assert({ 117 128 received: getErrorString(expected, promise), 118 - test, 119 129 message, 120 130 inlineSnapshot, 121 131 isInline: true, 122 132 error, 123 133 errorMessage, 134 + ...getTestNames(test), 124 135 }) 125 136 }, 126 137 )
+4 -130
packages/vitest/src/integrations/snapshot/client.ts
··· 1 - import { expect } from 'chai' 2 1 import { equals, iterableEquality, subsetEquality } from '@vitest/expect' 3 - import type { Test } from '@vitest/runner' 4 - import { getNames } from '@vitest/runner/utils' 5 - import { rpc } from '../../runtime/rpc' 6 - import { getWorkerState } from '../../utils' 7 - import { deepMergeSnapshot } from './port/utils' 8 - import SnapshotState from './port/state' 2 + import { SnapshotClient } from '@vitest/snapshot' 9 3 10 - export interface Context { 11 - file: string 12 - title?: string 13 - fullTitle?: string 14 - } 15 - 16 - interface AssertOptions { 17 - received: unknown 18 - test?: Test 19 - message?: string 20 - isInline?: boolean 21 - properties?: object 22 - inlineSnapshot?: string 23 - error?: Error 24 - errorMessage?: string 25 - } 26 - 27 - export class SnapshotClient { 28 - test: Test | undefined 29 - snapshotState: SnapshotState | undefined 30 - snapshotStateMap = new Map<string, SnapshotState>() 31 - 32 - async setTest(test: Test) { 33 - this.test = test 34 - 35 - if (this.snapshotState?.testFilePath !== this.test.file!.filepath) { 36 - this.saveCurrent() 37 - 38 - const filePath = this.test!.file!.filepath 39 - if (!this.getSnapshotState(test)) { 40 - this.snapshotStateMap.set( 41 - filePath, 42 - await SnapshotState.create( 43 - filePath, 44 - getWorkerState().config.snapshotOptions, 45 - ), 46 - ) 47 - } 48 - this.snapshotState = this.getSnapshotState(test) 49 - } 50 - } 51 - 52 - getSnapshotState(test: Test) { 53 - return this.snapshotStateMap.get(test.file!.filepath)! 54 - } 55 - 56 - clearTest() { 57 - this.test = undefined 58 - } 59 - 60 - skipTestSnapshots(test: Test) { 61 - this.snapshotState?.markSnapshotsAsCheckedForTest(test.name) 62 - } 63 - 64 - assert(options: AssertOptions): void { 65 - const { 66 - test = this.test, 67 - message, 68 - isInline = false, 69 - properties, 70 - inlineSnapshot, 71 - error, 72 - errorMessage, 73 - } = options 74 - let { received } = options 75 - 76 - if (!test) 77 - throw new Error('Snapshot cannot be used outside of test') 78 - 79 - if (typeof properties === 'object') { 80 - if (typeof received !== 'object' || !received) 81 - throw new Error('Received value must be an object when the matcher has properties') 82 - 83 - try { 84 - const pass = equals(received, properties, [iterableEquality, subsetEquality]) 85 - if (!pass) 86 - expect(received).equals(properties) 87 - else 88 - received = deepMergeSnapshot(received, properties) 89 - } 90 - catch (err: any) { 91 - err.message = errorMessage || 'Snapshot mismatched' 92 - throw err 93 - } 94 - } 95 - 96 - const testName = [ 97 - ...getNames(test).slice(1), 98 - ...(message ? [message] : []), 99 - ].join(' > ') 100 - 101 - const snapshotState = this.getSnapshotState(test) 102 - 103 - const { actual, expected, key, pass } = snapshotState.match({ 104 - testName, 105 - received, 106 - isInline, 107 - error, 108 - inlineSnapshot, 109 - }) 110 - 111 - if (!pass) { 112 - try { 113 - expect(actual.trim()).equals(expected ? expected.trim() : '') 114 - } 115 - catch (error: any) { 116 - error.message = errorMessage || `Snapshot \`${key || 'unknown'}\` mismatched` 117 - throw error 118 - } 119 - } 120 - } 121 - 122 - async saveCurrent() { 123 - if (!this.snapshotState) 124 - return 125 - const result = await this.snapshotState.pack() 126 - await rpc().snapshotSaved(result) 127 - 128 - this.snapshotState = undefined 129 - } 130 - 131 - clear() { 132 - this.snapshotStateMap.clear() 4 + export class VitestSnapshotClient extends SnapshotClient { 5 + equalityCheck(received: unknown, expected: unknown): boolean { 6 + return equals(received, expected, [iterableEquality, subsetEquality]) 133 7 } 134 8 }
-19
packages/vitest/src/integrations/snapshot/env.ts
··· 1 - export interface SnapshotEnvironment { 2 - resolvePath(filepath: string): Promise<string> 3 - prepareDirectory(filepath: string): Promise<void> 4 - saveSnapshotFile(filepath: string, snapshot: string): Promise<void> 5 - readSnapshotFile(filepath: string): Promise<string | null> 6 - removeSnapshotFile(filepath: string): Promise<void> 7 - } 8 - 9 - let _snapshotEnvironment: SnapshotEnvironment 10 - 11 - export function setupSnapshotEnvironment(environment: SnapshotEnvironment) { 12 - _snapshotEnvironment = environment 13 - } 14 - 15 - export function getSnapshotEnvironment() { 16 - if (!_snapshotEnvironment) 17 - throw new Error('Snapshot environment is not setup') 18 - return _snapshotEnvironment 19 - }
-76
packages/vitest/src/integrations/snapshot/manager.ts
··· 1 - import { basename, dirname, join } from 'pathe' 2 - import type { SnapshotResult, SnapshotStateOptions, SnapshotSummary } from '../../types' 3 - 4 - export class SnapshotManager { 5 - summary: SnapshotSummary = undefined! 6 - extension = '.snap' 7 - 8 - constructor(public options: SnapshotStateOptions) { 9 - this.clear() 10 - } 11 - 12 - clear() { 13 - this.summary = emptySummary(this.options) 14 - } 15 - 16 - add(result: SnapshotResult) { 17 - addSnapshotResult(this.summary, result) 18 - } 19 - 20 - resolvePath(testPath: string) { 21 - const resolver = this.options.resolveSnapshotPath || (() => { 22 - return join( 23 - join( 24 - dirname(testPath), '__snapshots__'), 25 - `${basename(testPath)}${this.extension}`, 26 - ) 27 - }) 28 - 29 - return resolver(testPath, this.extension) 30 - } 31 - } 32 - 33 - export function emptySummary(options: SnapshotStateOptions): SnapshotSummary { 34 - const summary = { 35 - added: 0, 36 - failure: false, 37 - filesAdded: 0, 38 - filesRemoved: 0, 39 - filesRemovedList: [], 40 - filesUnmatched: 0, 41 - filesUpdated: 0, 42 - matched: 0, 43 - total: 0, 44 - unchecked: 0, 45 - uncheckedKeysByFile: [], 46 - unmatched: 0, 47 - updated: 0, 48 - didUpdate: options.updateSnapshot === 'all', 49 - } 50 - return summary 51 - } 52 - 53 - export function addSnapshotResult(summary: SnapshotSummary, result: SnapshotResult): void { 54 - if (result.added) 55 - summary.filesAdded++ 56 - if (result.fileDeleted) 57 - summary.filesRemoved++ 58 - if (result.unmatched) 59 - summary.filesUnmatched++ 60 - if (result.updated) 61 - summary.filesUpdated++ 62 - 63 - summary.added += result.added 64 - summary.matched += result.matched 65 - summary.unchecked += result.unchecked 66 - if (result.uncheckedKeys && result.uncheckedKeys.length > 0) { 67 - summary.uncheckedKeysByFile.push({ 68 - filePath: result.filepath, 69 - keys: result.uncheckedKeys, 70 - }) 71 - } 72 - 73 - summary.unmatched += result.unmatched 74 - summary.updated += result.updated 75 - summary.total += result.added + result.matched + result.unmatched + result.updated 76 - }
+9 -4
packages/vitest/src/runtime/runners/test.ts
··· 2 2 import { GLOBAL_EXPECT, getState, setState } from '@vitest/expect' 3 3 import { getSnapshotClient } from '../../integrations/snapshot/chai' 4 4 import { vi } from '../../integrations/vi' 5 - import { getFullName, getWorkerState } from '../../utils' 5 + import { getFullName, getNames, getWorkerState } from '../../utils' 6 6 import { createExpect } from '../../integrations/chai/index' 7 7 import type { ResolvedConfig } from '../../types/config' 8 8 import type { VitestExecutor } from '../execute' 9 + import { rpc } from '../rpc' 9 10 10 11 export class VitestTestRunner implements VitestRunner { 11 12 private snapshotClient = getSnapshotClient() ··· 25 26 } 26 27 27 28 async onAfterRun() { 28 - await this.snapshotClient.saveCurrent() 29 + const result = await this.snapshotClient.resetCurrent() 30 + if (result) 31 + await rpc().snapshotSaved(result) 29 32 } 30 33 31 34 onAfterRunSuite(suite: Suite) { ··· 43 46 } 44 47 45 48 async onBeforeRunTest(test: Test) { 49 + const name = getNames(test).slice(1).join(' > ') 50 + 46 51 if (test.mode !== 'run') { 47 - this.snapshotClient.skipTestSnapshots(test) 52 + this.snapshotClient.skipTestSnapshots(name) 48 53 return 49 54 } 50 55 51 56 clearModuleMocks(this.config) 52 - await this.snapshotClient.setTest(test) 57 + await this.snapshotClient.setTest(test.file!.filepath, name, this.workerState.config.snapshotOptions) 53 58 54 59 this.workerState.current = test 55 60 }
+6 -22
packages/vitest/src/integrations/snapshot/environments/node.ts
··· 1 - import { existsSync, promises as fs } from 'node:fs' 1 + import { NodeSnapshotEnvironment } from '@vitest/snapshot/environment' 2 2 import { rpc } from '../../../runtime/rpc' 3 - import type { SnapshotEnvironment } from '../env' 4 3 5 - export class NodeSnapshotEnvironment implements SnapshotEnvironment { 4 + export class VitestSnapshotEnvironment extends NodeSnapshotEnvironment { 5 + getHeader(): string { 6 + return `// Vitest Snapshot v${this.getVersion()}, https://vitest.dev/guide/snapshot.html` 7 + } 8 + 6 9 resolvePath(filepath: string): Promise<string> { 7 10 return rpc().resolveSnapshotPath(filepath) 8 - } 9 - 10 - async prepareDirectory(filepath: string): Promise<void> { 11 - await fs.mkdir(filepath, { recursive: true }) 12 - } 13 - 14 - async saveSnapshotFile(filepath: string, snapshot: string): Promise<void> { 15 - await fs.writeFile(filepath, snapshot, 'utf-8') 16 - } 17 - 18 - async readSnapshotFile(filepath: string): Promise<string | null> { 19 - if (!existsSync(filepath)) 20 - return null 21 - return fs.readFile(filepath, 'utf-8') 22 - } 23 - 24 - async removeSnapshotFile(filepath: string): Promise<void> { 25 - if (existsSync(filepath)) 26 - await fs.unlink(filepath) 27 11 } 28 12 }
-138
packages/vitest/src/integrations/snapshot/port/inlineSnapshot.ts
··· 1 - import type MagicString from 'magic-string' 2 - import { lineSplitRE, offsetToLineNumber, positionToOffset } from '../../../utils/source-map' 3 - import { getCallLastIndex } from '../../../utils' 4 - import { getSnapshotEnvironment } from '../env' 5 - 6 - export interface InlineSnapshot { 7 - snapshot: string 8 - file: string 9 - line: number 10 - column: number 11 - } 12 - 13 - export async function saveInlineSnapshots( 14 - snapshots: Array<InlineSnapshot>, 15 - ) { 16 - const environment = getSnapshotEnvironment() 17 - const MagicString = (await import('magic-string')).default 18 - const files = new Set(snapshots.map(i => i.file)) 19 - await Promise.all(Array.from(files).map(async (file) => { 20 - const snaps = snapshots.filter(i => i.file === file) 21 - const code = await environment.readSnapshotFile(file) as string 22 - const s = new MagicString(code) 23 - 24 - for (const snap of snaps) { 25 - const index = positionToOffset(code, snap.line, snap.column) 26 - replaceInlineSnap(code, s, index, snap.snapshot) 27 - } 28 - 29 - const transformed = s.toString() 30 - if (transformed !== code) 31 - await environment.saveSnapshotFile(file, transformed) 32 - })) 33 - } 34 - 35 - const startObjectRegex = /(?:toMatchInlineSnapshot|toThrowErrorMatchingInlineSnapshot)\s*\(\s*(?:\/\*[\S\s]*\*\/\s*|\/\/.*\s+)*\s*({)/m 36 - 37 - function replaceObjectSnap(code: string, s: MagicString, index: number, newSnap: string) { 38 - code = code.slice(index) 39 - const startMatch = startObjectRegex.exec(code) 40 - if (!startMatch) 41 - return false 42 - 43 - code = code.slice(startMatch.index) 44 - const charIndex = getCallLastIndex(code) 45 - if (charIndex === null) 46 - return false 47 - 48 - s.appendLeft(index + startMatch.index + charIndex, `, ${prepareSnapString(newSnap, code, index)}`) 49 - 50 - return true 51 - } 52 - 53 - function prepareSnapString(snap: string, source: string, index: number) { 54 - const lineNumber = offsetToLineNumber(source, index) 55 - const line = source.split(lineSplitRE)[lineNumber - 1] 56 - const indent = line.match(/^\s*/)![0] || '' 57 - const indentNext = indent.includes('\t') ? `${indent}\t` : `${indent} ` 58 - 59 - const lines = snap 60 - .trim() 61 - .replace(/\\/g, '\\\\') 62 - .split(/\n/g) 63 - 64 - const isOneline = lines.length <= 1 65 - const quote = isOneline ? '\'' : '`' 66 - if (isOneline) 67 - return `'${lines.join('\n').replace(/'/g, '\\\'')}'` 68 - else 69 - return `${quote}\n${lines.map(i => i ? indentNext + i : '').join('\n').replace(/`/g, '\\`').replace(/\${/g, '\\${')}\n${indent}${quote}` 70 - } 71 - 72 - const startRegex = /(?:toMatchInlineSnapshot|toThrowErrorMatchingInlineSnapshot)\s*\(\s*(?:\/\*[\S\s]*\*\/\s*|\/\/.*\s+)*\s*[\w_$]*(['"`\)])/m 73 - export function replaceInlineSnap(code: string, s: MagicString, index: number, newSnap: string) { 74 - const startMatch = startRegex.exec(code.slice(index)) 75 - if (!startMatch) 76 - return replaceObjectSnap(code, s, index, newSnap) 77 - 78 - const quote = startMatch[1] 79 - const startIndex = index + startMatch.index! + startMatch[0].length 80 - const snapString = prepareSnapString(newSnap, code, index) 81 - 82 - if (quote === ')') { 83 - s.appendRight(startIndex - 1, snapString) 84 - return true 85 - } 86 - 87 - const quoteEndRE = new RegExp(`(?:^|[^\\\\])${quote}`) 88 - const endMatch = quoteEndRE.exec(code.slice(startIndex)) 89 - if (!endMatch) 90 - return false 91 - const endIndex = startIndex + endMatch.index! + endMatch[0].length 92 - s.overwrite(startIndex - 1, endIndex, snapString) 93 - 94 - return true 95 - } 96 - 97 - const INDENTATION_REGEX = /^([^\S\n]*)\S/m 98 - export function stripSnapshotIndentation(inlineSnapshot: string) { 99 - // Find indentation if exists. 100 - const match = inlineSnapshot.match(INDENTATION_REGEX) 101 - if (!match || !match[1]) { 102 - // No indentation. 103 - return inlineSnapshot 104 - } 105 - 106 - const indentation = match[1] 107 - const lines = inlineSnapshot.split(/\n/g) 108 - if (lines.length <= 2) { 109 - // Must be at least 3 lines. 110 - return inlineSnapshot 111 - } 112 - 113 - if (lines[0].trim() !== '' || lines[lines.length - 1].trim() !== '') { 114 - // If not blank first and last lines, abort. 115 - return inlineSnapshot 116 - } 117 - 118 - for (let i = 1; i < lines.length - 1; i++) { 119 - if (lines[i] !== '') { 120 - if (lines[i].indexOf(indentation) !== 0) { 121 - // All lines except first and last should either be blank or have the same 122 - // indent as the first line (or more). If this isn't the case we don't 123 - // want to touch the snapshot at all. 124 - return inlineSnapshot 125 - } 126 - 127 - lines[i] = lines[i].substring(indentation.length) 128 - } 129 - } 130 - 131 - // Last line is a special case because it won't have the same indent as others 132 - // but may still have been given some indent to line up. 133 - lines[lines.length - 1] = '' 134 - 135 - // Return inline snapshot, now at indent 0. 136 - inlineSnapshot = lines.join('\n') 137 - return inlineSnapshot 138 - }
-51
packages/vitest/src/integrations/snapshot/port/mockSerializer.ts
··· 1 - /** 2 - * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 3 - * 4 - * This source code is licensed under the MIT license found in the 5 - * LICENSE file in the root directory of this source tree. 6 - * 7 - * https://github.com/facebook/jest/blob/4eb4f6a59b6eae0e05b8e51dd8cd3fdca1c7aff1/packages/jest-snapshot/src/mockSerializer.ts#L4 8 - */ 9 - 10 - import type { NewPlugin } from 'pretty-format' 11 - 12 - export const serialize: NewPlugin['serialize'] = ( 13 - val, 14 - config, 15 - indentation, 16 - depth, 17 - refs, 18 - printer, 19 - ): string => { 20 - // Serialize a non-default name, even if config.printFunctionName is false. 21 - const name = val.getMockName() 22 - const nameString = name === 'vi.fn()' ? '' : ` ${name}` 23 - 24 - let callsString = '' 25 - if (val.mock.calls.length !== 0) { 26 - const indentationNext = indentation + config.indent 27 - callsString 28 - = ` {${ 29 - config.spacingOuter 30 - }${indentationNext 31 - }"calls": ${ 32 - printer(val.mock.calls, config, indentationNext, depth, refs) 33 - }${config.min ? ', ' : ',' 34 - }${config.spacingOuter 35 - }${indentationNext 36 - }"results": ${ 37 - printer(val.mock.results, config, indentationNext, depth, refs) 38 - }${config.min ? '' : ',' 39 - }${config.spacingOuter 40 - }${indentation 41 - }}` 42 - } 43 - 44 - return `[MockFunction${nameString}]${callsString}` 45 - } 46 - 47 - export const test: NewPlugin['test'] = val => val && !!val._isMockFunction 48 - 49 - const plugin: NewPlugin = { serialize, test } 50 - 51 - export default plugin
-41
packages/vitest/src/integrations/snapshot/port/plugins.ts
··· 1 - /** 2 - * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 3 - * 4 - * This source code is licensed under the MIT license found in the 5 - * LICENSE file in the root directory of this source tree. 6 - */ 7 - 8 - import type { 9 - Plugin as PrettyFormatPlugin, 10 - Plugins as PrettyFormatPlugins, 11 - } from 'pretty-format' 12 - import { 13 - plugins as prettyFormatPlugins, 14 - } from 'pretty-format' 15 - 16 - import MockSerializer from './mockSerializer' 17 - 18 - const { 19 - DOMCollection, 20 - DOMElement, 21 - Immutable, 22 - ReactElement, 23 - ReactTestComponent, 24 - AsymmetricMatcher, 25 - } = prettyFormatPlugins 26 - 27 - let PLUGINS: PrettyFormatPlugins = [ 28 - ReactTestComponent, 29 - ReactElement, 30 - DOMElement, 31 - DOMCollection, 32 - Immutable, 33 - AsymmetricMatcher, 34 - MockSerializer, 35 - ] 36 - 37 - export const addSerializer = (plugin: PrettyFormatPlugin): void => { 38 - PLUGINS = [plugin].concat(PLUGINS) 39 - } 40 - 41 - export const getSerializers = (): PrettyFormatPlugins => PLUGINS
-333
packages/vitest/src/integrations/snapshot/port/state.ts
··· 1 - /** 2 - * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 3 - * 4 - * This source code is licensed under the MIT license found in the 5 - * LICENSE file in the root directory of this source tree. 6 - */ 7 - 8 - import type { OptionsReceived as PrettyFormatOptions } from 'pretty-format' 9 - import type { ParsedStack, SnapshotData, SnapshotMatchOptions, SnapshotResult, SnapshotStateOptions, SnapshotUpdateState } from '../../../types' 10 - import { parseErrorStacktrace } from '../../../utils/source-map' 11 - import type { SnapshotEnvironment } from '../env' 12 - import { getSnapshotEnvironment } from '../env' 13 - import type { InlineSnapshot } from './inlineSnapshot' 14 - import { saveInlineSnapshots } from './inlineSnapshot' 15 - 16 - import { 17 - addExtraLineBreaks, 18 - getSnapshotData, 19 - keyToTestName, 20 - prepareExpected, 21 - removeExtraLineBreaks, 22 - saveSnapshotFile, 23 - serialize, 24 - testNameToKey, 25 - } from './utils' 26 - 27 - interface SnapshotReturnOptions { 28 - actual: string 29 - count: number 30 - expected?: string 31 - key: string 32 - pass: boolean 33 - } 34 - 35 - interface SaveStatus { 36 - deleted: boolean 37 - saved: boolean 38 - } 39 - 40 - export default class SnapshotState { 41 - private _counters: Map<string, number> 42 - private _dirty: boolean 43 - private _updateSnapshot: SnapshotUpdateState 44 - private _snapshotData: SnapshotData 45 - private _initialData: SnapshotData 46 - private _inlineSnapshots: Array<InlineSnapshot> 47 - private _uncheckedKeys: Set<string> 48 - private _snapshotFormat: PrettyFormatOptions 49 - private _environment: SnapshotEnvironment 50 - private _fileExists: boolean 51 - 52 - added: number 53 - expand: boolean 54 - matched: number 55 - unmatched: number 56 - updated: number 57 - 58 - private constructor( 59 - public testFilePath: string, 60 - public snapshotPath: string, 61 - snapshotContent: string | null, 62 - options: SnapshotStateOptions, 63 - ) { 64 - const { data, dirty } = getSnapshotData( 65 - snapshotContent, 66 - options, 67 - ) 68 - this._fileExists = snapshotContent != null // TODO: update on watch? 69 - this._initialData = data 70 - this._snapshotData = data 71 - this._dirty = dirty 72 - this._inlineSnapshots = [] 73 - this._uncheckedKeys = new Set(Object.keys(this._snapshotData)) 74 - this._counters = new Map() 75 - this.expand = options.expand || false 76 - this.added = 0 77 - this.matched = 0 78 - this.unmatched = 0 79 - this._updateSnapshot = options.updateSnapshot 80 - this.updated = 0 81 - this._snapshotFormat = { 82 - printBasicPrototype: false, 83 - ...options.snapshotFormat, 84 - } 85 - this._environment = getSnapshotEnvironment() 86 - } 87 - 88 - static async create( 89 - testFilePath: string, 90 - options: SnapshotStateOptions, 91 - ) { 92 - const environment = getSnapshotEnvironment() 93 - const snapshotPath = await environment.resolvePath(testFilePath) 94 - const content = await environment.readSnapshotFile(snapshotPath) 95 - return new SnapshotState(testFilePath, snapshotPath, content, options) 96 - } 97 - 98 - markSnapshotsAsCheckedForTest(testName: string): void { 99 - this._uncheckedKeys.forEach((uncheckedKey) => { 100 - if (keyToTestName(uncheckedKey) === testName) 101 - this._uncheckedKeys.delete(uncheckedKey) 102 - }) 103 - } 104 - 105 - private _inferInlineSnapshotStack(stacks: ParsedStack[]) { 106 - // if called inside resolves/rejects, stacktrace is different 107 - const promiseIndex = stacks.findIndex(i => i.method.match(/__VITEST_(RESOLVES|REJECTS)__/)) 108 - if (promiseIndex !== -1) 109 - return stacks[promiseIndex + 3] 110 - 111 - // inline snapshot function is called __VITEST_INLINE_SNAPSHOT__ 112 - // in integrations/snapshot/chai.ts 113 - const stackIndex = stacks.findIndex(i => i.method.includes('__VITEST_INLINE_SNAPSHOT__')) 114 - return stackIndex !== -1 ? stacks[stackIndex + 2] : null 115 - } 116 - 117 - private _addSnapshot( 118 - key: string, 119 - receivedSerialized: string, 120 - options: { isInline: boolean; error?: Error }, 121 - ): void { 122 - this._dirty = true 123 - if (options.isInline) { 124 - const stacks = parseErrorStacktrace(options.error || new Error('snapshot'), true) 125 - const stack = this._inferInlineSnapshotStack(stacks) 126 - if (!stack) { 127 - throw new Error( 128 - `Vitest: Couldn't infer stack frame for inline snapshot.\n${JSON.stringify(stacks)}`, 129 - ) 130 - } 131 - // removing 1 column, because source map points to the wrong 132 - // location for js files, but `column-1` points to the same in both js/ts 133 - // https://github.com/vitejs/vite/issues/8657 134 - stack.column-- 135 - this._inlineSnapshots.push({ 136 - snapshot: receivedSerialized, 137 - ...stack, 138 - }) 139 - } 140 - else { 141 - this._snapshotData[key] = receivedSerialized 142 - } 143 - } 144 - 145 - clear(): void { 146 - this._snapshotData = this._initialData 147 - // this._inlineSnapshots = [] 148 - this._counters = new Map() 149 - this.added = 0 150 - this.matched = 0 151 - this.unmatched = 0 152 - this.updated = 0 153 - this._dirty = false 154 - } 155 - 156 - async save(): Promise<SaveStatus> { 157 - const hasExternalSnapshots = Object.keys(this._snapshotData).length 158 - const hasInlineSnapshots = this._inlineSnapshots.length 159 - const isEmpty = !hasExternalSnapshots && !hasInlineSnapshots 160 - 161 - const status: SaveStatus = { 162 - deleted: false, 163 - saved: false, 164 - } 165 - 166 - if ((this._dirty || this._uncheckedKeys.size) && !isEmpty) { 167 - if (hasExternalSnapshots) { 168 - await saveSnapshotFile(this._snapshotData, this.snapshotPath) 169 - this._fileExists = true 170 - } 171 - if (hasInlineSnapshots) 172 - await saveInlineSnapshots(this._inlineSnapshots) 173 - 174 - status.saved = true 175 - } 176 - else if (!hasExternalSnapshots && this._fileExists) { 177 - if (this._updateSnapshot === 'all') { 178 - await this._environment.removeSnapshotFile(this.snapshotPath) 179 - this._fileExists = false 180 - } 181 - 182 - status.deleted = true 183 - } 184 - 185 - return status 186 - } 187 - 188 - getUncheckedCount(): number { 189 - return this._uncheckedKeys.size || 0 190 - } 191 - 192 - getUncheckedKeys(): Array<string> { 193 - return Array.from(this._uncheckedKeys) 194 - } 195 - 196 - removeUncheckedKeys(): void { 197 - if (this._updateSnapshot === 'all' && this._uncheckedKeys.size) { 198 - this._dirty = true 199 - this._uncheckedKeys.forEach(key => delete this._snapshotData[key]) 200 - this._uncheckedKeys.clear() 201 - } 202 - } 203 - 204 - match({ 205 - testName, 206 - received, 207 - key, 208 - inlineSnapshot, 209 - isInline, 210 - error, 211 - }: SnapshotMatchOptions): SnapshotReturnOptions { 212 - this._counters.set(testName, (this._counters.get(testName) || 0) + 1) 213 - const count = Number(this._counters.get(testName)) 214 - 215 - if (!key) 216 - key = testNameToKey(testName, count) 217 - 218 - // Do not mark the snapshot as "checked" if the snapshot is inline and 219 - // there's an external snapshot. This way the external snapshot can be 220 - // removed with `--updateSnapshot`. 221 - if (!(isInline && this._snapshotData[key] !== undefined)) 222 - this._uncheckedKeys.delete(key) 223 - 224 - const receivedSerialized = addExtraLineBreaks(serialize(received, undefined, this._snapshotFormat)) 225 - const expected = isInline ? inlineSnapshot : this._snapshotData[key] 226 - const expectedTrimmed = prepareExpected(expected) 227 - const pass = expectedTrimmed === prepareExpected(receivedSerialized) 228 - const hasSnapshot = expected !== undefined 229 - const snapshotIsPersisted = isInline || this._fileExists 230 - 231 - if (pass && !isInline) { 232 - // Executing a snapshot file as JavaScript and writing the strings back 233 - // when other snapshots have changed loses the proper escaping for some 234 - // characters. Since we check every snapshot in every test, use the newly 235 - // generated formatted string. 236 - // Note that this is only relevant when a snapshot is added and the dirty 237 - // flag is set. 238 - this._snapshotData[key] = receivedSerialized 239 - } 240 - 241 - // These are the conditions on when to write snapshots: 242 - // * There's no snapshot file in a non-CI environment. 243 - // * There is a snapshot file and we decided to update the snapshot. 244 - // * There is a snapshot file, but it doesn't have this snapshot. 245 - // These are the conditions on when not to write snapshots: 246 - // * The update flag is set to 'none'. 247 - // * There's no snapshot file or a file without this snapshot on a CI environment. 248 - if ( 249 - (hasSnapshot && this._updateSnapshot === 'all') 250 - || ((!hasSnapshot || !snapshotIsPersisted) 251 - && (this._updateSnapshot === 'new' || this._updateSnapshot === 'all')) 252 - ) { 253 - if (this._updateSnapshot === 'all') { 254 - if (!pass) { 255 - if (hasSnapshot) 256 - this.updated++ 257 - else 258 - this.added++ 259 - 260 - this._addSnapshot(key, receivedSerialized, { error, isInline }) 261 - } 262 - else { 263 - this.matched++ 264 - } 265 - } 266 - else { 267 - this._addSnapshot(key, receivedSerialized, { error, isInline }) 268 - this.added++ 269 - } 270 - 271 - return { 272 - actual: '', 273 - count, 274 - expected: '', 275 - key, 276 - pass: true, 277 - } 278 - } 279 - else { 280 - if (!pass) { 281 - this.unmatched++ 282 - return { 283 - actual: removeExtraLineBreaks(receivedSerialized), 284 - count, 285 - expected: 286 - expectedTrimmed !== undefined 287 - ? removeExtraLineBreaks(expectedTrimmed) 288 - : undefined, 289 - key, 290 - pass: false, 291 - } 292 - } 293 - else { 294 - this.matched++ 295 - return { 296 - actual: '', 297 - count, 298 - expected: '', 299 - key, 300 - pass: true, 301 - } 302 - } 303 - } 304 - } 305 - 306 - async pack(): Promise<SnapshotResult> { 307 - const snapshot: SnapshotResult = { 308 - filepath: this.testFilePath, 309 - added: 0, 310 - fileDeleted: false, 311 - matched: 0, 312 - unchecked: 0, 313 - uncheckedKeys: [], 314 - unmatched: 0, 315 - updated: 0, 316 - } 317 - const uncheckedCount = this.getUncheckedCount() 318 - const uncheckedKeys = this.getUncheckedKeys() 319 - if (uncheckedCount) 320 - this.removeUncheckedKeys() 321 - 322 - const status = await this.save() 323 - snapshot.fileDeleted = status.deleted 324 - snapshot.added = this.added 325 - snapshot.matched = this.matched 326 - snapshot.unmatched = this.unmatched 327 - snapshot.updated = this.updated 328 - snapshot.unchecked = !status.deleted ? uncheckedCount : 0 329 - snapshot.uncheckedKeys = Array.from(uncheckedKeys) 330 - 331 - return snapshot 332 - } 333 - }
-255
packages/vitest/src/integrations/snapshot/port/utils.ts
··· 1 - /** 2 - * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 3 - * 4 - * This source code is licensed under the MIT license found in the 5 - * LICENSE file in the root directory of this source tree. 6 - */ 7 - 8 - import { dirname, join } from 'pathe' 9 - import naturalCompare from 'natural-compare' 10 - import type { OptionsReceived as PrettyFormatOptions } from 'pretty-format' 11 - import { 12 - format as prettyFormat, 13 - } from 'pretty-format' 14 - import type { SnapshotData, SnapshotStateOptions } from '../../../types' 15 - import { isObject } from '../../../utils' 16 - import { getSnapshotEnvironment } from '../env' 17 - import { getSerializers } from './plugins' 18 - 19 - // TODO: rewrite and clean up 20 - 21 - export const SNAPSHOT_VERSION = '1' 22 - 23 - const writeSnapshotVersion = () => `// Vitest Snapshot v${SNAPSHOT_VERSION}, https://vitest.dev/guide/snapshot.html` 24 - 25 - export const testNameToKey = (testName: string, count: number): string => 26 - `${testName} ${count}` 27 - 28 - export const keyToTestName = (key: string): string => { 29 - if (!/ \d+$/.test(key)) 30 - throw new Error('Snapshot keys must end with a number.') 31 - 32 - return key.replace(/ \d+$/, '') 33 - } 34 - 35 - export const getSnapshotData = ( 36 - content: string | null, 37 - options: SnapshotStateOptions, 38 - ): { 39 - data: SnapshotData 40 - dirty: boolean 41 - } => { 42 - const update = options.updateSnapshot 43 - const data = Object.create(null) 44 - let snapshotContents = '' 45 - let dirty = false 46 - 47 - if (content != null) { 48 - try { 49 - snapshotContents = content 50 - // eslint-disable-next-line no-new-func 51 - const populate = new Function('exports', snapshotContents) 52 - populate(data) 53 - } 54 - catch {} 55 - } 56 - 57 - // const validationResult = validateSnapshotVersion(snapshotContents) 58 - const isInvalid = snapshotContents // && validationResult 59 - 60 - // if (update === 'none' && isInvalid) 61 - // throw validationResult 62 - 63 - if ((update === 'all' || update === 'new') && isInvalid) 64 - dirty = true 65 - 66 - return { data, dirty } 67 - } 68 - 69 - // Add extra line breaks at beginning and end of multiline snapshot 70 - // to make the content easier to read. 71 - export const addExtraLineBreaks = (string: string): string => 72 - string.includes('\n') ? `\n${string}\n` : string 73 - 74 - // Remove extra line breaks at beginning and end of multiline snapshot. 75 - // Instead of trim, which can remove additional newlines or spaces 76 - // at beginning or end of the content from a custom serializer. 77 - export const removeExtraLineBreaks = (string: string): string => 78 - string.length > 2 && string.startsWith('\n') && string.endsWith('\n') 79 - ? string.slice(1, -1) 80 - : string 81 - 82 - // export const removeLinesBeforeExternalMatcherTrap = (stack: string): string => { 83 - // const lines = stack.split('\n') 84 - 85 - // for (let i = 0; i < lines.length; i += 1) { 86 - // // It's a function name specified in `packages/expect/src/index.ts` 87 - // // for external custom matchers. 88 - // if (lines[i].includes('__EXTERNAL_MATCHER_TRAP__')) 89 - // return lines.slice(i + 1).join('\n') 90 - // } 91 - 92 - // return stack 93 - // } 94 - 95 - const escapeRegex = true 96 - const printFunctionName = false 97 - 98 - export function serialize(val: unknown, 99 - indent = 2, 100 - formatOverrides: PrettyFormatOptions = {}): string { 101 - return normalizeNewlines( 102 - prettyFormat(val, { 103 - escapeRegex, 104 - indent, 105 - plugins: getSerializers(), 106 - printFunctionName, 107 - ...formatOverrides, 108 - }), 109 - ) 110 - } 111 - 112 - export function minify(val: unknown): string { 113 - return prettyFormat(val, { 114 - escapeRegex, 115 - min: true, 116 - plugins: getSerializers(), 117 - printFunctionName, 118 - }) 119 - } 120 - 121 - // Remove double quote marks and unescape double quotes and backslashes. 122 - export function deserializeString(stringified: string): string { 123 - return stringified.slice(1, -1).replace(/\\("|\\)/g, '$1') 124 - } 125 - 126 - export function escapeBacktickString(str: string): string { 127 - return str.replace(/`|\\|\${/g, '\\$&') 128 - } 129 - 130 - function printBacktickString(str: string): string { 131 - return `\`${escapeBacktickString(str)}\`` 132 - } 133 - 134 - export async function ensureDirectoryExists(filePath: string) { 135 - try { 136 - const environment = getSnapshotEnvironment() 137 - await environment.prepareDirectory(join(dirname(filePath))) 138 - } 139 - catch { } 140 - } 141 - 142 - function normalizeNewlines(string: string) { 143 - return string.replace(/\r\n|\r/g, '\n') 144 - } 145 - 146 - export async function saveSnapshotFile( 147 - snapshotData: SnapshotData, 148 - snapshotPath: string, 149 - ) { 150 - const environment = getSnapshotEnvironment() 151 - const snapshots = Object.keys(snapshotData) 152 - .sort(naturalCompare) 153 - .map( 154 - key => `exports[${printBacktickString(key)}] = ${printBacktickString(normalizeNewlines(snapshotData[key]))};`, 155 - ) 156 - 157 - const content = `${writeSnapshotVersion()}\n\n${snapshots.join('\n\n')}\n` 158 - const oldContent = await environment.readSnapshotFile(snapshotPath) 159 - const skipWriting = oldContent && oldContent === content 160 - 161 - if (skipWriting) 162 - return 163 - 164 - await ensureDirectoryExists(snapshotPath) 165 - await environment.saveSnapshotFile( 166 - snapshotPath, 167 - content, 168 - ) 169 - } 170 - 171 - export function prepareExpected(expected?: string) { 172 - function findStartIndent() { 173 - // Attempts to find indentation for objects. 174 - // Matches the ending tag of the object. 175 - const matchObject = /^( +)}\s+$/m.exec(expected || '') 176 - const objectIndent = matchObject?.[1]?.length 177 - 178 - if (objectIndent) 179 - return objectIndent 180 - 181 - // Attempts to find indentation for texts. 182 - // Matches the quote of first line. 183 - const matchText = /^\n( +)"/.exec(expected || '') 184 - return matchText?.[1]?.length || 0 185 - } 186 - 187 - const startIndent = findStartIndent() 188 - 189 - let expectedTrimmed = expected?.trim() 190 - 191 - if (startIndent) { 192 - expectedTrimmed = expectedTrimmed 193 - ?.replace(new RegExp(`^${' '.repeat(startIndent)}`, 'gm'), '').replace(/ +}$/, '}') 194 - } 195 - 196 - return expectedTrimmed 197 - } 198 - 199 - function deepMergeArray(target: any[] = [], source: any[] = []) { 200 - const mergedOutput = Array.from(target) 201 - 202 - source.forEach((sourceElement, index) => { 203 - const targetElement = mergedOutput[index] 204 - 205 - if (Array.isArray(target[index])) { 206 - mergedOutput[index] = deepMergeArray(target[index], sourceElement) 207 - } 208 - else if (isObject(targetElement)) { 209 - mergedOutput[index] = deepMergeSnapshot(target[index], sourceElement) 210 - } 211 - else { 212 - // Source does not exist in target or target is primitive and cannot be deep merged 213 - mergedOutput[index] = sourceElement 214 - } 215 - }) 216 - 217 - return mergedOutput 218 - } 219 - 220 - /** 221 - * Deep merge, but considers asymmetric matchers. Unlike base util's deep merge, 222 - * will merge any object-like instance. 223 - * Compatible with Jest's snapshot matcher. Should not be used outside of snapshot. 224 - * 225 - * @example 226 - * ```ts 227 - * toMatchSnapshot({ 228 - * name: expect.stringContaining('text') 229 - * }) 230 - * ``` 231 - */ 232 - export function deepMergeSnapshot(target: any, source: any): any { 233 - if (isObject(target) && isObject(source)) { 234 - const mergedOutput = { ...target } 235 - Object.keys(source).forEach((key) => { 236 - if (isObject(source[key]) && !source[key].$$typeof) { 237 - if (!(key in target)) 238 - Object.assign(mergedOutput, { [key]: source[key] }) 239 - else mergedOutput[key] = deepMergeSnapshot(target[key], source[key]) 240 - } 241 - else if (Array.isArray(source[key])) { 242 - mergedOutput[key] = deepMergeArray(target[key], source[key]) 243 - } 244 - else { 245 - Object.assign(mergedOutput, { [key]: source[key] }) 246 - } 247 - }) 248 - 249 - return mergedOutput 250 - } 251 - else if (Array.isArray(target) && Array.isArray(source)) { 252 - return deepMergeArray(target, source) 253 - } 254 - return target 255 - }