Skip to content
Merged
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
21 changes: 16 additions & 5 deletions dist-raw/node-cjs-loader-utils.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,17 +5,28 @@
const path = require('path');
const packageJsonReader = require('./node-package-json-reader');
const {JSONParse} = require('./node-primordials');
const {normalizeSlashes} = require('../dist/util');

module.exports.assertScriptCanLoadAsCJSImpl = assertScriptCanLoadAsCJSImpl;

// copied from Module._extensions['.js']
// https://github.com/nodejs/node/blob/v15.3.0/lib/internal/modules/cjs/loader.js#L1113-L1120
function assertScriptCanLoadAsCJSImpl(filename) {
/**
* copied from Module._extensions['.js']
* https://github.com/nodejs/node/blob/v15.3.0/lib/internal/modules/cjs/loader.js#L1113-L1120
* @param {import('../src/index').Service} service
* @param {NodeJS.Module} module
* @param {string} filename
*/
function assertScriptCanLoadAsCJSImpl(service, module, filename) {
const pkg = readPackageScope(filename);

// ts-node modification: allow our configuration to override
const tsNodeClassification = service.moduleTypeClassifier.classifyModule(normalizeSlashes(filename));
if(tsNodeClassification.moduleType === 'cjs') return;

// Function require shouldn't be used in ES modules.
if (pkg && pkg.data && pkg.data.type === 'module') {
if (tsNodeClassification.moduleType === 'esm' || (pkg && pkg.data && pkg.data.type === 'module')) {
const parentPath = module.parent && module.parent.filename;
const packageJsonPath = path.resolve(pkg.path, 'package.json');
const packageJsonPath = pkg ? path.resolve(pkg.path, 'package.json') : null;
throw createErrRequireEsm(filename, parentPath, packageJsonPath);
}
}
Expand Down
1 change: 1 addition & 0 deletions src/bin.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -296,6 +296,7 @@ export function main(
const json = {
['ts-node']: {
...service.options,
optionBasePaths: undefined,
experimentalEsmLoader: undefined,
compilerOptions: undefined,
project: service.configFilePath ?? service.options.project,
Expand Down
26 changes: 24 additions & 2 deletions src/configuration.ts
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
import { resolve, dirname } from 'path';
import type * as _ts from 'typescript';
import { CreateOptions, DEFAULTS, TSCommon, TsConfigOptions } from './index';
import {
CreateOptions,
DEFAULTS,
OptionBasePaths,
TSCommon,
TsConfigOptions,
} from './index';
import type { TSInternal } from './ts-compiler-types';
import { createTsInternals } from './ts-internals';
import { getDefaultTsconfigJsonForNodeVersion } from './tsconfigs';
Expand DownExpand Up@@ -70,6 +76,7 @@ export function readConfig(
* this function.
*/
tsNodeOptionsFromTsconfig: TsConfigOptions;
optionBasePaths: OptionBasePaths;
} {
// Ordered [a, b, c] where config a extends b extends c
const configChain: Array<{
Expand DownExpand Up@@ -110,6 +117,7 @@ export function readConfig(
configFilePath,
config: { errors: [result.error], fileNames: [], options: {} },
tsNodeOptionsFromTsconfig: {},
optionBasePaths: {},
};
}

Expand DownExpand Up@@ -140,6 +148,7 @@ export function readConfig(
configFilePath,
config: { errors, fileNames: [], options: {} },
tsNodeOptionsFromTsconfig: {},
optionBasePaths: {},
};
}
if (resolvedExtendedConfigPath == null) break;
Expand All@@ -152,6 +161,7 @@ export function readConfig(

// Merge and fix ts-node options that come from tsconfig.json(s)
const tsNodeOptionsFromTsconfig: TsConfigOptions = {};
const optionBasePaths: OptionBasePaths = {};
for (let i = configChain.length - 1; i >= 0; i--) {
const { config, basePath, configPath } = configChain[i];
const options = filterRecognizedTsConfigTsNodeOptions(config['ts-node'])
Expand All@@ -169,6 +179,11 @@ export function readConfig(
options.scopeDir = resolve(basePath, options.scopeDir!);
}

// Downstream code uses the basePath; we do not do that here.
if (options.moduleTypes) {
optionBasePaths.moduleTypes = basePath;
}

assign(tsNodeOptionsFromTsconfig, options);
}

Expand DownExpand Up@@ -222,7 +237,12 @@ export function readConfig(
)
);

return { configFilePath, config: fixedConfig, tsNodeOptionsFromTsconfig };
return {
configFilePath,
config: fixedConfig,
tsNodeOptionsFromTsconfig,
optionBasePaths,
};
}

/**
Expand DownExpand Up@@ -251,6 +271,7 @@ function filterRecognizedTsConfigTsNodeOptions(
transpiler,
scope,
scopeDir,
moduleTypes,
...unrecognized
} = jsonObject as TsConfigOptions;
const filteredTsConfigOptions = {
Expand All@@ -271,6 +292,7 @@ function filterRecognizedTsConfigTsNodeOptions(
transpiler,
scope,
scopeDir,
moduleTypes,
};
// Use the typechecker to make sure this implementation has the correct set of properties
const catchExtraneousProps: keyof TsConfigOptions = (null as any) as keyof typeof filteredTsConfigOptions;
Expand Down
23 changes: 20 additions & 3 deletions src/esm.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ import {
} from 'url';
import { extname } from 'path';
import * as assert from 'assert';
import { normalizeSlashes } from './util';
const {
createResolve,
} = require('../dist-raw/node-esm-resolve-implementation');
Expand DownExpand Up@@ -96,11 +97,27 @@ export function registerAndCreateEsmHooks(opts?: RegisterOptions) {

// If file has .ts, .tsx, or .jsx extension, then ask node how it would treat this file if it were .js
const ext = extname(nativePath);
let nodeSays: { format: Format };
if (ext !== '.js' && !tsNodeInstance.ignored(nativePath)) {
return defer(formatUrl(pathToFileURL(nativePath + '.js')));
nodeSays = await defer(formatUrl(pathToFileURL(nativePath + '.js')));
} else {
nodeSays = await defer();
}

return defer();
// For files compiled by ts-node that node believes are either CJS or ESM, check if we should override that classification
if (
!tsNodeInstance.ignored(nativePath) &&
(nodeSays.format === 'commonjs' || nodeSays.format === 'module')
) {
const { moduleType } = tsNodeInstance.moduleTypeClassifier.classifyModule(
normalizeSlashes(nativePath)
);
if (moduleType === 'cjs') {
return { format: 'commonjs' };
} else if (moduleType === 'esm') {
return { format: 'module' };
}
}
return nodeSays;
}

async function transformSource(
Expand Down
Loading