fix(nx-plugin): local plugin execution should work with ts-node (#15066)

This commit is contained in:
Craigory Coppola 2023-02-17 17:25:30 -05:00 committed by GitHub
parent 7d80f25833
commit 6ff04d5a9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 95 additions and 3 deletions

View File

@ -15,7 +15,11 @@ import {
readFile,
removeFile,
cleanupProject,
runCommand,
getPackageManagerCommand,
updateJson,
} from '@nrwl/e2e/utils';
import type { PackageJson } from 'nx/src/utils/package-json';
import { ASYNC_GENERATOR_EXECUTOR_CONTENTS } from './nx-plugin.fixtures';
@ -360,6 +364,30 @@ describe('Nx Plugin', () => {
expect(() => checkFilesExist(`libs/${generatedProject}`)).not.toThrow();
expect(() => runCLI(`execute ${generatedProject}`)).not.toThrow();
});
it('should work with ts-node only', async () => {
const oldPackageJson: PackageJson = readJson('package.json');
updateJson<PackageJson>('package.json', (j) => {
delete j.dependencies['@swc-node/register'];
delete j.devDependencies['@swc-node/register'];
return j;
});
runCommand(getPackageManagerCommand().install);
const generator = uniq('generator');
expect(() => {
runCLI(
`generate @nrwl/nx-plugin:generator ${generator} --project=${plugin}`
);
runCLI(
`generate @${npmScope}/${plugin}:${generator} --name ${uniq('test')}`
);
}).not.toThrow();
updateFile('package.json', JSON.stringify(oldPackageJson, null, 2));
runCommand(getPackageManagerCommand().install);
});
});
describe('--directory', () => {

View File

@ -0,0 +1,20 @@
import { ModuleKind, ScriptTarget } from 'typescript';
import { getTsNodeCompilerOptions } from './register';
describe('getTsNodeCompilerOptions', () => {
it('should replace enum value with enum key for module', () => {
expect(
getTsNodeCompilerOptions({
module: ModuleKind.CommonJS,
}).module
).toEqual('CommonJS');
});
it('should replace enum value with enum key for target', () => {
expect(
getTsNodeCompilerOptions({
target: ScriptTarget.ES2020,
}).target
).toEqual('ES2020');
});
});

View File

@ -4,6 +4,7 @@ import { logger, NX_PREFIX, stripIndent } from './logger';
const swcNodeInstalled = packageIsInstalled('@swc-node/register');
const tsNodeInstalled = packageIsInstalled('ts-node/register');
let ts: typeof import('typescript');
/**
* Optionally, if swc-node and tsconfig-paths are available in the current workspace, apply the require
@ -63,7 +64,7 @@ export function registerTranspiler(
registerTranspiler = () => {
const service = register({
transpileOnly: true,
compilerOptions,
compilerOptions: getTsNodeCompilerOptions(compilerOptions),
});
// Don't warn if a faster transpiler is enabled
if (!service.options.transpiler && !service.options.swc) {
@ -121,8 +122,10 @@ function readCompilerOptions(tsConfigPath): CompilerOptions {
}
function readCompilerOptionsWithTypescript(tsConfigPath) {
const { readConfigFile, parseJsonConfigFileContent, sys } =
require('typescript') as typeof import('typescript');
if (!ts) {
ts = require('typescript');
}
const { readConfigFile, parseJsonConfigFileContent, sys } = ts;
const jsonContent = readConfigFile(tsConfigPath, sys.readFile);
const { options } = parseJsonConfigFileContent(
jsonContent,
@ -164,3 +167,44 @@ function packageIsInstalled(m: string) {
return false;
}
}
/**
* ts-node requires string values for enum based typescript options.
* `register`'s signature just types the field as `object`, so we
* unfortunately do not get any kind of type safety on this.
*/
export function getTsNodeCompilerOptions(compilerOptions: CompilerOptions) {
if (!ts) {
ts = require('typescript');
}
const flagMap: Partial<
Record<keyof RemoveIndex<CompilerOptions>, keyof typeof ts>
> = {
module: 'ModuleKind',
target: 'ScriptTarget',
moduleDetection: 'ModuleDetectionKind',
newLine: 'NewLineKind',
moduleResolution: 'ModuleResolutionKind',
importsNotUsedAsValues: 'ImportsNotUsedAsValues',
};
const result = { ...compilerOptions };
for (const flag in flagMap) {
if (compilerOptions[flag]) {
result[flag] = ts[flagMap[flag]][compilerOptions[flag]];
}
}
return result;
}
/**
* Index keys allow empty objects, where as "real" keys
* require a value. Thus, this filters out index keys
* See: https://stackoverflow.com/a/68261113/3662471
*/
type RemoveIndex<T> = {
[K in keyof T as {} extends Record<K, 1> ? never : K]: T[K];
};