Skip to content

Commit

Permalink
Auto-compile linked plugins (#650)
Browse files Browse the repository at this point in the history
* feat: autocompile linked plugins

* fix: return tsconfig

* chore: move ts-node to deps
  • Loading branch information
mdonnalley authored Mar 8, 2023
1 parent 8f4f165 commit f271403
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 12 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"strip-ansi": "^6.0.1",
"supports-color": "^8.1.1",
"supports-hyperlinks": "^2.2.0",
"ts-node": "^10.9.1",
"tslib": "^2.5.0",
"widest-line": "^3.1.0",
"wordwrap": "^1.0.0",
Expand Down Expand Up @@ -73,7 +74,6 @@
"shelljs": "^0.8.5",
"shx": "^0.3.4",
"sinon": "^11.1.2",
"ts-node": "^10.9.1",
"tsd": "^0.25.0",
"typescript": "^4.9.5"
},
Expand Down Expand Up @@ -114,4 +114,4 @@
"pretest": "yarn build --noEmit && tsc -p test --noEmit --skipLibCheck"
},
"types": "lib/index.d.ts"
}
}
9 changes: 7 additions & 2 deletions src/config/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ export class Plugin implements IPlugin {

hasManifest = false

private _commandsDir!: string | undefined

// eslint-disable-next-line new-cap
protected _debug = Debug()

Expand Down Expand Up @@ -175,7 +177,10 @@ export class Plugin implements IPlugin {
}

public get commandsDir(): string | undefined {
return tsPath(this.root, this.pjson.oclif.commands)
if (this._commandsDir) return this._commandsDir

this._commandsDir = tsPath(this.root, this.pjson.oclif.commands, this.type)
return this._commandsDir
}

public get commandIDs(): string[] {
Expand Down Expand Up @@ -217,7 +222,7 @@ export class Plugin implements IPlugin {

let m
try {
const p = path.join(this.pjson.oclif.commands as string, ...id.split(':'))
const p = path.join(this.commandsDir ?? this.pjson.oclif.commands, ...id.split(':'))
const {isESM, module, filePath} = await ModuleLoader.loadWithData(this, p)
this._debug(isESM ? '(import)' : '(require)', filePath)
m = module
Expand Down
60 changes: 52 additions & 8 deletions src/config/ts-node.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as fs from 'fs'
import * as path from 'path'
import * as TSNode from 'ts-node'

import {TSConfig} from '../interfaces/ts-config'
import {settings} from '../settings'
Expand All @@ -8,6 +9,9 @@ import {Debug} from './util'
// eslint-disable-next-line new-cap
const debug = Debug('ts-node')

const TYPE_ROOTS = [`${__dirname}/../node_modules/@types`]
const ROOT_DIRS: string[] = []

function loadTSConfig(root: string): TSConfig | undefined {
const tsconfigPath = path.join(root, 'tsconfig.json')
let typescript: typeof import('typescript') | undefined
Expand All @@ -34,27 +38,67 @@ function loadTSConfig(root: string): TSConfig | undefined {
}
}

function registerTSNode(root: string) {
const tsconfig = loadTSConfig(root)
if (!tsconfig) return
debug('registering ts-node at', root)
const tsNodePath = require.resolve('ts-node', {paths: [root, __dirname]})
const tsNode: typeof TSNode = require(tsNodePath)

TYPE_ROOTS.push(`${root}/node_modules/@types`)

if (tsconfig.compilerOptions.rootDirs) {
ROOT_DIRS.push(...tsconfig.compilerOptions.rootDirs.map(r => path.join(root, r)))
} else {
ROOT_DIRS.push(`${root}/src`)
}

const cwd = process.cwd()
try {
process.chdir(root)
tsNode.register({
skipProject: true,
transpileOnly: true,
compilerOptions: {
esModuleInterop: tsconfig.compilerOptions.esModuleInterop,
target: tsconfig.compilerOptions.target || 'es2017',
experimentalDecorators: tsconfig.compilerOptions.experimentalDecorators || false,
emitDecoratorMetadata: tsconfig.compilerOptions.emitDecoratorMetadata || false,
module: 'commonjs',
sourceMap: true,
rootDirs: ROOT_DIRS,
typeRoots: TYPE_ROOTS,
jsx: 'react',
},
})
return tsconfig
} finally {
process.chdir(cwd)
}
}

/**
* convert a path from the compiled ./lib files to the ./src typescript source
* Convert a path from the compiled ./lib files to the ./src typescript source
* this is for developing typescript plugins/CLIs
* if there is a tsconfig and the original sources exist, it attempts to require ts-
* if there is a tsconfig and the original sources exist, it attempts to require ts-node
*/
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, type?: string): string
export function tsPath(root: string, orig: string | undefined, type?: string): string | undefined
export function tsPath(root: string, orig: string | undefined, type?: string): string | undefined {
if (!orig) return orig
orig = path.join(root, orig)
orig = orig.startsWith(root) ? orig : path.join(root, orig)

const skipTSNode =
// the CLI specifically turned it off
(settings.tsnodeEnabled === false) ||
// the CLI didn't specify ts-node and it is production
(settings.tsnodeEnabled === undefined && isProd())

if (skipTSNode) return orig
// We always want to load the tsconfig for linked plugins.
if (skipTSNode && type !== 'link') return orig

try {
const tsconfig = loadTSConfig(root)
const tsconfig = type === 'link' ? registerTSNode(root) : loadTSConfig(root)
if (!tsconfig) return orig
const {rootDir, rootDirs, outDir} = tsconfig.compilerOptions
const rootDirPath = rootDir || (rootDirs || [])[0]
Expand Down

0 comments on commit f271403

Please sign in to comment.