├── .gitignore ├── tests ├── v1_git_ssh │ └── yarn.lock ├── bun_basic │ └── yarn.lock ├── bun_version_url │ └── yarn.lock ├── github_version │ ├── bun.lock │ ├── yarn1.lock │ └── yarn.lock ├── v1_git_url │ └── yarn.lock ├── bun_workspaces │ └── yarn.lock ├── v1_with_npm_bug │ └── yarn.lock ├── v2 │ └── yarn.lock └── v2_without_endline │ └── yarn.lock ├── .github └── workflows │ ├── release.yaml │ └── build.yaml ├── Cargo.toml ├── Makefile.toml ├── README.md ├── LICENSE └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /tests/v1_git_ssh/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "node-semver@ssh://git@github.com/npm/node-semver.git#semver:^7.5.0": 6 | version "7.6.3" 7 | resolved "ssh://git@github.com/npm/node-semver.git#0a12d6c7debb1dc82d8645c770e77c47bac5e1ea" 8 | -------------------------------------------------------------------------------- /tests/bun_basic/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | # bun ./bun.lockb --hash: 5572C9522DE896FD-4a82b28bb592ae3b-4B24ADDA3457FA29-1c299c64c91cddb0 4 | 5 | 6 | typescript@4.8.4: 7 | version "4.8.4" 8 | resolved "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz" 9 | integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== 10 | -------------------------------------------------------------------------------- /tests/bun_version_url/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | # bun ./bun.lockb --hash: F39C40069C5699FE-e92f957eedaf1599-2F0AC20C0586FF34-dc453d623755d47b 4 | 5 | 6 | "@a/verboden(name~'!*)@https://s.lnl.gay/@a/verboden(name~'!*)/-/verboden(name~'!*)-1.0.0.tgz": 7 | version "https://s.lnl.gay/@a/verboden(name~'!*)/-/verboden(name~'!*)-1.0.0.tgz" 8 | resolved "https://s.lnl.gay/@a/verboden(name~'!*)/-/verboden(name~'!*)-1.0.0.tgz" 9 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*.*.*' 7 | 8 | jobs: 9 | crates: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Setup Rust 13 | uses: hecrj/setup-rust-action@master 14 | with: 15 | rust-version: stable 16 | - name: Checkout 17 | uses: actions/checkout@v2 18 | - name: Publish to crates.io 19 | run: | 20 | cargo login ${{secrets.crates_key}} 21 | cargo publish 22 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "yarn-lock-parser" 3 | description = "yarn.lock parser" 4 | version = "0.12.0" 5 | authors = [ 6 | "Roberto Huertas ", 7 | "Riccardo Attilio Galli ", 8 | ] 9 | edition = "2021" 10 | license = "MIT" 11 | repository = "https://github.com/robertohuertasm/yarn-lock-parser" 12 | readme = "README.md" 13 | keywords = ["yarn", "parser"] 14 | categories = ["parsing"] 15 | 16 | exclude = [".github/*", "tests/*"] 17 | 18 | [badges] 19 | maintenance = { status = "actively-developed" } 20 | 21 | [dependencies] 22 | nom = "8.0.0" 23 | nom-language = "0.1.0" 24 | thiserror = "2.0.11" 25 | -------------------------------------------------------------------------------- /Makefile.toml: -------------------------------------------------------------------------------- 1 | [tasks.watch-test] 2 | install_crate = "cargo-watch" 3 | command = "cargo" 4 | args = ["watch", "-x", "test", ] 5 | 6 | [tasks.format] 7 | install_crate = "rustfmt" 8 | command = "cargo" 9 | args = ["fmt", "--all", "--", "--check"] 10 | 11 | [tasks.clippy] 12 | install_crate = "cargo-clippy" 13 | command = "cargo" 14 | args = ["clippy"] 15 | 16 | [tasks.clippy-z] 17 | install_crate = "cargo-clippy" 18 | toolchain = "nightly" 19 | command = "cargo" 20 | args = ["clippy", "-Z", "unstable-options"] 21 | 22 | [tasks.clippy-pedantic] 23 | install_crate = "cargo-clippy" 24 | command = "cargo" 25 | args = ["clippy", "--all", "--", "-D", "clippy::pedantic", "-D", "clippy::nursery", "-D", "warnings"] 26 | 27 | [tasks.all] 28 | dependencies = [ 29 | "format", 30 | "clippy", 31 | "test" 32 | ] 33 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | test: 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | fail-fast: true 16 | matrix: 17 | rust: [stable] 18 | os: [ubuntu-latest, macOS-latest, windows-latest] 19 | steps: 20 | - name: Setup Rust (with fmt and clippy) 21 | uses: hecrj/setup-rust-action@master 22 | with: 23 | rust-version: ${{ matrix.rust }} 24 | components: rustfmt, clippy 25 | - name: Checkout 26 | uses: actions/checkout@v2 27 | - name: Run cargo fmt 28 | if: matrix.os == 'ubuntu-latest' 29 | run: cargo fmt --all -- --check 30 | - name: Run cargo clippy 31 | if: matrix.os == 'ubuntu-latest' 32 | run: cargo clippy 33 | - name: Run tests 34 | run: cargo test 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # yarn-lock-parser 2 | 3 | [![ActionsStatus](https://github.com/robertohuertasm/yarn-lock-parser/workflows/Build/badge.svg)](https://github.com/robertohuertasm/yarn-lock-parser/actions) [![Crates.io](https://img.shields.io/crates/v/yarn-lock-parser.svg)](https://crates.io/crates/yarn-lock-parser) 4 | 5 | Easily parse `yarn-lock` files (v1 and v2). 6 | 7 | ## Example 8 | 9 | ```rust 10 | use std::{error::Error, fs}; 11 | use yarn_lock_parser::{parse_str, Entry}; 12 | 13 | fn main() -> Result<(), Box> { 14 | let yarn_lock_text = fs::read_to_string("yarn.lock")?; 15 | let entries: Vec = parse_str(&yarn_lock_text)?; 16 | 17 | println!("{:?}", entries); 18 | 19 | Ok(()) 20 | } 21 | ``` 22 | 23 | ## Documentation 24 | 25 | Visit [https://docs.rs/yarn-lock-parser/](https://docs.rs/yarn-lock-parser/) 26 | 27 | ## Build 28 | 29 | You will need [cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html), the Rust package manager. 30 | 31 | ```bash 32 | cargo build 33 | ``` 34 | 35 | ## Test 36 | 37 | ```bash 38 | cargo test 39 | ``` 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright © 2022 Roberto Huertas 3 | 4 | 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: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | 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. 9 | -------------------------------------------------------------------------------- /tests/github_version/bun.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | # bun ./bun.lockb --hash: 7F473F5D2B55CA2E-cb32e6eeae8aaed5-4B75F0417FE02D3A-7529672ac3001866 4 | 5 | 6 | eventemitter3@^4.0.0: 7 | version "4.0.7" 8 | resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" 9 | integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== 10 | 11 | follow-redirects@^1.0.0: 12 | version "1.15.5" 13 | resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz" 14 | integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw== 15 | 16 | "http-proxy@github:settlemint/node-http-proxy#master": 17 | version "github:settlemint/node-http-proxy#a19114f" 18 | resolved "github:settlemint/node-http-proxy#a19114f" 19 | dependencies: 20 | eventemitter3 "^4.0.0" 21 | follow-redirects "^1.0.0" 22 | requires-port "^1.0.0" 23 | 24 | requires-port@^1.0.0: 25 | version "1.0.0" 26 | resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" 27 | integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== 28 | -------------------------------------------------------------------------------- /tests/github_version/yarn1.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | eventemitter3@^4.0.0: 6 | version "4.0.7" 7 | resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" 8 | integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== 9 | 10 | follow-redirects@^1.0.0: 11 | version "1.15.5" 12 | resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020" 13 | integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw== 14 | 15 | "http-proxy@github:settlemint/node-http-proxy#master": 16 | version "1.18.1" 17 | resolved "https://codeload.github.com/settlemint/node-http-proxy/tar.gz/a19114ff99d40de15ef1112fe344e31f2328e521" 18 | dependencies: 19 | eventemitter3 "^4.0.0" 20 | follow-redirects "^1.0.0" 21 | requires-port "^1.0.0" 22 | 23 | requires-port@^1.0.0: 24 | version "1.0.0" 25 | resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" 26 | integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== 27 | -------------------------------------------------------------------------------- /tests/github_version/yarn.lock: -------------------------------------------------------------------------------- 1 | # This file is generated by running "yarn install" inside your project. 2 | # Manual changes might be lost - proceed with caution! 3 | 4 | __metadata: 5 | version: 6 6 | cacheKey: 8 7 | 8 | "eventemitter3@npm:^4.0.0": 9 | version: 4.0.7 10 | resolution: "eventemitter3@npm:4.0.7" 11 | checksum: 1875311c42fcfe9c707b2712c32664a245629b42bb0a5a84439762dd0fd637fc54d078155ea83c2af9e0323c9ac13687e03cfba79b03af9f40c89b4960099374 12 | languageName: node 13 | linkType: hard 14 | 15 | "follow-redirects@npm:^1.0.0": 16 | version: 1.15.5 17 | resolution: "follow-redirects@npm:1.15.5" 18 | peerDependenciesMeta: 19 | debug: 20 | optional: true 21 | checksum: 5ca49b5ce6f44338cbfc3546823357e7a70813cecc9b7b768158a1d32c1e62e7407c944402a918ea8c38ae2e78266312d617dc68783fac502cbb55e1047b34ec 22 | languageName: node 23 | linkType: hard 24 | 25 | "http-proxy@github:settlemint/node-http-proxy#master": 26 | version: 1.18.1 27 | resolution: "http-proxy@https://github.com/settlemint/node-http-proxy.git#commit=a19114ff99d40de15ef1112fe344e31f2328e521" 28 | dependencies: 29 | eventemitter3: ^4.0.0 30 | follow-redirects: ^1.0.0 31 | requires-port: ^1.0.0 32 | checksum: 97bac218fcc81afc9174c223671812e351b60d4c1610afbb9266bcdd26749c6deecda612bfb120d4bb15a20e47b4165b713ad1199bd09b231e81aa4aa5d5bb36 33 | languageName: node 34 | linkType: hard 35 | 36 | "requires-port@npm:^1.0.0": 37 | version: 1.0.0 38 | resolution: "requires-port@npm:1.0.0" 39 | checksum: eee0e303adffb69be55d1a214e415cf42b7441ae858c76dfc5353148644f6fd6e698926fc4643f510d5c126d12a705e7c8ed7e38061113bdf37547ab356797ff 40 | languageName: node 41 | linkType: hard 42 | 43 | "test@workspace:.": 44 | version: 0.0.0-use.local 45 | resolution: "test@workspace:." 46 | dependencies: 47 | http-proxy: "github:settlemint/node-http-proxy#master" 48 | languageName: unknown 49 | linkType: soft 50 | -------------------------------------------------------------------------------- /tests/v1_git_url/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | balanced-match@^1.0.0: 6 | version "1.0.2" 7 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 8 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 9 | 10 | brace-expansion@^2.0.1: 11 | version "2.0.1" 12 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" 13 | integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== 14 | dependencies: 15 | balanced-match "^1.0.0" 16 | 17 | is-buffer@^1.1.5: 18 | version "1.1.6" 19 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" 20 | integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== 21 | 22 | is-even@1.0.0: 23 | version "1.0.0" 24 | resolved "https://registry.yarnpkg.com/is-even/-/is-even-1.0.0.tgz#76b5055fbad8d294a86b6a949015e1c97b717c06" 25 | integrity sha512-LEhnkAdJqic4Dbqn58A0y52IXoHWlsueqQkKfMfdEnIYG8A1sm/GHidKkS6yvXlMoRrkM34csHnXQtOqcb+Jzg== 26 | dependencies: 27 | is-odd "^0.1.2" 28 | 29 | is-number@^3.0.0: 30 | version "3.0.0" 31 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" 32 | integrity sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg== 33 | dependencies: 34 | kind-of "^3.0.2" 35 | 36 | is-odd@^0.1.2: 37 | version "0.1.2" 38 | resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-0.1.2.tgz#bc573b5ce371ef2aad6e6f49799b72bef13978a7" 39 | integrity sha512-Ri7C2K7o5IrUU9UEI8losXJCCD/UtsaIrkR5sxIcFg4xQ9cRJXlWA5DQvTE0yDc0krvSNLsRGXN11UPS6KyfBw== 40 | dependencies: 41 | is-number "^3.0.0" 42 | 43 | kind-of@^3.0.2: 44 | version "3.2.2" 45 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" 46 | integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== 47 | dependencies: 48 | is-buffer "^1.1.5" 49 | 50 | "minimatch@https://github.com/isaacs/minimatch.git#v10.0.1": 51 | version "10.0.1" 52 | resolved "https://github.com/isaacs/minimatch.git#0569cd3373408f9d701d3aab187b3f43a24a0db7" 53 | dependencies: 54 | brace-expansion "^2.0.1" 55 | -------------------------------------------------------------------------------- /tests/bun_workspaces/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | # bun ./bun.lockb --hash: E151E01891DBD93E-1c58a71620b4e4d9-3F51147AB667CE03-f4f2d47740054ee8 4 | 5 | 6 | "@babel/helper-module-imports@7.16.0": 7 | version "7.16.0" 8 | resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz" 9 | integrity sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg== 10 | dependencies: 11 | "@babel/types" "^7.16.0" 12 | 13 | "@babel/helper-plugin-utils@^7.22.5": 14 | version "7.22.5" 15 | resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz" 16 | integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== 17 | 18 | "@babel/helper-string-parser@^7.22.5": 19 | version "7.22.5" 20 | resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz" 21 | integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== 22 | 23 | "@babel/helper-validator-identifier@^7.22.20": 24 | version "7.22.20" 25 | resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz" 26 | integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== 27 | 28 | "@babel/plugin-syntax-jsx@^7.16.5": 29 | version "7.22.5" 30 | resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz" 31 | integrity sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg== 32 | dependencies: 33 | "@babel/helper-plugin-utils" "^7.22.5" 34 | 35 | "@babel/types@^7.16.0": 36 | version "7.23.0" 37 | resolved "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz" 38 | integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg== 39 | dependencies: 40 | "@babel/helper-string-parser" "^7.22.5" 41 | "@babel/helper-validator-identifier" "^7.22.20" 42 | to-fast-properties "^2.0.0" 43 | 44 | babel-plugin-jsx-dom-expressions@^0.34.10: 45 | version "0.34.13" 46 | resolved "https://registry.npmjs.org/babel-plugin-jsx-dom-expressions/-/babel-plugin-jsx-dom-expressions-0.34.13.tgz" 47 | integrity sha512-rKkJ7a0arzqE180hPeZI/EIB4OTuByVgE5bsHlI/lZGpU+pVtuvIwwePIIFH8ld49a8pvM0fLfrryP/W6ZMx0g== 48 | dependencies: 49 | "@babel/helper-module-imports" "7.16.0" 50 | "@babel/plugin-syntax-jsx" "^7.16.5" 51 | "@babel/types" "^7.16.0" 52 | html-entities "2.3.2" 53 | 54 | babel-preset-solid@1.5.6: 55 | version "1.5.6" 56 | resolved "https://registry.npmjs.org/babel-preset-solid/-/babel-preset-solid-1.5.6.tgz" 57 | integrity sha512-DETqhEygtRq627y5jII5szev495CvbPZJDTaosCbRWdbBh7nMBPI9JuVBUdWs56M2D4mqYa6Z2vH4mdIS6srwA== 58 | dependencies: 59 | babel-plugin-jsx-dom-expressions "^0.34.10" 60 | 61 | csstype@^3.1.0: 62 | version "3.1.2" 63 | resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz" 64 | integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== 65 | 66 | html-entities@2.3.2: 67 | version "2.3.2" 68 | resolved "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz" 69 | integrity sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ== 70 | 71 | "js-tokens@^3.0.0 || ^4.0.0": 72 | version "4.0.0" 73 | resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" 74 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 75 | 76 | loose-envify@^1.1.0: 77 | version "1.4.0" 78 | resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" 79 | integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== 80 | dependencies: 81 | js-tokens "^3.0.0 || ^4.0.0" 82 | 83 | object-assign@^4.1.1: 84 | version "4.1.1" 85 | resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" 86 | integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== 87 | 88 | prettier@2.7.0: 89 | version "2.7.0" 90 | resolved "https://registry.npmjs.org/prettier/-/prettier-2.7.0.tgz" 91 | integrity sha512-nwoX4GMFgxoPC6diHvSwmK/4yU8FFH3V8XWtLQrbj4IBsK2pkYhG4kf/ljF/haaZ/aii+wNJqISrCDPgxGWDVQ== 92 | 93 | react@17.0.0: 94 | version "17.0.0" 95 | resolved "https://registry.npmjs.org/react/-/react-17.0.0.tgz" 96 | integrity sha512-rG9bqS3LMuetoSUKHN8G3fMNuQOePKDThK6+2yXFWtoeTDLVNh/QCaxT+Jr+rNf4lwNXpx+atdn3Aa0oi8/6eQ== 97 | dependencies: 98 | loose-envify "^1.1.0" 99 | object-assign "^4.1.1" 100 | 101 | solid-js@1.5.6: 102 | version "1.5.6" 103 | resolved "https://registry.npmjs.org/solid-js/-/solid-js-1.5.6.tgz" 104 | integrity sha512-EA7hjMIEdDUuV6Fk3WUQ2fPx7sRnhjl+3M59zj6Sh+c7c3JF3N1cSViBvX8MYJG9vEBEqKQBZUfKHPe/9JgKvQ== 105 | dependencies: 106 | csstype "^3.1.0" 107 | 108 | test-node-bun-base@base: 109 | version "workspace:base" 110 | resolved "workspace:base" 111 | dependencies: 112 | react "17.0.0" 113 | 114 | test-node-bun-other@other: 115 | version "workspace:other" 116 | resolved "workspace:other" 117 | devDependencies: 118 | babel-preset-solid "1.5.6" 119 | dependencies: 120 | solid-js "1.5.6" 121 | 122 | to-fast-properties@^2.0.0: 123 | version "2.0.0" 124 | resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" 125 | integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== 126 | -------------------------------------------------------------------------------- /tests/v1_with_npm_bug/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/code-frame@^7.18.6": 6 | "integrity" "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==" 7 | "resolved" "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz" 8 | "version" "7.18.6" 9 | dependencies: 10 | "@babel/highlight" "^7.18.6" 11 | 12 | "@babel/helper-validator-identifier@^7.18.6": 13 | "integrity" "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" 14 | "resolved" "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz" 15 | "version" "7.18.6" 16 | 17 | "@babel/highlight@^7.18.6": 18 | "integrity" "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==" 19 | "resolved" "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz" 20 | "version" "7.18.6" 21 | dependencies: 22 | "@babel/helper-validator-identifier" "^7.18.6" 23 | "chalk" "^2.0.0" 24 | "js-tokens" "^4.0.0" 25 | 26 | "ansi-regex@^5.0.1": 27 | "integrity" "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" 28 | "resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" 29 | "version" "5.0.1" 30 | 31 | "ansi-styles@^3.2.1": 32 | "integrity" "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==" 33 | "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" 34 | "version" "3.2.1" 35 | dependencies: 36 | "color-convert" "^1.9.0" 37 | 38 | "ansi-styles@^4.0.0": 39 | "integrity" "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==" 40 | "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" 41 | "version" "4.3.0" 42 | dependencies: 43 | "color-convert" "^2.0.1" 44 | 45 | "chalk@^2.0.0": 46 | "integrity" "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==" 47 | "resolved" "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" 48 | "version" "2.4.2" 49 | dependencies: 50 | "ansi-styles" "^3.2.1" 51 | "escape-string-regexp" "^1.0.5" 52 | "supports-color" "^5.3.0" 53 | 54 | "cliui@^7.0.2": 55 | "integrity" "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==" 56 | "resolved" "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" 57 | "version" "7.0.4" 58 | dependencies: 59 | "string-width" "^4.2.0" 60 | "strip-ansi" "^6.0.0" 61 | "wrap-ansi" "^7.0.0" 62 | 63 | "color-convert@^1.9.0": 64 | "integrity" "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==" 65 | "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" 66 | "version" "1.9.3" 67 | dependencies: 68 | "color-name" "1.1.3" 69 | 70 | "color-convert@^2.0.1": 71 | "integrity" "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==" 72 | "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" 73 | "version" "2.0.1" 74 | dependencies: 75 | "color-name" "~1.1.4" 76 | 77 | "color-name@~1.1.4": 78 | "integrity" "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" 79 | "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" 80 | "version" "1.1.4" 81 | 82 | "color-name@1.1.3": 83 | "integrity" "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" 84 | "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" 85 | "version" "1.1.3" 86 | 87 | "emoji-regex@^8.0.0": 88 | "integrity" "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" 89 | "resolved" "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" 90 | "version" "8.0.0" 91 | 92 | "escalade@^3.1.1": 93 | "integrity" "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" 94 | "resolved" "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" 95 | "version" "3.1.1" 96 | 97 | "escape-string-regexp@^1.0.5": 98 | "integrity" "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" 99 | "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" 100 | "version" "1.0.5" 101 | 102 | "get-caller-file@^2.0.5": 103 | "integrity" "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" 104 | "resolved" "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" 105 | "version" "2.0.5" 106 | 107 | "has-flag@^3.0.0": 108 | "integrity" "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" 109 | "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" 110 | "version" "3.0.0" 111 | 112 | "is-fullwidth-code-point@^3.0.0": 113 | "integrity" "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" 114 | "resolved" "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" 115 | "version" "3.0.0" 116 | 117 | "js-tokens@^4.0.0": 118 | "integrity" "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 119 | "resolved" "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" 120 | "version" "4.0.0" 121 | 122 | "require-directory@^2.1.1": 123 | "integrity" "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" 124 | "resolved" "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" 125 | "version" "2.1.1" 126 | 127 | "string-width@^4.1.0", "string-width@^4.2.0", "string-width@^4.2.3": 128 | "integrity" "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==" 129 | "resolved" "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" 130 | "version" "4.2.3" 131 | dependencies: 132 | "emoji-regex" "^8.0.0" 133 | "is-fullwidth-code-point" "^3.0.0" 134 | "strip-ansi" "^6.0.1" 135 | 136 | "strip-ansi@^6.0.0", "strip-ansi@^6.0.1": 137 | "integrity" "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==" 138 | "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" 139 | "version" "6.0.1" 140 | dependencies: 141 | "ansi-regex" "^5.0.1" 142 | 143 | "supports-color@^5.3.0": 144 | "integrity" "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==" 145 | "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" 146 | "version" "5.5.0" 147 | dependencies: 148 | "has-flag" "^3.0.0" 149 | 150 | "typescript@^4.7.4": 151 | "integrity" "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==" 152 | "resolved" "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz" 153 | "version" "4.7.4" 154 | 155 | "wrap-ansi@^7.0.0": 156 | "integrity" "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==" 157 | "resolved" "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" 158 | "version" "7.0.0" 159 | dependencies: 160 | "ansi-styles" "^4.0.0" 161 | "string-width" "^4.1.0" 162 | "strip-ansi" "^6.0.0" 163 | 164 | "y18n@^5.0.5": 165 | "integrity" "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" 166 | "resolved" "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" 167 | "version" "5.0.8" 168 | 169 | "yargs-parser@^21.0.0": 170 | "integrity" "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==" 171 | "resolved" "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz" 172 | "version" "21.0.1" 173 | 174 | "yargs@^17.5.1": 175 | "integrity" "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==" 176 | "resolved" "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz" 177 | "version" "17.5.1" 178 | dependencies: 179 | "cliui" "^7.0.2" 180 | "escalade" "^3.1.1" 181 | "get-caller-file" "^2.0.5" 182 | "require-directory" "^2.1.1" 183 | "string-width" "^4.2.3" 184 | "y18n" "^5.0.5" 185 | "yargs-parser" "^21.0.0" 186 | -------------------------------------------------------------------------------- /tests/v2/yarn.lock: -------------------------------------------------------------------------------- 1 | # This file is generated by running "yarn install" inside your project. 2 | # Manual changes might be lost - proceed with caution! 3 | 4 | __metadata: 5 | version: 6 6 | cacheKey: 8 7 | 8 | "@babel/code-frame@npm:^7.18.6": 9 | version: 7.18.6 10 | resolution: "@babel/code-frame@npm:7.18.6" 11 | dependencies: 12 | "@babel/highlight": ^7.18.6 13 | checksum: 195e2be3172d7684bf95cff69ae3b7a15a9841ea9d27d3c843662d50cdd7d6470fd9c8e64be84d031117e4a4083486effba39f9aef6bbb2c89f7f21bcfba33ba 14 | languageName: node 15 | linkType: hard 16 | 17 | "@babel/helper-validator-identifier@npm:^7.18.6": 18 | version: 7.18.6 19 | resolution: "@babel/helper-validator-identifier@npm:7.18.6" 20 | checksum: e295254d616bbe26e48c196a198476ab4d42a73b90478c9842536cf910ead887f5af6b5c4df544d3052a25ccb3614866fa808dc1e3a5a4291acd444e243c0648 21 | languageName: node 22 | linkType: hard 23 | 24 | "@babel/highlight@npm:^7.18.6": 25 | version: 7.18.6 26 | resolution: "@babel/highlight@npm:7.18.6" 27 | dependencies: 28 | "@babel/helper-validator-identifier": ^7.18.6 29 | chalk: ^2.0.0 30 | js-tokens: ^4.0.0 31 | checksum: 92d8ee61549de5ff5120e945e774728e5ccd57fd3b2ed6eace020ec744823d4a98e242be1453d21764a30a14769ecd62170fba28539b211799bbaf232bbb2789 32 | languageName: node 33 | linkType: hard 34 | 35 | "ansi-regex@npm:^5.0.1": 36 | version: 5.0.1 37 | resolution: "ansi-regex@npm:5.0.1" 38 | checksum: 2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b 39 | languageName: node 40 | linkType: hard 41 | 42 | "ansi-styles@npm:^3.2.1": 43 | version: 3.2.1 44 | resolution: "ansi-styles@npm:3.2.1" 45 | dependencies: 46 | color-convert: ^1.9.0 47 | checksum: d85ade01c10e5dd77b6c89f34ed7531da5830d2cb5882c645f330079975b716438cd7ebb81d0d6e6b4f9c577f19ae41ab55f07f19786b02f9dfd9e0377395665 48 | languageName: node 49 | linkType: hard 50 | 51 | "ansi-styles@npm:^4.0.0": 52 | version: 4.3.0 53 | resolution: "ansi-styles@npm:4.3.0" 54 | dependencies: 55 | color-convert: ^2.0.1 56 | checksum: 513b44c3b2105dd14cc42a19271e80f386466c4be574bccf60b627432f9198571ebf4ab1e4c3ba17347658f4ee1711c163d574248c0c1cdc2d5917a0ad582ec4 57 | languageName: node 58 | linkType: hard 59 | 60 | "chalk@npm:^2.0.0": 61 | version: 2.4.2 62 | resolution: "chalk@npm:2.4.2" 63 | dependencies: 64 | ansi-styles: ^3.2.1 65 | escape-string-regexp: ^1.0.5 66 | supports-color: ^5.3.0 67 | checksum: ec3661d38fe77f681200f878edbd9448821924e0f93a9cefc0e26a33b145f1027a2084bf19967160d11e1f03bfe4eaffcabf5493b89098b2782c3fe0b03d80c2 68 | languageName: node 69 | linkType: hard 70 | 71 | "cliui@npm:^7.0.2": 72 | version: 7.0.4 73 | resolution: "cliui@npm:7.0.4" 74 | dependencies: 75 | string-width: ^4.2.0 76 | strip-ansi: ^6.0.0 77 | wrap-ansi: ^7.0.0 78 | checksum: ce2e8f578a4813806788ac399b9e866297740eecd4ad1823c27fd344d78b22c5f8597d548adbcc46f0573e43e21e751f39446c5a5e804a12aace402b7a315d7f 79 | languageName: node 80 | linkType: hard 81 | 82 | "color-convert@npm:^1.9.0": 83 | version: 1.9.3 84 | resolution: "color-convert@npm:1.9.3" 85 | dependencies: 86 | color-name: 1.1.3 87 | checksum: fd7a64a17cde98fb923b1dd05c5f2e6f7aefda1b60d67e8d449f9328b4e53b228a428fd38bfeaeb2db2ff6b6503a776a996150b80cdf224062af08a5c8a3a203 88 | languageName: node 89 | linkType: hard 90 | 91 | "color-convert@npm:^2.0.1": 92 | version: 2.0.1 93 | resolution: "color-convert@npm:2.0.1" 94 | dependencies: 95 | color-name: ~1.1.4 96 | checksum: 79e6bdb9fd479a205c71d89574fccfb22bd9053bd98c6c4d870d65c132e5e904e6034978e55b43d69fcaa7433af2016ee203ce76eeba9cfa554b373e7f7db336 97 | languageName: node 98 | linkType: hard 99 | 100 | "color-name@npm:1.1.3": 101 | version: 1.1.3 102 | resolution: "color-name@npm:1.1.3" 103 | checksum: 09c5d3e33d2105850153b14466501f2bfb30324a2f76568a408763a3b7433b0e50e5b4ab1947868e65cb101bb7cb75029553f2c333b6d4b8138a73fcc133d69d 104 | languageName: node 105 | linkType: hard 106 | 107 | "color-name@npm:~1.1.4": 108 | version: 1.1.4 109 | resolution: "color-name@npm:1.1.4" 110 | checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 111 | languageName: node 112 | linkType: hard 113 | 114 | "emoji-regex@npm:^8.0.0": 115 | version: 8.0.0 116 | resolution: "emoji-regex@npm:8.0.0" 117 | checksum: d4c5c39d5a9868b5fa152f00cada8a936868fd3367f33f71be515ecee4c803132d11b31a6222b2571b1e5f7e13890156a94880345594d0ce7e3c9895f560f192 118 | languageName: node 119 | linkType: hard 120 | 121 | "escalade@npm:^3.1.1": 122 | version: 3.1.1 123 | resolution: "escalade@npm:3.1.1" 124 | checksum: a3e2a99f07acb74b3ad4989c48ca0c3140f69f923e56d0cba0526240ee470b91010f9d39001f2a4a313841d237ede70a729e92125191ba5d21e74b106800b133 125 | languageName: node 126 | linkType: hard 127 | 128 | "escape-string-regexp@npm:^1.0.5": 129 | version: 1.0.5 130 | resolution: "escape-string-regexp@npm:1.0.5" 131 | checksum: 6092fda75c63b110c706b6a9bfde8a612ad595b628f0bd2147eea1d3406723020810e591effc7db1da91d80a71a737a313567c5abb3813e8d9c71f4aa595b410 132 | languageName: node 133 | linkType: hard 134 | 135 | "get-caller-file@npm:^2.0.5": 136 | version: 2.0.5 137 | resolution: "get-caller-file@npm:2.0.5" 138 | checksum: b9769a836d2a98c3ee734a88ba712e62703f1df31b94b784762c433c27a386dd6029ff55c2a920c392e33657d80191edbf18c61487e198844844516f843496b9 139 | languageName: node 140 | linkType: hard 141 | 142 | "has-flag@npm:^3.0.0": 143 | version: 3.0.0 144 | resolution: "has-flag@npm:3.0.0" 145 | checksum: 4a15638b454bf086c8148979aae044dd6e39d63904cd452d970374fa6a87623423da485dfb814e7be882e05c096a7ccf1ebd48e7e7501d0208d8384ff4dea73b 146 | languageName: node 147 | linkType: hard 148 | 149 | "is-fullwidth-code-point@npm:^3.0.0": 150 | version: 3.0.0 151 | resolution: "is-fullwidth-code-point@npm:3.0.0" 152 | checksum: 44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 153 | languageName: node 154 | linkType: hard 155 | 156 | "js-tokens@npm:^4.0.0": 157 | version: 4.0.0 158 | resolution: "js-tokens@npm:4.0.0" 159 | checksum: 8a95213a5a77deb6cbe94d86340e8d9ace2b93bc367790b260101d2f36a2eaf4e4e22d9fa9cf459b38af3a32fb4190e638024cf82ec95ef708680e405ea7cc78 160 | languageName: node 161 | linkType: hard 162 | 163 | "kk@workspace:.": 164 | version: 0.0.0-use.local 165 | resolution: "kk@workspace:." 166 | dependencies: 167 | "@babel/code-frame": ^7.18.6 168 | "@babel/highlight": ^7.18.6 169 | typescript: ^4.7.4 170 | yargs: ^17.5.1 171 | languageName: unknown 172 | linkType: soft 173 | 174 | "require-directory@npm:^2.1.1": 175 | version: 2.1.1 176 | resolution: "require-directory@npm:2.1.1" 177 | checksum: fb47e70bf0001fdeabdc0429d431863e9475e7e43ea5f94ad86503d918423c1543361cc5166d713eaa7029dd7a3d34775af04764bebff99ef413111a5af18c80 178 | languageName: node 179 | linkType: hard 180 | 181 | "string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": 182 | version: 4.2.3 183 | resolution: "string-width@npm:4.2.3" 184 | dependencies: 185 | emoji-regex: ^8.0.0 186 | is-fullwidth-code-point: ^3.0.0 187 | strip-ansi: ^6.0.1 188 | checksum: e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb 189 | languageName: node 190 | linkType: hard 191 | 192 | "strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": 193 | version: 6.0.1 194 | resolution: "strip-ansi@npm:6.0.1" 195 | dependencies: 196 | ansi-regex: ^5.0.1 197 | checksum: f3cd25890aef3ba6e1a74e20896c21a46f482e93df4a06567cebf2b57edabb15133f1f94e57434e0a958d61186087b1008e89c94875d019910a213181a14fc8c 198 | languageName: node 199 | linkType: hard 200 | 201 | "supports-color@npm:^5.3.0": 202 | version: 5.5.0 203 | resolution: "supports-color@npm:5.5.0" 204 | dependencies: 205 | has-flag: ^3.0.0 206 | checksum: 95f6f4ba5afdf92f495b5a912d4abee8dcba766ae719b975c56c084f5004845f6f5a5f7769f52d53f40e21952a6d87411bafe34af4a01e65f9926002e38e1dac 207 | languageName: node 208 | linkType: hard 209 | 210 | "typescript@npm:^4.7.4": 211 | version: 4.7.4 212 | resolution: "typescript@npm:4.7.4" 213 | bin: 214 | tsc: bin/tsc 215 | tsserver: bin/tsserver 216 | checksum: 5750181b1cd7e6482c4195825547e70f944114fb47e58e4aa7553e62f11b3f3173766aef9c281783edfd881f7b8299cf35e3ca8caebe73d8464528c907a164df 217 | languageName: node 218 | linkType: hard 219 | 220 | "typescript@patch:typescript@^4.7.4#~builtin": 221 | version: 4.7.4 222 | resolution: "typescript@patch:typescript@npm%3A4.7.4#~builtin::version=4.7.4&hash=7ad353" 223 | bin: 224 | tsc: bin/tsc 225 | tsserver: bin/tsserver 226 | checksum: 9096d8f6c16cb80ef3bf96fcbbd055bf1c4a43bd14f3b7be45a9fbe7ada46ec977f604d5feed3263b4f2aa7d4c7477ce5f9cd87de0d6feedec69a983f3a4f93e 227 | languageName: node 228 | linkType: hard 229 | 230 | "wrap-ansi@npm:^7.0.0": 231 | version: 7.0.0 232 | resolution: "wrap-ansi@npm:7.0.0" 233 | dependencies: 234 | ansi-styles: ^4.0.0 235 | string-width: ^4.1.0 236 | strip-ansi: ^6.0.0 237 | checksum: a790b846fd4505de962ba728a21aaeda189b8ee1c7568ca5e817d85930e06ef8d1689d49dbf0e881e8ef84436af3a88bc49115c2e2788d841ff1b8b5b51a608b 238 | languageName: node 239 | linkType: hard 240 | 241 | "y18n@npm:^5.0.5": 242 | version: 5.0.8 243 | resolution: "y18n@npm:5.0.8" 244 | checksum: 54f0fb95621ee60898a38c572c515659e51cc9d9f787fb109cef6fde4befbe1c4602dc999d30110feee37456ad0f1660fa2edcfde6a9a740f86a290999550d30 245 | languageName: node 246 | linkType: hard 247 | 248 | "yargs-parser@npm:^21.0.0": 249 | version: 21.0.1 250 | resolution: "yargs-parser@npm:21.0.1" 251 | checksum: c3ea2ed12cad0377ce3096b3f138df8267edf7b1aa7d710cd502fe16af417bafe4443dd71b28158c22fcd1be5dfd0e86319597e47badf42ff83815485887323a 252 | languageName: node 253 | linkType: hard 254 | 255 | "yargs@npm:^17.5.1": 256 | version: 17.5.1 257 | resolution: "yargs@npm:17.5.1" 258 | dependencies: 259 | cliui: ^7.0.2 260 | escalade: ^3.1.1 261 | get-caller-file: ^2.0.5 262 | require-directory: ^2.1.1 263 | string-width: ^4.2.3 264 | y18n: ^5.0.5 265 | yargs-parser: ^21.0.0 266 | checksum: 00d58a2c052937fa044834313f07910fd0a115dec5ee35919e857eeee3736b21a4eafa8264535800ba8bac312991ce785ecb8a51f4d2cc8c4676d865af1cfbde 267 | languageName: node 268 | linkType: hard 269 | -------------------------------------------------------------------------------- /tests/v2_without_endline/yarn.lock: -------------------------------------------------------------------------------- 1 | # This file is generated by running "yarn install" inside your project. 2 | # Manual changes might be lost - proceed with caution! 3 | 4 | __metadata: 5 | version: 6 6 | cacheKey: 8 7 | 8 | "@babel/code-frame@npm:^7.18.6": 9 | version: 7.18.6 10 | resolution: "@babel/code-frame@npm:7.18.6" 11 | dependencies: 12 | "@babel/highlight": ^7.18.6 13 | checksum: 195e2be3172d7684bf95cff69ae3b7a15a9841ea9d27d3c843662d50cdd7d6470fd9c8e64be84d031117e4a4083486effba39f9aef6bbb2c89f7f21bcfba33ba 14 | languageName: node 15 | linkType: hard 16 | 17 | "@babel/helper-validator-identifier@npm:^7.18.6": 18 | version: 7.18.6 19 | resolution: "@babel/helper-validator-identifier@npm:7.18.6" 20 | checksum: e295254d616bbe26e48c196a198476ab4d42a73b90478c9842536cf910ead887f5af6b5c4df544d3052a25ccb3614866fa808dc1e3a5a4291acd444e243c0648 21 | languageName: node 22 | linkType: hard 23 | 24 | "@babel/highlight@npm:^7.18.6": 25 | version: 7.18.6 26 | resolution: "@babel/highlight@npm:7.18.6" 27 | dependencies: 28 | "@babel/helper-validator-identifier": ^7.18.6 29 | chalk: ^2.0.0 30 | js-tokens: ^4.0.0 31 | checksum: 92d8ee61549de5ff5120e945e774728e5ccd57fd3b2ed6eace020ec744823d4a98e242be1453d21764a30a14769ecd62170fba28539b211799bbaf232bbb2789 32 | languageName: node 33 | linkType: hard 34 | 35 | "ansi-regex@npm:^5.0.1": 36 | version: 5.0.1 37 | resolution: "ansi-regex@npm:5.0.1" 38 | checksum: 2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b 39 | languageName: node 40 | linkType: hard 41 | 42 | "ansi-styles@npm:^3.2.1": 43 | version: 3.2.1 44 | resolution: "ansi-styles@npm:3.2.1" 45 | dependencies: 46 | color-convert: ^1.9.0 47 | checksum: d85ade01c10e5dd77b6c89f34ed7531da5830d2cb5882c645f330079975b716438cd7ebb81d0d6e6b4f9c577f19ae41ab55f07f19786b02f9dfd9e0377395665 48 | languageName: node 49 | linkType: hard 50 | 51 | "ansi-styles@npm:^4.0.0": 52 | version: 4.3.0 53 | resolution: "ansi-styles@npm:4.3.0" 54 | dependencies: 55 | color-convert: ^2.0.1 56 | checksum: 513b44c3b2105dd14cc42a19271e80f386466c4be574bccf60b627432f9198571ebf4ab1e4c3ba17347658f4ee1711c163d574248c0c1cdc2d5917a0ad582ec4 57 | languageName: node 58 | linkType: hard 59 | 60 | "chalk@npm:^2.0.0": 61 | version: 2.4.2 62 | resolution: "chalk@npm:2.4.2" 63 | dependencies: 64 | ansi-styles: ^3.2.1 65 | escape-string-regexp: ^1.0.5 66 | supports-color: ^5.3.0 67 | checksum: ec3661d38fe77f681200f878edbd9448821924e0f93a9cefc0e26a33b145f1027a2084bf19967160d11e1f03bfe4eaffcabf5493b89098b2782c3fe0b03d80c2 68 | languageName: node 69 | linkType: hard 70 | 71 | "cliui@npm:^7.0.2": 72 | version: 7.0.4 73 | resolution: "cliui@npm:7.0.4" 74 | dependencies: 75 | string-width: ^4.2.0 76 | strip-ansi: ^6.0.0 77 | wrap-ansi: ^7.0.0 78 | checksum: ce2e8f578a4813806788ac399b9e866297740eecd4ad1823c27fd344d78b22c5f8597d548adbcc46f0573e43e21e751f39446c5a5e804a12aace402b7a315d7f 79 | languageName: node 80 | linkType: hard 81 | 82 | "color-convert@npm:^1.9.0": 83 | version: 1.9.3 84 | resolution: "color-convert@npm:1.9.3" 85 | dependencies: 86 | color-name: 1.1.3 87 | checksum: fd7a64a17cde98fb923b1dd05c5f2e6f7aefda1b60d67e8d449f9328b4e53b228a428fd38bfeaeb2db2ff6b6503a776a996150b80cdf224062af08a5c8a3a203 88 | languageName: node 89 | linkType: hard 90 | 91 | "color-convert@npm:^2.0.1": 92 | version: 2.0.1 93 | resolution: "color-convert@npm:2.0.1" 94 | dependencies: 95 | color-name: ~1.1.4 96 | checksum: 79e6bdb9fd479a205c71d89574fccfb22bd9053bd98c6c4d870d65c132e5e904e6034978e55b43d69fcaa7433af2016ee203ce76eeba9cfa554b373e7f7db336 97 | languageName: node 98 | linkType: hard 99 | 100 | "color-name@npm:1.1.3": 101 | version: 1.1.3 102 | resolution: "color-name@npm:1.1.3" 103 | checksum: 09c5d3e33d2105850153b14466501f2bfb30324a2f76568a408763a3b7433b0e50e5b4ab1947868e65cb101bb7cb75029553f2c333b6d4b8138a73fcc133d69d 104 | languageName: node 105 | linkType: hard 106 | 107 | "color-name@npm:~1.1.4": 108 | version: 1.1.4 109 | resolution: "color-name@npm:1.1.4" 110 | checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 111 | languageName: node 112 | linkType: hard 113 | 114 | "emoji-regex@npm:^8.0.0": 115 | version: 8.0.0 116 | resolution: "emoji-regex@npm:8.0.0" 117 | checksum: d4c5c39d5a9868b5fa152f00cada8a936868fd3367f33f71be515ecee4c803132d11b31a6222b2571b1e5f7e13890156a94880345594d0ce7e3c9895f560f192 118 | languageName: node 119 | linkType: hard 120 | 121 | "escalade@npm:^3.1.1": 122 | version: 3.1.1 123 | resolution: "escalade@npm:3.1.1" 124 | checksum: a3e2a99f07acb74b3ad4989c48ca0c3140f69f923e56d0cba0526240ee470b91010f9d39001f2a4a313841d237ede70a729e92125191ba5d21e74b106800b133 125 | languageName: node 126 | linkType: hard 127 | 128 | "escape-string-regexp@npm:^1.0.5": 129 | version: 1.0.5 130 | resolution: "escape-string-regexp@npm:1.0.5" 131 | checksum: 6092fda75c63b110c706b6a9bfde8a612ad595b628f0bd2147eea1d3406723020810e591effc7db1da91d80a71a737a313567c5abb3813e8d9c71f4aa595b410 132 | languageName: node 133 | linkType: hard 134 | 135 | "get-caller-file@npm:^2.0.5": 136 | version: 2.0.5 137 | resolution: "get-caller-file@npm:2.0.5" 138 | checksum: b9769a836d2a98c3ee734a88ba712e62703f1df31b94b784762c433c27a386dd6029ff55c2a920c392e33657d80191edbf18c61487e198844844516f843496b9 139 | languageName: node 140 | linkType: hard 141 | 142 | "has-flag@npm:^3.0.0": 143 | version: 3.0.0 144 | resolution: "has-flag@npm:3.0.0" 145 | checksum: 4a15638b454bf086c8148979aae044dd6e39d63904cd452d970374fa6a87623423da485dfb814e7be882e05c096a7ccf1ebd48e7e7501d0208d8384ff4dea73b 146 | languageName: node 147 | linkType: hard 148 | 149 | "is-fullwidth-code-point@npm:^3.0.0": 150 | version: 3.0.0 151 | resolution: "is-fullwidth-code-point@npm:3.0.0" 152 | checksum: 44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 153 | languageName: node 154 | linkType: hard 155 | 156 | "js-tokens@npm:^4.0.0": 157 | version: 4.0.0 158 | resolution: "js-tokens@npm:4.0.0" 159 | checksum: 8a95213a5a77deb6cbe94d86340e8d9ace2b93bc367790b260101d2f36a2eaf4e4e22d9fa9cf459b38af3a32fb4190e638024cf82ec95ef708680e405ea7cc78 160 | languageName: node 161 | linkType: hard 162 | 163 | "kk@workspace:.": 164 | version: 0.0.0-use.local 165 | resolution: "kk@workspace:." 166 | dependencies: 167 | "@babel/code-frame": ^7.18.6 168 | "@babel/highlight": ^7.18.6 169 | typescript: ^4.7.4 170 | yargs: ^17.5.1 171 | languageName: unknown 172 | linkType: soft 173 | 174 | "require-directory@npm:^2.1.1": 175 | version: 2.1.1 176 | resolution: "require-directory@npm:2.1.1" 177 | checksum: fb47e70bf0001fdeabdc0429d431863e9475e7e43ea5f94ad86503d918423c1543361cc5166d713eaa7029dd7a3d34775af04764bebff99ef413111a5af18c80 178 | languageName: node 179 | linkType: hard 180 | 181 | "string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": 182 | version: 4.2.3 183 | resolution: "string-width@npm:4.2.3" 184 | dependencies: 185 | emoji-regex: ^8.0.0 186 | is-fullwidth-code-point: ^3.0.0 187 | strip-ansi: ^6.0.1 188 | checksum: e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb 189 | languageName: node 190 | linkType: hard 191 | 192 | "strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": 193 | version: 6.0.1 194 | resolution: "strip-ansi@npm:6.0.1" 195 | dependencies: 196 | ansi-regex: ^5.0.1 197 | checksum: f3cd25890aef3ba6e1a74e20896c21a46f482e93df4a06567cebf2b57edabb15133f1f94e57434e0a958d61186087b1008e89c94875d019910a213181a14fc8c 198 | languageName: node 199 | linkType: hard 200 | 201 | "supports-color@npm:^5.3.0": 202 | version: 5.5.0 203 | resolution: "supports-color@npm:5.5.0" 204 | dependencies: 205 | has-flag: ^3.0.0 206 | checksum: 95f6f4ba5afdf92f495b5a912d4abee8dcba766ae719b975c56c084f5004845f6f5a5f7769f52d53f40e21952a6d87411bafe34af4a01e65f9926002e38e1dac 207 | languageName: node 208 | linkType: hard 209 | 210 | "typescript@npm:^4.7.4": 211 | version: 4.7.4 212 | resolution: "typescript@npm:4.7.4" 213 | bin: 214 | tsc: bin/tsc 215 | tsserver: bin/tsserver 216 | checksum: 5750181b1cd7e6482c4195825547e70f944114fb47e58e4aa7553e62f11b3f3173766aef9c281783edfd881f7b8299cf35e3ca8caebe73d8464528c907a164df 217 | languageName: node 218 | linkType: hard 219 | 220 | "typescript@patch:typescript@^4.7.4#~builtin": 221 | version: 4.7.4 222 | resolution: "typescript@patch:typescript@npm%3A4.7.4#~builtin::version=4.7.4&hash=7ad353" 223 | bin: 224 | tsc: bin/tsc 225 | tsserver: bin/tsserver 226 | checksum: 9096d8f6c16cb80ef3bf96fcbbd055bf1c4a43bd14f3b7be45a9fbe7ada46ec977f604d5feed3263b4f2aa7d4c7477ce5f9cd87de0d6feedec69a983f3a4f93e 227 | languageName: node 228 | linkType: hard 229 | 230 | "wrap-ansi@npm:^7.0.0": 231 | version: 7.0.0 232 | resolution: "wrap-ansi@npm:7.0.0" 233 | dependencies: 234 | ansi-styles: ^4.0.0 235 | string-width: ^4.1.0 236 | strip-ansi: ^6.0.0 237 | checksum: a790b846fd4505de962ba728a21aaeda189b8ee1c7568ca5e817d85930e06ef8d1689d49dbf0e881e8ef84436af3a88bc49115c2e2788d841ff1b8b5b51a608b 238 | languageName: node 239 | linkType: hard 240 | 241 | "y18n@npm:^5.0.5": 242 | version: 5.0.8 243 | resolution: "y18n@npm:5.0.8" 244 | checksum: 54f0fb95621ee60898a38c572c515659e51cc9d9f787fb109cef6fde4befbe1c4602dc999d30110feee37456ad0f1660fa2edcfde6a9a740f86a290999550d30 245 | languageName: node 246 | linkType: hard 247 | 248 | "yargs-parser@npm:^21.0.0": 249 | version: 21.0.1 250 | resolution: "yargs-parser@npm:21.0.1" 251 | checksum: c3ea2ed12cad0377ce3096b3f138df8267edf7b1aa7d710cd502fe16af417bafe4443dd71b28158c22fcd1be5dfd0e86319597e47badf42ff83815485887323a 252 | languageName: node 253 | linkType: hard 254 | 255 | "yargs@npm:^17.5.1": 256 | version: 17.5.1 257 | resolution: "yargs@npm:17.5.1" 258 | dependencies: 259 | cliui: ^7.0.2 260 | escalade: ^3.1.1 261 | get-caller-file: ^2.0.5 262 | require-directory: ^2.1.1 263 | string-width: ^4.2.3 264 | y18n: ^5.0.5 265 | yargs-parser: ^21.0.0 266 | checksum: 00d58a2c052937fa044834313f07910fd0a115dec5ee35919e857eeee3736b21a4eafa8264535800ba8bac312991ce785ecb8a51f4d2cc8c4676d865af1cfbde 267 | languageName: node 268 | linkType: hard -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | use nom::{ 2 | branch::alt, 3 | bytes::complete::{is_not, tag, take, take_till, take_until}, 4 | character::{ 5 | complete::{digit1, line_ending, not_line_ending, one_of, space0, space1}, 6 | streaming::multispace0, 7 | }, 8 | combinator::{cond, eof, map, map_res, opt, recognize}, 9 | error::{context, ParseError}, 10 | multi::{count, many0, many1, many_till, separated_list1}, 11 | sequence::{delimited, preceded, terminated}, 12 | IResult, Parser, 13 | }; 14 | use nom_language::error::VerboseError; 15 | 16 | use thiserror::Error; 17 | 18 | type Res = IResult>; 19 | 20 | /// Parser error 21 | #[derive(Debug, Error)] 22 | #[error("yarn.lock error")] 23 | pub enum YarnLockError { 24 | #[error("Error parsing yarn.lock file")] 25 | Parser { 26 | #[from] 27 | source: nom::Err>, 28 | }, 29 | } 30 | 31 | /// A parsed yarn.lock file. 32 | #[derive(Debug)] 33 | pub struct Lockfile<'a> { 34 | pub entries: Vec>, 35 | pub generator: Generator, 36 | pub version: u8, 37 | } 38 | 39 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] 40 | #[non_exhaustive] 41 | pub enum Generator { 42 | Yarn, 43 | Bun, 44 | } 45 | 46 | /// yarn.lock entry. 47 | /// It only shows the name of the dependency and the version. 48 | #[derive(Debug, PartialEq, Eq, Default)] 49 | pub struct Entry<'a> { 50 | pub name: &'a str, 51 | pub version: &'a str, 52 | pub resolved: &'a str, 53 | pub integrity: &'a str, 54 | pub dependencies: Vec<(&'a str, &'a str)>, 55 | pub optional_dependencies: Vec<(&'a str, &'a str)>, 56 | pub descriptors: Vec<(&'a str, &'a str)>, 57 | } 58 | 59 | /// Accepts the `yarn.lock` content and returns all the entries. 60 | /// # Errors 61 | /// - `YarnLockError` 62 | pub fn parse_str(content: &str) -> Result, YarnLockError> { 63 | parse(content).map(|(_, entries)| entries).map_err(|e| { 64 | e.map(|ve| { 65 | let errors = ve 66 | .errors 67 | .into_iter() 68 | .map(|v| (v.0.to_string(), v.1)) 69 | .collect(); 70 | VerboseError { errors } 71 | }) 72 | .into() 73 | }) 74 | } 75 | 76 | fn parse(input: &str) -> Res<&str, Lockfile<'_>> { 77 | let (i, (is_bun, is_v1)) = yarn_lock_header(input)?; 78 | let (i, version) = cond(!is_v1, yarn_lock_metadata).parse(i)?; 79 | let (i, mut entries) = many0(entry).parse(i)?; 80 | 81 | let generator = if is_bun { 82 | Generator::Bun 83 | } else { 84 | Generator::Yarn 85 | }; 86 | let version = match (is_v1, version) { 87 | (true, None) => 1, 88 | (false, Some(v)) => v, 89 | // This shouldn't happen. 90 | (true, Some(_)) | (false, None) => unreachable!(), 91 | }; 92 | 93 | // allow one extra line at the end as per #13 94 | if i.is_empty() { 95 | return Ok(( 96 | i, 97 | Lockfile { 98 | entries, 99 | generator, 100 | version, 101 | }, 102 | )); 103 | } 104 | 105 | let (i, final_entry) = entry_final(i)?; 106 | entries.push(final_entry); 107 | 108 | Ok(( 109 | i, 110 | Lockfile { 111 | entries, 112 | generator, 113 | version, 114 | }, 115 | )) 116 | } 117 | 118 | fn take_till_line_end(input: &str) -> Res<&str, &str> { 119 | recognize((alt((take_until("\n"), take_until("\r\n"))), take(1usize))).parse(input) 120 | } 121 | 122 | fn take_till_optional_line_end(input: &str) -> Res<&str, &str> { 123 | recognize(( 124 | alt((take_until("\n"), take_until("\r\n"), space0)), 125 | take(1usize), 126 | )) 127 | .parse(input) 128 | } 129 | 130 | fn yarn_lock_header(input: &str) -> Res<&str, (bool, bool)> { 131 | let is_bun = input 132 | .lines() 133 | .skip(2) 134 | .take(1) 135 | .any(|l| l.starts_with("# bun")); 136 | let is_v1 = input 137 | .lines() 138 | .skip(1) 139 | .take(1) 140 | .any(|l| l.starts_with("# yarn lockfile v1")); 141 | // 2 lines for Yarn 142 | // 3 lines for Bun 143 | let lines = if is_bun { 3 } else { 2 }; 144 | let (input, _) = recognize((count(take_till_line_end, lines), multispace0)).parse(input)?; 145 | Ok((input, (is_bun, is_v1))) 146 | } 147 | 148 | fn yarn_lock_metadata(input: &str) -> Res<&str, u8> { 149 | context( 150 | "metadata", 151 | terminated( 152 | preceded( 153 | (tag("__metadata:"), line_ending, space1, tag("version: ")), 154 | map_res(digit1, |d: &str| d.parse()), 155 | ), 156 | ( 157 | line_ending, 158 | many_till(take_till_line_end, (space0, line_ending)), 159 | multispace0, 160 | ), 161 | ), 162 | ) 163 | .parse(input) 164 | } 165 | 166 | fn entry_final(input: &str) -> Res<&str, Entry<'_>> { 167 | recognize(many_till(take_till_optional_line_end, eof)) 168 | .parse(input) 169 | .and_then(|(i, capture)| { 170 | let (_, my_entry) = parse_entry(capture)?; 171 | Ok((i, my_entry)) 172 | }) 173 | } 174 | 175 | fn entry(input: &str) -> Res<&str, Entry<'_>> { 176 | recognize(many_till( 177 | take_till_line_end, 178 | recognize((space0, line_ending)), 179 | )) 180 | .parse(input) 181 | .and_then(|(i, capture)| { 182 | let (_, my_entry) = parse_entry(capture)?; 183 | Ok((i, my_entry)) 184 | }) 185 | } 186 | 187 | #[derive(PartialEq, Debug)] 188 | enum EntryItem<'a> { 189 | Version(&'a str), 190 | Resolved(&'a str), 191 | Dependencies(Vec<(&'a str, &'a str)>), 192 | OptionalDependencies(Vec<(&'a str, &'a str)>), 193 | Integrity(&'a str), 194 | Unknown(&'a str), 195 | } 196 | 197 | fn unknown_line(input: &str) -> Res<&str, EntryItem<'_>> { 198 | take_till_line_end(input).map(|(i, res)| (i, EntryItem::Unknown(res))) 199 | } 200 | 201 | fn integrity(input: &str) -> Res<&str, EntryItem<'_>> { 202 | context( 203 | "integrity", 204 | ( 205 | space1, 206 | opt(tag("\"")), 207 | alt((tag("checksum"), tag("integrity"))), 208 | opt(tag("\"")), 209 | opt(tag(":")), 210 | space1, 211 | opt(tag("\"")), 212 | take_till(|c| c == '"' || c == '\n' || c == '\r'), 213 | ), 214 | ) 215 | .parse(input) 216 | .map(|(i, (_, _, _, _, _, _, _, integrity))| (i, EntryItem::Integrity(integrity))) 217 | } 218 | 219 | fn entry_item(input: &str) -> Res<&str, EntryItem<'_>> { 220 | alt(( 221 | entry_version, 222 | parse_dependencies, 223 | parse_optional_dependencies, 224 | integrity, 225 | entry_resolved, 226 | unknown_line, 227 | )) 228 | .parse(input) 229 | } 230 | 231 | fn parse_entry(input: &str) -> Res<&str, Entry<'_>> { 232 | context("entry", (entry_descriptors, many1(entry_item))) 233 | .parse(input) 234 | .and_then(|(next_input, res)| { 235 | let (descriptors, entry_items) = res; 236 | 237 | // descriptors is guaranteed to be of length >= 1 238 | let first_descriptor = descriptors.first().expect("Somehow descriptors is empty"); 239 | 240 | let name = first_descriptor.0; 241 | 242 | let mut version = ""; 243 | let mut resolved = ""; 244 | let mut dependencies = Vec::new(); 245 | let mut optional_dependencies = Vec::new(); 246 | let mut integrity = ""; 247 | 248 | for ei in entry_items { 249 | match ei { 250 | EntryItem::Version(v) => version = v, 251 | EntryItem::Resolved(r) => resolved = r, 252 | EntryItem::Dependencies(d) => dependencies = d, 253 | EntryItem::OptionalDependencies(d) => optional_dependencies = d, 254 | EntryItem::Integrity(c) => integrity = c, 255 | EntryItem::Unknown(_) => (), 256 | } 257 | } 258 | 259 | if version.is_empty() { 260 | return Err(nom::Err::Failure(VerboseError::from_error_kind( 261 | "version is empty for an entry", 262 | nom::error::ErrorKind::Fail, 263 | ))); 264 | } 265 | 266 | Ok(( 267 | next_input, 268 | Entry { 269 | name, 270 | version, 271 | resolved, 272 | integrity, 273 | dependencies, 274 | optional_dependencies, 275 | descriptors, 276 | }, 277 | )) 278 | }) 279 | } 280 | 281 | fn dependency_version(input: &str) -> Res<&str, &str> { 282 | alt((double_quoted_text, not_line_ending)).parse(input) 283 | } 284 | 285 | fn parse_dependencies(input: &str) -> Res<&str, EntryItem<'_>> { 286 | let (input, (indent, _, _)) = (space1, tag("dependencies:"), line_ending).parse(input)?; 287 | 288 | let dependencies_parser = many1(move |i| { 289 | ( 290 | tag(indent), // indented as much as the parent... 291 | space1, // ... plus extra indentation 292 | is_not(": "), // package name 293 | one_of(": "), 294 | space0, 295 | dependency_version, // version 296 | alt((line_ending, space0)), // newline or space 297 | ) 298 | .parse(i) 299 | .map(|(i, (_, _, p, _, _, v, _))| (i, (p.trim_matches('"'), v))) 300 | }); 301 | context("dependencies", dependencies_parser) 302 | .parse(input) 303 | .map(|(i, res)| (i, EntryItem::Dependencies(res))) 304 | } 305 | 306 | fn parse_optional_dependencies(input: &str) -> Res<&str, EntryItem<'_>> { 307 | let (input, (indent, _, _)) = 308 | (space1, tag("optionalDependencies:"), line_ending).parse(input)?; 309 | 310 | let optional_dependencies_parser = many1(move |i| { 311 | ( 312 | tag(indent), // indented as much as the parent... 313 | space1, // ... plus extra indentation 314 | is_not(": "), // package name 315 | one_of(": "), 316 | space0, 317 | dependency_version, // version 318 | alt((line_ending, space0)), // newline or space 319 | ) 320 | .parse(i) 321 | .map(|(i, (_, _, p, _, _, v, _))| (i, (p.trim_matches('"'), v))) 322 | }); 323 | context("optionalDependencies", optional_dependencies_parser) 324 | .parse(input) 325 | .map(|(i, res)| (i, EntryItem::OptionalDependencies(res))) 326 | } 327 | 328 | /** 329 | * Simple version, it doesn't consider escaped quotes since in our scenarios 330 | * it can't happen. 331 | */ 332 | fn double_quoted_text(input: &str) -> Res<&str, &str> { 333 | delimited(tag("\""), take_until("\""), tag("\"")).parse(input) 334 | } 335 | 336 | fn entry_single_descriptor<'a>(input: &'a str) -> Res<&'a str, (&'a str, &'a str)> { 337 | let (i, (_, desc)) = (opt(tag("\"")), is_not(",\"\n")).parse(input)?; 338 | let i = i.strip_prefix('"').unwrap_or(i); 339 | 340 | let (_, (name, version)) = context("entry single descriptor", |i: &'a str| { 341 | #[allow(clippy::manual_strip)] 342 | let name_end_idx = if i.starts_with('@') { 343 | i[1..].find('@').map(|idx| idx + 1) 344 | } else { 345 | i.find('@') 346 | }; 347 | 348 | let Some(name_end_idx) = name_end_idx else { 349 | return Err(nom::Err::Failure(VerboseError::from_error_kind( 350 | "version format error: @ not found", 351 | nom::error::ErrorKind::Fail, 352 | ))); 353 | }; 354 | 355 | let (name, version) = (&i[..name_end_idx], &i[name_end_idx + 1..]); 356 | 357 | Ok((i, (name, version))) 358 | }) 359 | .parse(desc)?; 360 | 361 | Ok((i, (name, version))) 362 | } 363 | 364 | fn entry_descriptors<'a>(input: &'a str) -> Res<&'a str, Vec<(&'a str, &'a str)>> { 365 | // foo@1: 366 | // "foo@npm:1.2": 367 | // "foo@1.2", "foo@npm:3.4": 368 | // "foo@npm:1.2, foo@npm:3.4": 369 | // "foo@npm:0.3.x, foo@npm:>= 0.3.2 < 0.4.0": 370 | 371 | context( 372 | "descriptors", 373 | |input: &'a str| -> Res<&str, Vec<(&str, &str)>> { 374 | let (input, line) = take_till_line_end(input)?; 375 | 376 | let line = line 377 | .strip_suffix(":\r\n") 378 | .or_else(|| line.strip_suffix(":\n")); 379 | 380 | if line.is_none() { 381 | return Err(nom::Err::Failure(VerboseError::from_error_kind( 382 | "descriptor does not end with : followed by newline", 383 | nom::error::ErrorKind::Fail, 384 | ))); 385 | } 386 | let line = line.unwrap(); 387 | 388 | let (_, res) = separated_list1((opt(tag("\"")), tag(", ")), entry_single_descriptor) 389 | .parse(line)?; 390 | 391 | Ok((input, res)) 392 | }, 393 | ) 394 | .parse(input) 395 | } 396 | 397 | fn entry_resolved(input: &str) -> Res<&str, EntryItem<'_>> { 398 | // " resolved \"https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c\"\r\n" 399 | // " resolution: \"@babel/code-frame@npm:7.18.6\"\r\n" 400 | 401 | context( 402 | "resolved", 403 | preceded( 404 | ( 405 | space1, 406 | opt(tag("\"")), 407 | alt((tag("resolved"), tag("resolution"))), 408 | opt(tag("\"")), 409 | opt(tag(":")), 410 | space1, 411 | tag("\""), 412 | ), 413 | terminated( 414 | map(is_not("\"\r\n"), EntryItem::Resolved), 415 | (tag("\""), line_ending), 416 | ), 417 | ), 418 | ) 419 | .parse(input) 420 | } 421 | 422 | fn entry_version(input: &str) -> Res<&str, EntryItem<'_>> { 423 | // "version \"7.12.13\"\r\n" 424 | // "version \"workspace:foobar\"\r\n" 425 | // "version \"https://s.lnl.gay/@a/verboden(name~'!*)/-/verboden(name~'!*)-1.0.0.tgz\"\r\n" 426 | 427 | context( 428 | "version", 429 | ( 430 | space1, 431 | opt(tag("\"")), 432 | tag("version"), 433 | opt(tag("\"")), 434 | opt(tag(":")), 435 | space1, 436 | opt(tag("\"")), 437 | is_version, 438 | opt(tag("\"")), 439 | line_ending, 440 | ), 441 | ) 442 | .parse(input) 443 | .map(|(i, (_, _, _, _, _, _, _, version, _, _))| (i, EntryItem::Version(version))) 444 | } 445 | 446 | fn is_version(input: &str) -> Res<&str, &str> { 447 | for (idx, byte) in input.as_bytes().iter().enumerate() { 448 | if !matches!( 449 | byte, 450 | // Regular semver 451 | b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z' 452 | | b'.' | b'-' | b'+' 453 | // URL chars, which might appear due to Bun bugs in yarn output. 454 | | b'@' | b':' | b'/' | b'#' | b'%' 455 | // Chars exempt from ECMA-262 encodeURIComponent. 456 | | b'!' | b'~' | b'*' | b'\'' | b'(' | b')' 457 | ) { 458 | return Ok((&input[idx..], &input[..idx])); 459 | } 460 | } 461 | Err(nom::Err::Error(VerboseError::from_error_kind( 462 | input, 463 | nom::error::ErrorKind::AlphaNumeric, 464 | ))) 465 | } 466 | 467 | #[cfg(test)] 468 | mod tests { 469 | use super::*; 470 | 471 | fn assert_v1(res: (&str, Lockfile)) { 472 | assert_eq!(res.0, ""); 473 | assert_eq!(res.1.generator, Generator::Yarn); 474 | assert_eq!(res.1.version, 1); 475 | assert_eq!( 476 | res.1.entries.first().unwrap(), 477 | &Entry { 478 | name: "@babel/code-frame", 479 | version: "7.12.13", 480 | resolved: "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658", 481 | descriptors: vec![("@babel/code-frame", "^7.0.0")], 482 | dependencies: vec![("@babel/highlight", "^7.12.13")], 483 | integrity: "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", 484 | ..Default::default() 485 | } 486 | ); 487 | 488 | assert_eq!( 489 | res.1.entries.last().unwrap(), 490 | &Entry { 491 | name: "yargs", 492 | version: "9.0.1", 493 | resolved: "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c", 494 | descriptors: vec![("yargs", "^9.0.0")], 495 | dependencies: vec![ 496 | ("camelcase", "^4.1.0"), 497 | ("cliui", "^3.2.0"), 498 | ("decamelize", "^1.1.1"), 499 | ("get-caller-file", "^1.0.1"), 500 | ("os-locale", "^2.0.0"), 501 | ("read-pkg-up", "^2.0.0"), 502 | ("require-directory", "^2.1.1"), 503 | ("require-main-filename", "^1.0.1"), 504 | ("set-blocking", "^2.0.0"), 505 | ("string-width", "^2.0.0"), 506 | ("which-module", "^2.0.0"), 507 | ("y18n", "^3.2.1"), 508 | ("yargs-parser", "^7.0.0"), 509 | ], 510 | integrity: "sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=", 511 | ..Default::default() 512 | } 513 | ); 514 | } 515 | 516 | #[test] 517 | fn parse_windows_server_from_memory_works() { 518 | let content = "# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.\r\n# yarn lockfile v1\r\n\r\n\r\n\"@babel/code-frame@^7.0.0\":\r\n version \"7.12.13\"\r\n resolved \"https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658\"\r\n integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==\r\n dependencies:\r\n \"@babel/highlight\" \"^7.12.13\"\r\n\r\nyargs-parser@^7.0.0:\r\n version \"7.0.0\"\r\n resolved \"https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9\"\r\n integrity sha1-jQrELxbqVd69MyyvTEA4s+P139k=\r\n dependencies:\r\n camelcase \"^4.1.0\"\r\n\r\nyargs@^9.0.0:\r\n version \"9.0.1\"\r\n resolved \"https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c\"\r\n integrity sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=\r\n dependencies:\r\n camelcase \"^4.1.0\"\r\n cliui \"^3.2.0\"\r\n decamelize \"^1.1.1\"\r\n get-caller-file \"^1.0.1\"\r\n os-locale \"^2.0.0\"\r\n read-pkg-up \"^2.0.0\"\r\n require-directory \"^2.1.1\"\r\n require-main-filename \"^1.0.1\"\r\n set-blocking \"^2.0.0\"\r\n string-width \"^2.0.0\"\r\n which-module \"^2.0.0\"\r\n y18n \"^3.2.1\"\r\n yargs-parser \"^7.0.0\"\r\n"; 519 | let res = parse(&content).unwrap(); 520 | assert_v1(res); 521 | } 522 | 523 | #[test] 524 | fn parse_bun_basic_v1() { 525 | let content = std::fs::read_to_string("tests/bun_basic/yarn.lock").unwrap(); 526 | let (_, res) = parse(&content).unwrap(); 527 | 528 | assert_eq!(res.generator, Generator::Bun); 529 | assert_eq!(res.entries.len(), 1); 530 | } 531 | 532 | #[test] 533 | fn parse_bun_workspaces_v1() { 534 | let content = std::fs::read_to_string("tests/bun_workspaces/yarn.lock").unwrap(); 535 | let (_, res) = parse(&content).unwrap(); 536 | 537 | assert_eq!(res.generator, Generator::Bun); 538 | assert_eq!(res.entries.len(), 19); 539 | } 540 | 541 | #[test] 542 | fn parse_v1_extra_end_line_from_file_works() { 543 | let content = std::fs::read_to_string("tests/v1_extra_end_line/yarn.lock").unwrap(); 544 | let res = parse(&content).unwrap(); 545 | assert_v1(res); 546 | } 547 | 548 | #[test] 549 | fn parse_v1_bad_format_doc_from_file_does_not_panic() { 550 | let content = std::fs::read_to_string("tests/v1_bad_format/yarn.lock").unwrap(); 551 | let res = parse(&content); 552 | assert!(res.is_err()); 553 | } 554 | 555 | #[test] 556 | fn parse_v1_doc_from_file_works() { 557 | let content = std::fs::read_to_string("tests/v1/yarn.lock").unwrap(); 558 | let res = parse(&content).unwrap(); 559 | assert_v1(res); 560 | } 561 | 562 | #[test] 563 | fn parse_v1_doc_from_file_without_endline_works() { 564 | let content = std::fs::read_to_string("tests/v1_without_endline/yarn.lock").unwrap(); 565 | let res = parse(&content).unwrap(); 566 | assert_v1(res) 567 | } 568 | 569 | #[test] 570 | fn parse_v1_doc_from_file_with_npm_bug_works() { 571 | // SEE: https://github.com/robertohuertasm/yarn-lock-parser/issues/3 572 | let content = std::fs::read_to_string("tests/v1_with_npm_bug/yarn.lock").unwrap(); 573 | let res = parse(&content).unwrap(); 574 | // using v6 as we generated the lock file with v6 information. 575 | // the npm bug convert it back to v1. 576 | assert_v6(res, true); 577 | } 578 | 579 | #[test] 580 | fn parse_v1_doc_from_memory_works_v1() { 581 | fn assert(input: &str, expect: &[Entry]) { 582 | let res = parse(input).unwrap(); 583 | assert_eq!(res.1.entries, expect); 584 | } 585 | 586 | assert( 587 | r#"# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 588 | # yarn lockfile v1 589 | 590 | 591 | "@babel/code-frame@^7.0.0": 592 | version "7.12.13" 593 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" 594 | integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== 595 | dependencies: 596 | "@babel/highlight" "^7.12.13" 597 | 598 | cli-table3@~0.6.1: 599 | version "0.6.5" 600 | resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.5.tgz#013b91351762739c16a9567c21a04632e449bf2f" 601 | integrity sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ== 602 | dependencies: 603 | string-width "^4.2.0" 604 | optionalDependencies: 605 | "@colors/colors" "1.5.0" 606 | 607 | "@babel/helper-validator-identifier@^7.12.11": 608 | version "7.12.11" 609 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" 610 | integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== 611 | "#, 612 | &[ 613 | Entry { 614 | name: "@babel/code-frame", 615 | version: "7.12.13", 616 | resolved: "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658", 617 | descriptors: vec![("@babel/code-frame", "^7.0.0")], 618 | dependencies: vec![("@babel/highlight", "^7.12.13")], 619 | integrity: "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", 620 | ..Default::default() 621 | }, 622 | Entry { 623 | name: "cli-table3", 624 | version: "0.6.5", 625 | resolved: "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.5.tgz#013b91351762739c16a9567c21a04632e449bf2f", 626 | descriptors: vec![("cli-table3", "~0.6.1")], 627 | dependencies: vec![("string-width", "^4.2.0")], 628 | optional_dependencies: vec![("@colors/colors", "1.5.0")], 629 | integrity: "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==" 630 | }, 631 | Entry { 632 | name: "@babel/helper-validator-identifier", 633 | version: "7.12.11", 634 | resolved: "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed", 635 | descriptors: vec![("@babel/helper-validator-identifier", "^7.12.11")], 636 | integrity: "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", 637 | ..Default::default() 638 | }, 639 | ], 640 | ); 641 | } 642 | 643 | fn assert_v6(res: (&str, Lockfile), with_bug: bool) { 644 | assert_eq!(res.0, ""); 645 | assert_eq!(res.1.generator, Generator::Yarn); 646 | assert_eq!(res.1.version, if with_bug { 1 } else { 6 }); 647 | assert_eq!( 648 | res.1.entries.first().unwrap(), 649 | &Entry { 650 | name: "@babel/code-frame", 651 | version: "7.18.6", 652 | resolved: if with_bug { 653 | "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz" 654 | } else { 655 | "@babel/code-frame@npm:7.18.6" 656 | }, 657 | descriptors: vec![( 658 | "@babel/code-frame", 659 | if with_bug { "^7.18.6" } else { "npm:^7.18.6" } 660 | )], 661 | dependencies: vec![("@babel/highlight", "^7.18.6")], 662 | integrity: if with_bug { 663 | "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==" 664 | } else { 665 | "195e2be3172d7684bf95cff69ae3b7a15a9841ea9d27d3c843662d50cdd7d6470fd9c8e64be84d031117e4a4083486effba39f9aef6bbb2c89f7f21bcfba33ba" 666 | }, 667 | ..Default::default() 668 | } 669 | ); 670 | 671 | assert_eq!( 672 | res.1.entries.last().unwrap(), 673 | &Entry { 674 | name: "yargs", 675 | version: "17.5.1", 676 | resolved: if with_bug { 677 | "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz" 678 | } else { 679 | "yargs@npm:17.5.1" 680 | }, 681 | descriptors: vec![("yargs", if with_bug { "^17.5.1" } else { "npm:^17.5.1" })], 682 | dependencies: vec![ 683 | ("cliui", "^7.0.2"), 684 | ("escalade", "^3.1.1"), 685 | ("get-caller-file", "^2.0.5"), 686 | ("require-directory", "^2.1.1"), 687 | ("string-width", "^4.2.3"), 688 | ("y18n", "^5.0.5"), 689 | ("yargs-parser", "^21.0.0"), 690 | ], 691 | integrity: if with_bug { 692 | "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==" 693 | } else { 694 | "00d58a2c052937fa044834313f07910fd0a115dec5ee35919e857eeee3736b21a4eafa8264535800ba8bac312991ce785ecb8a51f4d2cc8c4676d865af1cfbde" 695 | }, 696 | ..Default::default() 697 | } 698 | ); 699 | } 700 | 701 | #[test] 702 | fn parse_v6_doc_from_file_works() { 703 | let content = std::fs::read_to_string("tests/v2/yarn.lock").unwrap(); 704 | let res = parse(&content).unwrap(); 705 | assert_v6(res, false) 706 | } 707 | 708 | #[test] 709 | fn parse_v6_doc_from_file_without_endline_works() { 710 | let content = std::fs::read_to_string("tests/v2_without_endline/yarn.lock").unwrap(); 711 | let res = parse(&content).unwrap(); 712 | assert_v6(res, false) 713 | } 714 | 715 | #[test] 716 | fn parse_v6_doc_from_memory_works() { 717 | fn assert(input: &str, expect: &[Entry]) { 718 | let res = parse(input).unwrap(); 719 | assert_eq!(res.1.entries, expect); 720 | } 721 | 722 | assert( 723 | r#"# This file is generated by running "yarn install" inside your project. 724 | # Manual changes might be lost - proceed with caution! 725 | 726 | __metadata: 727 | version: 6 728 | cacheKey: 8 729 | 730 | "@babel/helper-plugin-utils@npm:^7.16.7": 731 | version: 7.16.7 732 | resolution: "@babel/helper-plugin-utils@npm:7.16.7" 733 | checksum: d08dd86554a186c2538547cd537552e4029f704994a9201d41d82015c10ed7f58f9036e8d1527c3760f042409163269d308b0b3706589039c5f1884619c6d4ce 734 | languageName: node 735 | linkType: hard 736 | 737 | "@babel/plugin-transform-for-of@npm:^7.12.1": 738 | version: 7.16.7 739 | resolution: "@babel/plugin-transform-for-of@npm:7.16.7" 740 | dependencies: 741 | "@babel/helper-plugin-utils": ^7.16.7 742 | peerDependencies: 743 | "@babel/core": ^7.0.0-0 744 | checksum: 35c9264ee4bef814818123d70afe8b2f0a85753a0a9dc7b73f93a71cadc5d7de852f1a3e300a7c69a491705805704611de1e2ccceb5686f7828d6bca2e5a7306 745 | languageName: node 746 | linkType: hard 747 | 748 | "@babel/runtime@npm:^7.12.5": 749 | version: 7.17.9 750 | resolution: "@babel/runtime@npm:7.17.9" 751 | dependencies: 752 | regenerator-runtime: ^0.13.4 753 | checksum: 4d56bdb82890f386d5a57c40ef985a0ed7f0a78f789377a2d0c3e8826819e0f7f16ba0fe906d9b2241c5f7ca56630ef0653f5bb99f03771f7b87ff8af4bf5fe3 754 | languageName: node 755 | linkType: hard 756 | "#, 757 | &[ 758 | Entry { 759 | name: "@babel/helper-plugin-utils", 760 | version: "7.16.7", 761 | resolved: "@babel/helper-plugin-utils@npm:7.16.7", 762 | descriptors: vec![("@babel/helper-plugin-utils", "npm:^7.16.7")], 763 | integrity: "d08dd86554a186c2538547cd537552e4029f704994a9201d41d82015c10ed7f58f9036e8d1527c3760f042409163269d308b0b3706589039c5f1884619c6d4ce", 764 | ..Default::default() 765 | }, 766 | Entry { 767 | name: "@babel/plugin-transform-for-of", 768 | version: "7.16.7", 769 | resolved: "@babel/plugin-transform-for-of@npm:7.16.7", 770 | descriptors: vec![("@babel/plugin-transform-for-of", "npm:^7.12.1")], 771 | dependencies: vec![("@babel/helper-plugin-utils", "^7.16.7")], 772 | integrity: "35c9264ee4bef814818123d70afe8b2f0a85753a0a9dc7b73f93a71cadc5d7de852f1a3e300a7c69a491705805704611de1e2ccceb5686f7828d6bca2e5a7306", 773 | ..Default::default() 774 | }, 775 | Entry { 776 | name: "@babel/runtime", 777 | version: "7.17.9", 778 | resolved: "@babel/runtime@npm:7.17.9", 779 | descriptors: vec![("@babel/runtime", "npm:^7.12.5")], 780 | dependencies: vec![("regenerator-runtime", "^0.13.4")], 781 | integrity: "4d56bdb82890f386d5a57c40ef985a0ed7f0a78f789377a2d0c3e8826819e0f7f16ba0fe906d9b2241c5f7ca56630ef0653f5bb99f03771f7b87ff8af4bf5fe3", 782 | ..Default::default() 783 | }, 784 | ], 785 | ); 786 | } 787 | 788 | #[test] 789 | fn parse_v6_doc_from_memory_with_npm_in_dependencies_works() { 790 | fn assert(input: &str, expect: &[Entry]) { 791 | let res = parse(input).unwrap(); 792 | assert_eq!(res.1.entries, expect); 793 | } 794 | 795 | assert( 796 | r#"# This file is generated by running "yarn install" inside your project. 797 | # Manual changes might be lost - proceed with caution! 798 | 799 | __metadata: 800 | version: 6 801 | cacheKey: 8 802 | 803 | "foo@workspace:.": 804 | version: 0.0.0-use.local 805 | resolution: "foo@workspace:." 806 | dependencies: 807 | valib-aliased: "npm:valib@1.0.0 || 1.0.1" 808 | languageName: unknown 809 | linkType: soft 810 | 811 | "valib-aliased@npm:valib@1.0.0 || 1.0.1": 812 | version: 1.0.0 813 | resolution: "valib@npm:1.0.0" 814 | checksum: ad4f5a0b5dde5ab5e3cc87050fad4d7096c32797454d8e37c7dadf3455a43a7221a3caaa0ad9e72b8cd96668168e5a25d5f0072e21990f7f80a64b1a4e34e921 815 | languageName: node 816 | linkType: hard 817 | "#, 818 | &[ 819 | Entry { 820 | name: "foo", 821 | version: "0.0.0-use.local", 822 | resolved: "foo@workspace:.", 823 | integrity: "", 824 | descriptors: vec![("foo", "workspace:.")], 825 | dependencies: vec![("valib-aliased", "npm:valib@1.0.0 || 1.0.1")], 826 | ..Default::default() 827 | }, 828 | Entry { 829 | name: "valib-aliased", 830 | version: "1.0.0", 831 | resolved: "valib@npm:1.0.0", 832 | integrity: "ad4f5a0b5dde5ab5e3cc87050fad4d7096c32797454d8e37c7dadf3455a43a7221a3caaa0ad9e72b8cd96668168e5a25d5f0072e21990f7f80a64b1a4e34e921", 833 | descriptors: vec![("valib-aliased", "npm:valib@1.0.0 || 1.0.1")], 834 | dependencies: vec![], 835 | ..Default::default() 836 | }, 837 | ], 838 | ); 839 | } 840 | 841 | #[test] 842 | fn entry_works() { 843 | fn assert(input: &str, expect: Entry) { 844 | let res = entry(input).unwrap(); 845 | assert_eq!(res.1, expect); 846 | } 847 | 848 | assert( 849 | "\"@babel/code-frame@^7.0.0\":\r\n version \"7.12.13\"\r\n resolved \"https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658\"\r\n integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==\r\n dependencies:\r\n \"@babel/highlight\" \"^7.12.13\"\r\n\r\n", 850 | Entry { 851 | name: "@babel/code-frame", 852 | version: "7.12.13", 853 | resolved: "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658", 854 | descriptors: vec![("@babel/code-frame", "^7.0.0")], 855 | dependencies: vec![("@babel/highlight", "^7.12.13")], 856 | integrity: "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", 857 | ..Default::default() 858 | }, 859 | ); 860 | 861 | assert( 862 | "\"@babel/code-frame@^7.0.0\":\n version \"7.12.13\"\n resolved \"https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658\"\n integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==\n dependencies:\n \"@babel/highlight\" \"^7.12.13\"\n\n", 863 | Entry { 864 | name: "@babel/code-frame", 865 | version: "7.12.13", 866 | resolved: "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658", 867 | descriptors: vec![("@babel/code-frame", "^7.0.0")], 868 | dependencies: vec![("@babel/highlight", "^7.12.13")], 869 | integrity: "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", 870 | ..Default::default() 871 | }, 872 | ); 873 | 874 | assert( 875 | r#""@babel/code-frame@^7.0.0": 876 | version "7.12.13" 877 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" 878 | integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== 879 | dependencies: 880 | "@babel/highlight" "^7.12.13" 881 | 882 | "#, 883 | Entry { 884 | name: "@babel/code-frame", 885 | version: "7.12.13", 886 | resolved: "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658", 887 | descriptors: vec![("@babel/code-frame", "^7.0.0")], 888 | dependencies: vec![("@babel/highlight", "^7.12.13")], 889 | integrity: "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", 890 | ..Default::default() 891 | }, 892 | ); 893 | 894 | // with final spaces 895 | assert( 896 | r#""@babel/helper-validator-identifier@^7.12.11": 897 | version "7.12.11" 898 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" 899 | integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== 900 | 901 | "#, 902 | Entry { 903 | name: "@babel/helper-validator-identifier", 904 | version: "7.12.11", 905 | resolved: "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed", 906 | descriptors: vec![("@babel/helper-validator-identifier", "^7.12.11")], 907 | integrity: "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", 908 | ..Default::default() 909 | }, 910 | ); 911 | 912 | // without final spaces 913 | assert( 914 | r#""@babel/helper-validator-identifier@^7.12.11": 915 | version "7.12.11" 916 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" 917 | integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== 918 | 919 | "#, 920 | Entry { 921 | name: "@babel/helper-validator-identifier", 922 | version: "7.12.11", 923 | resolved: "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed", 924 | descriptors: vec![("@babel/helper-validator-identifier", "^7.12.11")], 925 | integrity: "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", 926 | ..Default::default() 927 | }, 928 | ); 929 | } 930 | 931 | #[test] 932 | fn parse_entry_works() { 933 | fn assert(input: &str, expect: Entry) { 934 | let res = parse_entry(input).unwrap(); 935 | assert_eq!(res.1, expect); 936 | } 937 | // escaped lines 938 | assert( 939 | "\"@babel/code-frame@^7.0.0\":\n version \"7.12.13\"\n resolved \"https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658\"\n integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==\n dependencies:\n \"@babel/highlight\" \"^7.12.13\"\n\n", 940 | Entry { 941 | name: "@babel/code-frame", 942 | version: "7.12.13", 943 | resolved: "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658", 944 | descriptors: vec![("@babel/code-frame", "^7.0.0")], 945 | dependencies: vec![("@babel/highlight", "^7.12.13")], 946 | integrity: "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", 947 | ..Default::default() 948 | }, 949 | ); 950 | 951 | // escaped lines windows 952 | assert( 953 | "\"@babel/code-frame@^7.0.0\":\r\n version \"7.12.13\"\r\n resolved \"https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658\"\r\n integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==\r\n dependencies:\r\n \"@babel/highlight\" \"^7.12.13\"\r\n\r\n", 954 | Entry { 955 | name: "@babel/code-frame", 956 | version: "7.12.13", 957 | resolved: "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658", 958 | descriptors: vec![("@babel/code-frame", "^7.0.0")], 959 | dependencies: vec![("@babel/highlight", "^7.12.13")], 960 | integrity: "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", 961 | ..Default::default() 962 | }, 963 | ); 964 | 965 | // normal 966 | assert( 967 | r#""@babel/code-frame@^7.0.0": 968 | version "7.12.13" 969 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" 970 | integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== 971 | dependencies: 972 | "@babel/highlight" "^7.12.13" 973 | 974 | "#, 975 | Entry { 976 | name: "@babel/code-frame", 977 | version: "7.12.13", 978 | resolved: "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658", 979 | descriptors: vec![("@babel/code-frame", "^7.0.0")], 980 | dependencies: vec![("@babel/highlight", "^7.12.13")], 981 | integrity: "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", 982 | ..Default::default() 983 | }, 984 | ); 985 | } 986 | 987 | #[test] 988 | fn parse_entry_without_endline_works() { 989 | fn assert(input: &str, expect: Entry) { 990 | let res = parse_entry(input).unwrap(); 991 | assert_eq!(res.1, expect); 992 | } 993 | 994 | assert( 995 | r#""@babel/code-frame@^7.0.0": 996 | version "7.12.13" 997 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" 998 | integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== 999 | dependencies: 1000 | "@babel/highlight" "^7.12.13""#, 1001 | Entry { 1002 | name: "@babel/code-frame", 1003 | version: "7.12.13", 1004 | resolved: "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658", 1005 | descriptors: vec![("@babel/code-frame", "^7.0.0")], 1006 | dependencies: vec![("@babel/highlight", "^7.12.13")], 1007 | integrity: "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", 1008 | ..Default::default() 1009 | }, 1010 | ); 1011 | } 1012 | 1013 | #[test] 1014 | fn entry_version_works() { 1015 | assert_eq!( 1016 | entry_version(" version \"1.2.3\"\r\n"), 1017 | Ok(("", EntryItem::Version("1.2.3"))) 1018 | ); 1019 | assert_eq!( 1020 | entry_version(" version \"1.2.3\"\n"), 1021 | Ok(("", EntryItem::Version("1.2.3"))) 1022 | ); 1023 | assert_eq!( 1024 | entry_version(" version \"1.2.3-beta1\"\n"), 1025 | Ok(("", EntryItem::Version("1.2.3-beta1"))) 1026 | ); 1027 | assert_eq!( 1028 | entry_version(" version: 1.2.3\n"), 1029 | Ok(("", EntryItem::Version("1.2.3"))) 1030 | ); 1031 | assert!(entry_version(" node-version: 1.0.0\n").is_err()); 1032 | 1033 | // bun workspaces 1034 | assert_eq!( 1035 | entry_version(" version: \"workspace:foo\"\n"), 1036 | Ok(("", EntryItem::Version("workspace:foo"))) 1037 | ); 1038 | assert_eq!( 1039 | entry_version(" version: \"workspace:@bar/baz\"\r\n"), 1040 | Ok(("", EntryItem::Version("workspace:@bar/baz"))) 1041 | ); 1042 | 1043 | // github: 1044 | assert_eq!( 1045 | entry_version(" version \"github:settlemint/node-http-proxy\"\r\n"), 1046 | Ok(("", EntryItem::Version("github:settlemint/node-http-proxy"))) 1047 | ); 1048 | assert_eq!( 1049 | entry_version(" version \"github:settlemint/node-http-proxy#master\"\n"), 1050 | Ok(( 1051 | "", 1052 | EntryItem::Version("github:settlemint/node-http-proxy#master") 1053 | )) 1054 | ); 1055 | 1056 | // npm: 1057 | assert_eq!( 1058 | entry_version(" version \"npm:foo-bar\"\r\n"), 1059 | Ok(("", EntryItem::Version("npm:foo-bar"))) 1060 | ); 1061 | assert_eq!( 1062 | entry_version(" version \"npm:@scope/foo-bar\"\r\n"), 1063 | Ok(("", EntryItem::Version("npm:@scope/foo-bar"))) 1064 | ); 1065 | } 1066 | 1067 | #[test] 1068 | fn entry_descriptors_works() { 1069 | fn assert(input: &str, expect: Vec<(&str, &str)>) { 1070 | let res = entry_descriptors(input).unwrap(); 1071 | assert_eq!(res.1, expect); 1072 | } 1073 | 1074 | assert( 1075 | r#"abab@^1.0.3: 1076 | version "1.0.4" 1077 | "#, 1078 | vec![("abab", "^1.0.3")], 1079 | ); 1080 | 1081 | assert( 1082 | r#""@nodelib/fs.stat@2.0.3": 1083 | version "2.0.3" 1084 | "#, 1085 | vec![("@nodelib/fs.stat", "2.0.3")], 1086 | ); 1087 | 1088 | assert( 1089 | r#"abab@^1.0.3, abab@^1.0.4: 1090 | version "1.0.4" 1091 | "#, 1092 | vec![("abab", "^1.0.3"), ("abab", "^1.0.4")], 1093 | ); 1094 | 1095 | assert( 1096 | r#""@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": 1097 | version "2.0.3" 1098 | "#, 1099 | vec![ 1100 | ("@nodelib/fs.stat", "2.0.3"), 1101 | ("@nodelib/fs.stat", "^2.0.2"), 1102 | ], 1103 | ); 1104 | 1105 | // yarn >= 2.0 format 1106 | assert( 1107 | r#""@nodelib/fs.stat@npm:2.0.3, @nodelib/fs.stat@npm:^2.0.2": 1108 | version "2.0.3" 1109 | "#, 1110 | vec![ 1111 | ("@nodelib/fs.stat", "npm:2.0.3"), 1112 | ("@nodelib/fs.stat", "npm:^2.0.2"), 1113 | ], 1114 | ); 1115 | 1116 | assert( 1117 | r#"foolib@npm:1.2.3 || ^2.0.0": 1118 | version "1.2.3" 1119 | "#, 1120 | vec![("foolib", "npm:1.2.3 || ^2.0.0")], 1121 | ); 1122 | } 1123 | 1124 | #[test] 1125 | fn unknown_line_works() { 1126 | let res = unknown_line("foo\nbar").unwrap(); 1127 | assert_eq!(res, ("bar", EntryItem::Unknown("foo\n"))); 1128 | } 1129 | 1130 | #[test] 1131 | fn integrity_works() { 1132 | fn assert(input: &str, expect: EntryItem) { 1133 | let res = integrity(input).unwrap(); 1134 | assert_eq!(res.1, expect); 1135 | } 1136 | 1137 | assert( 1138 | r#" "integrity" "sha1-jQrELxbqVd69MyyvTEA4s+P139k=" 1139 | "#, 1140 | EntryItem::Integrity("sha1-jQrELxbqVd69MyyvTEA4s+P139k="), 1141 | ); 1142 | 1143 | assert( 1144 | r#" integrity sha1-jQrELxbqVd69MyyvTEA4s+P139k= 1145 | "#, 1146 | EntryItem::Integrity("sha1-jQrELxbqVd69MyyvTEA4s+P139k="), 1147 | ); 1148 | 1149 | assert( 1150 | r#" checksum: fb47e70bf0001fdeabdc0429d431863e9475e7e43ea5f94ad86503d918423c1543361cc5166d713eaa7029dd7a3d34775af04764bebff99ef413111a5af18c80 1151 | "#, 1152 | EntryItem::Integrity("fb47e70bf0001fdeabdc0429d431863e9475e7e43ea5f94ad86503d918423c1543361cc5166d713eaa7029dd7a3d34775af04764bebff99ef413111a5af18c80"), 1153 | ); 1154 | } 1155 | 1156 | #[test] 1157 | fn parse_dependencies_work() { 1158 | fn assert(input: &str, expect: EntryItem) { 1159 | let res = parse_dependencies(input).unwrap(); 1160 | assert_eq!(res.1, expect); 1161 | } 1162 | 1163 | assert( 1164 | r#" dependencies: 1165 | foo "1.0" 1166 | "bar" "0.3-alpha1" 1167 | "#, 1168 | EntryItem::Dependencies(vec![("foo", "1.0"), ("bar", "0.3-alpha1")]), 1169 | ); 1170 | 1171 | assert( 1172 | r#" dependencies: 1173 | foo "1.0 || 2.0" 1174 | "bar" "0.3-alpha1" 1175 | "#, 1176 | EntryItem::Dependencies(vec![("foo", "1.0 || 2.0"), ("bar", "0.3-alpha1")]), 1177 | ); 1178 | 1179 | assert( 1180 | r#" dependencies: 1181 | foo: 1.0 || 2.0 1182 | "bar": "0.3-alpha1" 1183 | "#, 1184 | EntryItem::Dependencies(vec![("foo", "1.0 || 2.0"), ("bar", "0.3-alpha1")]), 1185 | ); 1186 | } 1187 | 1188 | #[test] 1189 | fn parse_optional_dependencies_work() { 1190 | fn assert(input: &str, expect: EntryItem) { 1191 | let res = parse_optional_dependencies(input).unwrap(); 1192 | assert_eq!(res.1, expect); 1193 | } 1194 | 1195 | assert( 1196 | r#" optionalDependencies: 1197 | foo "1.0" 1198 | "bar" "0.3-alpha1" 1199 | "#, 1200 | EntryItem::OptionalDependencies(vec![("foo", "1.0"), ("bar", "0.3-alpha1")]), 1201 | ); 1202 | 1203 | assert( 1204 | r#" optionalDependencies: 1205 | foo "1.0 || 2.0" 1206 | "bar" "0.3-alpha1" 1207 | "#, 1208 | EntryItem::OptionalDependencies(vec![("foo", "1.0 || 2.0"), ("bar", "0.3-alpha1")]), 1209 | ); 1210 | 1211 | assert( 1212 | r#" optionalDependencies: 1213 | foo: 1.0 || 2.0 1214 | "bar": "0.3-alpha1" 1215 | "#, 1216 | EntryItem::OptionalDependencies(vec![("foo", "1.0 || 2.0"), ("bar", "0.3-alpha1")]), 1217 | ); 1218 | } 1219 | 1220 | #[test] 1221 | fn take_till_the_end_works() { 1222 | let k = take_till_line_end("foo\r\nbar").unwrap(); 1223 | assert_eq!(k.0, "bar"); 1224 | assert_eq!(k.1, "foo\r\n"); 1225 | } 1226 | 1227 | #[test] 1228 | fn supports_github_version_protocol() { 1229 | // yarn > 1 1230 | let content = std::fs::read_to_string("tests/github_version/yarn.lock").unwrap(); 1231 | let res = parse(&content); 1232 | assert!(!res.is_err()); 1233 | 1234 | // yarn 1 1235 | let content = std::fs::read_to_string("tests/github_version/yarn1.lock").unwrap(); 1236 | let res = parse(&content); 1237 | assert!(!res.is_err()); 1238 | 1239 | // bun 1240 | let content = std::fs::read_to_string("tests/github_version/bun.lock").unwrap(); 1241 | let res = parse(&content); 1242 | assert!(!res.is_err()); 1243 | } 1244 | 1245 | #[test] 1246 | fn supports_git_url_descriptor() { 1247 | let content = std::fs::read_to_string("tests/v1_git_url/yarn.lock").unwrap(); 1248 | let res = parse_str(&content).unwrap(); 1249 | 1250 | assert_eq!( 1251 | res.entries.last().unwrap(), 1252 | &Entry { 1253 | name: "minimatch", 1254 | version: "10.0.1", 1255 | resolved: "https://github.com/isaacs/minimatch.git#0569cd3373408f9d701d3aab187b3f43a24a0db7", 1256 | integrity: "", 1257 | dependencies: vec![("brace-expansion", "^2.0.1")], 1258 | descriptors: vec![( 1259 | "minimatch", 1260 | "https://github.com/isaacs/minimatch.git#v10.0.1" 1261 | )], 1262 | ..Default::default() 1263 | } 1264 | ); 1265 | } 1266 | 1267 | #[test] 1268 | fn supports_at_in_version_descriptor() { 1269 | let content = std::fs::read_to_string("tests/v1_git_ssh/yarn.lock").unwrap(); 1270 | let res = parse_str(&content).unwrap(); 1271 | 1272 | assert_eq!( 1273 | res.entries.last().unwrap(), 1274 | &Entry { 1275 | name: "node-semver", 1276 | version: "7.6.3", 1277 | resolved: "ssh://git@github.com/npm/node-semver.git#0a12d6c7debb1dc82d8645c770e77c47bac5e1ea", 1278 | integrity: "", 1279 | dependencies: vec![], 1280 | descriptors: vec![( 1281 | "node-semver", 1282 | "ssh://git@github.com/npm/node-semver.git#semver:^7.5.0" 1283 | )], 1284 | ..Default::default() 1285 | } 1286 | ); 1287 | } 1288 | 1289 | #[test] 1290 | fn supports_version_url() { 1291 | // https://github.com/oven-sh/bun/issues/17091 1292 | let content = std::fs::read_to_string("tests/bun_version_url/yarn.lock").unwrap(); 1293 | let res = parse_str(&content).unwrap(); 1294 | 1295 | assert_eq!( 1296 | res.entries.last().unwrap(), 1297 | &Entry { 1298 | name: "@a/verboden(name~'!*)", 1299 | version: "https://s.lnl.gay/@a/verboden(name~'!*)/-/verboden(name~'!*)-1.0.0.tgz", 1300 | resolved: "https://s.lnl.gay/@a/verboden(name~'!*)/-/verboden(name~'!*)-1.0.0.tgz", 1301 | integrity: "", 1302 | dependencies: vec![], 1303 | descriptors: vec![( 1304 | "@a/verboden(name~'!*)", 1305 | "https://s.lnl.gay/@a/verboden(name~'!*)/-/verboden(name~'!*)-1.0.0.tgz" 1306 | ),], 1307 | ..Default::default() 1308 | } 1309 | ) 1310 | } 1311 | } 1312 | --------------------------------------------------------------------------------