diff --git a/src/lib.rs b/src/lib.rs index 2b86eec..22363cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,10 +29,12 @@ pub enum YarnLockError { /// A parsed yarn.lock file. #[derive(Debug)] +#[non_exhaustive] pub struct Lockfile<'a> { pub entries: Vec>, pub generator: Generator, pub version: u8, + pub cache_key: Option<&'a str>, } #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -78,7 +80,7 @@ pub fn parse_str(content: &str) -> Result, 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 { @@ -86,9 +88,9 @@ fn parse(input: &str) -> Res<&str, Lockfile<'_>> { } 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!(), }; @@ -101,6 +103,7 @@ fn parse(input: &str) -> Res<&str, Lockfile<'_>> { entries, generator, version, + cache_key, }, )); } @@ -114,6 +117,7 @@ fn parse(input: &str) -> Res<&str, Lockfile<'_>> { entries, generator, version, + cache_key, }, )) } @@ -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, ), @@ -1468,6 +1478,7 @@ __metadata: } #[test] + fn empty_lockfile() { let content = std::fs::read_to_string("tests/v1_empty/yarn.lock").unwrap(); let res = parse_str(&content).unwrap(); @@ -1475,4 +1486,15 @@ __metadata: 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")); + } } diff --git a/tests/v2_cache_key/yarn.lock b/tests/v2_cache_key/yarn.lock new file mode 100644 index 0000000..59318ea --- /dev/null +++ b/tests/v2_cache_key/yarn.lock @@ -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