commit
245878ec81
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 bisubus
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
@ -0,0 +1,118 @@
|
|||||||
|
# hestia-cli-docs
|
||||||
|
|
||||||
|
Provides pre-generated Hestia CLI documentation, as well as tools to generate it from annotation comments and keep it in a good shape.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
**Ready-to-use documentation for Hestia CLI commands is available [online](https://hestiacp.com/docs/reference/cli.html)**.
|
||||||
|
|
||||||
|
If you are here to browse it, you don't need any of the below.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Supports Node.js 14 or higher.
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone https://github.com/hestiacp/hestia-cli-docs
|
||||||
|
cd hestia-cli-docs
|
||||||
|
npm i
|
||||||
|
```
|
||||||
|
|
||||||
|
## Use
|
||||||
|
|
||||||
|
### Generate command annotations
|
||||||
|
|
||||||
|
Auto-format comments in Hestia commands, label ones that are unique to Hestia, merge examples and categories from Hestia older documentation. This may be destructive for a branch that has been already edited:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run format-cmds -- --legacy path/to/local/hestiacp/bin https://github.com/hestiacp/hestiacp branch-that-contains-unformatted-comments
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update command annotations
|
||||||
|
|
||||||
|
Auto-format comments in Hestia command:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run format-cmds -- path/to/local/hestiacp/bin https://github.com/hestiacp/hestiacp branch-that-contains-formatted-comments
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check command annotations
|
||||||
|
|
||||||
|
Check comments in Hestia commands for potential problems and output hestia-cmds.json cache that can be used by other commands or externally processed:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run check-cmds -- --output https://github.com/hestiacp/hestiacp branch-that-contains-unformatted-comments
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generate CLI documentation
|
||||||
|
|
||||||
|
Generate one-page documentation for Hestia CLI commands, use hestia-cmds.json cache if available
|
||||||
|
```
|
||||||
|
npm run generate-docs -- https://github.com/hestiacp/hestiacp branch-that-contains-formatted-comments
|
||||||
|
```
|
||||||
|
|
||||||
|
## Format
|
||||||
|
|
||||||
|
The toolset detects inconsistencies in command annotation and keeps the format strict. Options closely follow the format that is used in script body.
|
||||||
|
|
||||||
|
This allows to simply and reliably parse annotations and use them to automatically generate the documentation:
|
||||||
|
|
||||||
|
- The annotation goes immediately after shebang
|
||||||
|
- No unnecessary duplicate, leading and trailing whitespaces unless specified, all lines start with `#` and a space, no space in empty line
|
||||||
|
- A comment after the description shouldn't be a part of the annotation
|
||||||
|
- PHP scripts follow the same format but have mandatory `<?php` tag and PHP `//` comment before `#` to match the syntax
|
||||||
|
- `info`, `options` and `labels` fields are mandatory and go in this order, 1 space after colon in case a field is filled
|
||||||
|
- `info` is concise, uncapitalized, doesn't end with a dot
|
||||||
|
- `options` are upper- and snake-cased, separated with 1 space, optional are wrapped with `[]`
|
||||||
|
- `labels` allow to group scripts, lower- and kebab-cased, delimited with 1 space
|
||||||
|
- `example` fields are optional and numerous, delimited and separated with empty line, multiline examples can be aligned, descriptions can contain additional `#` to be distinguished from a command
|
||||||
|
- the description is mandatory, delimited with empty line and consists of sentences wrapped for 80 width limit, each line is prepended with `#`
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
Bash script with variable options and an example (`v-add-fs-archive`):
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# info: archive directory
|
||||||
|
# options: USER ARCHIVE SOURCE [SOURCE...]
|
||||||
|
# labels:
|
||||||
|
#
|
||||||
|
# example: v-add-fs-archive admin archive.tar readme.txt
|
||||||
|
#
|
||||||
|
# The function creates tar archive
|
||||||
|
…
|
||||||
|
```
|
||||||
|
|
||||||
|
Bash script with multiline examples (`v-change-sys-db-alias`):
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# info: change phpmyadmin/phppgadmin alias url
|
||||||
|
# options: TYPE ALIAS
|
||||||
|
# labels: hestia
|
||||||
|
#
|
||||||
|
# example: v-change-sys-db-alias pma phpmyadmin
|
||||||
|
# # Sets phpMyAdmin alias to phpmyadmin
|
||||||
|
#
|
||||||
|
# example: v-change-sys-db-alias pga phppgadmin
|
||||||
|
# # Sets phpPgAdmin alias to phppgadmin
|
||||||
|
#
|
||||||
|
# This function changes the database editor url in
|
||||||
|
# apache2 or nginx configuration.
|
||||||
|
…
|
||||||
|
```
|
||||||
|
|
||||||
|
PHP script (`v-generate-password-hash`):
|
||||||
|
```php
|
||||||
|
#!/usr/local/hestia/php/bin/php
|
||||||
|
<?php
|
||||||
|
//# info: generate password hash
|
||||||
|
//# options: HASH_METHOD SALT PASSWORD
|
||||||
|
//# labels: panel
|
||||||
|
//#
|
||||||
|
//# example: v-generate-password-hash sha-512 rAnDom_string yourPassWord
|
||||||
|
//#
|
||||||
|
//# The function generates password hash
|
||||||
|
|
||||||
|
// Checking arguments
|
||||||
|
…
|
||||||
|
```
|
@ -0,0 +1,25 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const { processCmds } = require('../lib/process-cmds');
|
||||||
|
|
||||||
|
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
|
||||||
|
let isLegacy = false;
|
||||||
|
if (args[0] === '--legacy') {
|
||||||
|
isLegacy = true;
|
||||||
|
args.splice(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let isOutput = false;
|
||||||
|
if (args[0] === '--output') {
|
||||||
|
isOutput = true;
|
||||||
|
args.splice(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [hestiaRepo = 'https://github.com/hestiacp/hestiacp', hestiaBranch = 'main'] = args;
|
||||||
|
const cmds = processCmds({ hestiaRepo, hestiaBranch, cache: false });
|
||||||
|
|
||||||
|
if (isOutput) {
|
||||||
|
fs.writeFileSync(path.join(process.cwd(), 'hestia-cmds.json'), JSON.stringify(cmds, null, 2));
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
const assert = require('assert');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const { processCmds } = require('../lib/process-cmds');
|
||||||
|
|
||||||
|
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
|
||||||
|
let isLegacy = false;
|
||||||
|
if (args[0] === '--legacy') {
|
||||||
|
isLegacy = true;
|
||||||
|
args.splice(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let isCache = false;
|
||||||
|
if (args[0] === '--cache') {
|
||||||
|
isCache = true;
|
||||||
|
args.splice(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [hestiaBinRelPath, hestiaRepo = 'https://github.com/hestiacp/hestiacp', hestiaBranch = 'main'] = args;
|
||||||
|
|
||||||
|
assert(hestiaBinRelPath);
|
||||||
|
|
||||||
|
const cmds = processCmds({ hestiaRepo, hestiaBranch, cache: isCache, checkOldDocs: isLegacy, checkVesta: isLegacy });
|
||||||
|
|
||||||
|
const hestiaBinPath = path.resolve(process.cwd(), hestiaBinRelPath);
|
||||||
|
const hestiaBinFiles = fs.readdirSync(hestiaBinPath).filter(file => /^v-[\w-]+$/.test(file));
|
||||||
|
|
||||||
|
const mismatchedCmds = [
|
||||||
|
...Object.keys(cmds).filter(cmdName => !hestiaBinFiles.includes(cmdName)),
|
||||||
|
...hestiaBinFiles.filter(binName => !(binName in cmds))
|
||||||
|
];
|
||||||
|
|
||||||
|
if (mismatchedCmds.length) {
|
||||||
|
console.warn(mismatchedCmds);
|
||||||
|
throw new Error('Mismatched commands');
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [cmdName, cmd] of Object.entries(cmds)) {
|
||||||
|
try {
|
||||||
|
const cmdPath = path.join(hestiaBinPath, cmdName);
|
||||||
|
const bin = fs.readFileSync(cmdPath, 'utf8');
|
||||||
|
|
||||||
|
let generatedBinComment = [
|
||||||
|
`# info: ${cmd.info || ''}`,
|
||||||
|
`# options: ${cmd.options || ''}`,
|
||||||
|
`# labels: ${cmd.labels?.join(' ') || ''}`
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
if (cmd.examples?.length) {
|
||||||
|
generatedBinComment += '\n#\n' + cmd.examples
|
||||||
|
.map(example => (
|
||||||
|
example
|
||||||
|
.split('\n')
|
||||||
|
.map((line, i) => `# ${!i ? 'example: ' : ' '}${line}`)
|
||||||
|
.join('\n')
|
||||||
|
))
|
||||||
|
.join('\n#\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd.desc) {
|
||||||
|
generatedBinComment += '\n#\n' + cmd.desc.replace(/^/gm, '# ');
|
||||||
|
}
|
||||||
|
|
||||||
|
generatedBinComment += '\n';
|
||||||
|
|
||||||
|
let rebuiltBin;
|
||||||
|
if (cmd.php) {
|
||||||
|
generatedBinComment = generatedBinComment.replace(/^#/gm, '//#');
|
||||||
|
// replacement function to prevent unescaped $
|
||||||
|
rebuiltBin = bin.replace(/(?<=^#!\/usr\/local\/hestia\/php\/bin\/php\n<\?php\n)(?:(?:\/\/#.*)\n)+/, () => generatedBinComment);
|
||||||
|
} else {
|
||||||
|
rebuiltBin = bin.replace(/(?<=^#!\/bin\/bash\n)(?:(?:#.*)\n)+/, () => generatedBinComment);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bin !== rebuiltBin) {
|
||||||
|
console.log('Formatting:', cmdName);
|
||||||
|
fs.writeFileSync(cmdPath, rebuiltBin, 'utf8');
|
||||||
|
} else {
|
||||||
|
console.log('Skipping:', cmdName);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Command:', cmdName);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const { processCmds } = require('../lib/process-cmds');
|
||||||
|
const { generateAllCmdsDoc } = require('../lib/generate-docs');
|
||||||
|
|
||||||
|
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const [hestiaRepo = 'https://github.com/hestiacp/hestiacp', hestiaBranch = 'main'] = args;
|
||||||
|
|
||||||
|
const cmds = processCmds({ hestiaRepo, hestiaBranch, cache: true, checkOldDocs: false, checkVesta:false });
|
||||||
|
const allCmdsDoc = generateAllCmdsDoc(cmds);
|
||||||
|
|
||||||
|
fs.writeFileSync(path.join(__dirname, '../docs/commands.md'), allCmdsDoc, 'utf8');
|
@ -0,0 +1,29 @@
|
|||||||
|
const GfmEscape = require('gfm-escape');
|
||||||
|
const nunjucks = require('nunjucks');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
|
||||||
|
const mdEscaper = new GfmEscape();
|
||||||
|
const mdCodeEscaper = new GfmEscape({}, 'codeSpan');
|
||||||
|
const mdLinkTitleEscaper = new GfmEscape({}, 'linkTitle');
|
||||||
|
|
||||||
|
nunjucks
|
||||||
|
.configure(path.join(__dirname, 'templates'), {
|
||||||
|
autoescape: false,
|
||||||
|
noCache: true,
|
||||||
|
trimBlocks: true
|
||||||
|
})
|
||||||
|
.addFilter('md', str => mdEscaper.escape(str))
|
||||||
|
.addFilter('mdCode', str => mdCodeEscaper.escape(str))
|
||||||
|
.addFilter('mdLinkTitle', str => mdLinkTitleEscaper.escape(str));
|
||||||
|
|
||||||
|
const generateAllCmdsDoc = (cmds) => {
|
||||||
|
for (const [cmdName, cmd] of Object.entries(cmds)) {
|
||||||
|
cmd.options = cmd.options?.split(' ');
|
||||||
|
//cmd.desc = cmd.desc?.split(/ *\n */).join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
return nunjucks.render('doc-all.md', { cmds });
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.generateAllCmdsDoc = generateAllCmdsDoc;
|
@ -0,0 +1,263 @@
|
|||||||
|
const cp = require('child_process');
|
||||||
|
const fs = require('fs');
|
||||||
|
const os = require('os');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
|
||||||
|
function processCmds({ hestiaRepo, hestiaBranch, cache = false, checkOldDocs = true, checkVesta = true } = {}) {
|
||||||
|
let cmds;
|
||||||
|
|
||||||
|
if (cache && fs.existsSync(path.join(process.cwd(), 'hestia-cmds.json'))) {
|
||||||
|
console.log(`Reusing hestia-cmds.json`);
|
||||||
|
cmds = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'hestia-cmds.json')));
|
||||||
|
|
||||||
|
return cmds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// process Heistia old docs
|
||||||
|
const oldCmds = {};
|
||||||
|
if (checkOldDocs) {
|
||||||
|
const hestiaDocsPath = fs.mkdtempSync(path.join(os.tmpdir(), 'hestiadocs-'));
|
||||||
|
const gitHestiaDocs = cp.spawnSync('git', [...'clone --depth 1 https://github.com/hestiacp/hestiacp-docs'.split(' '), hestiaDocsPath], { stdio: 'inherit' });
|
||||||
|
|
||||||
|
if (gitHestiaDocs.status)
|
||||||
|
process.exit(1);
|
||||||
|
|
||||||
|
const hestiaCmdDocsPath = path.join(hestiaDocsPath, 'cli_commands');
|
||||||
|
const hestiaDocFiles = fs.readdirSync(hestiaCmdDocsPath).filter(file => /\.rst/.test(file));
|
||||||
|
for (const hestiaDocFile of hestiaDocFiles) {
|
||||||
|
try {
|
||||||
|
const doc = fs.readFileSync(path.join(hestiaCmdDocsPath, hestiaDocFile), 'utf8');
|
||||||
|
let [, label, content] = doc.match(/###+\n(\w+) .+?\n###+\n([\s\S]+)/);
|
||||||
|
for (const [, cmdName, cmdSection] of content.matchAll(/[*]{3,}\n(v-[\w-]+)\n[*]{3,}([\s\S]+?)(?=[*]{3}|$)/g)) {
|
||||||
|
try {
|
||||||
|
let examples;
|
||||||
|
// formatting is inconsistent
|
||||||
|
let [, example = ''] = cmdSection.match(/[*]{2}Example usage[*]{2}:? *`(.+)`/i) || [];
|
||||||
|
// remove dupe spaces in first line
|
||||||
|
example = example
|
||||||
|
.split('\n')
|
||||||
|
.map((line, i) => i ? line : line.replace(/ +/g, ' '))
|
||||||
|
.join('\n')
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
if (example)
|
||||||
|
examples = [example];
|
||||||
|
|
||||||
|
label = label.toLowerCase();
|
||||||
|
oldCmds[cmdName] = { labels: [label], examples };
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Hestia doc section:', cmdName);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Hestia doc:', hestiaDocFile);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.rmdirSync(hestiaDocsPath, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
// compare Hestia set of commands with Vesta for `hestia` label
|
||||||
|
const vestaCmds = {};
|
||||||
|
if (checkVesta) {
|
||||||
|
const vestaPath = fs.mkdtempSync(path.join(os.tmpdir(), 'hestiadocs-'));
|
||||||
|
const gitVesta = cp.spawnSync('git', [...'clone --depth 1 https://github.com/serghey-rodin/vesta'.split(' '), vestaPath], { stdio: 'inherit' });
|
||||||
|
|
||||||
|
if (gitVesta.status)
|
||||||
|
process.exit(1);
|
||||||
|
|
||||||
|
const vestaBinPath = path.join(vestaPath, 'bin');
|
||||||
|
const vestaBinFiles = fs.readdirSync(vestaBinPath).filter(file => /^v-[\w-]+$/.test(file));
|
||||||
|
for (const vestaBinFile of vestaBinFiles) {
|
||||||
|
const cmdName = vestaBinFile.replace('vesta', 'hestia');
|
||||||
|
vestaCmds[cmdName] = { ...vestaCmds[cmdName] };
|
||||||
|
vestaCmds[cmdName].labels = ['vesta'];
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.rmdirSync(vestaPath, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
// process Hestia comments
|
||||||
|
const hestiaPath = fs.mkdtempSync(path.join(os.tmpdir(), 'hestiadocs-'));
|
||||||
|
const gitHestia = cp.spawnSync('git', [...'clone --depth 1'.split(' '), hestiaRepo, '--branch', hestiaBranch, hestiaPath], { stdio: 'inherit' });
|
||||||
|
|
||||||
|
if (gitHestia.status)
|
||||||
|
process.exit(1);
|
||||||
|
|
||||||
|
cmds = {};
|
||||||
|
const hestiaBinPath = path.join(hestiaPath, 'bin');
|
||||||
|
const hestiaBinFiles = fs.readdirSync(hestiaBinPath).filter(file => /^v-[\w-]+$/.test(file));
|
||||||
|
for (const hestiaBinFile of hestiaBinFiles) {
|
||||||
|
const cmdName = hestiaBinFile;
|
||||||
|
try {
|
||||||
|
const bin = fs.readFileSync(path.join(hestiaBinPath, hestiaBinFile), 'utf8');
|
||||||
|
|
||||||
|
const [, shebang, content] = bin.match(/^(#!.+)\n([\s\S]+)/);
|
||||||
|
let introBlock;
|
||||||
|
let isPhp;
|
||||||
|
|
||||||
|
// Not all descriptions are separated with empty # (v-add-sys-theme)
|
||||||
|
if (shebang === '#!/usr/local/hestia/php/bin/php') {
|
||||||
|
// v-generate-password-hash
|
||||||
|
isPhp = true;
|
||||||
|
[, introBlock] = content.match(/^<\?php\n((?:(?:\/\/#|\/\/# .*|)\n)+)/);
|
||||||
|
introBlock = introBlock.replace(/^\/\//gm, '');
|
||||||
|
} else if (shebang === '#!/bin/bash') {
|
||||||
|
[, introBlock] = content.match(/^((?:(?:#|# .*|)\n)+)/);
|
||||||
|
} else {
|
||||||
|
throw new Error('Unknown interpreter');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/^(?!#)/gm.test(introBlock.trimEnd())) {
|
||||||
|
console.log(`${hestiaBinFile}: missing # on empty line`);
|
||||||
|
}
|
||||||
|
|
||||||
|
introBlock = introBlock.replace(/^#(?: | *$)/gm, '').trimStart();
|
||||||
|
|
||||||
|
let [, info, options, labelsList, othersBlock] = introBlock.match(/^(?:info: +(.*)\n|)(?:options: +(.*)\n|)(?:labels: ?(.*)\n|)([\s\S]*)/);
|
||||||
|
// May contain multiple example blocks (v-change-sys-db-alias) before description or extra comments after (v-search-command)
|
||||||
|
|
||||||
|
if (info)
|
||||||
|
info = info.trim();
|
||||||
|
|
||||||
|
if (options) {
|
||||||
|
options = options.trim();
|
||||||
|
|
||||||
|
const processedOptions = options.split(/\s+/)
|
||||||
|
.filter(Boolean)
|
||||||
|
.map(option => option.replace(/-/g, '_').toUpperCase())
|
||||||
|
.map(option => option.replace('[NONE]', 'NONE'))
|
||||||
|
.join(' ');
|
||||||
|
|
||||||
|
if (options !== processedOptions || !/^[A-Z0-9_\.\[\] ]+$/.test(options))
|
||||||
|
console.log(`${hestiaBinFile}: inconsistent options format`);
|
||||||
|
|
||||||
|
options = processedOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if options are up-to-date
|
||||||
|
// based on validated args
|
||||||
|
const optionsCount = (options !== 'NONE' && options?.split(' ').length) || 0;
|
||||||
|
let usedArgsCount = 0;
|
||||||
|
if (/args_usage=('[^\$\n]*'|"[^\$\n]*")/.test(content)) {
|
||||||
|
usedArgsCount = content.match(/args_usage=('[^\$\n]*'|"[^\$\n]*")/)[1]
|
||||||
|
.replace(/^['"](.*)['"]$/, '$1').trim()
|
||||||
|
.split(/\s+/).length;
|
||||||
|
} else if (/check_args .+('[^\$\n]*'|"[^\$\n]*") *\n/.test(content)) {
|
||||||
|
usedArgsCount = content.match(/check_args .+('[^\$\n]*'|"[^\$\n]*") *\n/)[1]
|
||||||
|
.replace(/^['"](.*)['"]$/, '$1').trim()
|
||||||
|
.split(/\s+/).length;
|
||||||
|
}
|
||||||
|
// based on directly refered args
|
||||||
|
const referedArgs = [...content.matchAll(isPhp ? /\$argv\[(\d+)\]/g : /=\${?(\d+)/g)].map(([, argNum]) => +argNum);
|
||||||
|
usedArgsCount = Math.max(usedArgsCount, ...referedArgs);
|
||||||
|
|
||||||
|
// based on wildcard arg
|
||||||
|
if (!optionsCount && !usedArgsCount && / \$#/.test(content)) {
|
||||||
|
usedArgsCount = Infinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optionsCount !== usedArgsCount)
|
||||||
|
console.log(`${hestiaBinFile}: possible options mismatch, ${optionsCount}/${usedArgsCount}`);
|
||||||
|
|
||||||
|
if (!info) {
|
||||||
|
console.log(`${hestiaBinFile}: no info`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options) {
|
||||||
|
console.log(`${hestiaBinFile}: no options`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let examplesSet = new Set(oldCmds[cmdName]?.examples);
|
||||||
|
let desc;
|
||||||
|
let isExtraComment;
|
||||||
|
|
||||||
|
if (othersBlock) {
|
||||||
|
// const commentBlocks = othersBlock.replace(/^ *(.*?) */gm, '$1').replace(/^\n*([\s\S]*?)\n*$/, '$1').split(/\n\n+/);
|
||||||
|
const commentBlocks = othersBlock.replace(/^ *(.*?) */gm, '$1').replace(/^\n*([\s\S]*?)\n*$/, '$1').split(/\n\n+/);
|
||||||
|
|
||||||
|
for (const commentBlock of commentBlocks) {
|
||||||
|
if (desc != null) {
|
||||||
|
isExtraComment = true;
|
||||||
|
} else if (/^example:/.test(commentBlock)) {
|
||||||
|
let [, example] = commentBlock.match(/^example: +([\s\S]+)/);
|
||||||
|
|
||||||
|
// remove dupe spaces in first line
|
||||||
|
example = example
|
||||||
|
.split('\n')
|
||||||
|
.map((line, i) => i ? line : line.replace(/ +/g, ' '))
|
||||||
|
.join('\n ')
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
examplesSet.add(example);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
desc = commentBlock.replace(/ +/g, ' ').trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!desc) {
|
||||||
|
console.log(`${hestiaBinFile}: no description`);
|
||||||
|
} else if (/(?<![.,:!?]) *\n *[A-Z]/.test(desc)) {
|
||||||
|
console.log(`${hestiaBinFile}: description punctuation missing`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isExtraComment) {
|
||||||
|
console.log(`${hestiaBinFile}: extra comments`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ownLabels = labelsList ? labelsList.trim().toLowerCase().split(/ +/) : [];
|
||||||
|
const labelsSet = new Set([
|
||||||
|
...(oldCmds[cmdName]?.labels || []),
|
||||||
|
...(vestaCmds[cmdName]?.labels || []),
|
||||||
|
...ownLabels
|
||||||
|
]);
|
||||||
|
// not useful
|
||||||
|
labelsSet.delete('common');
|
||||||
|
|
||||||
|
// specific to Hestia
|
||||||
|
if (checkVesta) {
|
||||||
|
if (labelsSet.has('vesta')) {
|
||||||
|
labelsSet.delete('vesta')
|
||||||
|
} else {
|
||||||
|
labelsSet.add('hestia');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let labels;
|
||||||
|
if (labelsSet.size)
|
||||||
|
labels = [...labelsSet].sort();
|
||||||
|
|
||||||
|
let examples;
|
||||||
|
|
||||||
|
for (const example of examplesSet) {
|
||||||
|
// no useless examples
|
||||||
|
if (example === cmdName)
|
||||||
|
examplesSet.delete(example);
|
||||||
|
else if (!example.startsWith(cmdName))
|
||||||
|
console.log(`${hestiaBinFile}: wrong example`);
|
||||||
|
}
|
||||||
|
if (examplesSet.size)
|
||||||
|
examples = [...examplesSet];
|
||||||
|
|
||||||
|
cmds[cmdName] = { info, options, labels, examples, desc };
|
||||||
|
|
||||||
|
if (isPhp) {
|
||||||
|
cmds[cmdName].php = true;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Hestia bin:', hestiaBinFile);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.rmdirSync(hestiaPath, { recursive: true });
|
||||||
|
|
||||||
|
return cmds;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.processCmds = processCmds;
|
@ -0,0 +1,436 @@
|
|||||||
|
{
|
||||||
|
"name": "hestia-cli-docs",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "hestia-cli-docs",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"gfm-escape": "~0.2.0",
|
||||||
|
"nunjucks": "~3.2.2",
|
||||||
|
"replace": "^1.2.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"check-cmds": "bin/check-cmds.js",
|
||||||
|
"format-cmds": "bin/format-cmds.js",
|
||||||
|
"generate-docs": "bin/generate-docs.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/a-sync-waterfall": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA=="
|
||||||
|
},
|
||||||
|
"node_modules/ansi-regex": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ansi-styles": {
|
||||||
|
"version": "3.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||||
|
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||||
|
"dependencies": {
|
||||||
|
"color-convert": "^1.9.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/asap": {
|
||||||
|
"version": "2.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
|
||||||
|
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
|
||||||
|
},
|
||||||
|
"node_modules/balanced-match": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||||
|
},
|
||||||
|
"node_modules/brace-expansion": {
|
||||||
|
"version": "1.1.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
|
"dependencies": {
|
||||||
|
"balanced-match": "^1.0.0",
|
||||||
|
"concat-map": "0.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/camelcase": {
|
||||||
|
"version": "5.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||||
|
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/chalk": {
|
||||||
|
"version": "2.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||||
|
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": "^3.2.1",
|
||||||
|
"escape-string-regexp": "^1.0.5",
|
||||||
|
"supports-color": "^5.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cliui": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"string-width": "^4.2.0",
|
||||||
|
"strip-ansi": "^6.0.0",
|
||||||
|
"wrap-ansi": "^6.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/color-convert": {
|
||||||
|
"version": "1.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||||
|
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||||
|
"dependencies": {
|
||||||
|
"color-name": "1.1.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/color-name": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||||
|
},
|
||||||
|
"node_modules/commander": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/concat-map": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
|
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
||||||
|
},
|
||||||
|
"node_modules/decamelize": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/emoji-regex": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||||
|
},
|
||||||
|
"node_modules/escape-string-regexp": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/find-up": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
|
||||||
|
"dependencies": {
|
||||||
|
"locate-path": "^5.0.0",
|
||||||
|
"path-exists": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/get-caller-file": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||||
|
"engines": {
|
||||||
|
"node": "6.* || 8.* || >= 10.*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/gfm-escape": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/gfm-escape/-/gfm-escape-0.2.0.tgz",
|
||||||
|
"integrity": "sha512-xUh/UUY/riL9zuz1pWjMvJjbYCRk3EzA+/4JltIlALW8swprpgiWPBaImeSzRNnnnzvvylPEdtzQ/576ckLusA==",
|
||||||
|
"dependencies": {
|
||||||
|
"union-replacer": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/has-flag": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-fullwidth-code-point": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/locate-path": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
|
||||||
|
"dependencies": {
|
||||||
|
"p-locate": "^4.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minimatch": {
|
||||||
|
"version": "3.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz",
|
||||||
|
"integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==",
|
||||||
|
"dependencies": {
|
||||||
|
"brace-expansion": "^1.1.7"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nunjucks": {
|
||||||
|
"version": "3.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.4.tgz",
|
||||||
|
"integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"a-sync-waterfall": "^1.0.0",
|
||||||
|
"asap": "^2.0.3",
|
||||||
|
"commander": "^5.1.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"nunjucks-precompile": "bin/precompile"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6.9.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"chokidar": "^3.3.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"chokidar": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/p-limit": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||||
|
"dependencies": {
|
||||||
|
"p-try": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/p-locate": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
|
||||||
|
"dependencies": {
|
||||||
|
"p-limit": "^2.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/p-try": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/path-exists": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/replace": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/replace/-/replace-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-C4EDifm22XZM2b2JOYe6Mhn+lBsLBAvLbK8drfUQLTfD1KYl/n3VaW/CDju0Ny4w3xTtegBpg8YNSpFJPUDSjA==",
|
||||||
|
"dependencies": {
|
||||||
|
"chalk": "2.4.2",
|
||||||
|
"minimatch": "3.0.5",
|
||||||
|
"yargs": "^15.3.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"replace": "bin/replace.js",
|
||||||
|
"search": "bin/search.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/require-directory": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/require-main-filename": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
|
||||||
|
},
|
||||||
|
"node_modules/set-blocking": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
|
||||||
|
},
|
||||||
|
"node_modules/string-width": {
|
||||||
|
"version": "4.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||||
|
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||||
|
"dependencies": {
|
||||||
|
"emoji-regex": "^8.0.0",
|
||||||
|
"is-fullwidth-code-point": "^3.0.0",
|
||||||
|
"strip-ansi": "^6.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/strip-ansi": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": "^5.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/supports-color": {
|
||||||
|
"version": "5.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||||
|
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||||
|
"dependencies": {
|
||||||
|
"has-flag": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/union-replacer": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/union-replacer/-/union-replacer-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-cD0EEWSP+EtZS0+mLThL2NYnyigOyB91j9jdlT/QDlhvHiPQ1co4xZESpTqnfOSZZbjijoYggpvzATlpisu4AQ=="
|
||||||
|
},
|
||||||
|
"node_modules/which-module": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="
|
||||||
|
},
|
||||||
|
"node_modules/wrap-ansi": {
|
||||||
|
"version": "6.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
|
||||||
|
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": "^4.0.0",
|
||||||
|
"string-width": "^4.1.0",
|
||||||
|
"strip-ansi": "^6.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/wrap-ansi/node_modules/ansi-styles": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||||
|
"dependencies": {
|
||||||
|
"color-convert": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/wrap-ansi/node_modules/color-convert": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"color-name": "~1.1.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/wrap-ansi/node_modules/color-name": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||||
|
},
|
||||||
|
"node_modules/y18n": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="
|
||||||
|
},
|
||||||
|
"node_modules/yargs": {
|
||||||
|
"version": "15.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
|
||||||
|
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
|
||||||
|
"dependencies": {
|
||||||
|
"cliui": "^6.0.0",
|
||||||
|
"decamelize": "^1.2.0",
|
||||||
|
"find-up": "^4.1.0",
|
||||||
|
"get-caller-file": "^2.0.1",
|
||||||
|
"require-directory": "^2.1.1",
|
||||||
|
"require-main-filename": "^2.0.0",
|
||||||
|
"set-blocking": "^2.0.0",
|
||||||
|
"string-width": "^4.2.0",
|
||||||
|
"which-module": "^2.0.0",
|
||||||
|
"y18n": "^4.0.0",
|
||||||
|
"yargs-parser": "^18.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/yargs-parser": {
|
||||||
|
"version": "18.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
|
||||||
|
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"camelcase": "^5.0.0",
|
||||||
|
"decamelize": "^1.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "hestia-cli-docs",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Generate and process Hestia CLI documentation from annotation comments",
|
||||||
|
"author": "bisubus",
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "index.js",
|
||||||
|
"bin": {
|
||||||
|
"check-cmds": "bin/check-cmds.js",
|
||||||
|
"generate-docs": "bin/generate-docs.js",
|
||||||
|
"format-cmds": "bin/format-cmds.js"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"check-cmds": "node bin/check-cmds.js",
|
||||||
|
"generate-docs": "node bin/generate-docs.js",
|
||||||
|
"format-cmds": "node bin/format-cmds.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"gfm-escape": "~0.2.0",
|
||||||
|
"nunjucks": "~3.2.2",
|
||||||
|
"replace": "^1.2.1"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue