feat(jsdoc-cli): move loadConfig() to Engine

This commit is contained in:
Jeff Williams 2024-01-07 20:18:03 -08:00
parent 46438fbfb5
commit 7fef4d303c
No known key found for this signature in database
3 changed files with 102 additions and 30 deletions

View File

@ -15,7 +15,7 @@
*/
/* eslint-disable no-process-exit */
import { Api } from '@jsdoc/core';
import { Api, config as jsdocConfig } from '@jsdoc/core';
import { getLogFunctions } from '@jsdoc/util';
import _ from 'lodash';
import ow from 'ow';
@ -37,6 +37,9 @@ function validateChoice(flagInfo, choices, values) {
}
}
const FATAL_ERROR_MESSAGE =
'Exiting JSDoc because an error occurred. See the previous log messages for details.';
/**
* `KNOWN_FLAGS` is a set of all known flag names, including the long and short forms.
*
@ -225,6 +228,7 @@ export default class Engine {
return `Options:\n${help({ maxLength })}\n\nVisit https://jsdoc.app/ for more information.`;
}
// TODO: Add a typedef for this.
/**
* Details about the command-line flags that JSDoc recognizes.
*/
@ -232,6 +236,40 @@ export default class Engine {
return flags;
}
// TODO: Add details about the directory and filenames that this method looks for.
/**
* Parses command-line flags; loads the JSDoc configuration file; and adds configuration details
* to the JSDoc environment.
*
* For details about supported command-line flags, see the value of the
* {@link module:@jsdoc/cli#knownFlags} property.
*
* @returns {Promise<undefined>} A promise that is fulfilled after the configuration is loaded.
*/
loadConfig() {
const { env } = this;
try {
env.opts = _.defaults({}, this.parseFlags(env.args), env.opts);
} catch (e) {
this.shouldPrintHelp = true;
this.exit(1, `${e.message}\n`);
return Promise.reject(e);
}
return jsdocConfig.load(env.opts.configure).then(
(conf) => {
env.conf = conf.config;
// Look for options on the command line, then in the config.
env.opts = _.defaults(env.opts, env.conf.opts);
},
(e) => {
this.exit(1, `Cannot parse the config file: ${e}\n${FATAL_ERROR_MESSAGE}`);
}
);
}
/**
* The log level to use. Messages are logged only if they are at or above this level.
* Must be an enumerated value of {@link module:@jsdoc/cli.LOG_LEVELS}.

View File

@ -14,7 +14,10 @@
limitations under the License.
*/
/* global jsdoc */
import EventEmitter from 'node:events';
import path from 'node:path';
import Engine from '../../../lib/engine.js';
import flags from '../../../lib/flags.js';
@ -265,6 +268,61 @@ describe('@jsdoc/cli/lib/engine', () => {
});
});
describe('loadConfig', () => {
const configPath = path.resolve(
path.join(jsdoc.dirname(import.meta.url), '../../fixtures/configs/conf.json')
);
let instance;
beforeEach(() => {
instance = new Engine();
instance.env.options.configure = configPath;
});
it('parses the command-line flags', async () => {
instance.env.args = ['-p', '-v'];
await instance.loadConfig();
expect(instance.env.options.private).toBeTrue();
expect(instance.env.options.version).toBeTrue();
});
it('exits if the command-line flags cannot be parsed', async () => {
instance.env.args = ['--not-a-real-flag'];
spyOn(instance, 'exit');
try {
await instance.loadConfig();
// We shouldn't get here.
expect(false).toBeTrue();
} catch (e) {
// Expected exit code.
expect(instance.exit.calls.argsFor(0)[0]).toBe(1);
// Expected error message.
expect(instance.exit.calls.argsFor(0)[1]).toContain(
'Unknown command-line option: --not-a-real-flag'
);
}
});
it('adds the config info to the JSDoc environment', async () => {
await instance.loadConfig();
expect(instance.env.config.sourceType).toBe('script');
});
it('merges the command-line flags from the config file with the real flags', async () => {
instance.env.args = ['-p'];
await instance.loadConfig();
expect(instance.env.options.private).toBeTrue();
expect(instance.env.options.version).toBeTrue();
});
});
describe('LOG_LEVELS', () => {
it('is lib/logger.LEVELS', () => {
expect(Engine.LOG_LEVELS).toBe(LEVELS);

View File

@ -20,11 +20,10 @@ import { readFile } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import Engine from '@jsdoc/cli';
import { config as jsdocConfig, plugins } from '@jsdoc/core';
import { plugins } from '@jsdoc/core';
import { augment, Package, resolveBorrows } from '@jsdoc/doclet';
import { createParser, handlers } from '@jsdoc/parse';
import { Dictionary } from '@jsdoc/tag';
import _ from 'lodash';
import stripBom from 'strip-bom';
import stripJsonComments from 'strip-json-comments';
@ -47,8 +46,6 @@ export default (() => {
const cli = {};
const engine = new Engine();
const { api, env, log } = engine;
const FATAL_ERROR_MESSAGE =
'Exiting JSDoc because an error occurred. See the previous log messages for details.';
// TODO: docs
cli.setVersionInfo = () => {
@ -69,31 +66,7 @@ export default (() => {
};
// TODO: docs
cli.loadConfig = async () => {
try {
env.opts = engine.parseFlags(env.args);
} catch (e) {
engine.shouldPrintHelp = true;
engine.exit(1, `${e.message}\n`);
return cli;
}
try {
// eslint-disable-next-line require-atomic-updates
env.conf = (await jsdocConfig.load(env.opts.configure)).config;
} catch (e) {
engine.exit(1, `Cannot parse the config file: ${e}\n${FATAL_ERROR_MESSAGE}`);
return cli;
}
// Look for options on the command line, then in the config.
env.opts = _.defaults(env.opts, env.conf.opts);
env.tags = Dictionary.fromConfig(env);
return cli;
};
cli.loadConfig = () => engine.loadConfig();
// TODO: docs
cli.configureLogger = () => {
@ -130,6 +103,9 @@ export default (() => {
let cmd;
const { options } = env;
// TODO: Move to `Api`.
env.tags = Dictionary.fromConfig(env);
// If we already need to exit with an error, don't do any more work.
if (engine.shouldExitWithError) {
cmd = () => Promise.resolve(0);