UNPKG

myst-parser

Version:
91 lines (90 loc) 3.82 kB
import { fileError, fileWarn, RuleId } from 'myst-common'; import { contentFromNode } from './utils.js'; export function parseOptions(name, node, vfile, optionsSpec) { var _a, _b; let validationError = false; // Handle options const options = {}; // Only look to the direct children here (i.e. for nested roles) const optionNodes = (_b = (_a = node.children) === null || _a === void 0 ? void 0 : _a.filter((c) => c.type === 'mystOption')) !== null && _b !== void 0 ? _b : []; const optionNodeLookup = {}; optionNodes.forEach((optionNode) => { if (optionNode.name === 'id' && optionNode.location === 'inline') { // The ID maps to the label optionNodeLookup.label = optionNode; return; } if (optionNode.name === 'class') { if (optionNodeLookup.class) { // Combine the option class nodes // Note: This results in an position error for additional classes // For example, pointing to a warning will always be the first class. // That is fine for now. optionNodeLookup.class.value += ` ${optionNode.value}`; } else { optionNodeLookup.class = optionNode; } return; } if (optionNodeLookup[optionNode.name]) { fileWarn(vfile, `duplicate option "${optionNode.name}" declared (in ${name})`, { node: optionNode, ruleId: RuleId.directiveOptionsCorrect, }); } else { optionNodeLookup[optionNode.name] = optionNode; } }); // Deal with each option in the spec Object.entries(optionsSpec || {}).forEach(([optionName, optionSpec]) => { var _a; let optionNameUsed = optionName; let optionNode = optionNodeLookup[optionName]; // Replace alias options or warn on duplicates (_a = optionSpec.alias) === null || _a === void 0 ? void 0 : _a.forEach((alias) => { const aliasNode = optionNodeLookup[alias]; if (!aliasNode) return; if (!optionNode && aliasNode) { optionNode = aliasNode; optionNameUsed = alias; optionNodeLookup[optionName] = optionNode; } else { fileWarn(vfile, `option "${optionNameUsed}" used instead of "${alias}" (in ${name})`, { node, ruleId: RuleId.directiveOptionsCorrect, }); } delete optionNodeLookup[alias]; }); if (optionSpec.required && !optionNode) { fileError(vfile, `required option "${optionName}" not provided (in ${name})`, { node, ruleId: RuleId.directiveOptionsCorrect, }); node.type = 'mystDirectiveError'; delete node.children; validationError = true; } else if (optionNode) { const content = contentFromNode(optionNode, optionSpec, vfile, `option "${optionName}" (in ${name})`, RuleId.directiveOptionsCorrect); if (content != null) { options[optionName] = content; } else if (optionSpec.required) { validationError = true; } delete optionNodeLookup[optionName]; } }); Object.values(optionNodeLookup).forEach((optionNode) => { fileWarn(vfile, `unexpected option "${optionNode.name}" provided (in ${name})`, { node: optionNode, ruleId: RuleId.directiveOptionsCorrect, }); }); return { valid: validationError, options: Object.keys(options).length ? options : undefined }; }