Skip to content

Commit f1fd8a8

Browse files
authored
Merge pull request #183 from bradennapier/feature/script-mode
Add --script-mode / -s and fix --dir as well as add tests
2 parents 62b8f12 + 9216025 commit f1fd8a8

File tree

6 files changed

+115
-3
lines changed

6 files changed

+115
-3
lines changed

bin/ts-node-dev

100644100755
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ var opts = minimist(devArgs, {
2222
'exit-child',
2323
'error-recompile',
2424
// ts-node
25-
'dir',
2625
'scope',
2726
'emit',
2827
'files',
@@ -40,6 +39,7 @@ var opts = minimist(devArgs, {
4039
'rs'
4140
],
4241
string: [
42+
'dir',
4343
'compile-timeout',
4444
'ignore-watch',
4545
'interval',
@@ -60,6 +60,7 @@ var opts = minimist(devArgs, {
6060
'compiler-options': 'O',
6161
compiler: 'C',
6262
project: 'P',
63+
'script-mode': 's'
6364
},
6465
default: { deps: false, notify: true, rs: false, 'type-check': true },
6566
unknown: function (arg) {

lib/compiler.js

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,48 @@ var originalJsHandler = require.extensions['.js']
2323

2424
var extHandlers = {}
2525

26+
function hasOwnProperty (object, property) {
27+
return Object.prototype.hasOwnProperty.call(object, property)
28+
}
29+
30+
function getCwd(dir, scriptMode, scriptPath) {
31+
if (scriptMode) {
32+
if (!scriptPath) {
33+
throw new TypeError('Script mode must be used with a script name, e.g. `ts-node-dev -s <script.ts>`')
34+
}
35+
36+
if (dir) {
37+
throw new TypeError('Script mode cannot be combined with `--dir`')
38+
}
39+
40+
// Use node's own resolution behavior to ensure we follow symlinks.
41+
// scriptPath may omit file extension or point to a directory with or without package.json.
42+
// This happens before we are registered, so we tell node's resolver to consider ts, tsx, and jsx files.
43+
// In extremely rare cases, is is technically possible to resolve the wrong directory,
44+
// because we do not yet know preferTsExts, jsx, nor allowJs.
45+
// See also, justification why this will not happen in real-world situations:
46+
// https://github.com/TypeStrong/ts-node/pull/1009#issuecomment-613017081
47+
const exts = ['.js', '.jsx', '.ts', '.tsx']
48+
const extsTemporarilyInstalled = []
49+
for (const ext of exts) {
50+
if (!hasOwnProperty(require.extensions, ext)) { // tslint:disable-line
51+
extsTemporarilyInstalled.push(ext)
52+
require.extensions[ext] = function() {} // tslint:disable-line
53+
}
54+
}
55+
try {
56+
return path.dirname(require.resolve(scriptPath))
57+
} finally {
58+
for (const ext of extsTemporarilyInstalled) {
59+
delete require.extensions[ext] // tslint:disable-line
60+
}
61+
}
62+
}
63+
64+
return dir
65+
}
66+
67+
2668
var compiler = {
2769
allowJs: false,
2870
tsConfigPath: '',
@@ -196,12 +238,14 @@ var compiler = {
196238
ignore = [ignore]
197239
}
198240

241+
const scriptPath = options._.length ? path.resolve(cwd, options._[0]) : undefined
242+
199243
var DEFAULTS = tsNode.DEFAULTS
200244

201245
try {
202246
compiler.service = tsNode.register({
203-
// should add --script-mode
204-
dir: options['dir'] || DEFAULTS.dir,
247+
// --dir does not work (it gives a boolean only) so we only check for script-mode
248+
dir: getCwd(options['dir'], options['script-mode'], scriptPath),
205249
scope: options['dir'] || DEFAULTS.scope,
206250
emit: options['emit'] || DEFAULTS.emit,
207251
files: options['files'] || DEFAULTS.files,

test/fixture/dir-test/imported.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
module.exports.hello = 'world'
2+
;

test/fixture/dir-test/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
import values from './imported'
3+
4+
console.log(values)

test/fixture/dir-test/tsconfig.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"extends": "../../../tsconfig.json",
3+
"include": ["./*.ts", "./*.js"],
4+
"compilerOptions": {
5+
"allowJs": true,
6+
"esModuleInterop": true,
7+
"allowSyntheticDefaultImports": true
8+
}
9+
}

test/index.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,58 @@ test('It handles resolveJsonModule option and loads JSON modules', async (t) =>
155155
await ps.exit()
156156
})
157157

158+
test('It should not allow --script-mode and --dir together', async (t) => {
159+
const ps = spawnTsNodeDev(
160+
[
161+
`--script-mode`,
162+
`--dir folder`,
163+
`simple.ts`,
164+
].join(' ')
165+
)//.turnOnOutput()
166+
await ps.waitForLine(/TypeError: Script mode cannot be combined with `--dir`/)
167+
t.pass('ok')
168+
await ps.exit()
169+
})
170+
171+
test('It should use the tsconfig at --dir when defined', async (t) => {
172+
const ps = spawnTsNodeDev(
173+
[
174+
`--dir dir-test`,
175+
`dir-test/index.ts`,
176+
].join(' ')
177+
)//.turnOnOutput()
178+
await ps.waitForLine(/\{ hello: 'world' \}/)
179+
t.pass('ok')
180+
await ps.exit()
181+
})
182+
183+
test('It should use the tsconfig at --script-mode when defined', async (t) => {
184+
const ps = spawnTsNodeDev(
185+
[
186+
`-s`,
187+
`dir-test/index.ts`,
188+
].join(' ')
189+
)//.turnOnOutput()
190+
await ps.waitForLine(/\{ hello: 'world' \}/)
191+
t.pass('ok')
192+
await ps.exit()
193+
})
194+
195+
test('It should fail if not using --dir or --script-mode on dir-test/index.ts', async (t) => {
196+
const cOptions = { allowJs: true }
197+
const ps = spawnTsNodeDev(
198+
[
199+
`--compiler-options=${JSON.stringify(cOptions)}`,
200+
`dir-test/index.ts`,
201+
].join(' ')
202+
).turnOnOutput()
203+
await ps.waitForLine(/has no default export./)
204+
t.pass('ok')
205+
await ps.exit()
206+
})
207+
208+
209+
158210
test('It allows to use TS Transformers', async (t) => {
159211
const cOptions = { plugins: [{ transform: 'ts-nameof', type: 'raw' }] }
160212
const ps = spawnTsNodeDev(

0 commit comments

Comments
 (0)