HEX
Server: Apache/2
System: Linux nexus-01 4.18.0-553.120.1.el8_10.x86_64 #1 SMP Mon Apr 20 18:04:27 EDT 2026 x86_64
User: aglcoke (1118)
PHP: 8.2.31
Disabled: mail,exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
Upload Files
File: //usr/share/rspamd/lualib/rspamadm/confighelp_plugins.lua
--[[
Copyright (c) 2025, Vsevolod Stakhov <vsevolod@rspamd.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
]]--

-- Convert plugin schemas to UCL format for confighelp

local function convert_schema(node)
  if not node then return {} end

  local res = {}
  if node.summary then res.data = node.summary end
  if node.description and not res.data then res.data = node.description end
  if node.examples and node.examples[1] then res.example = node.examples[1] end
  if node.default ~= nil then res.default = node.default end
  if node.optional ~= nil then res.required = not node.optional end

  if node.type == 'scalar' then
    res.type = node.kind or 'string'
  elseif node.type == 'table' then
    res.type = 'object'
  else
    res.type = node.type
  end

  if node.type == 'table' then
    local mixins = {}
    local mixin_field_names = {}
    for _, group in ipairs(node.mixin_groups or {}) do
      local entry = { name = group.mixin_name or group.schema_id, schema_id = group.schema_id }
      table.insert(mixins, entry)
      for _, mixin_field in ipairs(group.fields or {}) do
        mixin_field_names[mixin_field.name] = true
      end
    end
    if #mixins > 0 then res.mixins = mixins end

    for _, field in ipairs(node.fields or {}) do
      if not mixin_field_names[field.name] then
        local child = convert_schema(field.schema)
        child.required = not field.optional
        if field.schema and field.schema.summary and not child.data then
          child.data = field.schema.summary
        end
        res[field.name] = child
      end
    end

    if node.extra_schema then
      local extra_child = convert_schema(node.extra_schema)
      if not extra_child.data then extra_child.data = 'Entry schema' end
      res['entry'] = extra_child
    end

  elseif node.type == 'array' and node.item_schema then
    res.item = convert_schema(node.item_schema)

  elseif node.type == 'one_of' then
    local variants = {}
    local common_fields = {}
    local idx = 1

    -- Extract fields common to all variants
    local first_variant_fields = nil
    local all_have_common = true
    for _, variant in ipairs(node.variants or {}) do
      if variant.type == 'table' and variant.fields then
        local field_map = {}
        for _, field in ipairs(variant.fields) do
          field_map[field.name] = field
        end
        if first_variant_fields == nil then
          first_variant_fields = field_map
        else
          -- Check which fields are common
          for fname, _ in pairs(first_variant_fields) do
            if not field_map[fname] then
              first_variant_fields[fname] = nil
            end
          end
        end
      else
        all_have_common = false
      end
    end

    -- Convert common fields
    if first_variant_fields and all_have_common then
      for fname, field in pairs(first_variant_fields) do
        local child = convert_schema(field.schema)
        child.required = not field.optional
        if field.schema and field.schema.summary and not child.data then
          child.data = field.schema.summary
        end
        common_fields[fname] = true
        res[fname] = child
      end
    end

    -- Convert variants, excluding common fields
    for _, variant in ipairs(node.variants or {}) do
      local vname = variant.name or ('variant_' .. tostring(idx))
      local converted_variant = convert_schema(variant)

      -- Remove common fields from variant
      for fname, _ in pairs(common_fields) do
        converted_variant[fname] = nil
      end

      variants[vname] = converted_variant
      idx = idx + 1
    end
    res.options = variants
  end

  return res
end

return function()
  local Registry = require 'lua_shape.registry'
  local docs = require 'lua_shape.docs'
  local ucl = require 'ucl'

  local reg = Registry.global()
  if not reg then return nil end

  local exported = docs.for_registry(reg)
  if not exported or not exported.schemas then return nil end

  local converted = {}
  for id, schema in pairs(exported.schemas) do
    converted[id] = convert_schema(schema)
  end

  return ucl.to_format({ schemas = converted }, 'json-compact')
end