Skip to content
This repository has been archived by the owner on Aug 22, 2023. It is now read-only.

Commit

Permalink
fix: Use typescript's tsconfig.json parsing functionality instead of …
Browse files Browse the repository at this point in the history
…JSON.parse (#70)

* Use typescript config parse instead of JSON.parse

* remove unused loadJSONSync

* Update ts-node tests

* proxyquire bug

* fix failing test
  • Loading branch information
samuela authored and jdx committed Jan 30, 2019
1 parent 5718233 commit 7324a99
Show file tree
Hide file tree
Showing 5 changed files with 644 additions and 53 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
"@types/lodash": "^4.14.120",
"@types/mocha": "^5.2.5",
"@types/node": "^10.12.18",
"@types/proxyquire": "^1.3.28",
"@types/wrap-ansi": "^3.0.0",
"chai": "^4.2.0",
"conventional-changelog-cli": "^2.0.11",
"fancy-test": "^1.4.3",
"globby": "^9.0.0",
"lodash": "^4.17.11",
"mocha": "^5.2.0",
"proxyquire": "^2.1.0",
"ts-node": "^7.0.1",
"tslint": "^5.12.1",
"typescript": "^3.2.4"
Expand Down
22 changes: 12 additions & 10 deletions src/ts-node.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as fs from 'fs'
import * as path from 'path'
import * as TSNode from 'ts-node'
import {parseConfigFileTextToJson} from 'typescript'

import Debug from './debug'
import {loadJSONSync} from './util'

const tsconfigs: {[root: string]: TSConfig} = {}
const rootDirs: string[] = []
Expand Down Expand Up @@ -59,16 +59,18 @@ function registerTSNode(root: string) {
}

function loadTSConfig(root: string): TSConfig | undefined {
try {
// // ignore if no .git as it's likely not in dev mode
// if (!await fs.pathExists(path.join(this.root, '.git'))) return

const tsconfigPath = path.join(root, 'tsconfig.json')
const tsconfig = loadJSONSync(tsconfigPath)
if (!tsconfig || !tsconfig.compilerOptions) return
const tsconfigPath = path.join(root, 'tsconfig.json')
if (fs.existsSync(tsconfigPath)) {
const tsconfig = parseConfigFileTextToJson(
tsconfigPath,
fs.readFileSync(tsconfigPath, 'utf8')
).config
if (!tsconfig || !tsconfig.compilerOptions) {
throw new Error(
`Could not read and parse tsconfig.json at ${tsconfigPath}, or it ` +
'did not contain a "compilerOptions" section.')
}
return tsconfig
} catch (err) {
if (err.code !== 'ENOENT') throw err
}
}

Expand Down
8 changes: 0 additions & 8 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,6 @@ export function mapValues<T extends object, TResult>(obj: {[P in keyof T]: T[P]}
}, {} as any)
}

export function loadJSONSync(path: string): any {
debug('loadJSONSync %s', path)
// let loadJSON
// try { loadJSON = require('load-json-file') } catch {}
// if (loadJSON) return loadJSON.sync(path)
return JSON.parse(fs.readFileSync(path, 'utf8'))
}

export function exists(path: string): Promise<boolean> {
// tslint:disable-next-line
return new Promise(resolve => fs.exists(path, resolve))
Expand Down
44 changes: 19 additions & 25 deletions test/ts-node.test.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,48 @@
import * as path from 'path'
import * as proxyquire from 'proxyquire'
import * as tsNode from 'ts-node'

import {TSConfig} from '../src/ts-node'
import * as util from '../src/util'

import {expect, fancy} from './test'

const root = path.resolve(__dirname, 'fixtures/typescript')
const orig = 'src/hooks/init.ts'
let tsNodeRegisterCallArguments: any[] = []

/**
* Delete a module from the require cache before requiring it.
*/
export default function freshRequire(name: string) {
delete require.cache[require.resolve(name)]
return require(name)
}

const DEFAULT_TS_CONFIG: TSConfig = {
compilerOptions: {}
}

const withMockTsConfig = (config: TSConfig = DEFAULT_TS_CONFIG) =>
fancy
const withMockTsConfig = (config: TSConfig = DEFAULT_TS_CONFIG) => {
const tsNodePlugin = proxyquire('../src/ts-node', {fs: {
existsSync: () => true,
readFileSync: () => JSON.stringify(config)
}})

// This prints "loadTSConfig unstubbed" not "loadTSConfig proxyquire"!
tsNodePlugin.tsPath('poop', 'asdf')

return fancy
.add('tsNodePlugin', () => tsNodePlugin)
.stub(tsNode, 'register', (arg: any) => {
tsNodeRegisterCallArguments.push(arg)
})
.stub(util, 'loadJSONSync', (arg: string) => {
if (arg.endsWith('tsconfig.json')) {
return config
}
})
.finally(() => {
tsNodeRegisterCallArguments = []
})
}

describe('tsPath', () => {
withMockTsConfig()
.it('should resolve a .ts file', () => {
const {tsPath} = freshRequire('../src/ts-node')
const result = tsPath(root, orig)
.it('should resolve a .ts file', ctx => {
const result = ctx.tsNodePlugin.tsPath(root, orig)
expect(result).to.equal(path.join(root, orig))
})

withMockTsConfig()
.it('should leave esModuleInterop undefined by default', () => {
const {tsPath} = freshRequire('../src/ts-node')
tsPath(root, orig)
.it('should leave esModuleInterop undefined by default', ctx => {
ctx.tsNodePlugin.tsPath(root, orig)
expect(tsNodeRegisterCallArguments.length).is.equal(1)
expect(tsNodeRegisterCallArguments[0])
.to.have.nested.property('compilerOptions.esModuleInterop')
Expand All @@ -59,9 +54,8 @@ describe('tsPath', () => {
esModuleInterop: true
}
})
.it('should use the provided esModuleInterop option', () => {
const {tsPath} = freshRequire('../src/ts-node')
tsPath(root, orig)
.it('should use the provided esModuleInterop option', ctx => {
ctx.tsNodePlugin.tsPath(root, orig)
expect(tsNodeRegisterCallArguments.length).is.equal(1)
expect(tsNodeRegisterCallArguments[0])
.to.have.nested.property('compilerOptions.esModuleInterop')
Expand Down
Loading

0 comments on commit 7324a99

Please sign in to comment.