UNPKG

runkit-plus-ultra

Version:

Runkit tools for loading TypeScript, ES Modules and more. Makes testing Isomorphic code easyer, lets you use unstable features and import modules from git.

128 lines (119 loc) 4.18 kB
// Todo, depends on PWD to determine node_modules location // This makes testing hard. // This might work: node -e 'console.log(require.resolve("@babel/core"))' import dep from 'runkit-plus-ultra' import fs from 'fs' import { execSync } from 'child_process' import os from 'os' // import { URL } from 'url' const utils = {} // hoist const cm = { root: process.cwd(), NS: "runkit-plus-ultra", // Warning: Accessing non-existent property 'version' of module exports inside circular dependency // depVer: dep.version, defaultEnv: { NODE_OPTIONS: '--no-warnings --loader ts-node/esm/transpile-only' } } cm.workdir = `${cm.root}/.${cm.NS}` cm.myScripts = `${cm.workdir}/internal` export default class OmniLoader { constructor (argsRaw) { const args = argsRaw || { env: {} } Object.assign(this, { auto: true, nodeModules: '', runKitVersion: '', vcsVersion: '', promise: new Promise((resolve, reject) => resolve()), scriptSpecs: [], env: cm.defaultEnv }, args) Object.assign(this.env, args.env) console.debug(`cm.root is ${cm.root}`) if (this.auto) { // todo seperate prepare function and require promise this.prepareBasics() this.prepareTSNode() this.saveCode() this.runCode() } } // get promise {} // Use promise to allow async when { async: true } is set // Otherwise block until async resolves. static getPkgJson(path) { return JSON.parse(fs.readFileSync(`${path}/package.json`).toString()) } static getModVer(path) { return utils.getPkgJson(path).version } static getModRepo(path) { // https://docs.npmjs.com/cli/v7/configuring-npm/package-json#repository const repo = utils.getPkgJson(path).repository || {} if (typeof repo.url === 'undefined') throw new Error('CANT_READ_MOD_REPO_URL') return repo.url } prepareBasics() { execSync(`rm -r "${cm.workdir}" || :`) execSync(`mkdir -p "${cm.workdir}"`) execSync(`cd "${cm.workdir}" npm init --yes ${cm.NS}`) execSync(`cd "${cm.workdir}" && npm config set type=module`) if (process.env.RUNKIT_HOST) { // Create a symlink to the real node_modules under our work directory const upSince = Math.round(Date.now() / 1000 - os.uptime()) * 1000 execSync(`ln -s /app/available_modules/${upSince}/ "${cm.root}/node_modules" || :`) } else { console.debug('Not running in Runkit, not creating node_modules link.') } execSync(`mkdir -p "${cm.myScripts}"`) } prepareTSNode() { const tsConfig = { compilerOptions: { "target": "ESnext", "module": "ESNext", "allowJs": true, "moduleResolution": "node", "allowSyntheticDefaultImports": true } } fs.writeFileSync(`${cm.workdir}/tsconfig.json`, JSON.stringify(tsConfig, null, 2)) } /* canned due to overhead loadLatest(modName) { const modIPath = `${cm.myScripts}/${modName}` // const modRepo = utils.getModRepo(modNMPath) execSync(`git clone "${modRepo}" "${cm.myScripts}/${modName}"`) this.vcsVersion = utils.getModVer(modIPath) }*/ getScriptSpecs (scriptSpecsRaw) { return scriptSpecsRaw || this.scriptSpecs } saveCode(scriptSpecsRaw) { for (const spec of this.getScriptSpecs(scriptSpecsRaw)) { fs.writeFileSync(`${cm.workdir}/${spec.path}`, spec.code) } } getEnvString() { const envVars = Object.keys(this.env) const resultTokens = [] for (const envK of envVars) { resultTokens.push(`${envK}="${this.env[envK]}"`) } return resultTokens.join(' ') } runCode() { const results = [] for (const spec of this.scriptSpecs) { results.push({ path: spec.path, output: execSync(`cd "${cm.workdir}" && env ${this.getEnvString()} node ${spec.path}`).toString() }) } return results } } Object.assign(utils, ((ClassRef) => { // returns static Fn's as Object entries const pNames = Object.getOwnPropertyNames(ClassRef) // const staticFnNames = pNames.filter(n => typeof ClassRef[n] === 'function') const map = pNames.map(n => [n, ClassRef[n]]) return Object.fromEntries(map) })(OmniLoader))