Skip to content

fix(ext/node): expose internal/util/debuglog and add formatTime helper - #33665

Merged
bartlomieju merged 1 commit into
denoland:mainfrom
nathanwhitbot:fix/node-compat-iter66
Apr 30, 2026
Merged

bartlomieju merged 1 commit into
denoland:mainfrom
nathanwhitbot:fix/node-compat-iter66

Conversation

@nathanwhitbot

Copy link
Copy Markdown
Contributor

Summary

require('internal/util/debuglog') was unmapped, so any code reaching for formatTime/debuglog from the internal path got Error: Cannot find module 'internal/util/debuglog'. The polyfill at ext/node/polyfills/internal/util/debuglog.ts already implements debuglog, but the module was never wired into 01_require.js's internal-builtin map and never exported formatTime.

This change:

  • Adds internal/util/debuglog to 01_require.js so --expose-internals code can require('internal/util/debuglog').
  • Adds formatTime(ms) to internal/util/debuglog.ts, matching lib/internal/util/debuglog.js (the helper backing console.time* formatting in Node).

Enables parallel/test-console-formatTime.js.

Test plan

  • cargo test --test node_compat -- test-console-formatTime (passes)
  • Full cargo test --test node_compat on Linux — only pre-existing flaky failures (test-process-threadCpuUsage-worker-threads.js, test-dgram-send-cb-quelches-error.js, test-child-process-uid-gid.js, test-net-autoselectfamily.js, test-inspector-close-worker.js).

@nathanwhitbot
nathanwhitbot force-pushed the fix/node-compat-iter66 branch from 2a511e2 to ae88cf8 Compare April 29, 2026 03:05
@nathanwhitbot

Copy link
Copy Markdown
Contributor Author

Force-pushed ae88cf89b — branch had the same stale c00154065 (fs.watch signal option from #33650) as a base. Reset to upstream/main and cherry-picked just the iter66 commit. Diff is now 01_require.js (+8 -6) + internal/util/debuglog.ts (+44 -1) + config.jsonc (+1).

@nathanwhitbot nathanwhitbot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-review of `ae88cf89b`:

`formatTime` parity with Node (`lib/internal/util/debuglog.js:153-185`):

  • Constants `kSecond`/`kMinute`/`kHour` match. ✓
  • Branch structure (`ms >= kSecond` → `ms >= kMinute` → `ms >= kHour`) and the `hours = floor(ms/kHour); ms %= kHour` pattern match.
  • The `hours !== 0 || minutes !== 0` formatting branch produces `${res}:${pad(seconds)}.${ms} (${hours !== 0 ? "h:m" : ""}m:ss.mmm)` — same string layout, including the conditional `h:m` prefix.
  • Node uses primordials (`StringPrototypeSplit`, `NumberPrototypeToFixed`, `MathFloor`); ours uses `.toFixed`/`.split`/`Math.floor` directly. Behaviorally identical, deviates from the `prefer-primordials` lint policy only for the new code — happy to switch to primordials if the lint flags it. (The existing `debuglog` impl in this file already uses `.toFixed`/`Number.prototype` directly without primordials.)

`01_require.js` wiring:

  • Import + `setupBuiltinModules` map entry `"internal/util/debuglog": internalUtilDebuglog` mirrors the existing `internal/util/inspect` and `internal/util` entries. ✓
  • Default export `{ debuglog, formatTime }` is what the `require('internal/util/debuglog')` callers expect.

`Module.prototype.require` validation upgrade:
Replaced two TODO-marked generic `TypeError`s with the proper Node errors (`lib/internal/modules/cjs/loader.js:1567-1571`):

Before After Node
`new TypeError("Invalid argument type")` for non-string `id` `new internalErrors.ERR_INVALID_ARG_TYPE("id", "string", id)` `validateString(id, 'id')` (which throws ERR_INVALID_ARG_TYPE)
`new TypeError("id must be non empty")` for empty `id` `new internalErrors.ERR_INVALID_ARG_VALUE("id", id, "must be a non-empty string")` `new ERR_INVALID_ARG_VALUE('id', id, 'must be a non-empty string')`

`internalErrors` was already imported on line 129; both error classes are used elsewhere in this file (lines 698, 854, 882, 921). Resolves the TODO comments that flagged exactly this issue.

Test enrollment: `parallel/test-console-formatTime.js` is alphabetically positioned between `test-console-async-write-error.js` and `test-console-group.js`. ✓

LGTM, holding to COMMENT until CI completes.

@nathanwhitbot nathanwhitbot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single-commit PR, no scope-creep. Reviewed against Node:

  • formatTime (debuglog.ts): direct port of lib/internal/util/debuglog.js#L149-185 — same kSecond/kMinute/kHour constants, identical branch structure, output strings match (m:ss.mmm/h:mm:ss.mmm/Ns/Nms). The non-primordials use (Math.floor, Number, padStart, toFixed) matches the file's existing // deno-lint-ignore-file prefer-primordials.
  • 01_require.js: internal/util/debuglog mapping matches the existing pattern for internal/util and internal/util/inspect.
  • Default export now includes formatTime alongside debuglog so require('internal/util/debuglog').formatTime works.

LGTM.

@fibibot fibibot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Substance is right.

Verified the formatTime port is faithful to upstream lib/internal/util/debuglog.js:

  • Same kSecond/kMinute/kHour thresholds, same nested-if descending into hours/minutes/seconds
  • Same seconds.toFixed(3).split(".") shape; the local code uses String.prototype.split (a non-primordial) where upstream uses StringPrototypeSplit from primordials, but // deno-lint-ignore-file prefer-primordials at the top of the file (line 5) sanctions that — same opt-out the rest of the existing debuglog.ts already uses.
  • Same fallback rendering hierarchy: ≥ 1 minute → [h:]m:ss.mmm (h:mm:ss.mmm) shape, ≥ 1 second → Ns, otherwise → Nms. ✓

The 01_require.js wiring adds internal/util/debuglog to both the import list and the setupBuiltinModules map. --expose-internals callers can now require('internal/util/debuglog') and get both debuglog (existing) and formatTime (new) off the default export. ✓

pad(value) shadowing concern: the helper takes number | string and uses template-literal coercion + padStart(2, "0") — works for both branches the new code takes (pad(minutes) numeric, pad(secondsStr) already-stringified). ✓

Test enrollment alphabetically positioned correctly (test-console-async-write-error < test-console-formatTime < test-console-group). ✓

CI

52 success, 0 failure, 13 still pending. Holding to COMMENT per the CI-must-complete rule. Substance is straightforward; happy to flip to APPROVE once test node_compat debug × 6 platforms (the shard that runs test-console-formatTime) lands green.

@bartlomieju
bartlomieju merged commit ad37338 into denoland:main Apr 30, 2026
136 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants