@plugjs/tsrun
Version:
A simple TypeScript runner --------------------------
205 lines (202 loc) • 7.57 kB
JavaScript
// 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