Skip to content

Commit

Permalink
Support --prefer-ts-exts flag (#837)
Browse files Browse the repository at this point in the history
  • Loading branch information
G-Rath authored and blakeembrey committed Jun 15, 2019
1 parent b8fd523 commit 611d013
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -136,6 +136,7 @@ _Environment variable denoted in parentheses._
* `--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`)
* `--log-error` Logs errors of types instead of exit the process (`TS_NODE_LOG_ERROR`, default: `false`)
* `--prefer-ts-exts` Changes the order of file extensions used when matching file imports so that `.ts` files are preferred over `.js` (`TS_PREFER_TS_EXTS`, default: `false`)

### Programmatic Only Options

Expand Down
4 changes: 4 additions & 0 deletions src/bin.ts
Expand Up @@ -32,6 +32,7 @@ const args = arg({
'--pretty': Boolean,
'--skip-project': Boolean,
'--skip-ignore': Boolean,
'--prefer-ts-exts': Boolean,
'--log-error': Boolean,

// Aliases.
Expand Down Expand Up @@ -64,6 +65,7 @@ const {
'--pretty': pretty = DEFAULTS.pretty,
'--skip-project': skipProject = DEFAULTS.skipProject,
'--skip-ignore': skipIgnore = DEFAULTS.skipIgnore,
'--prefer-ts-exts': preferTsExts = DEFAULTS.preferTsExts,
'--log-error': logError = DEFAULTS.logError
} = args

Expand Down Expand Up @@ -91,6 +93,7 @@ Options:
--pretty Use pretty diagnostic formatter
--skip-project Skip reading \`tsconfig.json\`
--skip-ignore Skip \`--ignore\` checks
--prefer-ts-exts Prefer importing TypeScript files over JavaScript files
`)

process.exit(0)
Expand All @@ -115,6 +118,7 @@ const service = register({
ignore,
project,
skipIgnore,
preferTsExts,
logError,
skipProject,
compiler,
Expand Down
27 changes: 27 additions & 0 deletions src/index.spec.ts
Expand Up @@ -269,6 +269,33 @@ describe('ts-node', function () {
return done()
})
})

it('should import js before ts by default', function (done) {
exec(`${BIN_EXEC} tests/import-order/compiled`, function (err, stdout) {
expect(err).to.equal(null)
expect(stdout).to.equal('Hello, JavaScript!\n')

return done()
})
})

it('should import ts before js when --prefer-ts-exts flag is present', function (done) {
exec(`${BIN_EXEC} --prefer-ts-exts tests/import-order/compiled`, function (err, stdout) {
expect(err).to.equal(null)
expect(stdout).to.equal('Hello, TypeScript!\n')

return done()
})
})

it('should ignore .d.ts files', function (done) {
exec(`${BIN_EXEC} tests/import-order/importer`, function (err, stdout) {
expect(err).to.equal(null)
expect(stdout).to.equal('Hello, World!\n')

return done()
})
})
})

describe('register', function () {
Expand Down
44 changes: 41 additions & 3 deletions src/index.ts
Expand Up @@ -66,6 +66,7 @@ export interface Options {
project?: string
skipIgnore?: boolean | null
skipProject?: boolean | null
preferTsExts?: boolean | null
compilerOptions?: object
ignoreDiagnostics?: Array<number | string>
readFile?: (path: string) => string | undefined
Expand Down Expand Up @@ -105,6 +106,7 @@ export const DEFAULTS: Options = {
project: process.env['TS_NODE_PROJECT'],
skipIgnore: yn(process.env['TS_NODE_SKIP_IGNORE']),
skipProject: yn(process.env['TS_NODE_SKIP_PROJECT']),
preferTsExts: yn(process.env['TS_NODE_PREFER_TS_EXTS']),
ignoreDiagnostics: split(process.env['TS_NODE_IGNORE_DIAGNOSTICS']),
typeCheck: yn(process.env['TS_NODE_TYPE_CHECK']),
transpileOnly: yn(process.env['TS_NODE_TRANSPILE_ONLY']),
Expand Down Expand Up @@ -399,9 +401,7 @@ export function register (opts: Options = {}): Register {
const register: Register = { cwd, compile, getTypeInfo, extensions, ts }

// Register the extensions.
extensions.forEach(extension => {
registerExtension(extension, ignore, register, originalJsHandler)
})
registerExtensions(opts, extensions, ignore, register, originalJsHandler)

return register
}
Expand All @@ -415,6 +415,44 @@ function shouldIgnore (filename: string, ignore: RegExp[]) {
return ignore.some(x => x.test(relname))
}

/**
* "Refreshes" an extension on `require.extentions`.
*
* @param {string} ext
*/
function refreshRequireExtension (ext: string) {
const old = require.extensions[ext] // tslint:disable-line
delete require.extensions[ext] // tslint:disable-line
require.extensions[ext] = old // tslint:disable-line
}

/**
* Register the extensions to support when importing files.
*/
function registerExtensions (
opts: Options,
extensions: string[],
ignore: RegExp[],
register: Register,
originalJsHandler: (m: NodeModule, filename: string) => any
) {
if (opts.preferTsExts) {
extensions.unshift(
'.ts',
'.tsx',
...Object.keys(require.extensions), // tslint:disable-line
)
}

// @todo a better way with options
Array.from(new Set(extensions))
.forEach(ext => {
registerExtension(ext, ignore, register, originalJsHandler)

if (ext in require.extensions) refreshRequireExtension(ext) // tslint:disable-line
})
}

/**
* Register the extension for node.
*/
Expand Down
1 change: 1 addition & 0 deletions tests/import-order/compiled.js
@@ -0,0 +1 @@
console.log('Hello, JavaScript!');
1 change: 1 addition & 0 deletions tests/import-order/compiled.ts
@@ -0,0 +1 @@
console.log('Hello, TypeScript!')
3 changes: 3 additions & 0 deletions tests/import-order/defined.d.ts
@@ -0,0 +1,3 @@
declare const v = 'Hello, World!'

export default v
1 change: 1 addition & 0 deletions tests/import-order/defined.js
@@ -0,0 +1 @@
module.exports = 'Hello, World!';
3 changes: 3 additions & 0 deletions tests/import-order/importer.ts
@@ -0,0 +1,3 @@
const v = require('./defined')

console.log(v)

0 comments on commit 611d013

Please sign in to comment.