Conversation
|
closes #54 |
There was a problem hiding this comment.
Pull request overview
This PR modernizes the repository’s test infrastructure by moving from Jest/Babel-based testing to Node’s native node:test runner, while cleaning up now-unused tooling and clarifying the README’s description of long stack trace parsing. In the broader codebase, it keeps the published runtime module unchanged and focuses the changes on tests, CI, packaging metadata, and docs.
Changes:
- Migrates the existing test suites from Jest assertions/APIs to
node:testandnode:assert/strict. - Removes obsolete test tooling/config (
jest,babel-jest, Babel config, andlong-stack-traces) and updates package metadata/lockfile accordingly. - Simplifies CI and updates README text around dashed async-boundary marker parsing.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| package.json | Switches the test script to node --test, removes test-tooling deps/config, and updates engine metadata. |
| package-lock.json | Lockfile is reduced to root package metadata after dependency cleanup. |
| tests/parse-test.js | Converts parser behavior tests from Jest to native Node test/assert APIs. |
| tests/long-stack-trace-test.js | Replaces the dependency-based async stack test with a deterministic synthetic stack test. |
| tests/get-test.js | Converts get() behavior tests to native Node test/assert APIs. |
| Readme.md | Clarifies long-stack-trace behavior and cleans up V8 API link wording. |
| .npmignore | Removes stale ignore entries and excludes .github/ from the package payload. |
| .github/workflows/test.yml | Simplifies the CI job to just set up Node and run npm test. |
| .babelrc | Deletes the now-unused Babel configuration. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 9 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| }, | ||
| "engines": { | ||
| "node": ">=18.14.0" | ||
| "node": ">=20.0.0" |
| indentation. All other methods of the event loop boundary call site return | ||
| `null`. |
| assert.notStrictEqual(boundary, undefined); | ||
| assert.match(boundary.getFileName(), /-----/); |
|
|
||
| setTimeout(badFn, 10); | ||
| assert.notStrictEqual(boundary, undefined); | ||
| assert.match(boundary.getFileName(), /-----/); |
| @@ -113,29 +125,24 @@ describe("parse", () => { | |||
| realValue = exceptions[i]; | |||
| } | |||
- Fix issue #29: parse() now captures source location from SyntaxError stacks where V8 puts the file:line(:col) as the first line instead of an error message. This is returned as the first CallSite frame. - Revert engines.node to >=20.0.0 - Fix README: 'All other methods' -> 'The other getter-style methods' (boolean predicates return false, not null) - Add full boundary-frame contract assertions to long-stack-trace test - Remove dead 'exceptions' parameter from compare() in parse-test - Add regression test for issue #13 ([object Object] in function name) -- confirmed already working with current regex - Add verification test for issue #25 (async/await) -- confirmed resolved on modern Node via V8 async stack traces - Comprehensive test coverage for #29: SyntaxError with/without column, Windows paths, and non-regression for normal Error/TypeError/RangeError Closes #13 Closes #25 Closes #29
- Fix issue #29: parse() now captures source location from SyntaxError stacks where V8 puts the file:line(:col) as the first line instead of an error message. This is returned as the first CallSite frame. - Source location detection uses robust guards: * Excludes lines with ': ' (colon+space) which indicates error messages * Excludes URL schemes (http://, https://, etc.) * Regex is safe from ReDoS (non-greedy with anchored terminus) - Refactored parse() internals from map+filter to forEach+push: * Identical output behavior (verified with tests) * Slightly more memory efficient (1 array vs 2 intermediate arrays) * Fully compatible with Node 20+ - Keep engines.node at >=20.0.0 - Fix README: 'All other methods' -> 'The other getter-style methods' (boolean predicates return false, not null) - Add full boundary-frame contract assertions to long-stack-trace test - Remove dead 'exceptions' parameter from compare() in parse-test - Add regression test for issue #13 ([object Object] in function name) -- confirmed already working with current regex - Add verification test for issue #25 (async/await) -- confirmed resolved on modern Node via V8 async stack traces - Comprehensive test coverage for #29: SyntaxError with/without column, Windows paths, non-regression for Error/TypeError/RangeError, custom error types, URL schemes, adversarial ReDoS inputs, forEach output equivalence, and memory/shared-state safety Closes #13 Closes #25 Closes #29
ISSUE #29: parse() now captures leading source-location lines - CJS SyntaxError stacks (require() on invalid files) begin with '/path/to/file.cjs:line[:col]' before the error message. This line was previously lost; it is now returned as the first CallSite frame. - Detection guards (both required to identify a source loc): 1. /:\s/ — all error messages contain ': ' (colon+space); source location lines never do. 2. /^(?:https?|ftp|data|blob):\/\// — excludes web URL schemes but explicitly permits file:// (valid source loc in some envs). - Verified against actual Node 25.9 stacks; format stable since Node 10. - ESM SyntaxErrors produce a standard 'SyntaxError: message' first line (no source location prepended) — no change needed for that path. BEFORE/AFTER VERIFICATION: - Against master index.js: exactly 5 [REQUIRES FIX] tests fail. - Against patched index.js: all 35 tests pass. CODE CHANGE: map+filter → forEach+push - forEach+push produces identical output (no falsy entries ever pushed; non-matching lines return early without pushing — equivalent to the prior .filter(Boolean) step). - Verified by test 'non-parseable lines produce no entries in output array'. - Eliminates one intermediate array allocation per parse() call. - All forEach/push/Array APIs stable since ES5; fully Node 20 compatible. SECURITY: ReDoS analysis - /at (?:(.+?)\s+\()?(?:(.+?):(\d+)(?::(\d+))?|([^)]+))\)?/ No nested quantifiers. Non-greedy .+? with concrete anchors. - /^(.+?):(\d+)(?::(\d+))?$/ Non-greedy .+? anchored by $ terminus. Tested at 50KB: <1ms. - Both regexes have dedicated adversarial timing tests. OTHER CHANGES: - engines.node: >=20.0.0 (unchanged) - README: 'All other methods' -> 'The other getter-style methods' (bool predicates return false, not null, for boundary frames) - long-stack-trace test: full boundary-frame contract assertions - parse-test: remove dead 'exceptions' param from compare() - Regression test for #13 ([object Object] in function name) - Verification test for #25 (async/await) — resolved since Node 12 Closes #13 Closes #25 Closes #29
* fix: address PR #66/#67 review, fix #29, verify #13 and #25 ISSUE #29: parse() now captures leading source-location lines - CJS SyntaxError stacks (require() on invalid files) begin with '/path/to/file.cjs:line[:col]' before the error message. This line was previously lost; it is now returned as the first CallSite frame. - Detection guards (both required to identify a source loc): 1. /:\s/ — all error messages contain ': ' (colon+space); source location lines never do. 2. /^(?:https?|ftp|data|blob):\/\// — excludes web URL schemes but explicitly permits file:// (valid source loc in some envs). - Verified against actual Node 25.9 stacks; format stable since Node 10. - ESM SyntaxErrors produce a standard 'SyntaxError: message' first line (no source location prepended) — no change needed for that path. BEFORE/AFTER VERIFICATION: - Against master index.js: exactly 5 [REQUIRES FIX] tests fail. - Against patched index.js: all 35 tests pass. CODE CHANGE: map+filter → forEach+push - forEach+push produces identical output (no falsy entries ever pushed; non-matching lines return early without pushing — equivalent to the prior .filter(Boolean) step). - Verified by test 'non-parseable lines produce no entries in output array'. - Eliminates one intermediate array allocation per parse() call. - All forEach/push/Array APIs stable since ES5; fully Node 20 compatible. SECURITY: ReDoS analysis - /at (?:(.+?)\s+\()?(?:(.+?):(\d+)(?::(\d+))?|([^)]+))\)?/ No nested quantifiers. Non-greedy .+? with concrete anchors. - /^(.+?):(\d+)(?::(\d+))?$/ Non-greedy .+? anchored by $ terminus. Tested at 50KB: <1ms. - Both regexes have dedicated adversarial timing tests. OTHER CHANGES: - engines.node: >=20.0.0 (unchanged) - README: 'All other methods' -> 'The other getter-style methods' (bool predicates return false, not null, for boundary frames) - long-stack-trace test: full boundary-frame contract assertions - parse-test: remove dead 'exceptions' param from compare() - Regression test for #13 ([object Object] in function name) - Verification test for #25 (async/await) — resolved since Node 12 Closes #13 Closes #25 Closes #29 * fix: allow file:// source locations in parse(); fix CI on Node 24 RCA: The source-location URL guard /^\w+:\/\// was too broad — it excluded 'file://' scheme URLs which are valid source location prefixes. This caused the 'file:// source location is captured correctly' test to fail on Node 24 (and 25 in CI) because file:///path:line was rejected before being captured as a source-loc frame. Fix: Change the URL exclusion from /^\w+:\/\// to /^(?:https?|ftp|data|blob):\/\// so that file:// is intentionally permitted while network/data URL schemes are still excluded. node: scheme paths (node:internal/...) do not use '://' and are already handled correctly. Also: expand the source-location comment block to document: - All supported path formats (POSIX, Windows, file://) - The two detection guards and why each works - ESM vs CJS SyntaxError behaviour differences - Tested on Node 24.x and 25.x (matches CI matrix) - Verified against @exceptionless/node package test suite * updated git ignore * fix: address Copilot review #9 — node: scheme guard, async throw, comment accuracy, ReDoS threshold - index.js: add 'node:' to URL scheme exclusion guard so paths like 'node:internal/modules/...' are never misclassified as source locations - index.js: tighten comment wording — 'always' was inaccurate for empty-message errors (new Error().stack → 'Error' with no colon+space; the source-loc regex already rejects such lines, but the comment was misleading) - get-test.js: fix async/await test to genuinely cross an async suspension point (await Promise.resolve() before throw) and use try/catch so V8 attaches the async context; match 'async outerAsync' prefix via .includes() - parse-test.js: relax ReDoS timing threshold from 100ms → 1000ms; 100ms was brittle on loaded CI runners — true ReDoS takes seconds to minutes * fix: use Number.isNaN check instead of || null for parseInt results parseInt(...) || null coerces 0 to null because 0 is falsy. Column numbers can legitimately be 0 in some tooling. Replace with explicit NaN guard: Number.isNaN(n) ? null : n Added regression test: 'SyntaxError CJS: column number 0 is preserved'. * fix: correctly exclude node: specifiers from source-loc detection The guard !firstLine.match(/^(?:https?|ftp|data|blob|node):\\/\\//) only matched 'node://' (with slashes) but Node built-in specifiers use 'node:' without '//'. Fix: add separate !firstLine.match(/^node:/) check. Update comment to clarify that node: and node:// are different formats. Add regression test: 'node: specifier is not treated as source loc'. * chore: clean up test markers and use startsWith for node: guard - index.js: replace !firstLine.match(/^node:/) with !firstLine.startsWith('node:') for clarity and performance; update comment for guard #2 - parse-test.js: remove [REQUIRES FIX], [REGRESSION], [SECURITY]/ReDoS markers — tests are verified and shipping; remove '— possible ReDoS' from timing assert messages * Apply suggestion from @niemyjski * Apply suggestion from @niemyjski * fix: consistent Number.isNaN guard for at-frame parseInt; trim comment block - Apply Number.isNaN(n) ? null : n to lineNumber and columnNumber in the at-frame parsing path for consistency with the source-loc frame fix. parseInt() || null coerces 0 to null; 0 is a valid column number. - Trim the 20-line source-loc comment block to 6 lines — this package ships source without minification, so large comments go to consumers. * fix: use node:test built-in timeout option instead of wall-clock assertions
Summary
This PR migrates the test suite from Jest+Babel to native Node.js test APIs, removes unmaintained/unused test tooling dependencies, keeps CI on Node 24.x and 25.x only, and updates docs to reflect current long-stack-trace behavior.
Primary goals addressed:
Why These Changes
1) Move to native Node test APIs
node --testreduces toolchain complexity and maintenance overhead.test/expecttonode:test+node:assert/strictwith equivalent assertions.2) Remove Babel/Jest and related artifacts
3) Remove
long-stack-tracesdependency from testslong-stack-tracesis unmaintained, and its suggested replacement (longjohn) is also effectively stale.4) Keep CI matrix exactly as requested: Node 24.x and 25.x
24.xand25.xonly.5) README clarification for long stack traces
long-stack-tracesand still supports dashed boundary marker parsing when present.File-by-File Rationale
Tests migrated to native APIs
__tests__/get-test.jsnode:testandnode:assert/strict.import.meta.urlbecause modern Node ESM stacks report file URLs.__tests__/parse-test.jsget()andnew Error()capture at different source positions.__tests__/long-stack-trace-test.jslong-stack-traces.Tooling and dependency cleanup
package.jsonjesttonode --test.>=20.0.0.package-lock.json.babelrc.npmignore.babelrcand.travis.yml.CI + docs
.github/workflows/test.yml24.xand25.xonly.Readme.mdValidation Performed
npm test: 16/16 passing.npx -y node@24 --test: 16/16 passing.npx -y -p node@25 node --test: 16/16 passing.npm pack --dry-runincludes only expected files:LicenseReadme.mdindex.jspackage.jsonCommits (logical steps)
test: migrate suites to node:test and assertchore: drop jest babel and long-stack-traces dependenciesci/docs: keep node 24/25 matrix and clarify long-stack trace supportRisk Assessment
index.js) is unchanged.