Releases: frontops-dev/domino
Releases · frontops-dev/domino
Release list
PR #79 Preview (20e1d9c)
PR #78 Preview (b1ca585)
PR #77 Preview (c177c02)
PR #76 Preview (a7e21bc)
PR #75 Preview (d25aa25)
v1.0.0: feat: lockfile change detection with configurable strategy (#34)
* feat: add lockfile change detection with configurable strategy
Implement pure-Rust lockfile parsing and change detection for npm,
yarn, pnpm, and bun lockfiles. When a lockfile changes, domino now
identifies which direct dependencies were affected (including
transitive deps resolved via reverse dependency graph) and marks
projects that import those dependencies.
Three strategies control the depth of analysis via --lockfile-strategy:
- none: skip lockfile processing entirely
- direct (default): mark projects importing affected deps
- full: also trace the complete reference chain via process_changed_symbol
Partially addresses #14
Made-with: Cursor
* fix: harden lockfile detection with correctness, security, and test improvements
- Fix yarn parser to read base package.json from git revision (not cwd)
- Fix pnpm parser to collect deps from ALL workspace importers
- Return empty LockfileData when base lockfile missing (was parsing "{}")
- Store canonical dep name in LockfileChange cause (not raw import specifier)
- Add 256MB size guard on lockfile loading and parsing (OOM protection)
- Add depth guard on npm v1 recursive dependency parsing
- Return N-API error on invalid lockfile_strategy instead of silent fallback
- Scope get_file_from_revision to pub(crate)
- Rename is_affected_import -> match_affected_dependency returning Option<&str>
- Deduplicate AffectedState construction in Full strategy loop
- Use FxHashMap/FxHashSet throughout lockfile module
- LazyLock for yarn regex, allocation-free import matching
- Eliminate duplicate git merge-base subprocess via tuple return
- Zero-clone reverse dep graph using &str references
- Add 25 new unit tests (128 total): LockfileStrategy round-trip,
npm v1, malformed input, detect_package_manager, yarn scoped,
bun JSONC comments, orphan resolution, has_lockfile_changed for all PMs
- Add module and function documentation throughout lockfile.rs
- Update README with lockfile detection docs and strategies
Partially addresses #14
Made-with: Cursor
* fix: add Yarn Berry support and fix npm v3 duplicate package detection
Two bugs in lockfile change detection:
1. Yarn Berry (v2+/v4) lockfiles use a YAML format completely different from
Yarn Classic. The parser only handled Classic, so Berry lockfiles silently
failed to detect version changes (version: 3.3.1 vs version "3.3.1") and
corrupted the dependency graph with non-dep fields (checksum, linkType).
Fix: auto-detect Berry via __metadata header and parse with serde_yaml.
2. npm v3 lockfiles can contain multiple instances of the same package at
different node_modules paths (e.g. node_modules/ms and
node_modules/debug/node_modules/ms). The parser extracted the bare name
for all instances, so later HashMap entries overwrote earlier ones. If the
last-processed instance had the same version in both base and current,
the actual change was invisible.
Fix: use the full node_modules path as the HashMap key for npm v3.
Downstream functions (diff, reverse dep graph) extract bare names via
package_name_from_key().
- Add parse_yarn_berry_packages() with serde_yaml parsing
- Add extract_yarn_berry_name() for npm:/workspace:/patch: protocols
- Add yaml_value_to_string() for serde_yaml numeric coercion
- Refactor parse_yarn_lockfile into Berry vs Classic dispatch
- Rename parse_yarn_dep_line -> parse_yarn_classic_dep_line
- Extract extract_direct_deps_from_pkg_json() shared helper
- Add package_name_from_key() for full-path → name extraction
- Update diff_lockfile_packages and build_reverse_dep_graph to use
package_name_from_key for format-agnostic name extraction
- Add 7 new tests: Berry parsing, scoped packages, multi-specifier,
version change detection, name extraction, npm v3 dedup
Made-with: Cursor
* fix: address PR review comments for lockfile change detection
- Fix parse_pnpm_package_key matching wrong @ in peer dep suffixes
like "foo@1.0.0(bar@2.0.0)" and "foo@1.0.0_react@16.0.0" by
stripping parenthesized suffixes before parsing and using forward
find('@') instead of rfind
- Fix lockfile edges silently dropped from Cytoscape graph by treating
LockfileChange like AssetChange (mark as direct change)
- Add #[non_exhaustive] to LockfileStrategy enum for future-proofing
- Fix lossy float-to-string in yaml_value_to_string (1.0 rendered as
"1") by delegating to serde_yaml serializer for Number values
- Fix BFS vs DFS documentation mismatch in resolve_to_direct_deps
- Add comment about npm v1 last-write-wins limitation
- Add 4 new tests: pnpm peer-dep suffixes (parens, underscore, scoped)
and yaml float preservation
Made-with: Cursor
* fix: address second round of PR review comments
Five correctness and robustness improvements:
1. Add MAX_LOCKFILE_BYTES guard to get_file_from_revision — the base
revision path previously bypassed the 256MB size check by buffering
the full git show output before parse_lockfile could enforce it.
Now checks object size via git cat-file -s before materialization.
2. Include optionalDependencies in direct dependency tracking across
all four lockfile parsers (npm, pnpm, yarn, bun). Previously only
dependencies and devDependencies were collected, so changes to
optional direct deps couldn't be mapped back to importers.
3. Fix pnpm and Yarn parsers using bare package names as HashMap keys,
causing last-write-wins when multiple resolved versions exist. Now
uses the original lockfile key (e.g. /foo@1.0.0, image-lib@npm:^2.6.0)
to preserve all instances. package_name_from_key() extracts bare names
for downstream diffing and import matching.
4. Yarn workspaces: collect package.json from root + all workspace
packages (via workspace globs) instead of only the root manifest.
This ensures workspace-local dependencies are tracked in
direct_dependencies. Works for both current and base revisions.
5. Resolve removed deps against the union of current and previous data.
Previously only current_data was used for the reverse graph and
direct deps, so removed packages couldn't map back to importers.
Now merges both revisions' reverse graphs and direct dep sets.
Made-with: Cursor
* perf: optimize lockfile module performance, security, and test coverage
Performance:
- match_affected_dependency O(n)→O(1) via hash lookup instead of
linear scan over all affected deps per import
- Collapse 3 git process spawns per file (cat-file -e + cat-file -s +
show) into 1 (cat-file -p) with Option<String> return type
- Pre-allocate serde_yaml lookup keys outside hot loops in pnpm and
Yarn Berry parsers
- Replace from_utf8_lossy().to_string() double-allocation with
String::from_utf8() ownership transfer
- Add capacity hints (reserve) to FxHashMap in npm, pnpm, bun parsers
and reverse dep graph builder
- Filter git ls-tree with pathspec to avoid reading entire repo tree
- Use FxHashSet for reverse dep graph values (dedup + faster lookup)
- Remove extract_npm_package_name wrapper that allocated String just
to check is_empty()
- Return &str from extract_yarn_berry_name instead of owned String
- Avoid Vec allocation in parse_yarn_classic_dep_line via iterator
- Move git.rs regexes to LazyLock statics
- Build merged direct deps with capacity hint and iterator chain
Security:
- get_file_from_revision now returns Result<Option<String>> to
distinguish missing files from real failures (size limit, git errors)
- Add MAX_PKG_JSON_BYTES (10MB) size guard on package.json disk reads
- Base workspace enumeration uses git ls-tree instead of filesystem
globs, correctly discovering workspaces deleted in the PR
Tests (+20 new, 159 total):
- package_name_from_key: 8 tests (npm v3, scoped, pnpm, yarn, bare)
- glob_match: 4 tests (star, globstar, nested, no-match)
- resolve_to_direct_deps: 2 cyclic graph tests
- Yarn Classic optionalDependencies parsing
- extract_workspace_patterns: 4 tests (array, object, missing, invalid)
Addresses latest review comments on PR #34.
Made-with: Cursor
* fix: harden git operations and error propagation in lockfile module
- Restore pre-buffer size guard: use git cat-file -s to check size
before materializing content with cat-file -p, preventing OOM for
oversized lockfiles (256MB+) in memory-constrained CI
- Distinguish missing files from real git errors: inspect stderr from
cat-file -s to only return Ok(None) for missing objects, propagate
actual failures (corrupt repos, permission errors) as Err
- Fix git ls-tree pathspec: */package.json doesn't work with git
pathspec matching, now lists all files and filters for package.json
paths in Rust so base-revision workspace discovery works correctly
- Propagate errors from collect_base_workspace_pkg_jsons and
list_package_jsons_at_revision: return Result<Vec<String>> instead
of swallowing errors with empty vecs, callers use ? operator
Made-with: Cursor
* fix: address PR review comments on lockfile and report modules
- LockfileChange badge now uses 'direct' CSS class (was 'imported')
- LockfileChange and AssetChange now set has_direct=true so the project
card shows 'Direct Change' badge instead of falling through to 'Affected'
- npm v3 parser now collects direct deps from all workspace package
entries (e.g. packages/app-a), not just the root '' entry
- bun parser now collects direct deps from all workspace entries,
not just the root '' entry
Made-with: Cursor
* fix: resolve merge conflicts with main
- Fix semantic merge conflict in core.rs: update lockfile integration
to use new ProjectIndex API (get_package_names_by_path method and
&project_index parameter) instead of removed free function
- Fix mangled integration_test.rs: separate interleaved
test_shared_source_root_all_projects_affected (from main) from
setup_lockfile_test_repo (from this branch)
- Remove duplicate struct fields from merge overlap in lockfile tests
- Add lockfile_strategy field to new shared-source-root test
Made-with: Cursor
* fix: restore corrupted test_lockfile_no_change_zero_impact after merge
The merge interleaved Rust code from test_shared_source_root into the
raw string literal for proj-c/src/index.ts, causing the test to write
nonsensical TypeScript (mixed with git_in calls) and have duplicate
add/commit pairs with the wrong message. Restored to original content.
Made-with: Cursor