Skip to content
Open
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
12 changes: 4 additions & 8 deletions lib/internal/bootstrap/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -334,20 +334,16 @@ ObjectDefineProperty(process, 'features', {
const { emitWarning, emitWarningSync } = require('internal/process/warning');
const { getOptionValue } = require('internal/options');

let kTypeStrippingMode = process.config.variables.node_use_amaro ? null : false;
// This must be a getter, as getOptionValue does not work
// before bootstrapping.
ObjectDefineProperty(process.features, 'typescript', {
__proto__: null,
get() {
if (kTypeStrippingMode === null) {
if (getOptionValue('--strip-types')) {
kTypeStrippingMode = 'strip';
} else {
kTypeStrippingMode = false;
}
const { isTypeScriptEnabled, currentConfig } = require('internal/modules/typescript');
if (!isTypeScriptEnabled()) {
return false;
}
return kTypeStrippingMode;
return currentConfig.mode;
},
configurable: true,
enumerable: true,
Expand Down
3 changes: 2 additions & 1 deletion lib/internal/main/eval_stdin.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ readStdin((code) => {
const print = getOptionValue('--print');
const shouldLoadESM = getOptionValue('--import').length > 0;
const inputType = getOptionValue('--input-type');
const tsEnabled = getOptionValue('--strip-types');
const { isTypeScriptEnabled } = require('internal/modules/typescript');
const tsEnabled = isTypeScriptEnabled();
if (inputType === 'module') {
evalModuleEntryPoint(code, print);
} else if (inputType === 'module-typescript' && tsEnabled) {
Expand Down
3 changes: 2 additions & 1 deletion lib/internal/main/eval_string.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ const code = getOptionValue('--eval');
const print = getOptionValue('--print');
const shouldLoadESM = getOptionValue('--import').length > 0 || getOptionValue('--experimental-loader').length > 0;
const inputType = getOptionValue('--input-type');
const tsEnabled = getOptionValue('--strip-types');
const { isTypeScriptEnabled } = require('internal/modules/typescript');
const tsEnabled = isTypeScriptEnabled();
if (inputType === 'module') {
evalModuleEntryPoint(code, print);
} else if (inputType === 'module-typescript' && tsEnabled) {
Expand Down
3 changes: 2 additions & 1 deletion lib/internal/main/worker_thread.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@ port.on('message', (message) => {
value: filename,
});
ArrayPrototypeSplice(process.argv, 1, 0, name);
const tsEnabled = getOptionValue('--strip-types');
const { isTypeScriptEnabled } = require('internal/modules/typescript');
const tsEnabled = isTypeScriptEnabled();
const inputType = getOptionValue('--input-type');

if (inputType === 'module-typescript' && tsEnabled) {
Expand Down
4 changes: 2 additions & 2 deletions lib/internal/modules/cjs/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ const {
resolveWithHooks,
validateLoadStrict,
} = require('internal/modules/customization_hooks');
const { stripTypeScriptModuleTypes } = require('internal/modules/typescript');
const { isTypeScriptEnabled, stripTypeScriptModuleTypes } = require('internal/modules/typescript');
const packageJsonReader = require('internal/modules/package_json_reader');
const { getOptionValue, getEmbedderOptions } = require('internal/options');
const shouldReportRequiredModules = getLazy(() => process.env.WATCH_REPORT_DEPENDENCIES);
Expand Down Expand Up @@ -2032,7 +2032,7 @@ function getRequireESMError(mod, pkg, content, filename) {
*/
Module._extensions['.js'] = function(module, filename) {
let format, pkg;
const tsEnabled = getOptionValue('--strip-types');
const tsEnabled = isTypeScriptEnabled();
if (StringPrototypeEndsWith(filename, '.cjs')) {
format = 'commonjs';
} else if (StringPrototypeEndsWith(filename, '.mjs')) {
Expand Down
6 changes: 4 additions & 2 deletions lib/internal/modules/esm/get_format.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ function initializeExtensionFormatMap() {
extensionFormatMap['.node'] = 'addon';
}

if (getOptionValue('--strip-types')) {
const { isTypeScriptEnabled } = require('internal/modules/typescript');
if (isTypeScriptEnabled()) {
extensionFormatMap['.ts'] = 'module-typescript';
extensionFormatMap['.mts'] = 'module-typescript';
extensionFormatMap['.cts'] = 'commonjs-typescript';
Expand Down Expand Up @@ -190,7 +191,8 @@ function getFileProtocolModuleFormat(url, context = { __proto__: null }, ignoreE
}
return format;
}
if (ext === '.ts' && getOptionValue('--strip-types')) {
const { isTypeScriptEnabled } = require('internal/modules/typescript');
if (ext === '.ts' && isTypeScriptEnabled()) {
const { type: packageType, pjsonPath, exists: foundPackageJson } = getPackageScopeConfig(url);
if (packageType !== 'none') {
return `${packageType}-typescript`;
Expand Down
3 changes: 2 additions & 1 deletion lib/internal/modules/run_main.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ function shouldUseESMLoader(mainPath) {
if (mainPath && StringPrototypeEndsWith(mainPath, '.wasm')) { return true; }
if (!mainPath || StringPrototypeEndsWith(mainPath, '.cjs')) { return false; }

if (getOptionValue('--strip-types')) {
const { isTypeScriptEnabled } = require('internal/modules/typescript');
if (isTypeScriptEnabled()) {
if (!mainPath || StringPrototypeEndsWith(mainPath, '.cts')) { return false; }
// This will likely change in the future to start with commonjs loader by default
if (mainPath && StringPrototypeEndsWith(mainPath, '.mts')) { return true; }
Expand Down
87 changes: 81 additions & 6 deletions lib/internal/modules/typescript.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ const {
ObjectPrototypeHasOwnProperty,
} = primordials;
const {
validateBoolean,
validateOneOf,
validateObject,
validateString,
} = require('internal/validators');
const { getOptionValue } = require('internal/options');
const { assertTypeScript,
emitExperimentalWarning,
getLazy,
Expand All @@ -22,8 +24,66 @@ const assert = require('internal/assert');
const {
getCompileCacheEntry,
saveCompileCacheEntry,
cachedCodeTypes: { kStrippedTypeScript },
cachedCodeTypes: {
kStrippedTypeScript,
kTransformedTypeScript,
kTransformedTypeScriptWithSourceMaps,
},
} = internalBinding('modules');
const currentConfig = {
mode: 'strip',
nodeModules: false,
sourceMaps: undefined,
};
let typescriptEnabledViaAPI = false;

function isTypeScriptEnabled() {
return typescriptEnabledViaAPI || getOptionValue('--strip-types');
}

function configureTypeScript(options) {
if (options === undefined) {
return { ...currentConfig };
}
validateObject(options, 'options');
const newConfig = { ...currentConfig };
if (options.mode !== undefined) {
validateOneOf(options.mode, 'options.mode', ['strip', 'transform']);
newConfig.mode = options.mode;
}
if (options.nodeModules !== undefined) {
validateBoolean(options.nodeModules, 'options.nodeModules');
newConfig.nodeModules = options.nodeModules;
}
if (options.sourceMaps !== undefined) {
validateBoolean(options.sourceMaps, 'options.sourceMaps');
newConfig.sourceMaps = options.sourceMaps;
}
const previousConfig = { ...currentConfig };

// Mutate currentConfig in-place to preserve references for CJS exports
currentConfig.mode = newConfig.mode;
currentConfig.nodeModules = newConfig.nodeModules;
currentConfig.sourceMaps = newConfig.sourceMaps;

typescriptEnabledViaAPI = true;

// Dynamically map the TypeScript extensions in ESM get_format
const { extensionFormatMap } = require('internal/modules/esm/get_format');
extensionFormatMap['.ts'] = 'module-typescript';
extensionFormatMap['.mts'] = 'module-typescript';
extensionFormatMap['.cts'] = 'commonjs-typescript';

return previousConfig;
}

function getCachedCodeType(mode, sourceMap) {
if (mode === 'transform') {
if (sourceMap) { return kTransformedTypeScriptWithSourceMaps; }
return kTransformedTypeScript;
}
return kStrippedTypeScript;
}


/**
Expand Down Expand Up @@ -93,23 +153,29 @@ function stripTypeScriptTypes(code, options = kEmptyObject) {
validateString(code, 'code');
validateObject(options, 'options');

let {
mode = 'strip',
} = options;
const {
sourceMap = false,
sourceUrl = '',
} = options;
let { mode = 'strip' } = options;
validateOneOf(mode, 'options.mode', ['strip']);
validateOneOf(mode, 'options.mode', ['strip', 'transform']);
validateString(sourceUrl, 'options.sourceUrl');

if (mode === 'strip') {
validateOneOf(sourceMap, 'options.sourceMap', [false, undefined]);
// Rename mode from 'strip' to 'strip-only'.
// The reason is to match `process.features.typescript` which returns `strip`,
// but the parser expects `strip-only`.
mode = 'strip-only';
} else {
validateBoolean(sourceMap, 'options.sourceMap');
}

return processTypeScriptCode(code, {
mode,
sourceMap,
filename: sourceUrl,
});
}
Expand Down Expand Up @@ -151,21 +217,27 @@ function stripTypeScriptTypesForCoverage(code) {
*/
function stripTypeScriptModuleTypes(source, filename, sourceURL) {
assert(typeof source === 'string');
if (isUnderNodeModules(filename)) {
if (!currentConfig.nodeModules && isUnderNodeModules(filename)) {
throw new ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING(filename);
}

const mode = currentConfig.mode;
const sourceMap = mode === 'transform' ? (currentConfig.sourceMaps ?? true) : false;
const type = getCachedCodeType(mode, sourceMap);

// Get a compile cache entry into the native compile cache store,
// keyed by the filename. If the cache can already be loaded on disk,
// cached.transpiled contains the cached string. Otherwise we should do
// the transpilation and save it in the native store later using
// saveCompileCacheEntry().
const cached = (filename ? getCompileCacheEntry(source, filename, kStrippedTypeScript) : undefined);
const cached = (filename ? getCompileCacheEntry(source, filename, type) : undefined);
if (cached?.transpiled) { // TODO(joyeecheung): return Buffer here.
return cached.transpiled;
}

const options = {
mode: 'strip-only',
mode: mode === 'strip' ? 'strip-only' : mode,
sourceMap,
filename: sourceURL ?? filename,
};

Expand All @@ -182,6 +254,9 @@ function stripTypeScriptModuleTypes(source, filename, sourceURL) {
}

module.exports = {
configureTypeScript,
isTypeScriptEnabled,
currentConfig,
stripTypeScriptModuleTypes,
stripTypeScriptTypes,
stripTypeScriptTypesForCoverage,
Expand Down
4 changes: 2 additions & 2 deletions lib/internal/process/execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const {
kSourcePhase,
kEvaluationPhase,
} = internalBinding('module_wrap');
const { stripTypeScriptModuleTypes } = require('internal/modules/typescript');
const { isTypeScriptEnabled, stripTypeScriptModuleTypes } = require('internal/modules/typescript');

const {
executionAsyncId,
Expand Down Expand Up @@ -86,7 +86,7 @@ function evalScript(name, body, breakFirstLine, print, shouldLoadESM = false) {
const baseUrl = pathToFileURL(module.filename).href;

if (shouldUseModuleEntryPoint(name, body)) {
return getOptionValue('--strip-types') ?
return isTypeScriptEnabled() ?
evalTypeScriptModuleEntryPoint(body, print) :
evalModuleEntryPoint(body, print);
}
Expand Down
3 changes: 2 additions & 1 deletion lib/internal/test_runner/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ const kMaxRandomSeed = 0xFFFF_FFFF;

const kPatterns = ['test', 'test/**/*', 'test-*', '*[._-]test'];
const kFileExtensions = ['js', 'mjs', 'cjs'];
if (getOptionValue('--strip-types')) {
const { isTypeScriptEnabled } = require('internal/modules/typescript');
if (isTypeScriptEnabled()) {
ArrayPrototypePush(kFileExtensions, 'ts', 'mts', 'cts');
}
const kDefaultPattern = `**/{${ArrayPrototypeJoin(kPatterns, ',')}}.{${ArrayPrototypeJoin(kFileExtensions, ',')}}`;
Expand Down
3 changes: 2 additions & 1 deletion lib/module.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const {
const {
findPackageJSON,
} = require('internal/modules/package_json_reader');
const { stripTypeScriptTypes } = require('internal/modules/typescript');
const { stripTypeScriptTypes, configureTypeScript } = require('internal/modules/typescript');

Module.register = register;
Module.constants = constants;
Expand All @@ -28,6 +28,7 @@ Module.findPackageJSON = findPackageJSON;
Module.flushCompileCache = flushCompileCache;
Module.getCompileCacheDir = getCompileCacheDir;
Module.stripTypeScriptTypes = stripTypeScriptTypes;
Module.configureTypeScript = configureTypeScript;

// SourceMap APIs
Module.findSourceMap = findSourceMap;
Expand Down
8 changes: 7 additions & 1 deletion src/compile_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ const char* CompileCacheEntry::type_name() const {
return "ESM";
case CachedCodeType::kStrippedTypeScript:
return "StrippedTypeScript";
case CachedCodeType::kTransformedTypeScript:
return "TransformedTypeScript";
case CachedCodeType::kTransformedTypeScriptWithSourceMaps:
return "TransformedTypeScriptWithSourceMaps";
default:
UNREACHABLE();
}
Expand Down Expand Up @@ -349,7 +353,9 @@ void CompileCacheHandler::MaybeSave(CompileCacheEntry* entry,

void CompileCacheHandler::MaybeSave(CompileCacheEntry* entry,
std::string_view transpiled) {
CHECK(entry->type == CachedCodeType::kStrippedTypeScript);
CHECK(entry->type == CachedCodeType::kStrippedTypeScript ||
entry->type == CachedCodeType::kTransformedTypeScript ||
entry->type == CachedCodeType::kTransformedTypeScriptWithSourceMaps);
Debug("[compile cache] saving transpilation cache for %s %s\n",
entry->type_name(),
entry->source_filename);
Expand Down
4 changes: 3 additions & 1 deletion src/compile_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ class Environment;
#define CACHED_CODE_TYPES(V) \
V(kCommonJS, 0) \
V(kESM, 1) \
V(kStrippedTypeScript, 2)
V(kStrippedTypeScript, 2) \
V(kTransformedTypeScript, 3) \
V(kTransformedTypeScriptWithSourceMaps, 4)

enum class CachedCodeType : uint8_t {
#define V(type, value) type = value,
Expand Down
Loading
Loading