Skip to content

REPL, -e, and piped stdin globals are wrong: ,missing exports, module, etc. #1282

Closed

Description

@cspotcode

Expected Behavior

ts-node --interactive -e "<expression>" should behave the same as node --interactive -e "<expression>"

-e should be evaluated with exports, etc.

Actual Behavior

exports is not defined during the evaluation of a -e expression.

Steps to reproduce the problem / Minimal reproduction

ts-node --interactive -e "console.log(exports, __filename)"
node --interactive -e "console.log(exports, __filename)"

Notes

Looks like a blind spot in our REPL logic in bin.ts We should check that all the module-specific variables, exports, __filename, etc match nodejs.

Activity

  1. cspotcode commented on Mar 22, 2021

    @cspotcode
    CollaboratorAuthor

    Seems this bit of code, which only runs when you call start(), should actually be run earlier in some of our -e codepaths.
    https://github.com/TypeStrong/ts-node/blob/main/src/repl.ts#L263-L268

  2. added this to the next milestone on May 15, 2021
  3. modified the milestones: next, 10.0.0 on May 23, 2021
  4. cspotcode commented on May 23, 2021

    @cspotcode
    CollaboratorAuthor

    Did some more research here.

    node --interactive REPL uses the global object as the REPL's scope. We opt-in to the same via the API.

    node -e '< expression >' gets access to a bunch of variables added to the global object.
    So does REPL code.

    I did a test logging the set of fields on global which are added by calling new REPLServer()

    [
      'module',      'require',             'assert',
      'async_hooks', 'buffer',              'child_process',
      'cluster',     'constants',           'crypto',
      'dgram',       'diagnostics_channel', 'dns',
      'domain',      'events',              'fs',
      'http',        'http2',               'https',
      'inspector',   'net',                 'os',
      'path',        'perf_hooks',          'punycode',
      'querystring', 'readline',            'repl',
      'stream',      'string_decoder',      'sys',
      'timers',      'tls',                 'trace_events',
      'tty',         'url',                 'util',
      'v8',          'vm',                  'worker_threads',
      'zlib',        '_',                   '_error'
    ]
    

    The modules like fs are getters, presumably for performance.

    global.__filename and global.__dirname are set for -e or -p, but only stick around on the global object if you do node -p "" -i

    __filename is [eval] for -e, [stdin] for piped input.

    stdin and -e global.module, .exports, .require, .__filename, .__dirname set.

    new REPLServer() only sets .module, .require, but includes _ and _error.

    console is not overwritten. I thought it might have been to redirect console.log() to the stdin and stdout passed to the REPL, but no.

    Looks like we need to do these things:

    • call new REPLServer() before any sort of -e, -p, -i, or piped stdin
    • set __filename and __dirname only in certain codepaths
    • choose between [eval] and [stdin] for __filename
    • Continue to always set exports because TS emitted code requires it
    • update REPL API to let you opt-out of using the global object as context
    • ensure REPL API exposes .context
    • Consider adding call to REPL API to create REPLServer without starting it
  5. cspotcode commented on May 23, 2021

    @cspotcode
    CollaboratorAuthor

    Also must be sure module.paths matches in all cases. Appears to differ between -p and repl.

    ❯ node -p '[module.id, module.paths]' -i
    Welcome to Node.js v16.1.0.
    Type ".help" for more information.
    > [
      '[eval]',
      [
        '/d/Personal-dev/@TypeStrong/ts-node/node_modules',
        '/d/Personal-dev/@TypeStrong/node_modules',
        '/d/Personal-dev/node_modules',
        '/d/node_modules',
        '/node_modules'
      ]
    ]
    > [[module.id, module.paths]
    ... [module.id, module.paths]
    ...
    > [module.id, module.paths]
    [
      '<repl>',
      [
        '/d/Personal-dev/@TypeStrong/ts-node/repl/node_modules',
        '/d/Personal-dev/@TypeStrong/ts-node/node_modules',
        '/d/Personal-dev/@TypeStrong/node_modules',
        '/d/Personal-dev/node_modules',
        '/d/node_modules',
        '/node_modules',
        '/home/cspotcode/.node_modules',
        '/home/cspotcode/.node_libraries',
        '/home/cspotcode/n/lib/node'
      ]
    ]
    >
    
  6. cspotcode commented on May 24, 2021

    @cspotcode
    CollaboratorAuthor

    Discrepancy between:

    node -p 'process.argv' ./subdir/index.ts
    ts-node -p -e 'process.argv' ./subdir/index.ts
    

    node treats the positional as an argv string, does NOT attempt to execute it.

    ts-node breaks:

    • attempts to resolve it to a file; fails if doesn't exist
    • uses the path to set the location of internal EvalState
    • TS compiler complains if it points to a file that should not be compiled
  7. cspotcode commented on May 24, 2021

    @cspotcode
    CollaboratorAuthor

    Our repl does process.exit(). We should make the REPL API raise an error somehow, and call process.exit() in response to that error in our bin.ts.

  8. changed the title [-]`ts-node --interactive -e` evaluates `-e` expression without `exports`, `module`, etc.[/-] [+]REPL, `-e`, and piped stdin globals are wrong: ,missing `exports`, `module`, etc.[/+] on May 27, 2021
  9. cspotcode commented on May 27, 2021

    @cspotcode
    CollaboratorAuthor

    Renamed to capture scope of this ticket.

  10. modified the milestones: next, 10.x.x on May 27, 2021
  11. added a commit that references this issue on Jun 8, 2021
    6266ae2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions