UNPKG

@plugjs/tsrun

Version:

A simple TypeScript runner --------------------------

205 lines (202 loc) 7.57 kB
// src/loader-module.mts import _path2 from "node:path"; import _url from "node:url"; // src/loader-shared.ts import _fs from "node:fs"; import _path from "node:path"; import _util from "node:util"; import _esbuild from "esbuild"; var CJS = "commonjs"; var ESM = "module"; var _debugLog = _util.debuglog("plug:ts-loader"); var _debug = _debugLog.enabled; function logMessage(mode, arg, ...args) { if (!_debug) return; const t = mode === ESM ? "esm" : mode === CJS ? "cjs" : "---"; _debugLog(`[${t}] ${arg}`, ...args); } function throwError(mode, message, options = {}) { const t = mode === ESM ? "esm" : mode === CJS ? "cjs" : "---"; const prefix = `[ts-loader|${t}|pid=${process.pid}]`; const { start = throwError, ...extra } = options; const error = new Error(`${prefix} ${message}`); Error.captureStackTrace(error, start); Object.assign(error, extra); throw error; } function moduleType(mode) { if (process.env.__TS_LOADER_FORCE_TYPE) { const type = process.env.__TS_LOADER_FORCE_TYPE; if (type === CJS || type === ESM) { logMessage(mode, `Forcing type to "${type}" from environment`); return type; } else { throwError(mode, `Invalid type "${process.env.__TS_LOADER_FORCE_TYPE}"`); } } const _findType = (directory) => { const packageFile = _path.join(directory, "package.json"); try { const packageData = _fs.readFileSync(packageFile, "utf-8"); const packageJson = JSON.parse(packageData); const packageType = packageJson.type; switch (packageType) { case void 0: logMessage(mode, `File "${packageFile}" does not declare a default type`); return CJS; case CJS: case ESM: logMessage(mode, `File "${packageFile}" declares type as "${CJS}"`); return packageType; default: logMessage(mode, `File "${packageFile}" specifies unknown type "${packageType}"`); return CJS; } } catch (cause) { if (cause.code !== "ENOENT" && cause.code !== "EISDIR") { throwError(mode, `Unable to read or parse "${packageFile}"`, { cause, start: _findType }); } } const parent = _path.dirname(directory); if (directory !== parent) return _findType(directory); logMessage(mode, `Type defaulted to "${CJS}"`); return CJS; }; return _findType(process.cwd()); } function _esbReport(kind, messages = []) { const output = process.stderr; const options = { color: !!output.isTTY, terminalWidth: output.columns || 80 }; const array = _esbuild.formatMessagesSync(messages, { kind, ...options }); array.forEach((message) => output.write(`${message} `)); } function esbTranpile(filename, type) { logMessage(type, `Transpiling "${filename}" as "${type}"`); const [format, __fileurl] = type === ESM ? ["esm", "import.meta.url"] : ["cjs", "__filename"]; const options = { sourcefile: filename, // the original filename we're parsing format, // what are we actually transpiling to??? loader: "ts", // the format is always "typescript" sourcemap: "inline", // always inline source maps sourcesContent: false, // do not include sources content in sourcemap platform: "node", // d'oh! :-) minifyWhitespace: true, // https://github.com/evanw/esbuild/releases/tag/v0.16.14 logLevel: "silent", // catching those in our _esbReport below target: `node${process.versions["node"]}`, // target _this_ version define: { __fileurl } // from "globals.d.ts" }; if (_debug) { if (format === "esm") { options.banner = `;(await import('node:util')).debuglog('plug:ts-loader')('[esm] Loaded "%s"', ${__fileurl});`; } else if (format === "cjs") { options.banner = `;require('node:util').debuglog('plug:ts-loader')('[cjs] Loaded "%s"', ${__fileurl});`; } } let result; try { const source = _fs.readFileSync(filename, "utf-8"); result = _esbuild.transformSync(source, options); } catch (cause) { _esbReport("error", cause.errors); _esbReport("warning", cause.warnings); throwError(type, `ESBuild error transpiling "${filename}"`, { cause, start: esbTranpile }); } if (_debug) _esbReport("warning", result.warnings); return result.code; } function isFile(path) { try { return _fs.statSync(path).isFile(); } catch { return false; } } function isDirectory(path) { try { return _fs.statSync(path).isDirectory(); } catch { return false; } } // src/loader-module.mts var _type = moduleType(CJS); var resolve = (specifier, context, nextResolve) => { logMessage(ESM, `Resolving "${specifier}" from "${context.parentURL}"`); if (!specifier.match(/^\.\.?\//)) return nextResolve(specifier, context); const parentURL = context.parentURL; if (!parentURL) return nextResolve(specifier, context); if (!parentURL.startsWith("file:")) return nextResolve(specifier, context); if (!parentURL.match(/\.m?ts$/)) return nextResolve(specifier, context); const url = new URL(specifier, parentURL).href; const path = _url.fileURLToPath(url); if (isFile(path)) { logMessage(ESM, `Positive match for "${specifier}" as "${path}" (1)`); return nextResolve(specifier, context); } const match = specifier.match(/(.*)(\.[mc]?js$)/); if (match) { const [, base, ext] = match; const tsspecifier = base + ext.replace("js", "ts"); const tsurl = new URL(tsspecifier, parentURL).href; const tspath = _url.fileURLToPath(tsurl); if (isFile(tspath)) { logMessage(ESM, `Positive match for "${specifier}" as "${tspath}" (2)`); return nextResolve(tsspecifier, context); } } if (isFile(`${path}.ts`)) { logMessage(ESM, `Positive match for "${specifier}.ts" as "${path}.ts" (3)`); return nextResolve(`${specifier}.ts`, context); } if (isDirectory(path)) { const file = _path2.resolve(path, "index.ts"); if (isFile(file)) { logMessage(ESM, `Positive match for "${specifier}" as "${file}" (4)`); const spec = _url.pathToFileURL(file).pathname; return nextResolve(spec, context); } } return nextResolve(specifier, context); }; var load = (url, context, nextLoad) => { logMessage(ESM, `Attempting to load "${url}"`); if (!url.startsWith("file:")) return nextLoad(url, context); const ext = url.match(/\.[cm]?ts$/)?.[0]; if (!ext) return nextLoad(url, context); if (ext === ".cts") { logMessage(ESM, `Switching type from "module" to "commonjs" for "${url}"`); logMessage(ESM, "Please note that named import WILL NOT WORK in this case, as Node.js performs a"); logMessage(ESM, "static analisys on the CommonJS source code, and this file is transpiled from."); logMessage(ESM, "TypeScript to CommonJS dynamically."); return { format: CJS, shortCircuit: true }; } const filename = _url.fileURLToPath(url); if (ext === ".ts") { if (_type === CJS) { logMessage(ESM, `Switching type from "module" to "commonjs" for "${url}"`); logMessage(ESM, "Please note that named import WILL NOT WORK in this case, as Node.js performs a"); logMessage(ESM, "static analisys on the CommonJS source code, and this file is transpiled from."); logMessage(ESM, "TypeScript to CommonJS dynamically."); return { format: CJS, shortCircuit: true }; } } const source = esbTranpile(filename, ESM); return { source, format: ESM, shortCircuit: true }; }; logMessage(ESM, "TypeScript loader for ES Modules loaded"); export { load, resolve }; //# sourceMappingURL=loader-module.mjs.map