UNPKG

@knodes/typedoc-pluginutils

Version:
180 lines 7.17 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.OptionGroup = void 0; const assert_1 = __importDefault(require("assert")); const fastest_levenshtein_1 = require("fastest-levenshtein"); const lodash_1 = require("lodash"); const typedoc_1 = require("typedoc"); const path_1 = require("@knodes/typedoc-pluginutils/path"); const option_1 = require("./option"); const events_extra_1 = require("../events-extra"); class OptionGroup { /** * Generate a type-helper factory to constraint the option to be of the given {@link T2 type}. * * TODO: change signature once https://github.com/microsoft/TypeScript/pull/26349 is merged. * * @param plugin - The plugin declaring the option. * @returns a builder to use in order to generate the full option group. */ static factory(plugin) { return this._build(plugin, {}, {}); } /** * Create the actual option builder. * * @param plugin - The plugin declaring the option. * @param decs - The declarations so far. * @param mappers - The mappers so far. * @returns the builder to chain. */ static _build(plugin, decs, mappers) { return { add: (name, dec, ...[mapper]) => OptionGroup._build(plugin, Object.assign(Object.assign({}, decs), { [name]: Object.assign(Object.assign({}, dec), { name }) }), Object.assign(Object.assign({}, mappers), { [name]: mapper !== null && mapper !== void 0 ? mapper : lodash_1.identity })), build: () => new OptionGroup(plugin, decs, mappers), }; } get _rootOption() { const linkAppendix = 'documentation' in this.plugin.package ? ` See \u001b[96m${this.plugin.package.documentation}\u001b[0m for more informations.` : // Cyan ''; return { name: this.plugin.optionsPrefix, type: typedoc_1.ParameterType.Mixed, help: `[${this.plugin.package.name}]: Set all plugin options below as an object, a JSON string or from a file.${linkAppendix}`, }; } constructor(plugin, optionDeclarations, mappers) { this.plugin = plugin; this._options = Object.fromEntries(Object.entries(optionDeclarations) .map(([k, v]) => { (0, assert_1.default)(k !== 'options'); const fullDec = Object.assign(Object.assign({}, v), { name: k }); const opt = new option_1.Option(plugin, this, fullDec, mappers[k]); return [k, opt]; })); this.plugin.application.options.addDeclaration(this._rootOption); events_extra_1.EventsExtra.for(this.plugin.application) .beforeOptionsFreeze(this._onBeforeOptionsFreeze.bind(this)); } /** * Get the mapped values. * * @returns the group values. */ getValue() { return this._mapOptions((k, o) => o.getValue()); } setValue(...args) { if (args.length === 2) { const [key, value] = args; return this._setValue({ [key]: value }); } try { this._setValue(args[0]); } catch (e) { if (e.code !== 'MODULE_NOT_FOUND') { throw e; } this.plugin.logger.error(`Config file ${args[0]} not found`); } } /** * Set the raw values. * * @param value - The value to set. Paths, JSON & partial options are authorized. * @returns nothing. */ _setValue(value) { if (typeof value === 'object') { return this._setValueFromObject(value); } else if (value.startsWith('{') && value.endsWith('}')) { const parsedValue = JSON.parse(value); this._setValue(parsedValue); } else { this._setValueFromFile(value); } } /** * Set the raw values from a POJO. * * @param value - The values to set as object. */ _setValueFromObject(value) { const valKeys = Object.keys(value); const optKeys = Object.keys(this._options); for (const unknownOption of (0, lodash_1.difference)(valKeys, optKeys)) { this.plugin.logger.warn(`Unknown option "${unknownOption}". Did you mean "${(0, fastest_levenshtein_1.closest)(unknownOption, optKeys)}" ?`); } const newOpts = this._mapOptions((k, o) => { var _a; if (k in value) { try { o.setValue(value[k]); } catch (err) { throw new Error(`Could not set option "${o.fullName}": ${(_a = err.message) !== null && _a !== void 0 ? _a : err}`, { cause: err }); } } return o.getValue(); }); this.plugin.application.options.setValue(this.plugin.optionsPrefix, newOpts); } /** * Load the given file as being the full plugin options. * * @param filename - The file containing options. Any `require`able file can be provided. */ _setValueFromFile(filename) { const [filePath, objPath, ...left] = filename.split('#'); (0, assert_1.default)(left.length === 0); this.plugin.logger.verbose(`Reading config file @ ${filePath}`); const optsDirFile = this.plugin.application.options.getValue('options'); const resolved = require.resolve(filePath, { paths: [process.cwd(), optsDirFile, (0, path_1.dirname)(optsDirFile)] }); // eslint-disable-next-line @typescript-eslint/no-var-requires -- Rely in node require const result = require(resolved); if (objPath) { this._setValue((0, lodash_1.get)(result, objPath)); } else { this._setValue(result); } } /** * Try loading different options sources, and update plugin options with default values if not set. */ _onBeforeOptionsFreeze() { const defaultOpts = this.getValue(); // Try read default files const generalOpts = this.plugin.application.options.getValue(this.plugin.optionsPrefix); if (generalOpts) { this._setValue(generalOpts); } else { try { this._setValueFromFile(`./typedoc-${(0, lodash_1.kebabCase)(this.plugin.optionsPrefix)}`); // eslint-disable-next-line no-empty -- No-op error } catch (_err) { } } this.setValue((0, lodash_1.defaultsDeep)(this.getValue(), defaultOpts)); } /** * Execute a {@link cb callback} on each declared options, & return an object containing the resulting values. * * @param cb - The function to execute on each option. Called with the key & the {@link Option}. * @returns the mapped values. */ _mapOptions(cb) { return Object.fromEntries(Object.entries(this._options) .map(([k, v]) => [k, cb(k, v)])); } } exports.OptionGroup = OptionGroup; //# sourceMappingURL=option-group.js.map