11cb0ef41Sopenharmony_ciconst fs = require('fs/promises') 21cb0ef41Sopenharmony_ciconst { runInThisContext } = require('vm') 31cb0ef41Sopenharmony_ciconst { promisify } = require('util') 41cb0ef41Sopenharmony_ciconst { randomBytes } = require('crypto') 51cb0ef41Sopenharmony_ciconst { Module } = require('module') 61cb0ef41Sopenharmony_ciconst { dirname, basename } = require('path') 71cb0ef41Sopenharmony_ciconst read = require('read') 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ciconst files = {} 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_ciclass PromZard { 121cb0ef41Sopenharmony_ci #file = null 131cb0ef41Sopenharmony_ci #backupFile = null 141cb0ef41Sopenharmony_ci #ctx = null 151cb0ef41Sopenharmony_ci #unique = randomBytes(8).toString('hex') 161cb0ef41Sopenharmony_ci #prompts = [] 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ci constructor (file, ctx = {}, options = {}) { 191cb0ef41Sopenharmony_ci this.#file = file 201cb0ef41Sopenharmony_ci this.#ctx = ctx 211cb0ef41Sopenharmony_ci this.#backupFile = options.backupFile 221cb0ef41Sopenharmony_ci } 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ci static async promzard (file, ctx, options) { 251cb0ef41Sopenharmony_ci const pz = new PromZard(file, ctx, options) 261cb0ef41Sopenharmony_ci return pz.load() 271cb0ef41Sopenharmony_ci } 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ci static async fromBuffer (buf, ctx, options) { 301cb0ef41Sopenharmony_ci let filename = 0 311cb0ef41Sopenharmony_ci do { 321cb0ef41Sopenharmony_ci filename = '\0' + Math.random() 331cb0ef41Sopenharmony_ci } while (files[filename]) 341cb0ef41Sopenharmony_ci files[filename] = buf 351cb0ef41Sopenharmony_ci const ret = await PromZard.promzard(filename, ctx, options) 361cb0ef41Sopenharmony_ci delete files[filename] 371cb0ef41Sopenharmony_ci return ret 381cb0ef41Sopenharmony_ci } 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ci async load () { 411cb0ef41Sopenharmony_ci if (files[this.#file]) { 421cb0ef41Sopenharmony_ci return this.#loaded() 431cb0ef41Sopenharmony_ci } 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ci try { 461cb0ef41Sopenharmony_ci files[this.#file] = await fs.readFile(this.#file, 'utf8') 471cb0ef41Sopenharmony_ci } catch (er) { 481cb0ef41Sopenharmony_ci if (er && this.#backupFile) { 491cb0ef41Sopenharmony_ci this.#file = this.#backupFile 501cb0ef41Sopenharmony_ci this.#backupFile = null 511cb0ef41Sopenharmony_ci return this.load() 521cb0ef41Sopenharmony_ci } 531cb0ef41Sopenharmony_ci throw er 541cb0ef41Sopenharmony_ci } 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ci return this.#loaded() 571cb0ef41Sopenharmony_ci } 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ci async #loaded () { 601cb0ef41Sopenharmony_ci const mod = new Module(this.#file, module) 611cb0ef41Sopenharmony_ci mod.loaded = true 621cb0ef41Sopenharmony_ci mod.filename = this.#file 631cb0ef41Sopenharmony_ci mod.id = this.#file 641cb0ef41Sopenharmony_ci mod.paths = Module._nodeModulePaths(dirname(this.#file)) 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ci this.#ctx.prompt = this.#makePrompt() 671cb0ef41Sopenharmony_ci this.#ctx.__filename = this.#file 681cb0ef41Sopenharmony_ci this.#ctx.__dirname = dirname(this.#file) 691cb0ef41Sopenharmony_ci this.#ctx.__basename = basename(this.#file) 701cb0ef41Sopenharmony_ci this.#ctx.module = mod 711cb0ef41Sopenharmony_ci this.#ctx.require = (p) => mod.require(p) 721cb0ef41Sopenharmony_ci this.#ctx.require.resolve = (p) => Module._resolveFilename(p, mod) 731cb0ef41Sopenharmony_ci this.#ctx.exports = mod.exports 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci const body = `(function(${Object.keys(this.#ctx).join(', ')}) { ${files[this.#file]}\n })` 761cb0ef41Sopenharmony_ci runInThisContext(body, this.#file).apply(this.#ctx, Object.values(this.#ctx)) 771cb0ef41Sopenharmony_ci this.#ctx.res = mod.exports 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci return this.#walk() 801cb0ef41Sopenharmony_ci } 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci #makePrompt () { 831cb0ef41Sopenharmony_ci return (...args) => { 841cb0ef41Sopenharmony_ci let p, d, t 851cb0ef41Sopenharmony_ci for (let i = 0; i < args.length; i++) { 861cb0ef41Sopenharmony_ci const a = args[i] 871cb0ef41Sopenharmony_ci if (typeof a === 'string') { 881cb0ef41Sopenharmony_ci if (p) { 891cb0ef41Sopenharmony_ci d = a 901cb0ef41Sopenharmony_ci } else { 911cb0ef41Sopenharmony_ci p = a 921cb0ef41Sopenharmony_ci } 931cb0ef41Sopenharmony_ci } else if (typeof a === 'function') { 941cb0ef41Sopenharmony_ci t = a 951cb0ef41Sopenharmony_ci } else if (a && typeof a === 'object') { 961cb0ef41Sopenharmony_ci p = a.prompt || p 971cb0ef41Sopenharmony_ci d = a.default || d 981cb0ef41Sopenharmony_ci t = a.transform || t 991cb0ef41Sopenharmony_ci } 1001cb0ef41Sopenharmony_ci } 1011cb0ef41Sopenharmony_ci try { 1021cb0ef41Sopenharmony_ci return `${this.#unique}-${this.#prompts.length}` 1031cb0ef41Sopenharmony_ci } finally { 1041cb0ef41Sopenharmony_ci this.#prompts.push([p, d, t]) 1051cb0ef41Sopenharmony_ci } 1061cb0ef41Sopenharmony_ci } 1071cb0ef41Sopenharmony_ci } 1081cb0ef41Sopenharmony_ci 1091cb0ef41Sopenharmony_ci async #walk (o = this.#ctx.res) { 1101cb0ef41Sopenharmony_ci const keys = Object.keys(o) 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_ci const len = keys.length 1131cb0ef41Sopenharmony_ci let i = 0 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_ci while (i < len) { 1161cb0ef41Sopenharmony_ci const k = keys[i] 1171cb0ef41Sopenharmony_ci const v = o[k] 1181cb0ef41Sopenharmony_ci i++ 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci if (v && typeof v === 'object') { 1211cb0ef41Sopenharmony_ci o[k] = await this.#walk(v) 1221cb0ef41Sopenharmony_ci continue 1231cb0ef41Sopenharmony_ci } 1241cb0ef41Sopenharmony_ci 1251cb0ef41Sopenharmony_ci if (v && typeof v === 'string' && v.startsWith(this.#unique)) { 1261cb0ef41Sopenharmony_ci const n = +v.slice(this.#unique.length + 1) 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ci // default to the key 1291cb0ef41Sopenharmony_ci // default to the ctx value, if there is one 1301cb0ef41Sopenharmony_ci const [prompt = k, def = this.#ctx[k], tx] = this.#prompts[n] 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ci try { 1331cb0ef41Sopenharmony_ci o[k] = await this.#prompt(prompt, def, tx) 1341cb0ef41Sopenharmony_ci } catch (er) { 1351cb0ef41Sopenharmony_ci if (er.notValid) { 1361cb0ef41Sopenharmony_ci console.log(er.message) 1371cb0ef41Sopenharmony_ci i-- 1381cb0ef41Sopenharmony_ci } else { 1391cb0ef41Sopenharmony_ci throw er 1401cb0ef41Sopenharmony_ci } 1411cb0ef41Sopenharmony_ci } 1421cb0ef41Sopenharmony_ci continue 1431cb0ef41Sopenharmony_ci } 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ci if (typeof v === 'function') { 1461cb0ef41Sopenharmony_ci // XXX: remove v.length check to remove cb from functions 1471cb0ef41Sopenharmony_ci // would be a breaking change for `npm init` 1481cb0ef41Sopenharmony_ci // XXX: if cb is no longer an argument then this.#ctx should 1491cb0ef41Sopenharmony_ci // be passed in to allow arrow fns to be used and still access ctx 1501cb0ef41Sopenharmony_ci const fn = v.length ? promisify(v) : v 1511cb0ef41Sopenharmony_ci o[k] = await fn.call(this.#ctx) 1521cb0ef41Sopenharmony_ci // back up so that we process this one again. 1531cb0ef41Sopenharmony_ci // this is because it might return a prompt() call in the cb. 1541cb0ef41Sopenharmony_ci i-- 1551cb0ef41Sopenharmony_ci continue 1561cb0ef41Sopenharmony_ci } 1571cb0ef41Sopenharmony_ci } 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_ci return o 1601cb0ef41Sopenharmony_ci } 1611cb0ef41Sopenharmony_ci 1621cb0ef41Sopenharmony_ci async #prompt (prompt, def, tx) { 1631cb0ef41Sopenharmony_ci const res = await read({ prompt: prompt + ':', default: def }).then((r) => tx ? tx(r) : r) 1641cb0ef41Sopenharmony_ci // XXX: remove this to require throwing an error instead of 1651cb0ef41Sopenharmony_ci // returning it. would be a breaking change for `npm init` 1661cb0ef41Sopenharmony_ci if (res instanceof Error && res.notValid) { 1671cb0ef41Sopenharmony_ci throw res 1681cb0ef41Sopenharmony_ci } 1691cb0ef41Sopenharmony_ci return res 1701cb0ef41Sopenharmony_ci } 1711cb0ef41Sopenharmony_ci} 1721cb0ef41Sopenharmony_ci 1731cb0ef41Sopenharmony_cimodule.exports = PromZard.promzard 1741cb0ef41Sopenharmony_cimodule.exports.fromBuffer = PromZard.fromBuffer 1751cb0ef41Sopenharmony_cimodule.exports.PromZard = PromZard 176