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

github.com/npm/cli.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWassim Chegham <1699357+manekinekko@users.noreply.github.com>2022-02-24 20:46:37 +0300
committerGitHub <noreply@github.com>2022-02-24 20:46:37 +0300
commit6b68c1aaa282205eb4d47dbc81909c11851f7e06 (patch)
treea5a2ddafe61e5e475913a316a3ca59893629f986 /scripts
parentd438d61d4f689966de8f964afe212d1319b8d460 (diff)
docs: auto-generate npm usage for each command (#4450)
Closes #4189 * docs: auto-generate synopsis sections * feat: improve usage auto-generation' * chore: auto-generate npm usage for each command * docs: print default usage when usage is missing * docs: add special case for npx * fix: remove optional chaining
Diffstat (limited to 'scripts')
-rw-r--r--scripts/config-doc-command.js111
1 files changed, 93 insertions, 18 deletions
diff --git a/scripts/config-doc-command.js b/scripts/config-doc-command.js
index 9db026f30..af008b7e1 100644
--- a/scripts/config-doc-command.js
+++ b/scripts/config-doc-command.js
@@ -1,21 +1,78 @@
const { definitions } = require('../lib/utils/config/index.js')
+const usageFn = require('../lib/utils/usage.js')
const { writeFileSync, readFileSync } = require('fs')
const { resolve } = require('path')
const configDoc = process.argv[2]
const commandFile = process.argv[3]
+const TAGS = {
+ CONFIG: {
+ START: '<!-- AUTOGENERATED CONFIG DESCRIPTIONS START -->',
+ END: '<!-- AUTOGENERATED CONFIG DESCRIPTIONS END -->',
+ },
+ USAGE: {
+ START: '<!-- AUTOGENERATED USAGE DESCRIPTIONS START -->',
+ END: '<!-- AUTOGENERATED USAGE DESCRIPTIONS END -->',
+ },
+}
+
// Note: commands without params skip this whole process.
-const { params } = require(resolve(commandFile))
+const {
+ params,
+ usage,
+} = require(resolve(commandFile))
-const describeAll = () =>
- params.map(name => definitions[name].describe()).join(
+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 addBetweenTags = (doc, startTag, endTag, body) => {
+const describeUsage = ({ usage }) => {
+ 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 aliases = usageFn(commandName, '').trim()
+ if (aliases) {
+ synopsis.push(`\n${aliases}`)
+ }
+ }
+ } 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')
}
@@ -29,27 +86,45 @@ const addBetweenTags = (doc, startTag, endTag, body) => {
startSplit[0],
startTag,
'\n<!-- automatically generated, do not edit manually -->\n' +
- '<!-- see lib/utils/config/definitions.js -->\n',
+ '<!-- see ' + sourceFilepath + ' -->\n',
body,
'\n\n<!-- automatically generated, do not edit manually -->\n' +
- '<!-- see lib/utils/config/definitions.js -->',
+ '<!-- see ' + sourceFilepath + ' -->',
'\n\n',
endTag,
endSplit[1],
].join('')
}
-const addDescriptions = doc => {
- const startTag = '<!-- AUTOGENERATED CONFIG DESCRIPTIONS START -->'
- const endTag = '<!-- AUTOGENERATED CONFIG DESCRIPTIONS END -->'
- return addBetweenTags(doc, startTag, endTag, describeAll())
-}
+const addDescriptions = doc =>
+ addBetweenTags(doc, TAGS.CONFIG.START, TAGS.CONFIG.END, describeAll(params))
+
+const addUsageDescriptions = doc =>
+ addBetweenTags(doc, TAGS.USAGE.START, TAGS.USAGE.END,
+ describeUsage({ usage }),
+ commandFile
+ )
-// always write SOMETHING so that Make sees the file is up to date.
-const doc = readFileSync(configDoc, 'utf8')
-const hasTag = doc.includes('<!-- AUTOGENERATED CONFIG DESCRIPTIONS START -->')
-const newDoc = params && hasTag ? addDescriptions(doc) : doc
-if (params && !hasTag) {
- console.error('WARNING: did not find config description section', configDoc)
+try {
+ // always write SOMETHING so that Make sees the file is up to date.
+ const doc = readFileSync(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) : doc
+ newDoc = hasUsageTag ? addUsageDescriptions(newDoc) : 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)
+ }
+ writeFileSync(configDoc, newDoc)
+ }
+} catch (err) {
+ console.error(`WARNING: file cannot be open: ${configDoc}`)
+ console.error(err)
}
-writeFileSync(configDoc, newDoc)