UNPKG

cfg-test

Version:

In-source testing using Node.js Test Runner

189 lines (188 loc) 5.63 kB
// src/core/api.ts import { existsSync, readFileSync } from "node:fs"; import { createRequire, register as load } from "node:module"; import { resolve } from "node:path"; import { sep } from "node:path"; import process from "node:process"; import { pathToFileURL } from "node:url"; import { testEnv } from "./define.mjs"; import * as log from "./log.mjs"; var ARGV = ["/path/to/node", "/path/to/file"]; var fileIndex = ARGV.indexOf("/path/to/file"); var cwd = process.cwd(); var cwdUrl = pathToFileURL( cwd.endsWith(sep) ? sep : cwd + sep ); var require2 = createRequire(cwdUrl); var parentUrl = cwdUrl.toString(); function register(options = {}) { const argv = options.argv || process.argv; if (!(fileIndex in argv)) { return; } const file = resolve(argv[fileIndex]); const execArgv = options.execArgv || process.execArgv; const nodeOptions = `,${process.env["NODE_OPTIONS"] ? execArgv.concat(process. env["NODE_OPTIONS"].split(/\s/g)) : execArgv},`; const isEsmMode = /,--import,cfg-test[,/]/.test(nodeOptions); const isWatchMode = /,--watch,/.test(nodeOptions); const isDTsFile = file.endsWith(".d.ts"); const isTypeScript = /\.[cm]?tsx?$/i.test(file); log.debug(() => [ `esm mode -> ${isEsmMode}`, `watch mode -> ${isWatchMode}`, `typescript file -> ${isTypeScript}`, `declare file -> ${isDTsFile}`, `argv -> ${argv.map((a) => JSON.stringify(a)).join(" ")}`, `execArgv -> ${execArgv.map((a) => JSON.stringify(a)).join(" ")}`, `cwd -> ${JSON.stringify(cwd)}`, `parentUrl -> ${JSON.stringify(parentUrl)}`, `target file -> ${JSON.stringify(file)}` ]); if (isEsmMode && false) { log.error(() => ["Cannot import `cfg-test` in CommonJS"]); process.exit(1); } const env = { ...testEnv, CFG_TEST_CFG: process.env.CFG_TEST_CFG ?? `${[ ".config/cfg-test", ".config/cfg-test/config", "config/cfg-test", "config/cfg-test/config", "cfg-test" ]}`, CFG_TEST_FILE: file }; if (isEsmMode) { Object.assign(env, { CFG_TEST_URL: pathToFileURL(file) }); } Object.assign(env, { CFG_TEST_WATCH: `${isWatchMode}` }); const originalEnv = { ...process.env }; log.debug( () => Object.entries(env).filter(([k, v]) => [void 0, v].includes(originalEnv[k])). map(([k, v]) => `Added env.${k}=${JSON.stringify(v)} by cfg-test.`) ); log.warn( () => Object.entries(env).filter(([k, v]) => [void 0, v].every((v2) => v2 !== originalEnv[k])).map(([k, v]) => `Updated env.${k}=${JSON.stringify(v)} by c\ fg-test.`) ); Object.assign(process.env, env); const cfgTest = new Proxy(require2("node:test"), { get(target, p, receiver) { switch (p) { case "url": return process.env.CFG_TEST_URL; case "file": return process.env.CFG_TEST_FILE; case "watch": return process.env.CFG_TEST_WATCH === "true"; case "assert": return require2("node:assert/strict"); default: return Reflect.get(target, p, receiver); } } }); global.cfgTest = cfgTest; let cfg; for (const id of process.env.CFG_TEST_CFG.split(",")) { const cfgPath = id.endsWith(".json") ? id : `${id}.json`; if (existsSync(cfgPath)) { cfg = JSON.parse(readFileSync(cfgPath, "utf8")); break; } } if (cfg && cfg.env) { for (const [key, value] of Object.entries(cfg.env)) { if (typeof value !== "string") { continue; } if (process.env[key] === void 0) { log.debug(() => [`Added env.${key} by config file.`]); } else { log.warn(() => [`Updated env.${key} by config file.`]); } process.env[key] = value; } } if (cfg && cfg.globals) { for (const [key, value] of Object.entries(cfg.globals)) { if (key in global) { log.warn(() => [`Updated global.${key} by config file.`]); } else { log.debug(() => [`Added global.${key} by config file.`]); global[key] = value; } } } if (cfg && cfg.import) { if (!Array.isArray(cfg.import)) { cfg.import = [cfg.import]; } for (const id of cfg.import) { log.debug(() => [`Imported module ${id} by config file.`]); load(id, parentUrl); } } if (cfg && cfg.require) { if (!Array.isArray(cfg.require)) { cfg.require = [cfg.require]; } for (const id of cfg.require) { log.debug(() => [`Required module ${id} by config file.`]); require2(id); } } const ctx = { log, argv, file, execArgv, isEsmMode, parentUrl, isWatchMode, isTypeScript, import(id) { try { log.debug(() => [`Register ESM module ${id}.`]); load(id, parentUrl); log.debug(() => [`Registered ESM module ${id}.`]); } catch (e) { log.error(() => [`Cannot register ESM module ${id}.`]); throw e; } }, require(id, onLoad) { try { log.debug(() => [`Register CJS module ${id}`]); const mod = require2(id); log.debug(() => [`Loaded CJS module ${id}`]); onLoad(mod); log.debug(() => [`Registered CJS module ${id}`]); } catch (e) { log.error(() => [`Cannot register CJS module ${id}.`]); throw e; } } }; if (isDTsFile) { if (ctx.isEsmMode) { ctx.import("cfg-test/dts-loader"); } else { require2("node:module")._extensions[".ts"] = () => ""; ctx.log.debug(() => ["Registered CJS module cfg-test/dts-loader."]); } return; } return ctx; } export { register }; //# sourceMappingURL=api.mjs.map