@vuedoc/parser
Version:
Generate a JSON documentation for a Vue file
207 lines • 7.19 kB
JavaScript
import { lstat, writeFile } from 'node:fs/promises';
import { readFileSync, createWriteStream } from 'node:fs';
import { dirname, isAbsolute, join, parse } from 'node:path';
import { fileURLToPath } from 'node:url';
import { VuedocParser, parseComponent } from '../main.js';
import merge from 'deepmerge';
import JsonSchemav from 'jsonschemav';
import ValidationError from 'jsonschemav/lib/error.js';
import schema from '../schema/options.js';
const jsv = new JsonSchemav();
const validator = jsv.compile(schema);
const ARG_IGNORE_PREFIX = '--ignore-';
const usage = 'Usage: vuedoc-json [*.{js,vue} files]...';
export const MISSING_FILENAME_MESSAGE = `Missing filenames. ${usage}\n`;
async function validateOptions(options) {
if (options.join && options.output) {
if ((await lstat(options.output)).isDirectory()) {
throw new Error('--output value must be a file when using --join');
}
}
}
async function parseArgs(argv, requireFiles) {
const parsing = {
filecontent: '',
features: VuedocParser.SUPPORTED_FEATURES,
};
const options = {
join: false,
stream: true,
reduce: false,
filenames: [],
output: '',
parsing,
};
const promises = [];
for (let i = 0; i < argv.length; i++) {
const arg = argv[i];
switch (arg) {
/* istanbul ignore next */
case '-v':
/* istanbul ignore next */
case '--version': {
const __dirname = dirname(fileURLToPath(import.meta.url));
const packageFilename = join(__dirname, '../package.json');
const { name, version } = JSON.parse(readFileSync(packageFilename, 'utf-8'));
const output = `${name} v${version}\n`;
process.stdout.write(output);
return null;
}
case '-c':
case '--config': {
const configFile = argv[i + 1] || 'vuedoc.config.js';
const configPath = isAbsolute(configFile)
? configFile
: join(process.cwd(), configFile);
promises.push((async () => {
const config = await import(configPath);
if (config.default) {
Object.assign(options, config.default);
if (config.default.parsing) {
options.parsing = { ...parsing, ...config.default.parsing };
}
}
})());
i++;
break;
}
case '-o':
case '--output':
if (!argv[i + 1]) {
throw new Error('Missing output value. Usage: --output [file or directory]\n');
}
options.output = argv[i + 1];
i++;
break;
case '-j':
case '--join':
options.join = true;
break;
default: {
if (arg.startsWith(ARG_IGNORE_PREFIX)) {
const feature = arg.substring(ARG_IGNORE_PREFIX.length);
options.parsing.features = options.parsing.features.filter((item) => item !== feature);
}
else {
options.filenames.push(arg);
}
break;
}
}
}
await Promise.all(promises);
if (requireFiles && options.filenames.length === 0) {
throw new Error(MISSING_FILENAME_MESSAGE);
}
await validateOptions(options);
return options;
}
async function parseComponentOptions({ filename, ...options }) {
if (!options.parsing) {
options.parsing = {};
}
// compatibility with previous versions
if (filename && !options.filenames) {
options.filenames = [filename];
}
try {
const instance = await validator;
const { parsing: parsingOptions, join, filenames } = await instance.validate(options);
const promises = await new Promise((resolve, reject) => {
if (filenames.length) {
const promises = filenames.map((filename) => parseComponent({ ...parsingOptions, filename }));
if (join) {
resolve([
Promise.all(promises).then(merge.all),
]);
}
else {
resolve(promises);
}
}
else if (parsingOptions.filecontent) {
resolve([
parseComponent(parsingOptions),
]);
}
else {
reject(new Error('Invalid options. Missing options.filenames'));
}
});
const docs = await Promise.all(promises);
if (filenames.length === 1 && docs.length === 1) {
return docs[0];
}
return docs;
}
catch (err) {
if (err instanceof ValidationError) {
err.message = 'Invalid options';
}
throw err;
}
}
export async function processRawContent(argv, componentRawContent) {
const options = await parseArgs(argv, false);
if (options) {
options.stream = process.stdout;
options.parsing.filecontent = componentRawContent;
return parseComponentOptions(options);
}
return '';
}
async function prepareOutput(options) {
const stat = await lstat(options.output);
if (stat.isDirectory()) {
options.stream = (filename) => {
const info = parse(filename);
const mdname = `${info.name}.md`;
const dest = join(options.output, mdname);
return createWriteStream(dest);
};
}
else {
options.stream = createWriteStream(options.output);
}
return parseComponentOptions(options);
}
async function prepare(options, filenames) {
options.filenames = filenames;
if (options.output) {
return prepareOutput(options);
}
options.stream = process.stdout;
return parseComponentOptions(options);
}
export async function processWithOutputOption(options) {
const generatedDocs = await prepare(options, options.filenames);
await writeFile(options.output, JSON.stringify(generatedDocs, null, 2));
}
export async function processWithoutOutputOption(options) {
return prepare(options, options.filenames);
}
export async function exec(argv, componentRawContent = '') {
if (componentRawContent) {
await processRawContent(argv, componentRawContent);
}
else {
const options = await parseArgs(argv, true);
if (options) {
if (options.output) {
await processWithOutputOption(options);
}
else {
await processWithoutOutputOption(options);
}
}
}
}
export async function silenceExec(argv, componentRawContent = '') {
try {
await exec(argv, componentRawContent);
}
catch (err) {
process.stderr.write(`${err.message}\n`);
}
}
//# sourceMappingURL=CLI.js.map