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
2 changes: 1 addition & 1 deletion dependencies/npm.json

Large diffs are not rendered by default.

15 changes: 9 additions & 6 deletions src/twyn/dependency_parser/parsers/yarn_lock_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,29 @@ def parse(self) -> set[str]:

def _parse_v1(self, fp: TextIO) -> set[str]:
"""Parse a yarn.lock file and return all the dependencies in it."""
key_line_re = re.compile(r"^(?P<key>[^ \t].*?):\s*$", re.MULTILINE)
# Match the entire line up to the colon (allows multiple quoted keys)
key_line_re = re.compile(r"^(?P<key>[^ \t].*?):\s*$")
names = set()

for line in fp:
match = key_line_re.match(line)
if not match:
continue
key = match.group("key").strip()
# Remove surrounding quotes if present
if (key.startswith('"') and key.endswith('"')) or (key.startswith("'") and key.endswith("'")):
key = key[1:-1]

# Split selectors (comma-separated)
# Split on commas at the top level (handles multiple quoted keys)
parts = [p.strip() for p in key.split(",")]

for part in parts:
# Remove surrounding quotes if present
if (part.startswith('"') and part.endswith('"')) or (part.startswith("'") and part.endswith("'")):
part = part[1:-1] # noqa: PLW2901

# Skip anything without '@' (not a valid package selector)
if "@" not in part:
continue
# Package name is everything before the last '@'

# Get everything before the last '@' as the package name
pkg_name = part.rsplit("@", 1)[0]
names.add(pkg_name)

Expand Down
1 change: 1 addition & 0 deletions src/twyn/trusted_packages/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@
"b": ["g", "h", "v", "n"],
"n": ["h", "j", "b", "m"],
"m": ["j", "k", "n"],
"@": ["1", "2", "3", "q", "w"],
}
4 changes: 4 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,10 @@ def yarn_lock_file_v1(tmp_path: Path) -> Iterator[Path]:
dependencies:
loose-envify "^1.1.0"
react "^18.2.0"
"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.25.9", "@babel/helper-plugin-utils@^7.8.0":
version "7.26.5"
resolved "https://registry.npmmirror.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz#18580d00c9934117ad719392c4f6585c9333cc35"
integrity sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==
"""
with create_tmp_file(yarn_file, data) as tmp_file:
yield tmp_file
Expand Down
2 changes: 1 addition & 1 deletion tests/dependency_parser/test_dependency_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class TestYarnLockParser:
def test_parse_yarn_lock_v1(self, yarn_lock_file_v1: Path) -> None:
parser = YarnLockParser(file_path=str(yarn_lock_file_v1))

assert parser.parse() == {"lodash", "react", "react-dom"}
assert parser.parse() == {"lodash", "react", "react-dom", "@babel/helper-plugin-utils"}

def test_parse_yarn_lock_v2(self, yarn_lock_file_v2: Path) -> None:
parser = YarnLockParser(file_path=str(yarn_lock_file_v2))
Expand Down