diff --git a/.changeset/sweet-oranges-sneeze.md b/.changeset/sweet-oranges-sneeze.md new file mode 100644 index 000000000..a345502fc --- /dev/null +++ b/.changeset/sweet-oranges-sneeze.md @@ -0,0 +1,5 @@ +--- +"@layerzerolabs/devtools-cli": patch +--- + +Add TypeScript support diff --git a/packages/devtools-cli/src/commands/oapp/wire/index.ts b/packages/devtools-cli/src/commands/oapp/wire/index.ts index b7231167f..76995f2ba 100644 --- a/packages/devtools-cli/src/commands/oapp/wire/index.ts +++ b/packages/devtools-cli/src/commands/oapp/wire/index.ts @@ -1,21 +1,36 @@ import { Command } from 'commander' import { printLogo } from '@layerzerolabs/io-devtools/swag' import { createLogger, setDefaultLogLevel } from '@layerzerolabs/io-devtools' -import { type WithLogLevelOption, type WithSetupOption, createSetupFileOption } from '@/commands/options' +import { + type WithLogLevelOption, + type WithSetupOption, + WithTsConfigOption, + createLogLevelOption, + createSetupFileOption, + createTsConfigFileOption, +} from '@/commands/options' +import { setupTypescript } from '@/setup' -interface Args extends WithLogLevelOption, WithSetupOption {} +interface Args extends WithLogLevelOption, WithSetupOption, WithTsConfigOption {} -export const wire = new Command('wire').addOption(createSetupFileOption()).action(async ({ setup, logLevel }: Args) => { - printLogo() +export const wire = new Command('wire') + .addOption(createSetupFileOption()) + .addOption(createTsConfigFileOption()) + .addOption(createLogLevelOption()) + .action(async ({ setup, logLevel, tsConfig: tsConfigPath }: Args) => { + printLogo() - // We'll set the global logging level to get as much info as needed - setDefaultLogLevel(logLevel) + // We'll set the global logging level to get as much info as needed + setDefaultLogLevel(logLevel) - const logger = createLogger(logLevel) + // We'll setup TypeScript support so that we can dynamically load TypeScript config files + setupTypescript(tsConfigPath) - logger.debug(`Loading setup from ${setup}`) + const logger = createLogger(logLevel) - logger.warn( - `This command is just a placeholder. Please use @layerzerolabs/toolbox-hardhat package for the time being.` - ) -}) + logger.debug(`Loading setup from ${setup}`) + + logger.warn( + `This command is just a placeholder. Please use @layerzerolabs/toolbox-hardhat package for the time being.` + ) + }) diff --git a/packages/devtools-cli/src/commands/options.ts b/packages/devtools-cli/src/commands/options.ts index 3ce1f06b8..293027250 100644 --- a/packages/devtools-cli/src/commands/options.ts +++ b/packages/devtools-cli/src/commands/options.ts @@ -21,3 +21,10 @@ export const createLogLevelOption = () => return value }) + +export interface WithTsConfigOption { + tsConfig?: string +} + +export const createTsConfigFileOption = () => + new Option('--ts-config ', 'Path to TypeScript config file (tsconfig.json)').default('tsconfig.json') diff --git a/packages/devtools-cli/src/setup/typescript.ts b/packages/devtools-cli/src/setup/typescript.ts new file mode 100644 index 000000000..8c0735a49 --- /dev/null +++ b/packages/devtools-cli/src/setup/typescript.ts @@ -0,0 +1,55 @@ +import { createModuleLogger } from '@layerzerolabs/io-devtools' +import { resolve } from 'path' + +export const setupTypescript = (tsConfigPath?: string): void => { + const logger = createModuleLogger('TypeScript support') + + try { + require.resolve('typescript') + } catch { + return ( + logger.debug( + `typescript module not available. To enable TypeScript support for devtools, please install typescript NPM module` + ), + undefined + ) + } + + try { + require.resolve('ts-node') + } catch { + return ( + logger.debug( + `ts-node module not available. To enable TypeScript support for devtools, please install ts-node NPM module` + ), + undefined + ) + } + + // In case a custom tsconfig is required, we specify it using an env variable + if (tsConfigPath !== undefined) { + logger.debug(`Using tsconfig from ${tsConfigPath} (${resolve(tsConfigPath)})`) + + process.env.TS_NODE_PROJECT = resolve(tsConfigPath) + } + + if (process.env.TS_NODE_FILES === undefined) { + process.env.TS_NODE_FILES = 'true' + } + + try { + // tsup will optimize requires if string lterals are used directly in require() + // + // So require('ts-node/register') would result in ts-node being bundled with the module + const tsNode = 'ts-node/register/transpile-only' + + require(tsNode) + } catch (error) { + return ( + logger.debug( + `Failed to register ts-node. TypeScript support for devtools will not be available. Error:\n\n${error}` + ), + undefined + ) + } +}