Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 31 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ pub enum YarnLockError {

/// A parsed yarn.lock file.
#[derive(Debug)]
#[non_exhaustive]
pub struct Lockfile<'a> {
pub entries: Vec<Entry<'a>>,
pub generator: Generator,
pub version: u8,
pub cache_key: Option<&'a str>,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
Expand Down Expand Up @@ -78,17 +80,17 @@ pub fn parse_str(content: &str) -> Result<Lockfile<'_>, YarnLockError> {

fn parse(input: &str) -> Res<&str, Lockfile<'_>> {
let (i, (is_bun, is_v1)) = yarn_lock_header(input)?;
let (i, version) = cond(!is_v1, yarn_lock_metadata).parse(i)?;
let (i, metadata) = cond(!is_v1, yarn_lock_metadata).parse(i)?;
let (i, mut entries) = many0(entry).parse(i)?;

let generator = if is_bun {
Generator::Bun
} else {
Generator::Yarn
};
let version = match (is_v1, version) {
(true, None) => 1,
(false, Some(v)) => v,
let (version, cache_key) = match (is_v1, metadata) {
(true, None) => (1, None),
(false, Some(m)) => m,
// This shouldn't happen.
(true, Some(_)) | (false, None) => unreachable!(),
};
Expand All @@ -101,6 +103,7 @@ fn parse(input: &str) -> Res<&str, Lockfile<'_>> {
entries,
generator,
version,
cache_key,
},
));
}
Expand All @@ -114,6 +117,7 @@ fn parse(input: &str) -> Res<&str, Lockfile<'_>> {
entries,
generator,
version,
cache_key,
},
))
}
Expand Down Expand Up @@ -148,16 +152,22 @@ fn yarn_lock_header(input: &str) -> Res<&str, (bool, bool)> {
Ok((input, (is_bun, is_v1)))
}

fn yarn_lock_metadata(input: &str) -> Res<&str, u8> {
fn yarn_lock_metadata(input: &str) -> Res<&str, (u8, Option<&str>)> {
context(
"metadata",
terminated(
preceded(
(tag("__metadata:"), line_ending, space1, tag("version: ")),
map_res(digit1, |d: &str| d.parse()),
(
delimited(
(tag("__metadata:"), line_ending, space1, tag("version: ")),
map_res(digit1, |d: &str| d.parse()),
line_ending,
),
opt(preceded(
(space1, tag("cacheKey: ")),
recognize((digit1, opt((tag("c"), digit1)))),
)),
),
(
line_ending,
many_till(take_till_line_end, (space0, line_ending)),
multispace0,
),
Expand Down Expand Up @@ -1468,11 +1478,23 @@ __metadata:
}

#[test]

fn empty_lockfile() {
let content = std::fs::read_to_string("tests/v1_empty/yarn.lock").unwrap();
let res = parse_str(&content).unwrap();
assert_eq!(res.entries, []);
assert_eq!(res.generator, Generator::Yarn);
assert_eq!(res.version, 1);
}

#[test]
fn parses_cache_key() {
let content = std::fs::read_to_string("tests/v2/yarn.lock").unwrap();
let res = parse_str(&content).unwrap();
assert_eq!(res.cache_key, Some("8"));

let content = std::fs::read_to_string("tests/v2_cache_key/yarn.lock").unwrap();
let res = parse_str(&content).unwrap();
assert_eq!(res.cache_key, Some("10c0"));
}
}
124 changes: 124 additions & 0 deletions tests/v2_cache_key/yarn.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# This file is generated by running "yarn install" inside your project.
# Manual changes might be lost - proceed with caution!

__metadata:
version: 8
cacheKey: 10c0

"@chastelock/testcase@workspace:.":
version: 0.0.0-use.local
resolution: "@chastelock/testcase@workspace:."
dependencies:
tsec: "npm:0.2.8"
languageName: unknown
linkType: soft

"balanced-match@npm:^1.0.0":
version: 1.0.2
resolution: "balanced-match@npm:1.0.2"
checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee
languageName: node
linkType: hard

"brace-expansion@npm:^1.1.7":
version: 1.1.11
resolution: "brace-expansion@npm:1.1.11"
dependencies:
balanced-match: "npm:^1.0.0"
concat-map: "npm:0.0.1"
checksum: 10c0/695a56cd058096a7cb71fb09d9d6a7070113c7be516699ed361317aca2ec169f618e28b8af352e02ab4233fb54eb0168460a40dc320bab0034b36ab59aaad668
languageName: node
linkType: hard

"concat-map@npm:0.0.1":
version: 0.0.1
resolution: "concat-map@npm:0.0.1"
checksum: 10c0/c996b1cfdf95b6c90fee4dae37e332c8b6eb7d106430c17d538034c0ad9a1630cb194d2ab37293b1bdd4d779494beee7786d586a50bd9376fd6f7bcc2bd4c98f
languageName: node
linkType: hard

"fs.realpath@npm:^1.0.0":
version: 1.0.0
resolution: "fs.realpath@npm:1.0.0"
checksum: 10c0/444cf1291d997165dfd4c0d58b69f0e4782bfd9149fd72faa4fe299e68e0e93d6db941660b37dd29153bf7186672ececa3b50b7e7249477b03fdf850f287c948
languageName: node
linkType: hard

"glob@npm:^7.1.1":
version: 7.2.3
resolution: "glob@npm:7.2.3"
dependencies:
fs.realpath: "npm:^1.0.0"
inflight: "npm:^1.0.4"
inherits: "npm:2"
minimatch: "npm:^3.1.1"
once: "npm:^1.3.0"
path-is-absolute: "npm:^1.0.0"
checksum: 10c0/65676153e2b0c9095100fe7f25a778bf45608eeb32c6048cf307f579649bcc30353277b3b898a3792602c65764e5baa4f643714dfbdfd64ea271d210c7a425fe
languageName: node
linkType: hard

"inflight@npm:^1.0.4":
version: 1.0.6
resolution: "inflight@npm:1.0.6"
dependencies:
once: "npm:^1.3.0"
wrappy: "npm:1"
checksum: 10c0/7faca22584600a9dc5b9fca2cd5feb7135ac8c935449837b315676b4c90aa4f391ec4f42240178244b5a34e8bede1948627fda392ca3191522fc46b34e985ab2
languageName: node
linkType: hard

"inherits@npm:2":
version: 2.0.4
resolution: "inherits@npm:2.0.4"
checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2
languageName: node
linkType: hard

"minimatch@npm:^3.0.3, minimatch@npm:^3.1.1":
version: 3.1.2
resolution: "minimatch@npm:3.1.2"
dependencies:
brace-expansion: "npm:^1.1.7"
checksum: 10c0/0262810a8fc2e72cca45d6fd86bd349eee435eb95ac6aa45c9ea2180e7ee875ef44c32b55b5973ceabe95ea12682f6e3725cbb63d7a2d1da3ae1163c8b210311
languageName: node
linkType: hard

"once@npm:^1.3.0":
version: 1.4.0
resolution: "once@npm:1.4.0"
dependencies:
wrappy: "npm:1"
checksum: 10c0/5d48aca287dfefabd756621c5dfce5c91a549a93e9fdb7b8246bc4c4790aa2ec17b34a260530474635147aeb631a2dcc8b32c613df0675f96041cbb8244517d0
languageName: node
linkType: hard

"path-is-absolute@npm:^1.0.0":
version: 1.0.1
resolution: "path-is-absolute@npm:1.0.1"
checksum: 10c0/127da03c82172a2a50099cddbf02510c1791fc2cc5f7713ddb613a56838db1e8168b121a920079d052e0936c23005562059756d653b7c544c53185efe53be078
languageName: node
linkType: hard

"tsec@npm:0.2.8":
version: 0.2.8
resolution: "tsec@npm:0.2.8"
dependencies:
glob: "npm:^7.1.1"
minimatch: "npm:^3.0.3"
peerDependencies:
"@bazel/bazelisk": ">=1.7.5"
"@bazel/concatjs": ">=5.3.0"
typescript: ">=3.9.2"
bin:
tsec: bin/tsec
checksum: 10c0/7dfa9b6e45c85ee59cbfe634618d6f013d60bc1d70ad9e5a4d186016ee2880b5a523907640b9d2fa27de5d9594ed9d5c347de5a1521c7186e3b3dfbdd2d9cd87
languageName: node
linkType: hard

"wrappy@npm:1":
version: 1.0.2
resolution: "wrappy@npm:1.0.2"
checksum: 10c0/56fece1a4018c6a6c8e28fbc88c87e0fbf4ea8fd64fc6c63b18f4acc4bd13e0ad2515189786dd2c30d3eec9663d70f4ecf699330002f8ccb547e4a18231fc9f0
languageName: node
linkType: hard