UNPKG

@boost/module

Version:

Module resolving and loading utilities with TypeScript support.

194 lines (180 loc) 7.25 kB
// Bundled with Packemon: https://packemon.dev // Platform: node, Support: stable, Format: cjs 'use strict'; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } const fs = require('node:fs'); const _interopDefault = e => e && e.__esModule ? e : { default: e }; const fs__default = /*#__PURE__*/_interopDefault(fs); /* eslint-disable @typescript-eslint/consistent-type-assertions */ /** * Formats the shape of an imported module to align with the * ES module specification. * * For ES or ES-like modules, returns the shape as-is. * * For CommonJS modules, returns an object with the following: * - `module.exports` under the `default` property. * - `exports.<name>` under properties of the same name, * and also under a `default` object. */ function interopModule(result) { if (typeof result !== 'object' || result === null) { return { default: result }; } // Already a module, so return early if ('__esModule' in result || 'default' in result) { return result; } return _objectSpread(_objectSpread({}, result), {}, { default: result }); } /* eslint-disable no-magic-numbers */ const COMPILER_OPTIONS = { allowJs: true, allowSyntheticDefaultImports: true, esModuleInterop: true, noEmit: true }; const NODE_VERSION = Number.parseFloat(process.version.slice(1)); function isNodeNext(path) { return path.endsWith('.cts') || path.endsWith('.mts'); } function isTypeScript(path) { return path.endsWith('.ts') || path.endsWith('.tsx') || isNodeNext(path); } function getTargetFromNodeVersion(ts) { if (NODE_VERSION >= 20) { return ts.ScriptTarget.ESNext; } if (NODE_VERSION >= 18) { return ts.ScriptTarget.ES2022; } if (NODE_VERSION >= 17) { return ts.ScriptTarget.ES2021; } return ts.ScriptTarget.ES2020; } /* eslint-disable no-underscore-dangle, node/no-deprecated-api */ let tsInstance = null; function loadTypeScript() { if (!tsInstance) { try { tsInstance = require('typescript'); } catch { // Ignore and check at runtime } } return tsInstance; } function transform(contents, filePath) { const ts = loadTypeScript(); if (!ts) { throw new Error(`\`typescript\` package required for transforming file "${filePath}".`); } return ts.transpileModule(contents, { compilerOptions: _objectSpread(_objectSpread({}, COMPILER_OPTIONS), {}, { module: ts.ModuleKind.CommonJS, resolveJsonModule: true, target: getTargetFromNodeVersion(ts) }), fileName: filePath }).outputText; } function transformHandler(mod, filePath) { mod._compile(transform(fs__default.default.readFileSync(filePath, 'utf8'), filePath), filePath); } /** * Register `.ts` and `.tsx` file extensions into Node.js's resolution algorithm. */ function registerExtensions() { require.extensions['.ts'] = transformHandler; require.extensions['.tsx'] = transformHandler; require.extensions['.cts'] = transformHandler; require.extensions['.mts'] = transformHandler; } /** * Unregister `.ts` and `.tsx` file extensions. */ function unregisterExtensions() { delete require.extensions['.ts']; delete require.extensions['.tsx']; delete require.extensions['.cts']; delete require.extensions['.mts']; } /** * Like `requireModule` but for loading TypeScript files ending in `ts` or `tsx`. * When imported, will transform the file using the `typescript` package, * evaluate the code in the current module context, and apply the same process * to all child imports. * * ```ts * import { requireTSModule } from '@boost/module'; * * const result = requireTSModule('../../some/module.ts'); * ``` * * > This helper rarely needs to be used directly as `requireModule` will * > call it under the hood based on the file extension. */ function requireTSModule(path, requirer = require) { const filePath = String(path); if (!isTypeScript(filePath)) { throw new Error(`Unable to import non-TypeScript file "${filePath}", use \`requireModule\` instead.`); } registerExtensions(); const result = interopModule(requirer(filePath)); unregisterExtensions(); return result; } /** * Works in a similar fashion to the native NodeJS `require()`, but can also * import custom file types like TypeScript, and also returns a module shape * that aligns with the ESM loader specification. * * When loading custom file types, the extension in the file path is optional, * as NodeJS will iterate through each extension until a file is found. * * ```ts * import { requireModule } from '@boost/module'; * * const result = requireModule('../../some/module'); * ``` * * Caveats and differences: * * - CommonJS files that utilize `module.exports` (default export) will have this * value returned under a `default` property, instead of being returned directly. * - CommonJS files that utilize multiple `exports.<name>` (named exports) will * have these values returned as properties on the result object, and will also * be found on the `default` property. * - "ES module like" files will be returned as-is. These are files that are built * with Babel or TypeScript and export an `__esModule` internal property. * * These changes align with `import()` and the ES module system. We made this * decision for consistency and reliability. */ function requireModule(path, requirer = require) { const filePath = String(path); if (filePath.endsWith('.mjs') || filePath.endsWith('.mts')) { throw new Error(`Unable to require non-CommonJS file "${filePath}", use ESM imports instead.`); } if (isTypeScript(filePath)) { return requireTSModule(filePath, requirer); } return interopModule(requirer(filePath)); } exports.interopModule = interopModule; exports.registerExtensions = registerExtensions; exports.requireModule = requireModule; exports.requireTSModule = requireTSModule; exports.unregisterExtensions = unregisterExtensions; //# sourceMappingURL=index.cjs.map