Repository navigation
Replace picocolors with node:util styleText - #2139
mrpmohiburrahman wants to merge 2 commits into
Conversation
picocolors was only used to color terminal output, and node:util can do
the same since styleText() landed in Node.js 20.12. The new lib/colors.js
exports a createColor(...formats) factory and an isColorSupported flag,
so the three call sites keep their text => string shape.
Formats are combined in a single call rather than nested, because Node
re-opens the parent style after a nested one only since 22.19 and 24.5.
Arrays of formats are themselves supported only since 20.13, so the
guard is a feature detect rather than a version check: on 20.12
createColor('bold', 'red') would throw ERR_INVALID_ARG_VALUE while
formatting a syntax error.
Where styleText is missing the module degrades to plain text and the
color assertions degrade with it, so the old Node legs stay green and
engines is untouched.
lib/colors.js is stubbed in the browser map, so no Node builtin reaches
the browser bundle and showSourceCode() falls back to its identity
helpers there. HIGHLIGHT_THEME stays gated on isColorSupported because
./lib/terminal-highlight is a published export whose colors were
no-ops without color support.
|
|
||
| // util.styleText() was added in Node.js 20.12, but it accepts an array | ||
| // of formats only since 20.13. Detect what we actually use. | ||
| let hasStyleText = typeof styleText === 'function' |
There was a problem hiding this comment.
No, we do not need it. We will work with >=22 in PostCSS 9.
There was a problem hiding this comment.
Done — the detect and the plain-text fallback are gone, and engines is now >=22.
Heads-up on CI: the old job now runs entirely below that floor. Node 20 still passes (setup-node resolves it to 20.19, which has styleText and the array form), but 10, 12, 14, 16 and 18 have no styleText at all, so those five legs fail by design. I left .github/workflows/ alone since that job is yours to decide on — happy to drop it here, along with test/old-node.js and the old script, if you want that in this PR.
One detail worth knowing: eslint-plugin-n still flags util.styleText because it treats it as experimental until 23.5, so I kept the node-builtins ignore entry. >=22.13 doesn't clear it either — I checked.
PostCSS 9 will work with Node.js >=22, so the feature detect and the plain-text fallback are not needed: styleText() exists since 20.12 and accepts an array of formats since 20.13, both well below the new floor. Formats are still combined in a single call, because Node re-opens the parent style after a nested one only since 22.19 and 24.5.
Fixes #2116
picocolorswas only there to color terminal output, andnode:utildoes thesame job, so this drops it from
dependencies. Newlib/colors.jsexports acreateColor(...formats)factory plus anisColorSupportedflag, modelled onthe
colors.jsin size-limit; the three call sites keep theirtext => stringshape, so
HIGHLIGHT_THEMEandshowSourceCode()are unchanged in structure.Rather than eyeball the output, I diffed it against picocolors byte for byte —
old and new
showSourceCode()andshowSourceCode(true)are identical across9 environments (piped,
FORCE_COLOR,NO_COLOR,CI,TERM=dumb,--color,and the empty-string variants of each). The empty-string cases are why the
detector uses truthiness rather than presence:
NO_COLOR=""must not disablecolor, per no-color.org and picocolors.
Two details worth flagging, both of which changed the code:
styleTextaccepts an array of formats only since 20.13, not 20.12.On 20.12.x,
createColor('bold', 'red')throwsERR_INVALID_ARG_VALUE—while formatting a syntax error, which is the worst possible moment. So the
guard is a feature detect, not a version check.
./lib/terminal-highlightis a published entry inexports, and its oldpico.yellowvalues were no-ops when color was unsupported. The theme isgated on
isColorSupportedso direct importers keep that contract.size-limitdrops 16.38 kB → 16.18 kB, so I lowered the budget to 16.25 kB.New
test/colors.test.tscovers the detection signals and the degrade path;I checked it is not vacuous by breaking the code four ways and confirming a
specific test goes red each time.
One thing I need you to decide
This is the conservative version: on Node < 20.13 the module degrades to plain
text, the color assertions degrade with it, every CI leg stays green, and
enginesis untouched. The cost is a real regression — error output losesits color on Node 14, 16, 18 and 20.0–20.12, where picocolors colored fine.
It degrades silently rather than throwing.
If 9.0 is bumping the Node floor anyway, the other version is smaller and
cleaner:
engines→>=20.13, prune theoldmatrix to 20, and delete thefallback branch entirely. I did not want to make that call on your behalf.
Say which you prefer and I will rewrite this.