@@ -18,6 +18,7 @@ const {
1818 ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING ,
1919 ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX ,
2020} = require ( 'internal/errors' ) . codes ;
21+ const { getOptionValue } = require ( 'internal/options' ) ;
2122const assert = require ( 'internal/assert' ) ;
2223const {
2324 getCompileCacheEntry,
@@ -141,6 +142,35 @@ function stripTypeScriptTypesForCoverage(code) {
141142}
142143
143144
145+ /**
146+ * Whether type-stripping is allowed for files under node_modules belonging
147+ * to packages whose package.json contains `"private": true`.
148+ * @returns {boolean }
149+ */
150+ const isStripPrivateModulesEnabled = getLazy (
151+ ( ) => getOptionValue ( '--experimental-strip-private-modules' ) ,
152+ ) ;
153+
154+ /**
155+ * Checks whether a file under node_modules is owned by a private package, in
156+ * which case type stripping is allowed under `--experimental-strip-private-modules`.
157+ *
158+ * Every package enclosing the file inside `node_modules` must be marked
159+ * `"private": true`. npm refuses to publish a private package, so requiring
160+ * the package root (not a nested package.json, which is published verbatim)
161+ * and rejecting any non-private enclosing package (e.g. a publishable package
162+ * bundling a private dependency) prevents published packages from shipping
163+ * strippable TypeScript. See {@link getRootPackageJSON}.
164+ * @param {string } filename The filename (path or file URL) of the source code.
165+ * @returns {boolean } Whether the file belongs to a package with `"private": true`.
166+ */
167+ function isInsidePrivatePackage ( filename ) {
168+ const { getRootPackageJSON } = require ( 'internal/modules/package_json_reader' ) ;
169+ const { urlToFilename } = require ( 'internal/modules/helpers' ) ;
170+ const packageJSON = getRootPackageJSON ( urlToFilename ( filename ) ) ;
171+ return packageJSON ?. data . private === true ;
172+ }
173+
144174/**
145175 * Performs type-stripping to TypeScript source code internally.
146176 * It is used by internal loaders.
@@ -152,7 +182,10 @@ function stripTypeScriptTypesForCoverage(code) {
152182function stripTypeScriptModuleTypes ( source , filename , sourceURL ) {
153183 assert ( typeof source === 'string' ) ;
154184 if ( isUnderNodeModules ( filename ) ) {
155- throw new ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING ( filename ) ;
185+ if ( ! isStripPrivateModulesEnabled ( ) || ! isInsidePrivatePackage ( filename ) ) {
186+ throw new ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING ( filename ) ;
187+ }
188+ emitExperimentalWarning ( 'Type stripping in node_modules' ) ;
156189 }
157190 // Get a compile cache entry into the native compile cache store,
158191 // keyed by the filename. If the cache can already be loaded on disk,
0 commit comments