Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto-compile linked plugins #650

Merged
merged 4 commits into from
Mar 8, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
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'
cristiand391 marked this conversation as resolved.
Show resolved Hide resolved

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`]
cristiand391 marked this conversation as resolved.
Show resolved Hide resolved
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