feat(nxz): add --memlimit-decompress flag to CLI#117
Merged
Conversation
Support memory limit configuration during decompression via new --memlimit-decompress <SIZE> flag, matching xz CLI semantics. - Added parseMemlimitSize() helper accepting plain bytes, IEC binary suffixes (KiB, MiB, GiB, TiB), and SI decimal suffixes (KB, MB, GB, TB). - Special values 0 and max (case-insensitive) mean "no limit". - Threaded memlimit option through unxzSync() and createUnxz() call sites and benchmark cross-decompress. - LZMAMemoryLimitError now surfaces as CLI exit 1 when limit exceeded. - Added 7 vitest cases covering suffix parsing, edge cases, error handling, and default behavior preservation.
- Reject decimal mantissa in --memlimit-decompress (e.g. `1.5MiB` is now an error). xz CLI parity. Removes a silent-rounding pit and a Number() precision-loss path for very large suffixed inputs. - Parse the integer mantissa directly via BigInt (no Number() intermediary, no Math.round) — exact arbitrary-precision result. - Treat any zero form (`0`, `0MiB`, `0kb`, `max`, `MAX`) as "no limit". Previously `0<suffix>` produced 0n which the decoder rejected on every input — surprising vs the documented `0` synonym. - Apply memlimit symmetrically to both WASM decompression sites in `benchmarkFile` (was only applied to native sides). Native vs WASM benchmark is now apples-to-apples under --memlimit-decompress. - Add 29 direct unit tests for parseMemlimitSize covering decimal rejection, mixed-case suffix, negative input, empty string, whitespace tolerance, all-zero forms, and arbitrary-precision values beyond UINT64_MAX (downstream validateMemlimit handles upper bound). - Update JSDoc and --help to document integer-only mantissa, IEC (1024-based) vs SI (1000-based) suffix semantics, and the any-zero → no-limit synonym.
The unit-test file imported `parseMemlimitSize` from `nxz.ts`, which runs `main()` unconditionally on import. Under stricter vitest configurations the module's `process.exit(1)` fires during test collection. Extract `parseMemlimitSize` into `packages/nxz/src/memlimit.ts` as a side-effect-free helper module. `nxz.ts` imports + re-exports it for public API stability. Test file points at the new module directly. No behavior change: 29/29 unit cases still pass; 63 total in nxz (2 test files); workspace test suite stays at 707 passing.
oorabona
added a commit
that referenced
this pull request
Apr 30, 2026
- Curate `packages/nxz/CHANGELOG.md` v6.1.0 entry: keep the `--memlimit-decompress` Added line, drop noise from older commits the populate script picked up via the root `latestTag` baseline, add a `### Notes` section pointing at transitive `tar-xz@6.1.0` benefits (true streaming for `extract`/`list`, Win32 TOCTOU hardening, native `memlimit` parity). - TODO: mark #26 ✅ with PR #117 squash (`2e3c25f`) and release commit (`ecff028`); add LOW follow-ups for the upstream populate-script tag-baseline gap and the pre-existing `parseCliArgs` cognitive-complexity-17 refactor candidate. - Update package version matrix to reflect `nxz-cli@6.1.0`.
2 tasks
oorabona
added a commit
that referenced
this pull request
Apr 30, 2026
…#121) The PR #120 extract-method refactor introduced three defensive paths in parseSuffixed that vitest's v8 instrumentation flagged as unreachable: the '?? ""' fallbacks on regex capture groups (unreachable when exec returns non-null) and the 'mult === undefined' guard (unreachable because the regex constrains the suffix to keys present in the multiplier map). - Replace 'match[1] ?? ""' and 'match[2] ?? ""' with 'as string' type assertions: compile-time only, no runtime branch for v8 to instrument, and not flagged by biome's noNonNullAssertion rule (unlike non-null '!' which would re-introduce the lint warning we resolved in PR #117 fix-round 1). - Wrap the noUncheckedIndexedAccess-required mult-undefined guard with /* v8 ignore start ... stop */: TypeScript strict mode demands the check but the regex+map alignment makes it structurally unreachable. Project convention is start/stop pairs (never 'next'). Coverage: lines 95.2 -> 100, branches 83.3 -> 100 on memlimit.ts. 707 tests still pass byte-identical.
2 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
nxz(the CLI packaged asnxz-cli) gains a new--memlimit-decompress <SIZE>flag, matching the standardxzCLI's flag of the same name. Until now nxz calledunxzSync()andcreateUnxz()with hardcoded defaults — users had no way to cap decompression memory from the CLI even thoughnode-liblzma'sLZMAOptions.memlimithad supported it since PRs #111 (WASM) and #112 (Native).What's new
--memlimit-decompress <SIZE>, accepting plain integer bytes, IEC binary suffixes (KiB,MiB,GiB,TiB), and SI decimal suffixes (KB,MB,GB,TB).0andmax(case-insensitive) explicitly mean "no limit", matchingxzCLI semantics.parseMemlimitSize(s: string): bigint | undefinedexported fromnxz.ts. ThrowsTypeErroron malformed input.{ memlimit }through 5 decompression call sites (3×unxzSync, 1×createUnxz, 1× benchmark cross-decompress) via a singledecompressOptsvariable per function — keepsdecompressFile's cognitive complexity at 15 (was about to bump to 17 with inline ternaries).LZMAMemoryLimitErrornow surfaces as a CLI error with exit 1 when the limit is exceeded.Diff
2 files, +238 / -5 :
packages/nxz/src/nxz.ts: +101 / -5packages/nxz/test/cli.test.ts: +142 / -3Testing
7 new vitest cases :
maxand0→ no limit (nomemlimitkey in opts)TypeErrorLZMAMemoryLimitErrorthrown when limit exceeded (smoke test on real fixture)Gates :
pnpm install --frozen-lockfile✅,pnpm type-check✅,biome check packages/nxz/✅,pnpm test✅ (678 / 0 / 3 skipped, +7 new in nxz).Out-of-scope
tar-xz@6.1.0) — added post-merge as a manual[Unreleased]annotation before triggeringrelease.yml. The newGIT_CHANGELOG_PATH=.scoping (shipped via PR chore(release): scope per-package CHANGELOG via GIT_CHANGELOG_PATH #116) correctly filters out non-nxz commits, so transitive benefits need explicit annotation.--memlimit-compresswould have no effect and isn't added.Test plan
gh workflow run release.yml -f target_package=nxz-cli -f increment=minorproduces a clean v6.1.0 CHANGELOG entry scoped topackages/nxz/(no node-liblzma C++/wasm/CI leakage)nxz-cli@6.1.0exposes--memlimit-decompressinnxz --help