Skip to content

Commit e0a83b5

Browse files
authored
Add --build flag, improve TS module error (#896)
1 parent cb4b748 commit e0a83b5

File tree

10 files changed

+62
-45
lines changed

10 files changed

+62
-45
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ _Environment variable denoted in parentheses._
138138
* `--skip-project` Skip project config resolution and loading (`TS_NODE_SKIP_PROJECT`, default: `false`)
139139
* `--skip-ignore` Skip ignore checks (`TS_NODE_SKIP_IGNORE`, default: `false`)
140140
* `--log-error` Logs errors of types instead of exit the process (`TS_NODE_LOG_ERROR`, default: `false`)
141+
* `--build` Emit output files into `.ts-node` directory (`TS_NODE_BUILD`, default: `false`)
141142
* `--prefer-ts-exts` Re-order file extensions so that TypeScript imports are preferred (`TS_NODE_PREFER_TS_EXTS`, default: `false`)
142143

143144
### Programmatic Only Options

src/bin.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,15 @@ const args = arg({
3434
'--skip-ignore': Boolean,
3535
'--prefer-ts-exts': Boolean,
3636
'--log-error': Boolean,
37+
'--build': Boolean,
3738

3839
// Aliases.
3940
'-e': '--eval',
4041
'-p': '--print',
4142
'-r': '--require',
4243
'-h': '--help',
4344
'-v': '--version',
45+
'-B': '--build',
4446
'-T': '--transpile-only',
4547
'-I': '--ignore',
4648
'-P': '--project',
@@ -66,7 +68,8 @@ const {
6668
'--skip-project': skipProject = DEFAULTS.skipProject,
6769
'--skip-ignore': skipIgnore = DEFAULTS.skipIgnore,
6870
'--prefer-ts-exts': preferTsExts = DEFAULTS.preferTsExts,
69-
'--log-error': logError = DEFAULTS.logError
71+
'--log-error': logError = DEFAULTS.logError,
72+
'--build': build = DEFAULTS.build
7073
} = args
7174

7275
if (help) {
@@ -118,16 +121,17 @@ const EVAL_INSTANCE = { input: '', output: '', version: 0, lines: 0 }
118121

119122
// Register the TypeScript compiler instance.
120123
const service = register({
124+
build,
121125
files,
122126
pretty,
123127
typeCheck,
124128
transpileOnly,
125129
ignore,
126130
project,
127-
skipIgnore,
128131
preferTsExts,
129132
logError,
130133
skipProject,
134+
skipIgnore,
131135
compiler,
132136
ignoreDiagnostics,
133137
compilerOptions,

src/index.spec.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { register, VERSION } from './index'
88

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

1414
const SOURCE_MAP_REGEXP = /\/\/# sourceMappingURL=data:application\/json;charset=utf\-8;base64,[\w\+]+=*$/
@@ -165,7 +165,7 @@ describe('ts-node', function () {
165165
})
166166
})
167167

168-
it.skip('eval should work with source maps', function (done) {
168+
it('eval should work with source maps', function (done) {
169169
exec(`${BIN_EXEC} -pe "import './tests/throw'"`, function (err) {
170170
if (err === null) {
171171
return done('Command was expected to fail, but it succeeded.')
@@ -305,6 +305,16 @@ describe('ts-node', function () {
305305
return done()
306306
})
307307
})
308+
309+
it('should give ts error for invalid node_modules', function (done) {
310+
exec(`${BIN_EXEC} --skip-ignore tests/from-node-modules`, function (err, stdout) {
311+
if (err === null) return done('Expected an error')
312+
313+
expect(err.message).to.contain('Unable to compile file from external library')
314+
315+
return done()
316+
})
317+
})
308318
})
309319

310320
describe('register', function () {

src/index.ts

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export const VERSION = require('../package.json').version
5656
* Registration options.
5757
*/
5858
export interface Options {
59+
build?: boolean | null
5960
pretty?: boolean | null
6061
typeCheck?: boolean | null
6162
transpileOnly?: boolean | null
@@ -64,8 +65,8 @@ export interface Options {
6465
compiler?: string
6566
ignore?: string[]
6667
project?: string
67-
skipIgnore?: boolean | null
6868
skipProject?: boolean | null
69+
skipIgnore?: boolean | null
6970
preferTsExts?: boolean | null
7071
compilerOptions?: object
7172
ignoreDiagnostics?: Array<number | string>
@@ -95,19 +96,20 @@ export interface TypeInfo {
9596
* Default register options.
9697
*/
9798
export const DEFAULTS: Options = {
98-
files: yn(process.env['TS_NODE_FILES']),
99-
pretty: yn(process.env['TS_NODE_PRETTY']),
100-
compiler: process.env['TS_NODE_COMPILER'],
101-
compilerOptions: parse(process.env['TS_NODE_COMPILER_OPTIONS']),
102-
ignore: split(process.env['TS_NODE_IGNORE']),
103-
project: process.env['TS_NODE_PROJECT'],
104-
skipIgnore: yn(process.env['TS_NODE_SKIP_IGNORE']),
105-
skipProject: yn(process.env['TS_NODE_SKIP_PROJECT']),
106-
preferTsExts: yn(process.env['TS_NODE_PREFER_TS_EXTS']),
107-
ignoreDiagnostics: split(process.env['TS_NODE_IGNORE_DIAGNOSTICS']),
108-
typeCheck: yn(process.env['TS_NODE_TYPE_CHECK']),
109-
transpileOnly: yn(process.env['TS_NODE_TRANSPILE_ONLY']),
110-
logError: yn(process.env['TS_NODE_LOG_ERROR'])
99+
files: yn(process.env.TS_NODE_FILES),
100+
pretty: yn(process.env.TS_NODE_PRETTY),
101+
compiler: process.env.TS_NODE_COMPILER,
102+
compilerOptions: parse(process.env.TS_NODE_COMPILER_OPTIONS),
103+
ignore: split(process.env.TS_NODE_IGNORE),
104+
project: process.env.TS_NODE_PROJECT,
105+
skipProject: yn(process.env.TS_NODE_SKIP_PROJECT),
106+
skipIgnore: yn(process.env.TS_NODE_SKIP_IGNORE),
107+
preferTsExts: yn(process.env.TS_NODE_PREFER_TS_EXTS),
108+
ignoreDiagnostics: split(process.env.TS_NODE_IGNORE_DIAGNOSTICS),
109+
typeCheck: yn(process.env.TS_NODE_TYPE_CHECK),
110+
transpileOnly: yn(process.env.TS_NODE_TRANSPILE_ONLY),
111+
logError: yn(process.env.TS_NODE_LOG_ERROR),
112+
build: yn(process.env.TS_NODE_BUILD)
111113
}
112114

113115
/**
@@ -191,7 +193,7 @@ function cachedLookup <T> (fn: (arg: string) => T): (arg: string) => T {
191193
* Register TypeScript compiler.
192194
*/
193195
export function register (opts: Options = {}): Register {
194-
const options = Object.assign({}, DEFAULTS, opts)
196+
const options = { ...DEFAULTS, ...opts }
195197
const originalJsHandler = require.extensions['.js'] // tslint:disable-line
196198

197199
const ignoreDiagnostics = [
@@ -201,9 +203,7 @@ export function register (opts: Options = {}): Register {
201203
...(options.ignoreDiagnostics || [])
202204
].map(Number)
203205

204-
const ignore = options.skipIgnore ? [] : (
205-
options.ignore || ['/node_modules/']
206-
).map(str => new RegExp(str))
206+
const ignore = options.skipIgnore ? [] : (options.ignore || ['/node_modules/']).map(str => new RegExp(str))
207207

208208
// Require the TypeScript compiler and configuration.
209209
const cwd = process.cwd()
@@ -369,31 +369,37 @@ export function register (opts: Options = {}): Register {
369369
const sourceFile = builderProgram.getSourceFile(fileName)
370370
if (!sourceFile) throw new TypeError(`Unable to read file: ${fileName}`)
371371

372-
const diagnostics = ts.getPreEmitDiagnostics(builderProgram.getProgram(), sourceFile)
372+
const program = builderProgram.getProgram()
373+
const diagnostics = ts.getPreEmitDiagnostics(program, sourceFile)
373374
const diagnosticList = filterDiagnostics(diagnostics, ignoreDiagnostics)
374375

375376
if (diagnosticList.length) reportTSError(diagnosticList)
376377

377-
const result = builderProgram.emit(sourceFile, (path, file) => {
378+
const result = builderProgram.emit(sourceFile, (path, file, writeByteOrderMark) => {
378379
if (path.endsWith('.map')) {
379380
output[1] = file
380381
} else {
381382
output[0] = file
382383
}
384+
385+
if (options.build) sys.writeFile(path, file, writeByteOrderMark)
383386
}, undefined, undefined, getCustomTransformers())
384387

385388
if (result.emitSkipped) {
386389
throw new TypeError(`${relative(cwd, fileName)}: Emit skipped`)
387390
}
388391

389-
// Throw an error when requiring `.d.ts` files.
392+
// Throw an error when requiring files that cannot be compiled.
390393
if (output[0] === '') {
394+
if (program.isSourceFileFromExternalLibrary(sourceFile)) {
395+
throw new TypeError(`Unable to compile file from external library: ${relative(cwd, fileName)}`)
396+
}
397+
391398
throw new TypeError(
392-
'Unable to require `.d.ts` file.\n' +
399+
`Unable to require file: ${relative(cwd, fileName)}\n` +
393400
'This is usually the result of a faulty configuration or import. ' +
394-
'Make sure there is a `.js`, `.json` or another executable extension and ' +
395-
'loader (attached before `ts-node`) available alongside ' +
396-
`\`${basename(fileName)}\`.`
401+
'Make sure there is a `.js`, `.json` or other executable extension with ' +
402+
'loader attached before `ts-node` available.'
397403
)
398404
}
399405

@@ -420,7 +426,8 @@ export function register (opts: Options = {}): Register {
420426
}
421427
}
422428

423-
if (config.options.incremental) {
429+
// Write `.tsbuildinfo` when `--build` is enabled.
430+
if (options.build && config.options.incremental) {
424431
process.on('exit', () => {
425432
// Emits `.tsbuildinfo` to filesystem.
426433
(builderProgram.getProgram() as any).emitBuildInfo()

tests/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
!node_modules/

tests/emit-compiled.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ extensions.forEach(ext => {
44
const old = require.extensions[ext]
55

66
require.extensions[ext] = (m, path) => {
7-
const _compile = m._compile
7+
const _compile = (m as any)._compile
88

9-
m._compile = (code, path) => {
9+
;(m as any)._compile = (code, path) => {
1010
console.error(code)
1111
return _compile.call(this, code, path)
1212
}

tests/from-node-modules.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import 'test'

tests/node_modules/test.ts

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/tsconfig.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
"compilerOptions": {
33
"jsx": "react",
44
"noEmit": true,
5+
// Global type definitions.
56
"typeRoots": [
67
"./typings",
7-
"../node_modules/@types"
8-
]
8+
"../node_modules/@types",
9+
],
910
}
1011
}

tests/tsconfig.json5

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)