11cb0ef41Sopenharmony_ciconst { stripVTControlCharacters } = require('node:util')
21cb0ef41Sopenharmony_ciconst { Minipass } = require('minipass')
31cb0ef41Sopenharmony_ciconst columnify = require('columnify')
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci// This module consumes package data in the following format:
61cb0ef41Sopenharmony_ci//
71cb0ef41Sopenharmony_ci// {
81cb0ef41Sopenharmony_ci//   name: String,
91cb0ef41Sopenharmony_ci//   description: String,
101cb0ef41Sopenharmony_ci//   maintainers: [{ username: String, email: String }],
111cb0ef41Sopenharmony_ci//   keywords: String | [String],
121cb0ef41Sopenharmony_ci//   version: String,
131cb0ef41Sopenharmony_ci//   date: Date // can be null,
141cb0ef41Sopenharmony_ci// }
151cb0ef41Sopenharmony_ci//
161cb0ef41Sopenharmony_ci// The returned stream will format this package data
171cb0ef41Sopenharmony_ci// into a byte stream of formatted, displayable output.
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_cimodule.exports = async (opts) => {
201cb0ef41Sopenharmony_ci  return opts.json ? new JSONOutputStream() : new TextOutputStream(opts)
211cb0ef41Sopenharmony_ci}
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ciclass JSONOutputStream extends Minipass {
241cb0ef41Sopenharmony_ci  #didFirst = false
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci  write (obj) {
271cb0ef41Sopenharmony_ci    if (!this.#didFirst) {
281cb0ef41Sopenharmony_ci      super.write('[\n')
291cb0ef41Sopenharmony_ci      this.#didFirst = true
301cb0ef41Sopenharmony_ci    } else {
311cb0ef41Sopenharmony_ci      super.write('\n,\n')
321cb0ef41Sopenharmony_ci    }
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ci    return super.write(JSON.stringify(obj))
351cb0ef41Sopenharmony_ci  }
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci  end () {
381cb0ef41Sopenharmony_ci    super.write(this.#didFirst ? ']\n' : '\n[]\n')
391cb0ef41Sopenharmony_ci    super.end()
401cb0ef41Sopenharmony_ci  }
411cb0ef41Sopenharmony_ci}
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ciclass TextOutputStream extends Minipass {
441cb0ef41Sopenharmony_ci  #opts
451cb0ef41Sopenharmony_ci  #line = 0
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci  constructor (opts) {
481cb0ef41Sopenharmony_ci    super()
491cb0ef41Sopenharmony_ci    this.#opts = opts
501cb0ef41Sopenharmony_ci  }
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci  write (pkg) {
531cb0ef41Sopenharmony_ci    return super.write(this.#prettify(pkg))
541cb0ef41Sopenharmony_ci  }
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci  #prettify (data) {
571cb0ef41Sopenharmony_ci    const pkg = {
581cb0ef41Sopenharmony_ci      author: data.maintainers.map((m) => `=${stripVTControlCharacters(m.username)}`).join(' '),
591cb0ef41Sopenharmony_ci      date: 'prehistoric',
601cb0ef41Sopenharmony_ci      description: stripVTControlCharacters(data.description ?? ''),
611cb0ef41Sopenharmony_ci      keywords: '',
621cb0ef41Sopenharmony_ci      name: stripVTControlCharacters(data.name),
631cb0ef41Sopenharmony_ci      version: data.version,
641cb0ef41Sopenharmony_ci    }
651cb0ef41Sopenharmony_ci    if (Array.isArray(data.keywords)) {
661cb0ef41Sopenharmony_ci      pkg.keywords = data.keywords.map((k) => stripVTControlCharacters(k)).join(' ')
671cb0ef41Sopenharmony_ci    } else if (typeof data.keywords === 'string') {
681cb0ef41Sopenharmony_ci      pkg.keywords = stripVTControlCharacters(data.keywords.replace(/[,\s]+/, ' '))
691cb0ef41Sopenharmony_ci    }
701cb0ef41Sopenharmony_ci    if (data.date) {
711cb0ef41Sopenharmony_ci      pkg.date = data.date.toISOString().split('T')[0] // remove time
721cb0ef41Sopenharmony_ci    }
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci    const columns = ['name', 'description', 'author', 'date', 'version', 'keywords']
751cb0ef41Sopenharmony_ci    if (this.#opts.parseable) {
761cb0ef41Sopenharmony_ci      return columns.map((col) => pkg[col] && ('' + pkg[col]).replace(/\t/g, ' ')).join('\t')
771cb0ef41Sopenharmony_ci    }
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci    // stdout in tap is never a tty
801cb0ef41Sopenharmony_ci    /* istanbul ignore next */
811cb0ef41Sopenharmony_ci    const maxWidth = process.stdout.isTTY ? process.stdout.getWindowSize()[0] : Infinity
821cb0ef41Sopenharmony_ci    let output = columnify(
831cb0ef41Sopenharmony_ci      [pkg],
841cb0ef41Sopenharmony_ci      {
851cb0ef41Sopenharmony_ci        include: columns,
861cb0ef41Sopenharmony_ci        showHeaders: ++this.#line <= 1,
871cb0ef41Sopenharmony_ci        columnSplitter: ' | ',
881cb0ef41Sopenharmony_ci        truncate: !this.#opts.long,
891cb0ef41Sopenharmony_ci        config: {
901cb0ef41Sopenharmony_ci          name: { minWidth: 25, maxWidth: 25, truncate: false, truncateMarker: '' },
911cb0ef41Sopenharmony_ci          description: { minWidth: 20, maxWidth: 20 },
921cb0ef41Sopenharmony_ci          author: { minWidth: 15, maxWidth: 15 },
931cb0ef41Sopenharmony_ci          date: { maxWidth: 11 },
941cb0ef41Sopenharmony_ci          version: { minWidth: 8, maxWidth: 8 },
951cb0ef41Sopenharmony_ci          keywords: { maxWidth: Infinity },
961cb0ef41Sopenharmony_ci        },
971cb0ef41Sopenharmony_ci      }
981cb0ef41Sopenharmony_ci    ).split('\n').map(line => line.slice(0, maxWidth)).join('\n')
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci    if (!this.#opts.color) {
1011cb0ef41Sopenharmony_ci      return output
1021cb0ef41Sopenharmony_ci    }
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci    const colors = ['31m', '33m', '32m', '36m', '34m', '35m']
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci    this.#opts.args.forEach((arg, i) => {
1071cb0ef41Sopenharmony_ci      const markStart = String.fromCharCode(i % colors.length + 1)
1081cb0ef41Sopenharmony_ci      const markEnd = String.fromCharCode(0)
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ci      if (arg.charAt(0) === '/') {
1111cb0ef41Sopenharmony_ci        output = output.replace(
1121cb0ef41Sopenharmony_ci          new RegExp(arg.slice(1, -1), 'gi'),
1131cb0ef41Sopenharmony_ci          bit => `${markStart}${bit}${markEnd}`
1141cb0ef41Sopenharmony_ci        )
1151cb0ef41Sopenharmony_ci      } else {
1161cb0ef41Sopenharmony_ci        // just a normal string, do the split/map thing
1171cb0ef41Sopenharmony_ci        let p = 0
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci        output = output.toLowerCase().split(arg.toLowerCase()).map(piece => {
1201cb0ef41Sopenharmony_ci          piece = output.slice(p, p + piece.length)
1211cb0ef41Sopenharmony_ci          p += piece.length
1221cb0ef41Sopenharmony_ci          const mark = `${markStart}${output.slice(p, p + arg.length)}${markEnd}`
1231cb0ef41Sopenharmony_ci          p += arg.length
1241cb0ef41Sopenharmony_ci          return `${piece}${mark}`
1251cb0ef41Sopenharmony_ci        }).join('')
1261cb0ef41Sopenharmony_ci      }
1271cb0ef41Sopenharmony_ci    })
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci    for (let i = 1; i <= colors.length; i++) {
1301cb0ef41Sopenharmony_ci      output = output.split(String.fromCharCode(i)).join(`\u001B[${colors[i - 1]}`)
1311cb0ef41Sopenharmony_ci    }
1321cb0ef41Sopenharmony_ci    return output.split('\u0000').join('\u001B[0m').trim()
1331cb0ef41Sopenharmony_ci  }
1341cb0ef41Sopenharmony_ci}
135