diff --git a/README.md b/README.md index 9dad209f1..4071cb226 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,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 @@ -123,13 +123,13 @@ Supports `--print`, `--eval` and `--require` from [node.js CLI options](https:// _Environment variable denoted in parentheses._ -* `-T, --transpileOnly` Use TypeScript's faster `transpileModule` (`TS_NODE_TRANSPILE_ONLY`, default: `false`) +* `-T, --transpile-only` Use TypeScript's faster `transpileModule` (`TS_NODE_TRANSPILE_ONLY`, default: `false`) * `--cacheDirectory` Configure the output file cache directory (`TS_NODE_CACHE_DIRECTORY`) * `-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`, default: `typescript`) -* `-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`) +* `-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`) * `--no-cache` Disable the local TypeScript Node cache (`TS_NODE_CACHE`, default: `true`) diff --git a/package-lock.json b/package-lock.json index 7a53b4173..2fe6c0cbe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -107,6 +107,12 @@ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, + "arg": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz", + "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==", + "dev": true + }, "argparse": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", @@ -731,11 +737,6 @@ "brace-expansion": "^1.1.7" } }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", diff --git a/package.json b/package.json index 7a020a242..cd89628a9 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "@types/semver": "^5.3.34", "@types/source-map-support": "^0.4.0", "@types/yn": "types/npm-yn#ca75f6c82940fae6a06fb41d2d37a6aa9b4ea8e9", + "arg": "^4.1.0", "chai": "^4.0.1", "istanbul": "^0.4.0", "mocha": "^5.0.1", @@ -78,7 +79,6 @@ "arrify": "^1.0.0", "diff": "^3.1.0", "make-error": "^1.1.1", - "minimist": "^1.2.0", "source-map-support": "^0.5.6", "yn": "^2.0.0" } diff --git a/src/bin.ts b/src/bin.ts index 9ca3dd656..426d71646 100644 --- a/src/bin.ts +++ b/src/bin.ts @@ -3,79 +3,76 @@ 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 arg = require('arg') import { diffLines } from 'diff' import { Script } from 'vm' import { readFileSync, statSync } from 'fs' 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. - pretty?: boolean - typeCheck?: boolean - transpileOnly?: boolean - files?: boolean - 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(process.argv.slice(2), { - stopEarly: true, - string: ['eval', 'print', 'compiler', 'project', 'ignoreDiagnostics', 'require', 'ignore'], - boolean: ['help', 'transpileOnly', 'typeCheck', 'version', 'files', 'pretty', 'skipProject', 'skipIgnore'], - alias: { - eval: ['e'], - print: ['p'], - require: ['r'], - help: ['h'], - version: ['v'], - typeCheck: ['type-check'], - transpileOnly: ['T', 'transpile-only'], - ignore: ['I'], - project: ['P'], - skipIgnore: ['skip-ignore'], - skipProject: ['skip-project'], - compiler: ['C'], - ignoreDiagnostics: ['D', 'ignore-diagnostics'], - compilerOptions: ['O', 'compiler-options'] - }, - default: { - files: DEFAULTS.files, - pretty: DEFAULTS.pretty, - typeCheck: DEFAULTS.typeCheck, - transpileOnly: DEFAULTS.transpileOnly, - ignore: DEFAULTS.ignore, - project: DEFAULTS.project, - skipIgnore: DEFAULTS.skipIgnore, - skipProject: DEFAULTS.skipProject, - compiler: DEFAULTS.compiler, - ignoreDiagnostics: DEFAULTS.ignoreDiagnostics - } + // 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 @@ -85,8 +82,8 @@ Options: -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 --files Load files from \`tsconfig.json\` on startup --pretty Use pretty diagnostic formatter @@ -97,38 +94,43 @@ Options: 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({ - files: argv.files, - pretty: argv.pretty, - typeCheck: argv.typeCheck, - transpileOnly: argv.transpileOnly, - ignore: argv.ignore, - project: argv.project, - skipIgnore: argv.skipIgnore, - skipProject: argv.skipProject, - compiler: argv.compiler, - ignoreDiagnostics: argv.ignoreDiagnostics, - compilerOptions: parse(argv.compilerOptions) || DEFAULTS.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(`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. @@ -138,16 +140,16 @@ const EVAL_PATH = join(cwd, EVAL_FILENAME) const EVAL_INSTANCE = { input: '', output: '', version: 0, lines: 0 } // 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)) + if (args._.length) { + process.argv = ['node'].concat(resolve(cwd, args._[0])).concat(args._.slice(1)) process.execArgv.unshift(__filename) 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 = '' diff --git a/src/index.spec.ts b/src/index.spec.ts index 1803ed306..565285fa4 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -53,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') @@ -67,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) @@ -83,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) @@ -133,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.') @@ -166,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.') } @@ -182,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.') } @@ -216,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') @@ -227,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') diff --git a/src/index.ts b/src/index.ts index 901b0da88..9ac1d2d59 100644 --- a/src/index.ts +++ b/src/index.ts @@ -62,12 +62,12 @@ export interface Options { transpileOnly?: boolean | null files?: boolean | null compiler?: string - ignore?: string | string[] + ignore?: string[] project?: string skipIgnore?: boolean | null skipProject?: boolean | null compilerOptions?: object - ignoreDiagnostics?: number | string | Array + ignoreDiagnostics?: Array readFile?: (path: string) => string | undefined fileExists?: (path: string) => boolean transformers?: _ts.CustomTransformers @@ -176,11 +176,12 @@ export function register (opts: Options = {}): Register { const options = Object.assign({}, DEFAULTS, opts) const originalJsHandler = require.extensions['.js'] - const ignoreDiagnostics = arrify(options.ignoreDiagnostics).concat([ + const ignoreDiagnostics = [ 6059, // "'rootDir' is expected to contain all source files." 18002, // "The 'files' list in config file is empty." - 18003 // "No inputs were found in config file." - ]).map(Number) + 18003, // "No inputs were found in config file." + ...(options.ignoreDiagnostics || []) + ].map(Number) const memoryCache: MemoryCache = { contents: Object.create(null),