arcanis / clipanion

Type-safe CLI library / framework with no runtime dependencies
https://mael.dev/clipanion/
1.11k stars 64 forks source link

Fix "TypeError: tty__default.default.WriteStream.prototype is not an Object" #147

Closed niieani closed 1 year ago

niieani commented 1 year ago

The rollup-compiled .js version of the distributable lib/platform/node.js tries to access the default property of the default export from the 'tty' package. Somehow this works in node (probably because node circularly re-wraps default export), but fails in bun, which is more strict. The code generated by Rollup is clearly invalid (offending part tty__default['default']).

This PR fixes the problem by correcting the tty import, and changing the check for getColorDepth function to be a little more permissive (WriteStream is not fully implemented in bun yet).

Original error:

 7 | function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
 8 | 
 9 | var tty__default = /*#__PURE__*/_interopDefaultLegacy(tty);
10 | 
11 | function getDefaultColorDepth() {
12 |     if (tty__default['default'] && `getColorDepth` in tty__default['default'].WriteStream.prototype)
                                       ^
TypeError: tty__default.default.WriteStream.prototype is not an Object. (evaluating '"getColorDepth" in tty__default.default.WriteStream.prototype')
      at getDefaultColorDepth (/node_modules/clipanion/lib/platform/node.js:12:35)
      at /node_modules/clipanion/lib/advanced/Cli.js:454:16
      at globalThis (/node_modules/clipanion/lib/advanced/Cli.js:462:18)

Offending code:

Screenshot 2023-08-14 at 22 56 10
niieani commented 1 year ago

@arcanis got any feedback? would love to get this merged, as it's making it impossible to use clipanion in bun without manually patching the package.

arcanis commented 1 year ago

What's the exact repro? Running the following with bun 1.0 doesn't fail for me (the code doesn't seem incorrect to me):

'use strict';

Object.defineProperty(exports, `__esModule`, {value: true});

var tty = require(`tty`);

function _interopDefaultLegacy (e) { return e && typeof e === `object` && `default` in e ? e : {default: e}; }

var tty__default = /*#__PURE__*/_interopDefaultLegacy(tty);

tty__default.default && `getColorDepth` in tty__default.default.WriteStream.prototype;

Making a require('./lib/advanced') fails, but with an error that suggests it's a bug in Bun:

82 |     }, WriteStream.prototype.clearScreenDown = function(cb) {
83 |       return (readline ??= @getInternalField(@internalModuleRegistry, 33) || @createInternalModuleById(33)).clearScreenDown(this, cb);
84 |     }, WriteStream.prototype.cursorTo = function(x, y, cb) {
85 |       return (readline ??= @getInternalField(@internalModuleRegistry, 33) || @createInternalModuleById(33)).cursorTo(this, x, y, cb);
86 |
87 |     }, WriteStream.prototype.getColorDepth = function(env = process.env) {
                                                                                                             ^
ReferenceError: Can't find variable: RegExpPrototypeExec
      at node:tty:87:106
      at getDefaultColorDepth (/Users/mael.nison/clipanion/lib/platform/node.js:13:15)
      at /Users/mael.nison/clipanion/lib/advanced/Cli.js:454:16
      at globalThis (/Users/mael.nison/clipanion/lib/advanced/Cli.js:462:18)
      at require (:1:20)
      at /Users/mael.nison/clipanion/lib/advanced/index.js:8:4
      at globalThis (/Users/mael.nison/clipanion/lib/advanced/index.js:21:17)
      at require (:1:20)
arcanis commented 1 year ago

From the look of it Bun 1.0.3 seems to work great with Clipanion, I'm going to close this PR:

$ bun init -y
$ bun add clipanion
$ cp ~/clipanion/demos/advanced.ts .
$ sed -i '' 's#../sources/advanced#clipanion#' ./advanced.ts
$ bun run ./advanced.ts

Usage Error: Invalid value for maxRetries: expected to be at least 1 (got 0)

$ yarn [--frozen-lockfile] [--max-retries #0]