{"id":14965761,"url":"https://github.com/yarnpkg/pnp-rs","last_synced_at":"2025-04-05T23:05:42.641Z","repository":{"id":152171460,"uuid":"609117573","full_name":"yarnpkg/pnp-rs","owner":"yarnpkg","description":null,"archived":false,"fork":false,"pushed_at":"2025-02-21T09:33:28.000Z","size":470,"stargazers_count":39,"open_issues_count":2,"forks_count":5,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-02T21:15:49.285Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yarnpkg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-03T12:13:33.000Z","updated_at":"2025-03-13T16:11:18.000Z","dependencies_parsed_at":null,"dependency_job_id":"baec9c6f-f9f8-4353-ad06-6fda2f3e1949","html_url":"https://github.com/yarnpkg/pnp-rs","commit_stats":{"total_commits":44,"total_committers":2,"mean_commits":22.0,"dds":"0.045454545454545414","last_synced_commit":"80e67fc36ddec97ec5df2b830683083b99e5fe95"},"previous_names":["yarnpkg/pnp-rs"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yarnpkg%2Fpnp-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yarnpkg%2Fpnp-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yarnpkg%2Fpnp-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yarnpkg%2Fpnp-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yarnpkg","download_url":"https://codeload.github.com/yarnpkg/pnp-rs/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247411226,"owners_count":20934653,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-09-24T13:35:15.707Z","updated_at":"2025-04-05T23:05:42.620Z","avatar_url":"https://github.com/yarnpkg.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `pnp-rs`\n\nThis crate implements the Yarn Plug'n'Play [resolution algorithms](https://yarnpkg.com/advanced/pnp-spec) for Rust so that it can be easily reused within Rust-based tools. It also includes utilities allowing to transparently read files from within zip archives.\n\n## Install\n\n```\ncargo add pnp\n```\n\n## Resolution\n\n```rust\nfn example() {\n    let manifest\n        = load_pnp_manifest(\".pnp.cjs\").unwrap();\n\n    let host = ResolutionHost {\n        find_pnp_manifest: Box::new(move |_| Ok(Some(manifest.clone()))),\n        ..Default::default()\n    };\n\n    let config = ResolutionConfig {\n        host,\n        ..Default::default()\n    };\n\n    let resolution = resolve_to_unqualified(\n        \"lodash/cloneDeep\",\n        std::path::PathBuf::from(\"/path/to/index.js\"),\n        \u0026config,\n    );\n\n    match resolution {\n        Ok(Resolution::Resolved(path, subpath)) =\u003e {\n            // path = \"/path/to/lodash.zip\"\n            // subpath = \"cloneDeep\"\n        },\n        Ok(Resolution::Skipped) =\u003e {\n            // This is returned when the PnP resolver decides that it shouldn't\n            // handle the resolution for this particular specifier. In that case,\n            // the specifier should be forwarded to the default resolver.\n        },\n        Err(err) =\u003e {\n            // An error happened during the resolution. Falling back to the default\n            // resolver isn't recommended.\n        },\n    };\n}\n```\n\n## Filesystem utilities\n\nWhile PnP only deals with the resolution, not the filesystem, the file maps generated by Yarn rely on virtual filesystem layers for two reasons:\n\n- [Virtual packages](https://yarnpkg.com/advanced/lexicon#virtual-package), which require a same package to have different paths to account for different set of dependencies (this only happens for packages that list peer dependencies)\n\n- Zip storage, which Yarn uses so the installed files never have to be unpacked from their archives, leading to faster installs and fewer risks of cache corruption.\n\nTo make it easier to work with these virtual filesystems, the `pnp` crate also includes a `VPath` enum that lets you resolve virtual paths, and a set of zip manipulation utils (`open_zip_via_read` by default, and `open_zip_via_mmap` if the `mmap` feature is enabled).\n\n```rust\nuse pnp::fs::{VPath, open_zip_via_read};\n\nfn read_file(p: PathBuf) -\u003e std::io::Result\u003cString\u003e {\n    match VPath::from(\u0026p).unwrap() {\n        // The path was virtual and stored within a zip file; we need to read from the zip file\n        // Note that this opens the zip file every time, which is expensive; we'll see how to optimize that\n        VPath::Zip(info) =\u003e {\n            open_zip_via_read(info.physical_base_path()).unwrap().read_to_string(\u0026zip_path)\n        },\n\n        // The path was virtual but not a zip file; we just need to read from the provided location\n        VPath::Virtual(info) =\u003e {\n            std::fs::read_to_string(info.physical_base_path())\n        },\n\n        // Nothing special to do, it's a regular path\n        VPath::Native(p) =\u003e {\n            std::fs::read_to_string(\u0026p)\n        },\n    }\n}\n```\n\n## Cache reuse\n\nOpening and dropping a zip archive for every single file access would be expensive. To avoid that, `pnp-rs` provides an helper class called `LruZipCache` which lets you abstract away the zip opening and closing, and only keep the most recently used archives open.\n\n```rust\nuse pnp::fs::{VPath, LruZipCache, open_zip_via_read};\n\nconst ZIP_CACHE: Lazy\u003cLruZipCache\u003cVec\u003cu8\u003e\u003e\u003e = Lazy::new(|| {\n    // It'll keep the last 50 zip archives open\n    LruZipCache::new(50, open_zip_via_read_p)\n});\n\nfn read_file(p: PathBuf) -\u003e std::io::Result\u003cString\u003e {\n    match VPath::from(\u0026p).unwrap() {\n        // The path was virtual and stored within a zip file; we need to read from the zip file\n        VPath::Zip(info) =\u003e {\n            ZIP_CACHE.read_to_string(info.physical_base_path(), \u0026zip_path)\n        },\n\n        // The path was virtual but not a zip file; we just need to read from the provided location\n        VPath::Virtual(info) =\u003e {\n            std::fs::read_to_string(info.physical_base_path())\n        },\n\n        // Nothing special to do, it's a regular path\n        VPath::Native(p) =\u003e {\n            std::fs::read_to_string(\u0026p)\n        },\n    }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyarnpkg%2Fpnp-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyarnpkg%2Fpnp-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyarnpkg%2Fpnp-rs/lists"}