transform.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. "use strict";
  2. var __create = Object.create;
  3. var __defProp = Object.defineProperty;
  4. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  5. var __getOwnPropNames = Object.getOwnPropertyNames;
  6. var __getProtoOf = Object.getPrototypeOf;
  7. var __hasOwnProp = Object.prototype.hasOwnProperty;
  8. var __export = (target, all) => {
  9. for (var name in all)
  10. __defProp(target, name, { get: all[name], enumerable: true });
  11. };
  12. var __copyProps = (to, from, except, desc) => {
  13. if (from && typeof from === "object" || typeof from === "function") {
  14. for (let key of __getOwnPropNames(from))
  15. if (!__hasOwnProp.call(to, key) && key !== except)
  16. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  17. }
  18. return to;
  19. };
  20. var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  21. // If the importer is in node compatibility mode or this is not an ESM
  22. // file that has been converted to a CommonJS file using a Babel-
  23. // compatible transform (i.e. "__esModule" has not been set), then set
  24. // "default" to the CommonJS "module.exports" for node compatibility.
  25. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  26. mod
  27. ));
  28. var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
  29. var transform_exports = {};
  30. __export(transform_exports, {
  31. requireOrImport: () => requireOrImport,
  32. resolveHook: () => resolveHook,
  33. setSingleTSConfig: () => setSingleTSConfig,
  34. setTransformConfig: () => setTransformConfig,
  35. setTransformData: () => setTransformData,
  36. shouldTransform: () => shouldTransform,
  37. singleTSConfig: () => singleTSConfig,
  38. transformConfig: () => transformConfig,
  39. transformHook: () => transformHook,
  40. wrapFunctionWithLocation: () => wrapFunctionWithLocation
  41. });
  42. module.exports = __toCommonJS(transform_exports);
  43. var import_fs = __toESM(require("fs"));
  44. var import_module = __toESM(require("module"));
  45. var import_path = __toESM(require("path"));
  46. var import_url = __toESM(require("url"));
  47. var import_crypto = __toESM(require("crypto"));
  48. var import_tsconfig_loader = require("../third_party/tsconfig-loader");
  49. var import_util = require("../util");
  50. var import_utilsBundle = require("../utilsBundle");
  51. var import_compilationCache = require("./compilationCache");
  52. var import_pirates = require("../third_party/pirates");
  53. const version = require("../../package.json").version;
  54. const cachedTSConfigs = /* @__PURE__ */ new Map();
  55. let _transformConfig = {
  56. babelPlugins: [],
  57. external: []
  58. };
  59. let _externalMatcher = () => false;
  60. function setTransformConfig(config) {
  61. _transformConfig = config;
  62. _externalMatcher = (0, import_util.createFileMatcher)(_transformConfig.external);
  63. }
  64. function transformConfig() {
  65. return _transformConfig;
  66. }
  67. let _singleTSConfigPath;
  68. let _singleTSConfig;
  69. function setSingleTSConfig(value) {
  70. _singleTSConfigPath = value;
  71. }
  72. function singleTSConfig() {
  73. return _singleTSConfigPath;
  74. }
  75. function validateTsConfig(tsconfig) {
  76. const pathsBase = tsconfig.absoluteBaseUrl ?? tsconfig.paths?.pathsBasePath;
  77. const pathsFallback = tsconfig.absoluteBaseUrl ? [{ key: "*", values: ["*"] }] : [];
  78. return {
  79. allowJs: !!tsconfig.allowJs,
  80. pathsBase,
  81. paths: Object.entries(tsconfig.paths?.mapping || {}).map(([key, values]) => ({ key, values })).concat(pathsFallback)
  82. };
  83. }
  84. function loadAndValidateTsconfigsForFile(file2) {
  85. if (_singleTSConfigPath && !_singleTSConfig)
  86. _singleTSConfig = (0, import_tsconfig_loader.loadTsConfig)(_singleTSConfigPath).map(validateTsConfig);
  87. if (_singleTSConfig)
  88. return _singleTSConfig;
  89. return loadAndValidateTsconfigsForFolder(import_path.default.dirname(file2));
  90. }
  91. function loadAndValidateTsconfigsForFolder(folder) {
  92. const foldersWithConfig = [];
  93. let currentFolder = import_path.default.resolve(folder);
  94. let result2;
  95. while (true) {
  96. const cached = cachedTSConfigs.get(currentFolder);
  97. if (cached) {
  98. result2 = cached;
  99. break;
  100. }
  101. foldersWithConfig.push(currentFolder);
  102. for (const name of ["tsconfig.json", "jsconfig.json"]) {
  103. const configPath = import_path.default.join(currentFolder, name);
  104. if (import_fs.default.existsSync(configPath)) {
  105. const loaded = (0, import_tsconfig_loader.loadTsConfig)(configPath);
  106. result2 = loaded.map(validateTsConfig);
  107. break;
  108. }
  109. }
  110. if (result2)
  111. break;
  112. const parentFolder = import_path.default.resolve(currentFolder, "../");
  113. if (currentFolder === parentFolder)
  114. break;
  115. currentFolder = parentFolder;
  116. }
  117. result2 = result2 || [];
  118. for (const folder2 of foldersWithConfig)
  119. cachedTSConfigs.set(folder2, result2);
  120. return result2;
  121. }
  122. const pathSeparator = process.platform === "win32" ? ";" : ":";
  123. const builtins = new Set(import_module.default.builtinModules);
  124. function resolveHook(filename, specifier) {
  125. if (specifier.startsWith("node:") || builtins.has(specifier))
  126. return;
  127. if (!shouldTransform(filename))
  128. return;
  129. if (isRelativeSpecifier(specifier))
  130. return (0, import_util.resolveImportSpecifierAfterMapping)(import_path.default.resolve(import_path.default.dirname(filename), specifier), false);
  131. const isTypeScript = filename.endsWith(".ts") || filename.endsWith(".tsx");
  132. const tsconfigs = loadAndValidateTsconfigsForFile(filename);
  133. for (const tsconfig of tsconfigs) {
  134. if (!isTypeScript && !tsconfig.allowJs)
  135. continue;
  136. let longestPrefixLength = -1;
  137. let pathMatchedByLongestPrefix;
  138. for (const { key, values } of tsconfig.paths) {
  139. let matchedPartOfSpecifier = specifier;
  140. const [keyPrefix, keySuffix] = key.split("*");
  141. if (key.includes("*")) {
  142. if (keyPrefix) {
  143. if (!specifier.startsWith(keyPrefix))
  144. continue;
  145. matchedPartOfSpecifier = matchedPartOfSpecifier.substring(keyPrefix.length, matchedPartOfSpecifier.length);
  146. }
  147. if (keySuffix) {
  148. if (!specifier.endsWith(keySuffix))
  149. continue;
  150. matchedPartOfSpecifier = matchedPartOfSpecifier.substring(0, matchedPartOfSpecifier.length - keySuffix.length);
  151. }
  152. } else {
  153. if (specifier !== key)
  154. continue;
  155. matchedPartOfSpecifier = specifier;
  156. }
  157. if (keyPrefix.length <= longestPrefixLength)
  158. continue;
  159. for (const value of values) {
  160. let candidate = value;
  161. if (value.includes("*"))
  162. candidate = candidate.replace("*", matchedPartOfSpecifier);
  163. candidate = import_path.default.resolve(tsconfig.pathsBase, candidate);
  164. const existing = (0, import_util.resolveImportSpecifierAfterMapping)(candidate, true);
  165. if (existing) {
  166. longestPrefixLength = keyPrefix.length;
  167. pathMatchedByLongestPrefix = existing;
  168. }
  169. }
  170. }
  171. if (pathMatchedByLongestPrefix)
  172. return pathMatchedByLongestPrefix;
  173. }
  174. if (import_path.default.isAbsolute(specifier)) {
  175. return (0, import_util.resolveImportSpecifierAfterMapping)(specifier, false);
  176. }
  177. }
  178. function shouldTransform(filename) {
  179. if (_externalMatcher(filename))
  180. return false;
  181. return !(0, import_compilationCache.belongsToNodeModules)(filename);
  182. }
  183. let transformData;
  184. function setTransformData(pluginName, value) {
  185. transformData.set(pluginName, value);
  186. }
  187. function transformHook(originalCode, filename, moduleUrl) {
  188. const hasPreprocessor = process.env.PW_TEST_SOURCE_TRANSFORM && process.env.PW_TEST_SOURCE_TRANSFORM_SCOPE && process.env.PW_TEST_SOURCE_TRANSFORM_SCOPE.split(pathSeparator).some((f) => filename.startsWith(f));
  189. const pluginsPrologue = _transformConfig.babelPlugins;
  190. const pluginsEpilogue = hasPreprocessor ? [[process.env.PW_TEST_SOURCE_TRANSFORM]] : [];
  191. const hash = calculateHash(originalCode, filename, !!moduleUrl, pluginsPrologue, pluginsEpilogue);
  192. const { cachedCode, addToCache, serializedCache } = (0, import_compilationCache.getFromCompilationCache)(filename, hash, moduleUrl);
  193. if (cachedCode !== void 0)
  194. return { code: cachedCode, serializedCache };
  195. process.env.BROWSERSLIST_IGNORE_OLD_DATA = "true";
  196. const { babelTransform } = require("./babelBundle");
  197. transformData = /* @__PURE__ */ new Map();
  198. const babelResult = babelTransform(originalCode, filename, !!moduleUrl, pluginsPrologue, pluginsEpilogue);
  199. if (!babelResult?.code)
  200. return { code: originalCode, serializedCache };
  201. const { code, map } = babelResult;
  202. const added = addToCache(code, map, transformData);
  203. return { code, serializedCache: added.serializedCache };
  204. }
  205. function calculateHash(content, filePath, isModule2, pluginsPrologue, pluginsEpilogue) {
  206. const hash = import_crypto.default.createHash("sha1").update(isModule2 ? "esm" : "no_esm").update(content).update(filePath).update(version).update(pluginsPrologue.map((p) => p[0]).join(",")).update(pluginsEpilogue.map((p) => p[0]).join(",")).digest("hex");
  207. return hash;
  208. }
  209. async function requireOrImport(file) {
  210. installTransformIfNeeded();
  211. const isModule = (0, import_util.fileIsModule)(file);
  212. const esmImport = () => eval(`import(${JSON.stringify(import_url.default.pathToFileURL(file))})`);
  213. if (isModule) {
  214. return await esmImport().finally(async () => {
  215. await new Promise((resolve) => setTimeout(resolve, 0));
  216. });
  217. }
  218. const result = require(file);
  219. const depsCollector = (0, import_compilationCache.currentFileDepsCollector)();
  220. if (depsCollector) {
  221. const module2 = require.cache[file];
  222. if (module2)
  223. collectCJSDependencies(module2, depsCollector);
  224. }
  225. return result;
  226. }
  227. let transformInstalled = false;
  228. function installTransformIfNeeded() {
  229. if (transformInstalled)
  230. return;
  231. transformInstalled = true;
  232. (0, import_compilationCache.installSourceMapSupport)();
  233. const originalResolveFilename = import_module.default._resolveFilename;
  234. function resolveFilename(specifier, parent, ...rest) {
  235. if (parent) {
  236. const resolved = resolveHook(parent.filename, specifier);
  237. if (resolved !== void 0)
  238. specifier = resolved;
  239. }
  240. return originalResolveFilename.call(this, specifier, parent, ...rest);
  241. }
  242. import_module.default._resolveFilename = resolveFilename;
  243. (0, import_pirates.addHook)((code, filename) => {
  244. return transformHook(code, filename).code;
  245. }, shouldTransform, [".ts", ".tsx", ".js", ".jsx", ".mjs", ".mts", ".cjs", ".cts"]);
  246. }
  247. const collectCJSDependencies = (module2, dependencies) => {
  248. module2.children.forEach((child) => {
  249. if (!(0, import_compilationCache.belongsToNodeModules)(child.filename) && !dependencies.has(child.filename)) {
  250. dependencies.add(child.filename);
  251. collectCJSDependencies(child, dependencies);
  252. }
  253. });
  254. };
  255. function wrapFunctionWithLocation(func) {
  256. return (...args) => {
  257. const oldPrepareStackTrace = Error.prepareStackTrace;
  258. Error.prepareStackTrace = (error, stackFrames) => {
  259. const frame = import_utilsBundle.sourceMapSupport.wrapCallSite(stackFrames[1]);
  260. const fileName = frame.getFileName();
  261. const file2 = fileName && fileName.startsWith("file://") ? import_url.default.fileURLToPath(fileName) : fileName;
  262. return {
  263. file: file2,
  264. line: frame.getLineNumber(),
  265. column: frame.getColumnNumber()
  266. };
  267. };
  268. const oldStackTraceLimit = Error.stackTraceLimit;
  269. Error.stackTraceLimit = 2;
  270. const obj = {};
  271. Error.captureStackTrace(obj);
  272. const location = obj.stack;
  273. Error.stackTraceLimit = oldStackTraceLimit;
  274. Error.prepareStackTrace = oldPrepareStackTrace;
  275. return func(location, ...args);
  276. };
  277. }
  278. function isRelativeSpecifier(specifier) {
  279. return specifier === "." || specifier === ".." || specifier.startsWith("./") || specifier.startsWith("../");
  280. }
  281. // Annotate the CommonJS export names for ESM import in node:
  282. 0 && (module.exports = {
  283. requireOrImport,
  284. resolveHook,
  285. setSingleTSConfig,
  286. setTransformConfig,
  287. setTransformData,
  288. shouldTransform,
  289. singleTSConfig,
  290. transformConfig,
  291. transformHook,
  292. wrapFunctionWithLocation
  293. });