Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: TypeStrong/ts-node
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v6.0.0
Choose a base ref
...
head repository: TypeStrong/ts-node
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v8.0.2
Choose a head ref

Commits on Apr 17, 2018

  1. Copy the full SHA
    4385d96 View commit details

Commits on Apr 26, 2018

  1. Add -T CLI option (#577)

    steadicat authored and blakeembrey committed Apr 26, 2018
    Copy the full SHA
    c691e49 View commit details
  2. 6.0.1

    blakeembrey committed Apr 26, 2018
    Copy the full SHA
    3085eaa View commit details

Commits on Apr 29, 2018

  1. Copy the full SHA
    56256e5 View commit details
  2. 6.0.2

    blakeembrey committed Apr 29, 2018
    Copy the full SHA
    876d3cb View commit details

Commits on May 3, 2018

  1. Copy the full SHA
    5af28ee View commit details

Commits on May 6, 2018

  1. Update @types/node

    blakeembrey committed May 6, 2018
    Copy the full SHA
    3a40962 View commit details
  2. Copy the full SHA
    7a58901 View commit details
  3. 6.0.3

    blakeembrey committed May 6, 2018
    Copy the full SHA
    df41bdb View commit details

Commits on May 24, 2018

  1. Copy the full SHA
    45664e7 View commit details
  2. Use Buffer.from

    blakeembrey committed May 24, 2018
    Copy the full SHA
    4f40026 View commit details
  3. 6.0.4

    blakeembrey committed May 24, 2018
    Copy the full SHA
    98d72ce View commit details
  4. Copy the full SHA
    33aca82 View commit details
  5. 6.0.5

    blakeembrey committed May 24, 2018
    Copy the full SHA
    e2e3eaf View commit details

Commits on May 26, 2018

  1. Copy the full SHA
    2e44bc0 View commit details
  2. Copy the full SHA
    6c610b4 View commit details

Commits on May 30, 2018

  1. Document -T alias in README (#600)

    capaj authored and blakeembrey committed May 30, 2018
    Copy the full SHA
    70d68ef View commit details

Commits on Jun 3, 2018

  1. Copy the full SHA
    57f09b5 View commit details
  2. 6.1.0

    blakeembrey committed Jun 3, 2018
    Copy the full SHA
    ee5c1b3 View commit details

Commits on Jun 12, 2018

  1. Copy the full SHA
    1063e28 View commit details
  2. Copy the full SHA
    8a1cbe0 View commit details
  3. 6.1.1

    blakeembrey committed Jun 12, 2018
    Copy the full SHA
    e034830 View commit details

Commits on Jun 17, 2018

  1. Add logo (#607)

    kumarashwin authored and blakeembrey committed Jun 17, 2018
    Copy the full SHA
    8a6da5a View commit details
  2. Show logo on README

    blakeembrey committed Jun 17, 2018
    Copy the full SHA
    a9cbbb2 View commit details
  3. Copy the full SHA
    22915fd View commit details

Commits on Jun 20, 2018

  1. Use buffer-from (#610)

    burnnat authored and blakeembrey committed Jun 20, 2018
    Copy the full SHA
    80f25fe View commit details
  2. Copy the full SHA
    b751d82 View commit details
  3. 6.1.2

    blakeembrey committed Jun 20, 2018
    Copy the full SHA
    f645d9e View commit details

Commits on Jun 22, 2018

  1. Copy the full SHA
    14c7e26 View commit details
  2. 6.2.0

    blakeembrey committed Jun 22, 2018
    Copy the full SHA
    f260591 View commit details
  3. 4
    Copy the full SHA
    33cb1b5 View commit details
  4. 7.0.0

    blakeembrey committed Jun 22, 2018
    Copy the full SHA
    6ce7c97 View commit details

Commits on Jun 25, 2018

  1. Copy the full SHA
    c692f94 View commit details
  2. Copy the full SHA
    ff8ed42 View commit details

Commits on Jun 29, 2018

  1. Copy the full SHA
    55741b6 View commit details

Commits on Jul 14, 2018

  1. Copy the full SHA
    743e80f View commit details

Commits on Jul 21, 2018

  1. Copy the full SHA
    2017b3a View commit details

Commits on Aug 7, 2018

  1. Copy the full SHA
    6df09a9 View commit details

Commits on Aug 11, 2018

  1. 7.0.1

    blakeembrey committed Aug 11, 2018
    Copy the full SHA
    ad6183a View commit details

Commits on Sep 11, 2018

  1. Add missing word to README (#680)

    Psidium authored and blakeembrey committed Sep 11, 2018
    Copy the full SHA
    3ff4a69 View commit details

Commits on Oct 7, 2018

  1. Copy the full SHA
    77eff53 View commit details
  2. Copy the full SHA
    9d15a72 View commit details
  3. Copy the full SHA
    df1ac1d View commit details
  4. Copy the full SHA
    b61c745 View commit details
  5. Copy the full SHA
    ebe239a View commit details

Commits on Oct 19, 2018

  1. Use prettier screenshot (#710)

    abraham authored and blakeembrey committed Oct 19, 2018
    Copy the full SHA
    132e569 View commit details

Commits on Oct 30, 2018

  1. Copy the full SHA
    5ee273e View commit details

Commits on Oct 31, 2018

  1. Copy the full SHA
    d58488b View commit details

Commits on Jan 21, 2019

  1. Remove unused code (#751)

    3mard authored and blakeembrey committed Jan 21, 2019
    Copy the full SHA
    abcb13b View commit details
  2. Copy the full SHA
    f148008 View commit details
Showing with 850 additions and 661 deletions.
  1. +0 −1 .gitignore
  2. +4 −3 .travis.yml
  3. +73 −22 README.md
  4. +180 −0 logo.svg
  5. +276 −267 package-lock.json
  6. +14 −20 package.json
  7. BIN screenshot.png
  8. +111 −103 src/bin.ts
  9. +42 −16 src/index.spec.ts
  10. +116 −224 src/index.ts
  11. +8 −4 tests/allow-js/with-jsx.jsx
  12. +4 −0 tests/child-process.ts
  13. +3 −0 tests/custom-types.ts
  14. 0 tests/empty.ts
  15. +5 −1 tests/tsconfig.json
  16. +11 −0 tests/tsconfig.json5
  17. +3 −0 tests/typings/does-not-exist/index.d.ts
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
node_modules/
bower_components/
coverage/
.DS_Store
npm-debug.log
7 changes: 4 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -10,15 +10,16 @@ before_install:

script:
- npm run lint
- npm run build
- npm rm tslint
- npm install $TYPESCRIPT --force
- npm run test-cov

env:
- NODE=8 TYPESCRIPT=typescript@2.0
- NODE=6 TYPESCRIPT=typescript@latest
- NODE=8 TYPESCRIPT=typescript@latest
- NODE=8 TYPESCRIPT=typescript@next
- NODE=stable TYPESCRIPT=typescript@latest
- NODE=stable TYPESCRIPT=typescript@2.0
- NODE=stable TYPESCRIPT=typescript@next

node_js:
- stable
95 changes: 73 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
# TypeScript Node
# ![TypeScript Node](logo.svg)

[![NPM version][npm-image]][npm-url]
[![NPM downloads][downloads-image]][downloads-url]
[![Build status][travis-image]][travis-url]
[![Test coverage][coveralls-image]][coveralls-url]

> TypeScript execution and REPL for node. **Works with `typescript@>=2.0`**.
> TypeScript execution and REPL for node.js, with source map support. **Works with `typescript@>=2.0`**.
## Installation

```sh
# Locally in your project.
npm install -D ts-node
npm install -D typescript

# Or globally.
npm install -g ts-node
npm install -g typescript
```

## Features

* Execute TypeScript files with node
* Interactive REPL
* Execute (and print) TypeScript through the CLI
* Source map support
* Loads compiler options from `tsconfig.json`
**Tip:** Installing modules locally allows you to control and share the versions through `package.json`.

## Usage

@@ -35,7 +33,7 @@ ts-node
ts-node -e 'console.log("Hello, world!")'

# Execute, and print, code with TypeScript.
ts-node -p '"Hello, world!"'
ts-node -p -e '"Hello, world!"'

# Pipe scripts to execute with TypeScript.
echo "console.log('Hello, world!')" | ts-node
@@ -91,13 +89,17 @@ Create a new node.js configuration, add `-r ts-node/register` to node args and m

## How It Works

**TypeScript Node** works by registering the TypeScript compiler for `.tsx?` and `.jsx?` extension (when `allowJs == true`). When node.js has an extension registered (via `require.extensions`), it will use the extension internally for module resolution. When an extension is unknown to node.js, it handles the file as `.js` (JavaScript).
**TypeScript Node** works by registering the TypeScript compiler for `.tsx?` and `.jsx?` (when `allowJs == true`) extensions. When node.js has an extension registered (via `require.extensions`), it will use the extension internally for module resolution. When an extension is unknown to node.js, it handles the file as `.js` (JavaScript). By default, **TypeScript Node** avoids compiling files in `/node_modules/` for three reasons:

1. Modules should always be published in a format node.js can consume
2. Transpiling the entire dependency tree will make your project slower
3. Differing behaviours between TypeScript and node.js (e.g. ES2015 modules) can result in a project that works until you decide to support a feature natively from node.js

**P.S.** This means if you don't register an extension, it is compiled as JavaScript. When `ts-node` is used with `allowJs`, JavaScript files are transpiled using the TypeScript compiler.

## Loading `tsconfig.json`

**Typescript Node** loads `tsconfig.json` automatically. Use `--skip-project` to the loading `tsconfig.json`.
**Typescript Node** loads `tsconfig.json` automatically. Use `--skip-project` to skip loading the `tsconfig.json`.

**Tip**: You can use `ts-node` together with [tsconfig-paths](https://www.npmjs.com/package/tsconfig-paths) to load modules according to the `paths` section in `tsconfig.json`.

@@ -120,23 +122,72 @@ Supports `--print`, `--eval` and `--require` from [node.js CLI options](https://

_Environment variable denoted in parentheses._

* `--transpileOnly` Use TypeScript's faster `transpileModule` (`TS_NODE_TRANSPILE_ONLY`)
* `--cacheDirectory` Configure the output file cache directory (`TS_NODE_CACHE_DIRECTORY`)
* `-I, --ignore [pattern]` Override the path patterns to skip compilation (`TS_NODE_IGNORE`)
* `-T, --transpile-only` Use TypeScript's faster `transpileModule` (`TS_NODE_TRANSPILE_ONLY`, default: `false`)
* `-I, --ignore [pattern]` Override the path patterns to skip compilation (`TS_NODE_IGNORE`, default: `/node_modules/`)
* `-P, --project [path]` Path to TypeScript JSON project file (`TS_NODE_PROJECT`)
* `-C, --compiler [name]` Specify a custom TypeScript compiler (`TS_NODE_COMPILER`)
* `-D, --ignoreDiagnostics [code]` Ignore TypeScript warnings by diagnostic code (`TS_NODE_IGNORE_DIAGNOSTICS`)
* `-O, --compilerOptions [opts]` JSON object to merge with compiler options (`TS_NODE_COMPILER_OPTIONS`)
* `--no-cache` Disable the local TypeScript Node cache (`TS_NODE_CACHE`)
* `--skip-project` Skip project config resolution and loading (`TS_NODE_SKIP_PROJECT`)
* `--skip-ignore` Skip ignore checks (`TS_NODE_SKIP_IGNORE`)
* `-C, --compiler [name]` Specify a custom TypeScript compiler (`TS_NODE_COMPILER`, default: `typescript`)
* `-D, --ignore-diagnostics [code]` Ignore TypeScript warnings by diagnostic code (`TS_NODE_IGNORE_DIAGNOSTICS`)
* `-O, --compiler-options [opts]` JSON object to merge with compiler options (`TS_NODE_COMPILER_OPTIONS`)
* `--files` Load files from `tsconfig.json` on startup (`TS_NODE_FILES`, default: `false`)
* `--pretty` Use pretty diagnostic formatter (`TS_NODE_PRETTY`, default: `false`)
* `--skip-project` Skip project config resolution and loading (`TS_NODE_SKIP_PROJECT`, default: `false`)
* `--skip-ignore` Skip ignore checks (`TS_NODE_SKIP_IGNORE`, default: `false`)

### Programmatic Only Options

* `transformers` An array of transformers to pass to TypeScript
* `readFile` Custom TypeScript-compatible file reading function
* `fileExists` Custom TypeScript-compatible file existence function

## Help! My Types Are Missing!

**TypeScript Node** does _not_ use `files`, `include` or `exclude`, by default. This is because a large majority projects do not use all of the files in a project directory (e.g. `Gulpfile.ts`, runtime vs tests) and parsing every file for types slows startup time. Instead, `ts-node` starts with the script file (e.g. `ts-node index.ts`) and TypeScript resolves dependencies based on imports and references.

For global definitions, you can use the `typeRoots` compiler option. This requires that your type definitions be structured as type packages (not loose TypeScript definition files). More details on how this works can be found in the [TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html#types-typeroots-and-types).

Example `tsconfig.json`:

```
{
"compilerOptions": {
"typeRoots" : ["./node_modules/@types", "./typings"]
}
}
```

Example project structure:

```
<project_root>/
-- tsconfig.json
-- typings/
-- <module_name>/
-- index.d.ts
```

Example module declaration file:

```
declare module '<module_name>' {
// module definitions go here
}
```

For module definitions, you can use [`paths`](https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping):

```json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"custom-module-type": ["types/custom-module-type"]
}
}
}
```

**Tip:** If you _must_ use `files`, enable `--files` flags or set `TS_NODE_FILES=true`.

## Watching and Restarting

**TypeScript Node** compiles source code via `require()`, watching files and code reloads are out of scope for the project. If you want to restart the `ts-node` process on file change, existing node.js tools such as [nodemon](https://github.com/remy/nodemon), [onchange](https://github.com/Qard/onchange) and [node-dev](https://github.com/fgnass/node-dev) work.
180 changes: 180 additions & 0 deletions logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
543 changes: 276 additions & 267 deletions package-lock.json

Large diffs are not rendered by default.

34 changes: 14 additions & 20 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ts-node",
"version": "6.0.0",
"description": "TypeScript execution environment and REPL for node",
"version": "8.0.2",
"description": "TypeScript execution environment and REPL for node.js, with source map support",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"bin": {
@@ -14,13 +14,11 @@
],
"scripts": {
"lint": "tslint \"src/**/*.ts\" --project tsconfig.json",
"clean": "rimraf dist",
"tsc": "tsc",
"build": "npm run clean && npm run tsc",
"build": "rimraf dist && tsc",
"test-spec": "mocha dist/**/*.spec.js -R spec --bail",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- \"dist/**/*.spec.js\" -R spec --bail",
"test": "npm run build && npm run lint && npm run test-cov",
"prepublish": "npm run build"
"prepare": "npm run build"
},
"engines": {
"node": ">=4.2.0"
@@ -48,18 +46,14 @@
},
"homepage": "https://github.com/TypeStrong/ts-node",
"devDependencies": {
"@types/arrify": "^1.0.1",
"@types/chai": "^4.0.4",
"@types/diff": "^3.2.1",
"@types/minimist": "^1.2.0",
"@types/mkdirp": "^0.5.0",
"@types/mocha": "^5.0.0",
"@types/node": "^9.4.6",
"@types/node": "^10.0.3",
"@types/proxyquire": "^1.3.28",
"@types/react": "^16.0.2",
"@types/semver": "^5.3.34",
"@types/source-map-support": "^0.4.0",
"@types/yn": "types/npm-yn#ca75f6c82940fae6a06fb41d2d37a6aa9b4ea8e9",
"chai": "^4.0.1",
"istanbul": "^0.4.0",
"mocha": "^5.0.1",
@@ -68,18 +62,18 @@
"react": "^16.0.0",
"rimraf": "^2.5.4",
"semver": "^5.1.0",
"tslint": "^5.0.0",
"tslint-config-standard": "^7.0.0",
"typescript": "^2.7.2"
"tslint": "^5.11.0",
"tslint-config-standard": "^8.0.1",
"typescript": "^3.2.4"
},
"peerDependencies": {
"typescript": ">=2.0"
},
"dependencies": {
"arrify": "^1.0.0",
"chalk": "^2.3.0",
"arg": "^4.1.0",
"diff": "^3.1.0",
"make-error": "^1.1.1",
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
"source-map-support": "^0.5.3",
"yn": "^2.0.0"
"source-map-support": "^0.5.6",
"yn": "^3.0.0"
}
}
Binary file modified screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
214 changes: 111 additions & 103 deletions src/bin.ts
Original file line number Diff line number Diff line change
@@ -3,130 +3,134 @@
import { join, resolve } from 'path'
import { start, Recoverable } from 'repl'
import { inspect } from 'util'
import arrify = require('arrify')
import Module = require('module')
import minimist = require('minimist')
import chalk from 'chalk'
import arg = require('arg')
import { diffLines } from 'diff'
import { Script } from 'vm'
import { readFileSync, statSync } from 'fs'
import { register, VERSION, DEFAULTS, TSError, parse, printError } from './index'
import { register, VERSION, DEFAULTS, TSError, parse } from './index'

interface Argv {
const args = arg({
// Node.js-like options.
eval?: string
print?: string
require?: string | string[]
// CLI options.
help?: boolean
version?: boolean
// Register options.
typeCheck?: boolean
transpileOnly?: boolean
cache?: boolean
cacheDirectory?: string
compiler?: string
ignore?: string | string[]
project?: string
skipIgnore?: boolean
skipProject?: boolean
ignoreDiagnostics?: string | string[]
compilerOptions?: string
_: string[]
}
'--eval': String,
'--print': Boolean,
'--require': [String],

const argv = minimist<Argv>(process.argv.slice(2), {
stopEarly: true,
string: ['eval', 'print', 'compiler', 'project', 'ignoreDiagnostics', 'require', 'cacheDirectory', 'ignore'],
boolean: ['help', 'transpileOnly', 'typeCheck', 'version', 'cache', 'skipProject', 'skipIgnore'],
alias: {
eval: ['e'],
print: ['p'],
require: ['r'],
help: ['h'],
version: ['v'],
typeCheck: ['type-check'],
transpileOnly: ['transpile-only'],
cacheDirectory: ['cache-directory'],
ignore: ['I'],
project: ['P'],
skipIgnore: ['skip-ignore'],
skipProject: ['skip-project'],
compiler: ['C'],
ignoreDiagnostics: ['D', 'ignore-diagnostics'],
compilerOptions: ['O', 'compiler-options']
},
default: {
cache: DEFAULTS.cache,
typeCheck: DEFAULTS.typeCheck,
transpileOnly: DEFAULTS.transpileOnly,
skipIgnore: DEFAULTS.skipIgnore,
skipProject: DEFAULTS.skipProject
}
// CLI options.
'--files': Boolean,
'--help': Boolean,
'--version': arg.COUNT,

// Project options.
'--compiler': String,
'--compiler-options': parse,
'--project': String,
'--ignore-diagnostics': [String],
'--ignore': [String],
'--transpile-only': Boolean,
'--type-check': Boolean,
'--pretty': Boolean,
'--skip-project': Boolean,
'--skip-ignore': Boolean,

// Aliases.
'-e': '--eval',
'-p': '--print',
'-r': '--require',
'-h': '--help',
'-v': '--version',
'-T': '--transpile-only',
'-I': '--ignore',
'-P': '--project',
'-C': '--compiler',
'-D': '--ignore-diagnostics',
'-O': '--compiler-options'
}, {
stopAtPositional: true
})

if (argv.help) {
const {
'--help': help = false,
'--version': version = 0,
'--files': files = DEFAULTS.files,
'--compiler': compiler = DEFAULTS.compiler,
'--compiler-options': compilerOptions = DEFAULTS.compilerOptions,
'--project': project = DEFAULTS.project,
'--ignore-diagnostics': ignoreDiagnostics = DEFAULTS.ignoreDiagnostics,
'--ignore': ignore = DEFAULTS.ignore,
'--transpile-only': transpileOnly = DEFAULTS.transpileOnly,
'--type-check': typeCheck = DEFAULTS.typeCheck,
'--pretty': pretty = DEFAULTS.pretty,
'--skip-project': skipProject = DEFAULTS.skipProject,
'--skip-ignore': skipIgnore = DEFAULTS.skipIgnore
} = args

if (help) {
console.log(`
Usage: ts-node [options] [ -e script | script.ts ] [arguments]
Options:
-e, --eval [code] Evaluate code
-p, --print [code] Evaluate code and print result
-p, --print Print result of \`--eval\`
-r, --require [path] Require a node module before execution
-h, --help Print CLI usage
-v, --version Print module version information
-T, --transpile-only Use TypeScript's faster \`transpileModule\`
--cache-directory Configure the output file cache directory
-I, --ignore [pattern] Override the path patterns to skip compilation
-P, --project [path] Path to TypeScript JSON project file
-C, --compiler [name] Specify a custom TypeScript compiler
-D, --ignoreDiagnostics [code] Ignore TypeScript warnings by diagnostic code
-O, --compilerOptions [opts] JSON object to merge with compiler options
-D, --ignore-diagnostics [code] Ignore TypeScript warnings by diagnostic code
-O, --compiler-options [opts] JSON object to merge with compiler options
--no-cache Disable the local TypeScript Node cache
--files Load files from \`tsconfig.json\` on startup
--pretty Use pretty diagnostic formatter
--skip-project Skip reading \`tsconfig.json\`
--skip-ignore Skip \`--ignore\` checks
`)

process.exit(0)
}

// Output project information.
if (version === 1) {
console.log(`v${VERSION}`)
process.exit(0)
}

const cwd = process.cwd()
const code = argv.eval === undefined ? argv.print : argv.eval
const isEval = typeof argv.eval === 'string' || !!argv.print // Minimist struggles with empty strings.
const isPrinted = argv.print !== undefined
const code = args['--eval']
const isPrinted = args['--print'] !== undefined

// Register the TypeScript compiler instance.
const service = register({
typeCheck: argv.typeCheck,
transpileOnly: argv.transpileOnly,
cache: argv.cache,
cacheDirectory: argv.cacheDirectory,
ignore: argv.ignore,
project: argv.project,
skipIgnore: argv.skipIgnore,
skipProject: argv.skipProject,
compiler: argv.compiler,
ignoreDiagnostics: argv.ignoreDiagnostics,
compilerOptions: parse(argv.compilerOptions),
readFile: isEval ? readFileEval : undefined,
fileExists: isEval ? fileExistsEval : undefined
files,
pretty,
typeCheck,
transpileOnly,
ignore,
project,
skipIgnore,
skipProject,
compiler,
ignoreDiagnostics,
compilerOptions,
readFile: code ? readFileEval : undefined,
fileExists: code ? fileExistsEval : undefined
})

// Output project information.
if (argv.version) {
if (version >= 2) {
console.log(`ts-node v${VERSION}`)
console.log(`node ${process.version}`)
console.log(`typescript v${service.ts.version}`)
console.log(`cache ${JSON.stringify(service.cachedir)}`)
console.log(`compiler v${service.ts.version}`)
process.exit(0)
}

// Require specified modules before start-up.
(Module as any)._preloadModules(arrify(argv.require))
if (args['--require']) (Module as any)._preloadModules(args['--require'])

/**
* Eval helpers.
@@ -135,17 +139,19 @@ const EVAL_FILENAME = `[eval].ts`
const EVAL_PATH = join(cwd, EVAL_FILENAME)
const EVAL_INSTANCE = { input: '', output: '', version: 0, lines: 0 }

// Prepend `ts-node` arguments to CLI for child processes.
process.execArgv.unshift(__filename, ...process.argv.slice(2, process.argv.length - args._.length))
process.argv = [process.argv[1]].concat(args._.length ? resolve(cwd, args._[0]) : []).concat(args._.slice(1))

// Execute the main contents (either eval, script or piped).
if (isEval) {
evalAndExit(code as string, isPrinted)
if (code) {
evalAndExit(code, isPrinted)
} else {
if (argv._.length) {
process.argv = ['node'].concat(resolve(cwd, argv._[0])).concat(argv._.slice(1))
process.execArgv.unshift(__filename)
if (args._.length) {
Module.runMain()
} else {
// Piping of execution _only_ occurs when no other script is specified.
if ((process.stdin as any).isTTY) {
if (process.stdin.isTTY) {
startRepl()
} else {
let code = ''
@@ -172,10 +178,10 @@ function evalAndExit (code: string, isPrinted: boolean) {
let result: any

try {
result = _eval(code, global)
result = _eval(code)
} catch (error) {
if (error instanceof TSError) {
console.error(printError(error))
console.error(error.diagnosticText)
process.exit(1)
}

@@ -190,7 +196,7 @@ function evalAndExit (code: string, isPrinted: boolean) {
/**
* Evaluate the code snippet.
*/
function _eval (input: string, context: any) {
function _eval (input: string) {
const lines = EVAL_INSTANCE.lines
const isCompletion = !/\n$/.test(input)
const undo = appendEval(input)
@@ -213,17 +219,17 @@ function _eval (input: string, context: any) {
}

return changes.reduce((result, change) => {
return change.added ? exec(change.value, EVAL_FILENAME, context) : result
return change.added ? exec(change.value, EVAL_FILENAME) : result
}, undefined)
}

/**
* Execute some code.
*/
function exec (code: string, filename: string, context: any) {
function exec (code: string, filename: string) {
const script = new Script(code, { filename: filename })

return script.runInNewContext(context)
return script.runInThisContext()
}

/**
@@ -234,8 +240,9 @@ function startRepl () {
prompt: '> ',
input: process.stdin,
output: process.stdout,
terminal: process.stdout.isTTY,
eval: replEval,
useGlobal: false
useGlobal: true
})

// Bookmark the point where we should reset the REPL state.
@@ -245,7 +252,7 @@ function startRepl () {
resetEval()

// Hard fix for TypeScript forcing `Object.defineProperty(exports, ...)`.
exec('exports = module.exports', EVAL_FILENAME, (repl as any).context)
exec('exports = module.exports', EVAL_FILENAME)
}

reset()
@@ -264,7 +271,7 @@ function startRepl () {

undo()

repl.outputStream.write(`${chalk.bold(name)}\n${comment ? `${comment}\n` : ''}`)
repl.outputStream.write(`${name}\n${comment ? `${comment}\n` : ''}`)
repl.displayPrompt()
}
})
@@ -273,25 +280,25 @@ function startRepl () {
/**
* Eval code from the REPL.
*/
function replEval (code: string, context: any, _filename: string, callback: (err?: Error, result?: any) => any) {
let err: any
function replEval (code: string, _context: any, _filename: string, callback: (err: Error | null, result?: any) => any) {
let err: Error | null = null
let result: any

// TODO: Figure out how to handle completion here.
if (code === '.scope') {
callback()
callback(err)
return
}

try {
result = _eval(code, context)
result = _eval(code)
} catch (error) {
if (error instanceof TSError) {
// Support recoverable compilations using >= node 6.
if (Recoverable && isRecoverable(error)) {
err = new Recoverable(error)
} else {
err = printError(error)
console.error(error.diagnosticText)
}
} else {
err = error
@@ -367,18 +374,19 @@ function fileExistsEval (path: string) {
}
}

const RECOVERY_CODES: number[] = [
const RECOVERY_CODES: Set<number> = new Set([
1003, // "Identifier expected."
1005, // "')' expected."
1109, // "Expression expected."
1126, // "Unexpected end of text."
1160, // "Unterminated template literal."
1161 // "Unterminated regular expression literal."
]
1161, // "Unterminated regular expression literal."
2355 // "A function whose declared type is neither 'void' nor 'any' must return a value."
])

/**
* Check if a function can recover gracefully.
*/
function isRecoverable (error: TSError) {
return error.diagnostics.every(x => RECOVERY_CODES.indexOf(x.code) > -1)
return error.diagnosticCodes.every(code => RECOVERY_CODES.has(code))
}
58 changes: 42 additions & 16 deletions src/index.spec.ts
Original file line number Diff line number Diff line change
@@ -6,9 +6,10 @@ import ts = require('typescript')
import proxyquire = require('proxyquire')
import { register, VERSION } from './index'

const testDir = join(__dirname, '../tests')
const TEST_DIR = join(__dirname, '../tests')
const EXEC_PATH = join(__dirname, '../dist/bin')
const BIN_EXEC = `node "${EXEC_PATH}" --project "${testDir}/tsconfig.json"`
const PROJECT = join(TEST_DIR, semver.gte(ts.version, '2.5.0') ? 'tsconfig.json5' : 'tsconfig.json')
const BIN_EXEC = `node "${EXEC_PATH}" --project "${PROJECT}"`

const SOURCE_MAP_REGEXP = /\/\/# sourceMappingURL=data:application\/json;charset=utf\-8;base64,[\w\+]+=*$/

@@ -33,7 +34,7 @@ describe('ts-node', function () {

it('should register via cli', function (done) {
exec(`node -r ../register hello-world.ts`, {
cwd: testDir
cwd: TEST_DIR
}, function (err, stdout) {
expect(err).to.equal(null)
expect(stdout).to.equal('Hello, world!\n')
@@ -43,7 +44,7 @@ describe('ts-node', function () {
})

it('should execute cli with absolute path', function (done) {
exec(`${BIN_EXEC} "${join(testDir, 'hello-world')}"`, function (err, stdout) {
exec(`${BIN_EXEC} "${join(TEST_DIR, 'hello-world')}"`, function (err, stdout) {
expect(err).to.equal(null)
expect(stdout).to.equal('Hello, world!\n')

@@ -52,7 +53,7 @@ describe('ts-node', function () {
})

it('should print scripts', function (done) {
exec(`${BIN_EXEC} -p "import { example } from './tests/complex/index';example()"`, function (err, stdout) {
exec(`${BIN_EXEC} -pe "import { example } from './tests/complex/index';example()"`, function (err, stdout) {
expect(err).to.equal(null)
expect(stdout).to.equal('example\n')

@@ -66,7 +67,7 @@ describe('ts-node', function () {
[
BIN_EXEC,
'-O "{\\\"allowJs\\\":true}"',
'-p "import { main } from \'./tests/allow-js/run\';main()"'
'-pe "import { main } from \'./tests/allow-js/run\';main()"'
].join(' '),
function (err, stdout) {
expect(err).to.equal(null)
@@ -82,7 +83,7 @@ describe('ts-node', function () {
[
BIN_EXEC,
'-O "{\\\"allowJs\\\":true}"',
'-p "import { Foo2 } from \'./tests/allow-js/with-jsx\'; Foo2.sayHi()"'
'-pe "import { Foo2 } from \'./tests/allow-js/with-jsx\'; Foo2.sayHi()"'
].join(' '),
function (err, stdout) {
expect(err).to.equal(null)
@@ -106,16 +107,24 @@ describe('ts-node', function () {
)
})

it('should import empty files', function (done) {
exec(`${BIN_EXEC} -e "import './tests/empty'"`, function (err, stdout) {
expect(err).to.equal(null)
expect(stdout).to.equal('')

return done()
})
})

it('should throw errors', function (done) {
exec(`${BIN_EXEC} -e "import * as m from './tests/module';console.log(m.example(123))"`, function (err) {
if (err === null) {
return done('Command was expected to fail, but it succeeded.')
}

expect(err.message).to.match(new RegExp(
// Node 0.10 can not override the `lineOffset` option.
'\\[eval\\]\\.ts \\(1,59\\): Argument of type \'(?:number|123)\' ' +
'is not assignable to parameter of type \'string\'\\. \\(2345\\)'
'TS2345: Argument of type \'(?:number|123)\' ' +
'is not assignable to parameter of type \'string\'\\.'
))

return done()
@@ -124,7 +133,7 @@ describe('ts-node', function () {

it('should be able to ignore diagnostic', function (done) {
exec(
`${BIN_EXEC} --ignoreDiagnostics 2345 -e "import * as m from './tests/module';console.log(m.example(123))"`,
`${BIN_EXEC} --ignore-diagnostics 2345 -e "import * as m from './tests/module';console.log(m.example(123))"`,
function (err) {
if (err === null) {
return done('Command was expected to fail, but it succeeded.')
@@ -157,7 +166,7 @@ describe('ts-node', function () {
})

it.skip('eval should work with source maps', function (done) {
exec(`${BIN_EXEC} -p "import './tests/throw'"`, function (err) {
exec(`${BIN_EXEC} -pe "import './tests/throw'"`, function (err) {
if (err === null) {
return done('Command was expected to fail, but it succeeded.')
}
@@ -173,7 +182,7 @@ describe('ts-node', function () {
})

it('should support transpile only mode', function (done) {
exec(`${BIN_EXEC} --transpileOnly -p "x"`, function (err) {
exec(`${BIN_EXEC} --transpile-only -pe "x"`, function (err) {
if (err === null) {
return done('Command was expected to fail, but it succeeded.')
}
@@ -207,7 +216,7 @@ describe('ts-node', function () {
})

it('should pipe into an eval script', function (done) {
const cp = exec(`${BIN_EXEC} --fast -p 'process.stdin.isTTY'`, function (err, stdout) {
const cp = exec(`${BIN_EXEC} --transpile-only -pe 'process.stdin.isTTY'`, function (err, stdout) {
expect(err).to.equal(null)
expect(stdout).to.equal('undefined\n')

@@ -218,7 +227,7 @@ describe('ts-node', function () {
})

it('should support require flags', function (done) {
exec(`${BIN_EXEC} -r ./tests/hello-world -p "console.log('success')"`, function (err, stdout) {
exec(`${BIN_EXEC} -r ./tests/hello-world -pe "console.log('success')"`, function (err, stdout) {
expect(err).to.equal(null)
expect(stdout).to.equal('Hello, world!\nsuccess\nundefined\n')

@@ -243,11 +252,28 @@ describe('ts-node', function () {
return done()
})
})

it('should allow custom typings', function (done) {
exec(`${BIN_EXEC} tests/custom-types`, function (err, stdout) {
expect(err).to.match(/Error: Cannot find module 'does-not-exist'/)

return done()
})
})

it('should preserve `ts-node` context with child process', function (done) {
exec(`${BIN_EXEC} tests/child-process`, function (err, stdout) {
expect(err).to.equal(null)
expect(stdout).to.equal('Hello, world!\n')

return done()
})
})
})

describe('register', function () {
register({
project: join(testDir, 'tsconfig.json'),
project: PROJECT,
compilerOptions: {
jsx: 'preserve'
}
340 changes: 116 additions & 224 deletions src/index.ts

Large diffs are not rendered by default.

12 changes: 8 additions & 4 deletions tests/allow-js/with-jsx.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
export class Foo2 {
render () {
return <div />

static sayHi () {
return 'hello world'
}

render () {
return <div />
}

}

Foo2.sayHi = () => 'hello world'
4 changes: 4 additions & 0 deletions tests/child-process.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { join } from 'path'
import { fork } from 'child_process'

fork(join(__dirname, 'hello-world.ts'))
3 changes: 3 additions & 0 deletions tests/custom-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { foobar } from 'does-not-exist'

console.log(foobar)
Empty file added tests/empty.ts
Empty file.
6 changes: 5 additions & 1 deletion tests/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"compilerOptions": {
"jsx": "react",
"noEmit": true
"noEmit": true,
"typeRoots": [
"./typings",
"../node_modules/@types"
]
}
}
11 changes: 11 additions & 0 deletions tests/tsconfig.json5
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"jsx": "react",
"noEmit": true,
// Global type definitions.
"typeRoots": [
"./typings",
"../node_modules/@types",
],
}
}
3 changes: 3 additions & 0 deletions tests/typings/does-not-exist/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
declare module "does-not-exist" {
export const foobar = 'test'
}