core_plugin-interface.js

'use strict';

/**
 * @fileoverview Plugin validation and help formatting.
 * Validates plugin structure and generates CLI help output.
 * @module plugin-interface
 */

/** @type {Array<string>} */
const PLUGIN_TYPES = ['parser', 'adapter', 'provider'];

const checkName = p =>
  (!p.name || typeof p.name !== 'string') && 'Plugin must have a string "name"';
const checkType = p =>
  (!p.type || !PLUGIN_TYPES.includes(p.type)) &&
  `Plugin type must be one of: ${PLUGIN_TYPES.join(', ')}`;
const checkMeta = p => !p.meta?.description && 'Plugin must have meta.description';

function validateBasicFields(plugin) {
  return [checkName(plugin), checkType(plugin), checkMeta(plugin)].filter(Boolean);
}

function validateTypeSpecificMethods(plugin) {
  const methodErrors = {
    parser: () =>
      typeof plugin.extract !== 'function' &&
      'Parser plugins must have an extract(content, filePath, options) method',
    adapter: () =>
      typeof plugin.transform !== 'function' &&
      'Adapter plugins must have a transform(content, text, key, context) method',
    provider: () =>
      typeof plugin.translate !== 'function' &&
      typeof plugin.translateBatch !== 'function' &&
      'Provider plugins must have translate() or translateBatch() method',
  };
  const validator = methodErrors[plugin.type];
  return validator ? validator() : false;
}

/**
 * Validates a plugin has required fields and methods.
 * @param {Plugin} plugin
 * @returns {PluginValidation}
 */
function validatePlugin(plugin) {
  const errors = validateBasicFields(plugin);
  const typeError = validateTypeSpecificMethods(plugin);
  if (typeError) {
    errors.push(typeError);
  }
  return { valid: errors.length === 0, errors };
}

function formatPluginBasic(plugin) {
  const source = plugin.source || 'builtin';
  return [`  ${plugin.name} (${source})`, `    ${plugin.meta?.description || 'No description'}`];
}

function formatPluginOptions(plugin) {
  if (!plugin.options?.length) {
    return [];
  }
  return plugin.options.map(opt => `    ${opt.flag.padEnd(20)} ${opt.description}`);
}

/**
 * Formats plugin information for CLI help output.
 * @param {Plugin} plugin
 * @returns {string}
 */
function formatPluginHelp(plugin) {
  const lines = formatPluginBasic(plugin);
  if (plugin.extensions?.length) {
    lines.push(`    Extensions: ${plugin.extensions.join(', ')}`);
  }
  lines.push(...formatPluginOptions(plugin));
  if (plugin.env?.length) {
    lines.push(`    Env: ${plugin.env.map(e => e.name).join(', ')}`);
  }
  return lines.join('\n');
}

module.exports = { validatePlugin, formatPluginHelp };