Skip to content

Commit d5a01bb

Browse files
committed
add new ts sources
1 parent 7d8a18d commit d5a01bb

14 files changed

+1426
-0
lines changed

src/bin.ts

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
#!/usr/bin/env node
2+
3+
const dev = require('.')
4+
import minimist from 'minimist'
5+
6+
const nodeArgs: string[] = []
7+
const unknown: string[] = []
8+
9+
const devArgs = process.argv.slice(2, 100)
10+
11+
const tsNodeFlags = {
12+
boolean: [
13+
'scope',
14+
'emit',
15+
'files',
16+
'pretty',
17+
'transpile-only',
18+
'prefer-ts-exts',
19+
'prefer-ts',
20+
'log-error',
21+
'skip-project',
22+
'skip-ignore',
23+
'compiler-host',
24+
'script-mode',
25+
],
26+
27+
string: [
28+
'compiler',
29+
'project',
30+
'ignore',
31+
'ignore-diagnostics',
32+
'compiler-options',
33+
],
34+
}
35+
36+
const tsNodeAlias = {
37+
'transpile-only': 'T',
38+
'compiler-host': 'H',
39+
ignore: 'I',
40+
'ignore-diagnostics': 'D',
41+
'compiler-options': 'O',
42+
compiler: 'C',
43+
project: 'P',
44+
'script-mode': 's',
45+
}
46+
47+
type TSNodeOptions = {
48+
project: string
49+
compilerOptions: any
50+
'compiler-options': any
51+
'prefer-ts-exts': boolean
52+
ignore?: string
53+
54+
dir: string
55+
'script-mode': boolean
56+
emit: boolean
57+
files: boolean
58+
'transpile-only': boolean
59+
pretty: boolean
60+
scope: boolean
61+
'log-error': boolean
62+
'skip-project': boolean
63+
'skip-ignore': boolean
64+
compiler: string
65+
'compiler-host': boolean
66+
'ignore-diagnostics': string
67+
}
68+
69+
const devFlags = {
70+
boolean: [
71+
'deps',
72+
'all-deps',
73+
'dedupe',
74+
'exec-check',
75+
'debug',
76+
'poll',
77+
'respawn',
78+
'notify',
79+
'tree-kill',
80+
'clear',
81+
'cls',
82+
'exit-child',
83+
'error-recompile',
84+
'rs',
85+
],
86+
string: [
87+
'dir',
88+
'deps-level',
89+
'compile-timeout',
90+
'ignore-watch',
91+
'interval',
92+
'debounce',
93+
'watch',
94+
],
95+
}
96+
97+
type DevOptions = {
98+
poll: boolean
99+
debug: boolean,
100+
watch: string
101+
interval: string
102+
rs: boolean
103+
deps: boolean,
104+
dedupe: boolean,
105+
respawn: boolean,
106+
notify: boolean,
107+
clear: boolean,
108+
cls: boolean,
109+
'ignore-watch': string,
110+
'all-deps': boolean,
111+
['deps-level']: string
112+
'compile-timeout': string
113+
'exec-check': boolean
114+
'exit-child': boolean
115+
'cache-directory': string
116+
'error-recompile': boolean,
117+
'tree-kill': boolean
118+
}
119+
120+
export type Options = {
121+
priorNodeArgs: string[]
122+
_: string[]
123+
} & DevOptions &
124+
TSNodeOptions
125+
126+
const opts = minimist(devArgs, {
127+
stopEarly: true,
128+
boolean: [...devFlags.boolean, ...tsNodeFlags.boolean],
129+
string: [...devFlags.string, ...tsNodeFlags.string],
130+
alias: {
131+
...tsNodeAlias,
132+
'prefer-ts-exts': 'prefer-ts',
133+
},
134+
default: {},
135+
unknown: function (arg) {
136+
unknown.push(arg)
137+
return true
138+
},
139+
}) as Options
140+
141+
const script = opts._[0]
142+
const scriptArgs = opts._.slice(1)
143+
144+
opts.priorNodeArgs = []
145+
146+
unknown.forEach(function (arg) {
147+
if (arg === script || nodeArgs.indexOf(arg) >= 0) return
148+
149+
const argName = arg.replace(/^-+/, '')
150+
// fix this
151+
const argOpts = (opts as any)[argName]
152+
const argValues = Array.isArray(argOpts) ? argOpts : [argOpts]
153+
argValues.forEach(function (argValue) {
154+
if ((arg === '-r' || arg === '--require') && argValue === 'esm') {
155+
opts.priorNodeArgs.push(arg, argValue)
156+
return false
157+
}
158+
nodeArgs.push(arg)
159+
if (typeof argValue === 'string') {
160+
nodeArgs.push(argValue)
161+
}
162+
})
163+
})
164+
165+
if (!script) {
166+
console.log('Usage: ts-node-dev [options] script [arguments]\n')
167+
process.exit(1)
168+
}
169+
170+
dev(script, scriptArgs, nodeArgs, opts)

src/cfg.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import fs from 'fs'
2+
import path from 'path'
3+
import { Options } from './bin'
4+
5+
function read(dir: string) {
6+
const f = path.resolve(dir, '.node-dev.json')
7+
return fs.existsSync(f) ? JSON.parse(fs.readFileSync(f, 'utf-8')) : null
8+
}
9+
10+
function resolvePath(unresolvedPath: string) {
11+
return path.resolve(process.cwd(), unresolvedPath)
12+
}
13+
14+
export type Config = {
15+
vm: boolean
16+
fork: boolean
17+
notify: boolean
18+
deps: number
19+
timestamp: number
20+
clear: boolean
21+
dedupe: boolean
22+
ignore: string[]
23+
respawn: boolean
24+
debug: boolean
25+
extensions: Record<string, string>
26+
}
27+
28+
export const makeCfg = (main: string, opts: Partial<Options>): Config => {
29+
const dir = main ? path.dirname(main) : '.'
30+
const userDir = process.env.HOME || process.env.USERPROFILE
31+
const c = read(dir) || read(process.cwd()) || (userDir && read(userDir)) || {}
32+
33+
c.deps = parseInt(opts['deps-level'] || '') || 0
34+
if (typeof c.depsLevel === 'number') c.deps = c.depsLevel
35+
36+
if (opts) {
37+
// Overwrite with CLI opts ...
38+
if (opts['deps'] || opts['all-deps']) c.deps = -1
39+
if (opts.dedupe) c.dedupe = true
40+
if (opts.respawn) c.respawn = true
41+
if (opts.notify === false) c.notify = false
42+
if (opts.clear || opts.cls) c.clear = true
43+
}
44+
const ignoreWatchItems: string[] = opts['ignore-watch']
45+
? opts['ignore-watch'].split(/,/).map((_) => _.trim())
46+
: []
47+
48+
const ignoreWatch: string[] = ignoreWatchItems.concat(c.ignore || [])
49+
opts.debug && console.log('Ignore watch:', ignoreWatch)
50+
const ignore = ignoreWatch.concat(ignoreWatch.map(resolvePath))
51+
return {
52+
vm: c.vm !== false,
53+
fork: c.fork !== false,
54+
notify: c.notify !== false,
55+
deps: c.deps,
56+
timestamp: c.timestamp || (c.timestamp !== false && 'HH:MM:ss'),
57+
clear: !!c.clear,
58+
dedupe: !!c.dedupe,
59+
ignore: ignore,
60+
respawn: c.respawn || false,
61+
debug: !!opts.debug,
62+
extensions: c.extensions,
63+
}
64+
}

src/check-file-exists.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import fs from 'fs'
2+
const filePath = process.argv[2]
3+
4+
const handler = function (stat: fs.Stats) {
5+
if (stat && stat.birthtime.getTime() > 0) {
6+
process.exit(0)
7+
}
8+
}
9+
10+
fs.watchFile(filePath, { interval: 100 }, handler)
11+
fs.stat(filePath, function (err, stat) {
12+
handler(stat)
13+
})

src/child-require-hook.ts

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
const fs = require('fs')
2+
const getCompiledPath = require('./get-compiled-path').getCompiledPath
3+
const sep = require('path').sep
4+
const join = require('path').join
5+
const extname = require('path').extname
6+
const execSync = require('child_process').execSync
7+
const Module = require('module')
8+
const compilationId = ''
9+
const timeThreshold = 0
10+
const allowJs = false
11+
const compiledDir = ''
12+
const preferTs = false
13+
const ignore = [/node_modules/]
14+
const readyFile = ''
15+
const execCheck = false
16+
const exitChild = false
17+
const sourceMapSupportPath = ''
18+
const libPath = ''
19+
20+
const checkFileScript = join(__dirname, 'check-file-exists.js')
21+
22+
const waitForFile = function (fileName: string) {
23+
const start = new Date().getTime()
24+
while (true) {
25+
const exists = execCheck
26+
? execSync(['node', checkFileScript, '"' + fileName + '"'].join(' '), {
27+
stdio: 'inherit',
28+
}) || true
29+
: fs.existsSync(fileName)
30+
31+
if (exists) {
32+
return
33+
}
34+
const passed = new Date().getTime() - start
35+
if (timeThreshold && passed > timeThreshold) {
36+
throw new Error('Could not require ' + fileName)
37+
}
38+
}
39+
}
40+
41+
const compile = (code: string, fileName: string) => {
42+
const compiledPath = getCompiledPath(code, fileName, compiledDir)
43+
process.send &&
44+
process.send({
45+
compile: fileName,
46+
compiledPath: compiledPath,
47+
})
48+
const compileRequestFile = [compiledDir, compilationId + '.req'].join(sep)
49+
fs.writeFileSync(compileRequestFile, [fileName, compiledPath].join('\n'))
50+
waitForFile(compiledPath + '.done')
51+
const compiled = fs.readFileSync(compiledPath, 'utf-8')
52+
return compiled
53+
}
54+
55+
function registerExtensions(extensions: string[]) {
56+
extensions.forEach(function (ext) {
57+
const old = require.extensions[ext] || require.extensions['.js']
58+
require.extensions[ext] = function (m: any, fileName) {
59+
const _compile = m._compile
60+
m._compile = function (code: string, fileName: string) {
61+
return _compile.call(this, compile(code, fileName), fileName)
62+
}
63+
return old(m, fileName)
64+
}
65+
})
66+
if (preferTs) {
67+
const reorderRequireExtension = (ext: string) => {
68+
const old = require.extensions[ext]
69+
delete require.extensions[ext]
70+
require.extensions[ext] = old
71+
}
72+
const order = ['.ts', '.tsx'].concat(
73+
Object.keys(require.extensions).filter((_) => _ !== '.ts' && _ !== '.tsx')
74+
)
75+
order.forEach(function (ext) {
76+
reorderRequireExtension(ext)
77+
})
78+
}
79+
}
80+
81+
function isFileInNodeModules(fileName: string) {
82+
return fileName.indexOf(sep + 'node_modules' + sep) >= 0
83+
}
84+
85+
function registerJsExtension() {
86+
const old = require.extensions['.js']
87+
// handling preferTs probably redundant after reordering
88+
if (allowJs) {
89+
require.extensions['.jsx'] = require.extensions['.js'] = function (
90+
m: any,
91+
fileName
92+
) {
93+
if (fileName.indexOf(libPath) === 0) {
94+
return old(m, fileName)
95+
}
96+
const tsCode: string | undefined = undefined
97+
const tsFileName = ''
98+
const _compile = m._compile
99+
const isIgnored =
100+
ignore &&
101+
ignore.reduce(function (res, ignore) {
102+
return res || ignore.test(fileName)
103+
}, false)
104+
const ext = extname(fileName)
105+
if (tsCode !== undefined || (allowJs && !isIgnored && ext == '.js')) {
106+
m._compile = function (code: string, fileName: string) {
107+
if (tsCode !== undefined) {
108+
code = tsCode
109+
fileName = tsFileName
110+
}
111+
return _compile.call(this, compile(code, fileName), fileName)
112+
}
113+
}
114+
115+
return old(m, fileName)
116+
}
117+
}
118+
}
119+
120+
const sourceMapRequire = Module.createRequire
121+
? Module.createRequire(sourceMapSupportPath)
122+
: require
123+
124+
sourceMapRequire(sourceMapSupportPath).install({
125+
hookRequire: true,
126+
})
127+
128+
registerJsExtension()
129+
registerExtensions(['.ts', '.tsx'])
130+
131+
if (readyFile) {
132+
const time = new Date().getTime()
133+
while (!fs.existsSync(readyFile)) {
134+
if (new Date().getTime() - time > 5000) {
135+
throw new Error('Waiting ts-node-dev ready file failed')
136+
}
137+
}
138+
}
139+
140+
if (exitChild) {
141+
process.on('SIGTERM', function () {
142+
console.log('Child got SIGTERM, exiting.')
143+
process.exit()
144+
})
145+
}
146+
147+
module.exports.registerExtensions = registerExtensions

0 commit comments

Comments
 (0)