nodejs / node-core-test

Node 18's node:test, as an npm package

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Can we reduce dependency count to make this actiually minimal ? Readme says minimal dependencies but actually has 165 dependencies which is absolutely insane.

Raynos opened this issue · comments

  • string.prototype.replaceall seems like an excessive dependency to use here when we can use regex replace with the g parameter. ( https://stackoverflow.com/a/17606289 ) there are alternative implementations that take 4 lines instead of 30 npm packages.
  • readable-stream ; this seems excessive, it's a large package and a duplicate of require('stream')

Leaving minimist as is seems ok, but I'd also inline all the argument parsing and go for zero dependencies. But at least I understand the purpose of it.

raynos at system76-pc  
~/soundxyz/test123
$ npm ls --depth 9999 | wc -l
167

The test package claims to have minimal dependencies but has 167 transitive dependencies because string.prototype.replaceall is the literal definition of dependency hell and over engineering.

test123@1.0.0 /home/raynos/soundxyz/test123
└─┬ test@3.3.0
  ├── minimist@1.2.8
  ├─┬ readable-stream@4.4.2
  │ ├─┬ abort-controller@3.0.0
  │ │ └── event-target-shim@5.0.1
  │ ├─┬ buffer@6.0.3
  │ │ ├── base64-js@1.5.1
  │ │ └── ieee754@1.2.1
  │ ├── events@3.3.0
  │ ├── process@0.11.10
  │ └─┬ string_decoder@1.3.0
  │   └── safe-buffer@5.2.1
  └─┬ string.prototype.replaceall@1.0.7
    ├─┬ call-bind@1.0.2
    │ ├── function-bind@1.1.1
    │ └── get-intrinsic@1.2.1 deduped
    ├─┬ define-properties@1.2.0
    │ ├─┬ has-property-descriptors@1.0.0
    │ │ └── get-intrinsic@1.2.1 deduped
    │ └── object-keys@1.1.1
    ├─┬ es-abstract@1.22.1
    │ ├─┬ array-buffer-byte-length@1.0.0
    │ │ ├── call-bind@1.0.2 deduped
    │ │ └── is-array-buffer@3.0.2 deduped
    │ ├─┬ arraybuffer.prototype.slice@1.0.1
    │ │ ├── array-buffer-byte-length@1.0.0 deduped
    │ │ ├── call-bind@1.0.2 deduped
    │ │ ├── define-properties@1.2.0 deduped
    │ │ ├── get-intrinsic@1.2.1 deduped
    │ │ ├── is-array-buffer@3.0.2 deduped
    │ │ └── is-shared-array-buffer@1.0.2 deduped
    │ ├── available-typed-arrays@1.0.5
    │ ├── call-bind@1.0.2 deduped
    │ ├─┬ es-set-tostringtag@2.0.1
    │ │ ├── get-intrinsic@1.2.1 deduped
    │ │ ├── has-tostringtag@1.0.0 deduped
    │ │ └── has@1.0.3 deduped
    │ ├─┬ es-to-primitive@1.2.1
    │ │ ├── is-callable@1.2.7 deduped
    │ │ ├─┬ is-date-object@1.0.5
    │ │ │ └── has-tostringtag@1.0.0 deduped
    │ │ └─┬ is-symbol@1.0.4
    │ │   └── has-symbols@1.0.3 deduped
    │ ├─┬ function.prototype.name@1.1.5
    │ │ ├── call-bind@1.0.2 deduped
    │ │ ├── define-properties@1.2.0 deduped
    │ │ ├── es-abstract@1.22.1 deduped
    │ │ └── functions-have-names@1.2.3
    │ ├── get-intrinsic@1.2.1 deduped
    │ ├─┬ get-symbol-description@1.0.0
    │ │ ├── call-bind@1.0.2 deduped
    │ │ └── get-intrinsic@1.2.1 deduped
    │ ├─┬ globalthis@1.0.3
    │ │ └── define-properties@1.2.0 deduped
    │ ├─┬ gopd@1.0.1
    │ │ └── get-intrinsic@1.2.1 deduped
    │ ├── has-property-descriptors@1.0.0 deduped
    │ ├── has-proto@1.0.1
    │ ├── has-symbols@1.0.3 deduped
    │ ├─┬ has@1.0.3
    │ │ └── function-bind@1.1.1 deduped
    │ ├─┬ internal-slot@1.0.5
    │ │ ├── get-intrinsic@1.2.1 deduped
    │ │ ├── has@1.0.3 deduped
    │ │ └─┬ side-channel@1.0.4
    │ │   ├── call-bind@1.0.2 deduped
    │ │   ├── get-intrinsic@1.2.1 deduped
    │ │   └── object-inspect@1.12.3 deduped
    │ ├─┬ is-array-buffer@3.0.2
    │ │ ├── call-bind@1.0.2 deduped
    │ │ ├── get-intrinsic@1.2.1 deduped
    │ │ └── is-typed-array@1.1.12 deduped
    │ ├── is-callable@1.2.7
    │ ├── is-negative-zero@2.0.2
    │ ├── is-regex@1.1.4 deduped
    │ ├─┬ is-shared-array-buffer@1.0.2
    │ │ └── call-bind@1.0.2 deduped
    │ ├─┬ is-string@1.0.7
    │ │ └── has-tostringtag@1.0.0 deduped
    │ ├─┬ is-typed-array@1.1.12
    │ │ └── which-typed-array@1.1.11 deduped
    │ ├─┬ is-weakref@1.0.2
    │ │ └── call-bind@1.0.2 deduped
    │ ├── object-inspect@1.12.3
    │ ├── object-keys@1.1.1 deduped
    │ ├─┬ object.assign@4.1.4
    │ │ ├── call-bind@1.0.2 deduped
    │ │ ├── define-properties@1.2.0 deduped
    │ │ ├── has-symbols@1.0.3 deduped
    │ │ └── object-keys@1.1.1 deduped
    │ ├─┬ regexp.prototype.flags@1.5.0
    │ │ ├── call-bind@1.0.2 deduped
    │ │ ├── define-properties@1.2.0 deduped
    │ │ └── functions-have-names@1.2.3 deduped
    │ ├─┬ safe-array-concat@1.0.0
    │ │ ├── call-bind@1.0.2 deduped
    │ │ ├── get-intrinsic@1.2.1 deduped
    │ │ ├── has-symbols@1.0.3 deduped
    │ │ └── isarray@2.0.5
    │ ├─┬ safe-regex-test@1.0.0
    │ │ ├── call-bind@1.0.2 deduped
    │ │ ├── get-intrinsic@1.2.1 deduped
    │ │ └── is-regex@1.1.4 deduped
    │ ├─┬ string.prototype.trim@1.2.7
    │ │ ├── call-bind@1.0.2 deduped
    │ │ ├── define-properties@1.2.0 deduped
    │ │ └── es-abstract@1.22.1 deduped
    │ ├─┬ string.prototype.trimend@1.0.6
    │ │ ├── call-bind@1.0.2 deduped
    │ │ ├── define-properties@1.2.0 deduped
    │ │ └── es-abstract@1.22.1 deduped
    │ ├─┬ string.prototype.trimstart@1.0.6
    │ │ ├── call-bind@1.0.2 deduped
    │ │ ├── define-properties@1.2.0 deduped
    │ │ └── es-abstract@1.22.1 deduped
    │ ├─┬ typed-array-buffer@1.0.0
    │ │ ├── call-bind@1.0.2 deduped
    │ │ ├── get-intrinsic@1.2.1 deduped
    │ │ └── is-typed-array@1.1.12 deduped
    │ ├─┬ typed-array-byte-length@1.0.0
    │ │ ├── call-bind@1.0.2 deduped
    │ │ ├─┬ for-each@0.3.3
    │ │ │ └── is-callable@1.2.7 deduped
    │ │ ├── has-proto@1.0.1 deduped
    │ │ └── is-typed-array@1.1.12 deduped
    │ ├─┬ typed-array-byte-offset@1.0.0
    │ │ ├── available-typed-arrays@1.0.5 deduped
    │ │ ├── call-bind@1.0.2 deduped
    │ │ ├── for-each@0.3.3 deduped
    │ │ ├── has-proto@1.0.1 deduped
    │ │ └── is-typed-array@1.1.12 deduped
    │ ├─┬ typed-array-length@1.0.4
    │ │ ├── call-bind@1.0.2 deduped
    │ │ ├── for-each@0.3.3 deduped
    │ │ └── is-typed-array@1.1.12 deduped
    │ ├─┬ unbox-primitive@1.0.2
    │ │ ├── call-bind@1.0.2 deduped
    │ │ ├── has-bigints@1.0.2
    │ │ ├── has-symbols@1.0.3 deduped
    │ │ └─┬ which-boxed-primitive@1.0.2
    │ │   ├─┬ is-bigint@1.0.4
    │ │   │ └── has-bigints@1.0.2 deduped
    │ │   ├─┬ is-boolean-object@1.1.2
    │ │   │ ├── call-bind@1.0.2 deduped
    │ │   │ └── has-tostringtag@1.0.0 deduped
    │ │   ├─┬ is-number-object@1.0.7
    │ │   │ └── has-tostringtag@1.0.0 deduped
    │ │   ├── is-string@1.0.7 deduped
    │ │   └── is-symbol@1.0.4 deduped
    │ └─┬ which-typed-array@1.1.11
    │   ├── available-typed-arrays@1.0.5 deduped
    │   ├── call-bind@1.0.2 deduped
    │   ├── for-each@0.3.3 deduped
    │   ├── gopd@1.0.1 deduped
    │   └── has-tostringtag@1.0.0 deduped
    ├─┬ get-intrinsic@1.2.1
    │ ├── function-bind@1.1.1 deduped
    │ ├── has-proto@1.0.1 deduped
    │ ├── has-symbols@1.0.3 deduped
    │ └── has@1.0.3 deduped
    ├── has-symbols@1.0.3
    └─┬ is-regex@1.1.4
      ├── call-bind@1.0.2 deduped
      └─┬ has-tostringtag@1.0.0
        └── has-symbols@1.0.3 deduped

I'm being a little bit unfair

aynos at system76-pc  
~/soundxyz/test123
$ npm ls --depth 9999 | grep -v deduped
test123@1.0.0 /home/raynos/soundxyz/test123
└─┬ test@3.3.0
  ├── minimist@1.2.8
  ├─┬ readable-stream@4.4.2
  │ ├─┬ abort-controller@3.0.0
  │ │ └── event-target-shim@5.0.1
  │ ├─┬ buffer@6.0.3
  │ │ ├── base64-js@1.5.1
  │ │ └── ieee754@1.2.1
  │ ├── events@3.3.0
  │ ├── process@0.11.10
  │ └─┬ string_decoder@1.3.0
  │   └── safe-buffer@5.2.1
  └─┬ string.prototype.replaceall@1.0.7
    ├─┬ call-bind@1.0.2
    │ ├── function-bind@1.1.1
    ├─┬ define-properties@1.2.0
    │ ├─┬ has-property-descriptors@1.0.0
    │ └── object-keys@1.1.1
    ├─┬ es-abstract@1.22.1
    │ ├─┬ array-buffer-byte-length@1.0.0
    │ ├─┬ arraybuffer.prototype.slice@1.0.1
    │ ├── available-typed-arrays@1.0.5
    │ ├─┬ es-set-tostringtag@2.0.1
    │ ├─┬ es-to-primitive@1.2.1
    │ │ ├─┬ is-date-object@1.0.5
    │ │ └─┬ is-symbol@1.0.4
    │ ├─┬ function.prototype.name@1.1.5
    │ │ └── functions-have-names@1.2.3
    │ ├─┬ get-symbol-description@1.0.0
    │ ├─┬ globalthis@1.0.3
    │ ├─┬ gopd@1.0.1
    │ ├── has-proto@1.0.1
    │ ├─┬ has@1.0.3
    │ ├─┬ internal-slot@1.0.5
    │ │ └─┬ side-channel@1.0.4
    │ ├─┬ is-array-buffer@3.0.2
    │ ├── is-callable@1.2.7
    │ ├── is-negative-zero@2.0.2
    │ ├─┬ is-shared-array-buffer@1.0.2
    │ ├─┬ is-string@1.0.7
    │ ├─┬ is-typed-array@1.1.12
    │ ├─┬ is-weakref@1.0.2
    │ ├── object-inspect@1.12.3
    │ ├─┬ object.assign@4.1.4
    │ ├─┬ regexp.prototype.flags@1.5.0
    │ ├─┬ safe-array-concat@1.0.0
    │ │ └── isarray@2.0.5
    │ ├─┬ safe-regex-test@1.0.0
    │ ├─┬ string.prototype.trim@1.2.7
    │ ├─┬ string.prototype.trimend@1.0.6
    │ ├─┬ string.prototype.trimstart@1.0.6
    │ ├─┬ typed-array-buffer@1.0.0
    │ ├─┬ typed-array-byte-length@1.0.0
    │ │ ├─┬ for-each@0.3.3
    │ ├─┬ typed-array-byte-offset@1.0.0
    │ ├─┬ typed-array-length@1.0.4
    │ ├─┬ unbox-primitive@1.0.2
    │ │ ├── has-bigints@1.0.2
    │ │ └─┬ which-boxed-primitive@1.0.2
    │ │   ├─┬ is-bigint@1.0.4
    │ │   ├─┬ is-boolean-object@1.1.2
    │ │   ├─┬ is-number-object@1.0.7
    │ └─┬ which-typed-array@1.1.11
    ├─┬ get-intrinsic@1.2.1
    ├── has-symbols@1.0.3
    └─┬ is-regex@1.1.4
      └─┬ has-tostringtag@1.0.0

raynos at system76-pc  
~/soundxyz/test123
$ npm ls --depth 9999 | grep -v deduped | wc -l
69

It's only 67 dependencies, not 167.

util.parseArgs exists now, so that seems like a viable way to replace minimist, at least.

Oh wow i didn't know that, I've been using horrible horrible code for a while now

const IS_DRY_RUN = process.argv.includes('--dry-run', 1);

// or 
  const maxSizeArg = argv.find(x => x.startsWith('--max-size='))
  const maxSize = maxSizeArg && maxSizeArg.split('=')[1]

Although util.parseArgs does not match nodejs 14 so it breaks compat. Where as require('stream') is pretty stable since nodejs 14.

The readable-stream package was more a streams 1 / 2 / 3 ; for nodejs 0.8 0.10 0.12 4.0 artifact.

  • please refrain from judgements like "insane", we all have different ways to write programs
  • I agree the dependency tree of string.prototype.replaceall could be optimized. I have chosen it because i expect it to behave as close to the original as possible, with any kind of argument types provided
    • if we drop node 14 support (out of maintanance) we can remove it
    • otherwise, finding a replacement that is 100% correct could be tricky
  • +1 to using util.parseArgs, and creating a ponyfill for older node versions
  • we're using readable-stream because some imports reach deep into its files, impossible (or risky) with core
> require('stream/lib/internal/streams/operators')
Uncaught Error: Cannot find module 'stream/lib/internal/streams/operators'

replaceAll exists Natively in Node.js 16+ which itself is soon EoL, we should just use the native versions probably.

@juliangruber re string.prototype.replaceall, i doubt it can be while retaining the same robustness, back compat, and correctness, but i'm certainly open to PRs.

With Node.js 16.x EoL in about two weeks, and v18.x having an (almost?) up-to-date version of the test runner, maybe we should consider making this package a simple wrapper around the native node:test.
EDIT: oops, that's what Ben has suggested already, sorry for the duplicate comment

Great, then I see a path towards this package having zero dependencies. which is exciting.

@Raynos now would be a good time to say that PRs are welcome :)

I'll open a PR if I get time or it becomes my problem.

Right now my problem is that I use ava and that's a big problem. using test would be a step in the right direction, need to implement a codemod to auto port all the tests 😢