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

feat: Add support for Custom tsconfig.json, Resolve extended configs #225

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"mocha": "^8.2.1",
"proxyquire": "^2.1.0",
"ts-node": "^9.0.0",
"typescript": "3.8.3"
"typescript": "4.2.3"
},
"engines": {
"node": ">=8.0.0"
Expand Down
6 changes: 3 additions & 3 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,18 +247,18 @@ export class Config implements IConfig {
s3.templates = {
...s3.templates,
target: {
...s3.templates && s3.templates.target,
baseDir: '<%- bin %>',
unversioned: "<%- channel === 'stable' ? '' : 'channels/' + channel + '/' %><%- bin %>-<%- platform %>-<%- arch %><%- ext %>",
versioned: "<%- channel === 'stable' ? '' : 'channels/' + channel + '/' %><%- bin %>-v<%- version %>/<%- bin %>-v<%- version %>-<%- platform %>-<%- arch %><%- ext %>",
manifest: "<%- channel === 'stable' ? '' : 'channels/' + channel + '/' %><%- platform %>-<%- arch %>",
...s3.templates && s3.templates.target,
},
vanilla: {
...s3.templates && s3.templates.vanilla,
unversioned: "<%- channel === 'stable' ? '' : 'channels/' + channel + '/' %><%- bin %><%- ext %>",
versioned: "<%- channel === 'stable' ? '' : 'channels/' + channel + '/' %><%- bin %>-v<%- version %>/<%- bin %>-v<%- version %><%- ext %>",
baseDir: '<%- bin %>',
manifest: "<%- channel === 'stable' ? '' : 'channels/' + channel + '/' %>version",
...s3.templates && s3.templates.vanilla,
},
}

Expand Down Expand Up @@ -327,7 +327,7 @@ export class Config implements IConfig {
return Promise.all((p.hooks[event] || [])
.map(async hook => {
try {
const f = tsPath(p.root, hook)
const f = tsPath(p.root, hook, this.pjson.oclif.tsConfig)
debug('start', f)
const search = (m: any): Hook<T> => {
if (typeof m === 'function') return m
Expand Down
13 changes: 9 additions & 4 deletions src/pjson.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
export interface PJSON {
[k: string]: any;
dependencies?: {[name: string]: string};
dependencies?: { [name: string]: string };
oclif: {
schema?: number;
tsConfig?: string;
};
}

Expand All @@ -14,7 +15,7 @@ export namespace PJSON {
schema?: number;
title?: string;
description?: string;
hooks?: { [name: string]: (string | string[]) };
hooks?: { [name: string]: string | string[] };
commands?: string;
plugins?: string[];
devPlugins?: string[];
Expand Down Expand Up @@ -76,10 +77,14 @@ export namespace PJSON {
export interface User extends PJSON {
private?: boolean;
oclif: PJSON['oclif'] & {
plugins?: (string | PluginTypes.User | PluginTypes.Link)[]; };
plugins?: (string | PluginTypes.User | PluginTypes.Link)[];
};
}

export type PluginTypes = PluginTypes.User | PluginTypes.Link | {root: string}
export type PluginTypes =
| PluginTypes.User
| PluginTypes.Link
| { root: string };
export namespace PluginTypes {
export interface User {
type: 'user';
Expand Down
2 changes: 1 addition & 1 deletion src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ export class Plugin implements IPlugin {
}

get commandsDir() {
return tsPath(this.root, this.pjson.oclif.commands)
return tsPath(this.root, this.pjson.oclif.commands, this.pjson.oclif.tsConfig)
}

get commandIDs() {
Expand Down
63 changes: 35 additions & 28 deletions src/ts-node.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as fs from 'fs'
import * as path from 'path'
import * as TSNode from 'ts-node'
import type * as TS from 'typescript'

import Debug from './debug'
// eslint-disable-next-line new-cap
Expand All @@ -11,46 +12,51 @@ const rootDirs: string[] = []
const typeRoots = [`${__dirname}/../node_modules/@types`]

export interface TSConfig {
compilerOptions: {
rootDir?: string;
rootDirs?: string[];
outDir?: string;
target?: string;
esModuleInterop?: boolean;
experimentalDecorators?: boolean;
emitDecoratorMetadata?: boolean;
};
compilerOptions: TS.CompilerOptions;
}

function loadTSConfig(root: string): TSConfig | undefined {
const tsconfigPath = path.join(root, 'tsconfig.json')
let typescript: typeof import('typescript') | undefined
function loadTSConfig(root: string, configPath = 'tsconfig.json'): TSConfig | undefined {
let typescript: typeof TS | undefined
try {
typescript = require('typescript')
} catch {
try {
typescript = require(root + '/node_modules/typescript')
} catch { }
}

if (fs.existsSync(tsconfigPath) && typescript) {
const tsconfig = typescript.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 ` +
if (typescript) {
const {findConfigFile, readConfigFile, parseJsonConfigFileContent, sys} = typescript
const tsconfigPath = findConfigFile(
root,
sys.fileExists,
configPath,
)
if (tsconfigPath) {
// Read the user's raw tsconfig file
const readFile = (path: string): string | undefined => fs.readFileSync(path).toString('utf8')
const tsconfig = readConfigFile(tsconfigPath, readFile).config
// Parse the raw config, resolving any configuration files it extends from
const compilerOptions = parseJsonConfigFileContent(
tsconfig,
sys,
root,
).options
console.log({root, tsconfig, compilerOptions})
if (!tsconfig || !compilerOptions) {
throw new Error(
`Could not read and parse tsconfig.json at ${tsconfigPath}, or it ` +
'did not contain a "compilerOptions" section.')
}
// Return only the combined compiler options
return {compilerOptions}
}
return tsconfig
}
}

function registerTSNode(root: string) {
function registerTSNode(root: string, configPath?: string) {
if (process.env.OCLIF_TS_NODE === '0') return
if (tsconfigs[root]) return
const tsconfig = loadTSConfig(root)
const tsconfig = loadTSConfig(root, configPath)
if (!tsconfig) return
debug('registering ts-node at', root)
const tsNodePath = require.resolve('ts-node', {paths: [root, __dirname]})
Expand All @@ -71,6 +77,7 @@ function registerTSNode(root: string) {
// cache: false,
// typeCheck: true,
compilerOptions: {
...tsconfig.compilerOptions,
esModuleInterop: tsconfig.compilerOptions.esModuleInterop,
target: tsconfig.compilerOptions.target || 'es2017',
experimentalDecorators: tsconfig.compilerOptions.experimentalDecorators || false,
Expand All @@ -92,13 +99,13 @@ function registerTSNode(root: string) {
* this is for developing typescript plugins/CLIs
* if there is a tsconfig and the original sources exist, it attempts to require ts-
*/
export function tsPath(root: string, orig: string): string
export function tsPath(root: string, orig: string | undefined): string | undefined
export function tsPath(root: string, orig: string | undefined): string | undefined {
export function tsPath(root: string, orig: string, configPath?: string): string
export function tsPath(root: string, orig: string | undefined, configPath?: string): string | undefined
export function tsPath(root: string, orig: string | undefined, configPath?: string): string | undefined {
if (!orig) return orig
orig = path.join(root, orig)
try {
registerTSNode(root)
registerTSNode(root, configPath)
const tsconfig = tsconfigs[root]
if (!tsconfig) return orig
const {rootDir, rootDirs, outDir} = tsconfig.compilerOptions
Expand Down
4 changes: 4 additions & 0 deletions test/fixtures/typescript/tsconfig.custom.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json"
}

1 change: 1 addition & 0 deletions test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as Config from '../src'
export const fancy = base
.register('resetConfig', () => ({
run(ctx: {config: Config.IConfig}) {
// @ts-expect-error
delete ctx.config
},
}))
Expand Down
7 changes: 6 additions & 1 deletion test/ts-node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as path from 'path'
import * as proxyquire from 'proxyquire'
import * as tsNode from 'ts-node'

import {TSConfig} from '../src/ts-node'
import {TSConfig, tsPath} from '../src/ts-node'

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

Expand Down Expand Up @@ -40,6 +40,11 @@ describe('tsPath', () => {
expect(result).to.equal(path.join(root, orig))
})

it('should resolve a .ts file using custom config using "extends"', () => {
const result = tsPath(root, orig, 'tsconfig.custom.json')
expect(result).to.equal(path.join(root, orig))
})

withMockTsConfig()
.it('should leave esModuleInterop undefined by default', ctx => {
ctx.tsNodePlugin.tsPath(root, orig)
Expand Down
11 changes: 5 additions & 6 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1706,12 +1706,11 @@ lodash.zip@^4.2.0:
resolved "https://registry.yarnpkg.com/lodash.zip/-/lodash.zip-4.2.0.tgz#ec6662e4896408ed4ab6c542a3990b72cc080020"
integrity sha1-7GZi5IlkCO1KtsVCo5kLcswIACA=

lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20:
lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.20:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==


[email protected]:
version "4.0.0"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920"
Expand Down Expand Up @@ -2776,10 +2775,10 @@ type-fest@^0.8.1:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==

typescript@3.8.3:
version "3.8.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061"
integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==
typescript@4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3"
integrity sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==

uglify-js@^3.1.4:
version "3.7.3"
Expand Down