Welcome to mirror list, hosted at ThFree Co, Russian Federation.

config-doc-command.js « bin « docs - github.com/npm/cli.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: f55213cdcfd6dd198082f7b2bead24f4436eaa1f (plain)
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
137
138
139
140
141
142
const fs = require('fs').promises
const { resolve } = require('path')
const { definitions, aliases } = require('../lib/npm.js')

const describeAll = (content) =>
  content.map(name => definitions[name].describe()).join(
    '\n\n<!-- automatically generated, do not edit manually -->\n' +
      '<!-- see lib/utils/config/definitions.js -->\n\n'
  )

const describeUsage = ({ usage, configDoc, commandFile }) => {
  const synopsis = []

  // Grab the command name from the *.md filename
  // NOTE: We cannot use the name property command file because in the case of
  // `npx` the file being used is `lib/commands/exec.js`
  const commandName = configDoc.split('/').pop().split('.')[0].replace('npm-', '')
  synopsis.push('\n```bash')

  if (commandName) {
    // special case for `npx`:
    // `npx` is not technically a command in and of itself,
    // so it just needs the usage and parameters of npm exec, and none of the aliases
    if (commandName === 'npx') {
      synopsis.push(usage.map(usageInfo => `npx ${usageInfo}`).join('\n'))
    } else {
      const baseCommand = `npm ${commandName}`
      if (!usage) {
        synopsis.push(baseCommand)
      } else {
        synopsis.push(usage.map(usageInfo => `${baseCommand} ${usageInfo}`).join('\n'))
      }

      const cmdAliases = Object.keys(aliases).reduce((p, c) => {
        if (aliases[c] === commandName) {
          p.push(c)
        }
        return p
      }, [])

      if (cmdAliases.length === 1) {
        synopsis.push('')
        synopsis.push(`alias: ${cmdAliases[0]}`)
      } else if (cmdAliases.length > 1) {
        synopsis.push('')
        synopsis.push(`aliases: ${cmdAliases.join(', ')}`)
      }
    }
  } else {
    console.error(`could not determine command name from ${commandFile}`)
  }

  synopsis.push('```')
  return synopsis.join('\n')
}

const addBetweenTags = (
  doc,
  startTag,
  endTag,
  body,
  sourceFilepath = 'lib/utils/config/definitions.js') => {
  const startSplit = doc.split(startTag)

  if (startSplit.length !== 2) {
    throw new Error('Did not find exactly one start tag')
  }

  const endSplit = startSplit[1].split(endTag)
  if (endSplit.length !== 2) {
    throw new Error('Did not find exactly one end tag')
  }

  return [
    startSplit[0],
    startTag,
    '\n<!-- automatically generated, do not edit manually -->\n' +
      '<!-- see ' + sourceFilepath + ' -->\n',
    body,
    '\n\n<!-- automatically generated, do not edit manually -->\n' +
      '<!-- see ' + sourceFilepath + ' -->',
    '\n\n',
    endTag,
    endSplit[1],
  ].join('')
}

const TAGS = {
  CONFIG: {
    START: '<!-- AUTOGENERATED CONFIG DESCRIPTIONS START -->',
    END: '<!-- AUTOGENERATED CONFIG DESCRIPTIONS END -->',
  },
  USAGE: {
    START: '<!-- AUTOGENERATED USAGE DESCRIPTIONS START -->',
    END: '<!-- AUTOGENERATED USAGE DESCRIPTIONS END -->',
  },
}

const addDescriptions = ({ doc, params }) =>
  addBetweenTags(doc, TAGS.CONFIG.START, TAGS.CONFIG.END, describeAll(params))

const addUsageDescriptions = ({ doc, usage, configDoc, commandFile }) =>
  addBetweenTags(doc, TAGS.USAGE.START, TAGS.USAGE.END,
    describeUsage({ usage, configDoc, commandFile }),
    commandFile
  )

const run = async (configDoc, commandFile) => {
  try {
    // Note: commands without params skip this whole process.
    const { params, usage } = require(resolve(commandFile))

    // always write SOMETHING so that Make sees the file is up to date.
    const doc = await fs.readFile(configDoc, 'utf8')
    const hasTag = doc.includes(TAGS.CONFIG.START)
    const hasUsageTag = doc.includes(TAGS.USAGE.START)

    if (params && params.length) {
      let newDoc = hasTag ? addDescriptions({ doc, params }) : doc
      newDoc = hasUsageTag
        ? addUsageDescriptions({ doc: newDoc, usage, configDoc, commandFile })
        : newDoc

      if (!hasTag) {
        console.error('WARNING: did not find config description section', configDoc)
      }

      if ((usage && usage.length) && !hasUsageTag) {
        console.error('WARNING: did not find usage description section', configDoc)
      }
      await fs.writeFile(configDoc, newDoc)
    }
  } catch (err) {
    console.error(`WARNING: file cannot be open: ${configDoc}`)
    throw err
  }
}

run(...process.argv.slice(2)).catch((err) => {
  process.exitCode = 1
  console.error(err)
})