Skip to content

Commit 47c6e6f

Browse files
committed
Add Yarn v2 Plug and Play .pnp.cjs handler support
Signed-off-by: hashaam-011 <hashaamkhan975@gmail.com>
1 parent 7dbb3c7 commit 47c6e6f

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

src/packagedcode/npm.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2023,3 +2023,59 @@ def keywords_mapper(keywords, package):
20232023

20242024
package.keywords = keywords
20252025
return package
2026+
class YarnPnpHandler(BaseNpmHandler):
2027+
"""
2028+
Handle Yarn v2 Plug and Play .pnp.cjs files
2029+
See https://yarnpkg.com/features/pnp
2030+
"""
2031+
datasource_id = 'yarn_pnp'
2032+
path_patterns = ('*/.pnp.cjs',)
2033+
default_package_type = 'npm'
2034+
default_primary_language = 'JavaScript'
2035+
description = 'Yarn Plug and Play manifest'
2036+
documentation_url = 'https://yarnpkg.com/features/pnp'
2037+
2038+
@classmethod
2039+
def parse(cls, location, package_only=False):
2040+
with io.open(location, encoding='utf-8') as f:
2041+
content = f.read()
2042+
2043+
# Extract the JSON data embedded in the .pnp.cjs file
2044+
match = re.search(r'const RAW_RUNTIME_STATE\s*=\s*(\{.*?\});', content, re.DOTALL)
2045+
if not match:
2046+
return
2047+
2048+
pnp_data = json.loads(match.group(1))
2049+
packages = pnp_data.get('packageRegistryData') or {}
2050+
2051+
dependencies = []
2052+
for name, versions in packages.items():
2053+
if not name:
2054+
continue
2055+
for version, _data in (versions or {}).items():
2056+
if not version:
2057+
continue
2058+
ns, _, pkg_name = name.rpartition('/')
2059+
purl = PackageURL(
2060+
type=cls.default_package_type,
2061+
namespace=ns or None,
2062+
name=pkg_name,
2063+
version=version,
2064+
).to_string()
2065+
dep = models.DependentPackage(
2066+
purl=purl,
2067+
extracted_requirement=version,
2068+
scope='dependencies',
2069+
is_runtime=True,
2070+
is_optional=False,
2071+
is_pinned=True,
2072+
)
2073+
dependencies.append(dep.to_dict())
2074+
2075+
package_data = dict(
2076+
datasource_id=cls.datasource_id,
2077+
type=cls.default_package_type,
2078+
primary_language=cls.default_primary_language,
2079+
dependencies=dependencies,
2080+
)
2081+
yield models.PackageData.from_data(package_data, package_only)

0 commit comments

Comments
 (0)