aboutsummaryrefslogtreecommitdiff
path: root/sandbox/testAppNevena/Front/node_modules/read-package-json-fast/index.js
blob: 646ff7dfbbd761dfa662cd2858872dc4502979f3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
const {promisify} = require('util')
const fs = require('fs')
const readFile = promisify(fs.readFile)
const lstat = promisify(fs.lstat)
const readdir = promisify(fs.readdir)
const parse = require('json-parse-even-better-errors')

const { resolve, dirname, join, relative } = require('path')

const rpj = path => readFile(path, 'utf8')
  .then(data => readBinDir(path, normalize(stripUnderscores(parse(data)))))
  .catch(er => {
    er.path = path
    throw er
  })

const normalizePackageBin = require('npm-normalize-package-bin')

// load the directories.bin folder as a 'bin' object
const readBinDir = async (path, data) => {
  if (data.bin)
    return data

  const m = data.directories && data.directories.bin
  if (!m || typeof m !== 'string')
    return data

  // cut off any monkey business, like setting directories.bin
  // to ../../../etc/passwd or /etc/passwd or something like that.
  const root = dirname(path)
  const dir = join('.', join('/', m))
  data.bin = await walkBinDir(root, dir, {})
  return data
}

const walkBinDir = async (root, dir, obj) => {
  const entries = await readdir(resolve(root, dir)).catch(() => [])
  for (const entry of entries) {
    if (entry.charAt(0) === '.')
      continue
    const f = resolve(root, dir, entry)
    // ignore stat errors, weird file types, symlinks, etc.
    const st = await lstat(f).catch(() => null)
    if (!st)
      continue
    else if (st.isFile())
      obj[entry] = relative(root, f)
    else if (st.isDirectory())
      await walkBinDir(root, join(dir, entry), obj)
  }
  return obj
}

// do not preserve _fields set in files, they are sus
const stripUnderscores = data => {
  for (const key of Object.keys(data).filter(k => /^_/.test(k)))
    delete data[key]
  return data
}

const normalize = data => {
  add_id(data)
  fixBundled(data)
  pruneRepeatedOptionals(data)
  fixScripts(data)
  fixFunding(data)
  normalizePackageBin(data)
  return data
}

rpj.normalize = normalize

const add_id = data => {
  if (data.name && data.version)
    data._id = `${data.name}@${data.version}`
  return data
}

// it was once common practice to list deps both in optionalDependencies
// and in dependencies, to support npm versions that did not know abbout
// optionalDependencies.  This is no longer a relevant need, so duplicating
// the deps in two places is unnecessary and excessive.
const pruneRepeatedOptionals = data => {
  const od = data.optionalDependencies
  const dd = data.dependencies || {}
  if (od && typeof od === 'object') {
    for (const name of Object.keys(od)) {
      delete dd[name]
    }
  }
  if (Object.keys(dd).length === 0)
    delete data.dependencies
  return data
}

const fixBundled = data => {
  const bdd = data.bundledDependencies
  const bd = data.bundleDependencies === undefined ? bdd
    : data.bundleDependencies

  if (bd === false)
    data.bundleDependencies = []
  else if (bd === true)
    data.bundleDependencies = Object.keys(data.dependencies || {})
  else if (bd && typeof bd === 'object') {
    if (!Array.isArray(bd))
      data.bundleDependencies = Object.keys(bd)
    else
      data.bundleDependencies = bd
  } else
    delete data.bundleDependencies

  delete data.bundledDependencies
  return data
}

const fixScripts = data => {
  if (!data.scripts || typeof data.scripts !== 'object') {
    delete data.scripts
    return data
  }

  for (const [name, script] of Object.entries(data.scripts)) {
    if (typeof script !== 'string')
      delete data.scripts[name]
  }
  return data
}

const fixFunding = data => {
  if (data.funding && typeof data.funding === 'string')
    data.funding = { url: data.funding }
  return data
}

module.exports = rpj