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