From: Vsevolod Stakhov Date: Mon, 17 Nov 2025 18:07:34 +0000 (+0000) Subject: [Minor] Migrate lua_mime.lua from tableshape to lua_shape X-Git-Tag: 3.14.1~11^2~40 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0529c7c98456502bfc21d1ee669bb48c4829632a;p=thirdparty%2Frspamd.git [Minor] Migrate lua_mime.lua from tableshape to lua_shape Replace tableshape with lua_shape in message_to_ucl_schema function: - Convert ts.shape to T.table - Convert :describe() to :doc({ summary = ... }) - Convert :is_optional() to :optional() - Convert ts.array_of to T.array - Convert ts.pattern to T.string({ pattern = ... }) - Convert ts.one_of to T.enum for simple value lists - Convert ts.integer/string/boolean to T.integer()/string()/boolean() Transforms nested schemas: headers_schema, part_schema, email_addr_schema, envelope_schema. No functional changes, luacheck passes. --- diff --git a/lualib/lua_mime.lua b/lualib/lua_mime.lua index bb72c64938..65f206ee4c 100644 --- a/lualib/lua_mime.lua +++ b/lualib/lua_mime.lua @@ -706,72 +706,72 @@ end -- Returns schema for a message to verify result/document fields --]] exports.message_to_ucl_schema = function() - local ts = require("tableshape").types + local T = require "lua_shape.core" local function headers_schema() - return ts.shape { - order = ts.integer:describe('Header order in a message'), - raw = ts.string:describe('Raw header value'):is_optional(), - empty_separator = ts.boolean:describe('Whether header has an empty separator'), - separator = ts.string:describe('Separator between a header and a value'), - decoded = ts.string:describe('Decoded value'):is_optional(), - value = ts.string:describe('Decoded value'):is_optional(), - name = ts.string:describe('Header name'), - tab_separated = ts.boolean:describe('Whether header has tab as a separator') - } + return T.table({ + order = T.integer():doc({ summary = 'Header order in a message' }), + raw = T.string():doc({ summary = 'Raw header value' }):optional(), + empty_separator = T.boolean():doc({ summary = 'Whether header has an empty separator' }), + separator = T.string():doc({ summary = 'Separator between a header and a value' }), + decoded = T.string():doc({ summary = 'Decoded value' }):optional(), + value = T.string():doc({ summary = 'Decoded value' }):optional(), + name = T.string():doc({ summary = 'Header name' }), + tab_separated = T.boolean():doc({ summary = 'Whether header has tab as a separator' }) + }) end local function part_schema() - return ts.shape { - content = ts.string:describe('Decoded content'):is_optional(), - multipart_boundary = ts.string:describe('Multipart service boundary'):is_optional(), - size = ts.integer:describe('Size of the part'), - type = ts.string:describe('Announced type'):is_optional(), - detected_type = ts.string:describe('Detected type'):is_optional(), - boundary = ts.string:describe('Eclosing boundary'):is_optional(), - filename = ts.string:describe('File name for attachments'):is_optional(), - headers = ts.array_of(headers_schema()):describe('Part headers'), - } + return T.table({ + content = T.string():doc({ summary = 'Decoded content' }):optional(), + multipart_boundary = T.string():doc({ summary = 'Multipart service boundary' }):optional(), + size = T.integer():doc({ summary = 'Size of the part' }), + type = T.string():doc({ summary = 'Announced type' }):optional(), + detected_type = T.string():doc({ summary = 'Detected type' }):optional(), + boundary = T.string():doc({ summary = 'Eclosing boundary' }):optional(), + filename = T.string():doc({ summary = 'File name for attachments' }):optional(), + headers = T.array(headers_schema()):doc({ summary = 'Part headers' }), + }) end local function email_addr_schema() - return ts.shape { - addr = ts.string:describe('Parsed address'):is_optional(), - raw = ts.string:describe('Raw address'), - flags = ts.shape { - valid = ts.boolean:describe('Valid address'):is_optional(), - ip = ts.boolean:describe('IP like address'):is_optional(), - braced = ts.boolean:describe('Have braces around address'):is_optional(), - quoted = ts.boolean:describe('Have quotes around address'):is_optional(), - empty = ts.boolean:describe('Empty address'):is_optional(), - backslash = ts.boolean:describe('Backslash in address'):is_optional(), - ['8bit'] = ts.boolean:describe('8 bit characters in address'):is_optional(), - }, - user = ts.string:describe('Parsed user part'):is_optional(), - name = ts.string:describe('Displayed name'):is_optional(), - domain = ts.string:describe('Parsed domain part'):is_optional(), - } + return T.table({ + addr = T.string():doc({ summary = 'Parsed address' }):optional(), + raw = T.string():doc({ summary = 'Raw address' }), + flags = T.table({ + valid = T.boolean():doc({ summary = 'Valid address' }):optional(), + ip = T.boolean():doc({ summary = 'IP like address' }):optional(), + braced = T.boolean():doc({ summary = 'Have braces around address' }):optional(), + quoted = T.boolean():doc({ summary = 'Have quotes around address' }):optional(), + empty = T.boolean():doc({ summary = 'Empty address' }):optional(), + backslash = T.boolean():doc({ summary = 'Backslash in address' }):optional(), + ['8bit'] = T.boolean():doc({ summary = '8 bit characters in address' }):optional(), + }), + user = T.string():doc({ summary = 'Parsed user part' }):optional(), + name = T.string():doc({ summary = 'Displayed name' }):optional(), + domain = T.string():doc({ summary = 'Parsed domain part' }):optional(), + }) end local function envelope_schema() - return ts.shape { - from_smtp = email_addr_schema():describe('SMTP from'):is_optional(), - recipients_smtp = ts.array_of(email_addr_schema()):describe('SMTP recipients'):is_optional(), - helo = ts.string:describe('SMTP Helo'):is_optional(), - hostname = ts.string:describe('Sender hostname'):is_optional(), - client_ip = ts.string:describe('Client ip'):is_optional(), - from_ip = ts.string:describe('Sender ip'):is_optional(), - } + return T.table({ + from_smtp = email_addr_schema():doc({ summary = 'SMTP from' }):optional(), + recipients_smtp = T.array(email_addr_schema()):doc({ summary = 'SMTP recipients' }):optional(), + helo = T.string():doc({ summary = 'SMTP Helo' }):optional(), + hostname = T.string():doc({ summary = 'Sender hostname' }):optional(), + client_ip = T.string():doc({ summary = 'Client ip' }):optional(), + from_ip = T.string():doc({ summary = 'Sender ip' }):optional(), + }) end - return ts.shape { - headers = ts.array_of(headers_schema()), - parts = ts.array_of(part_schema()), - digest = ts.pattern(string.format('^%s$', string.rep('%x', 32))) - :describe('Message digest'), - newlines = ts.one_of({ "cr", "lf", "crlf" }):describe('Newlines type'), - size = ts.integer:describe('Size of the message in bytes'), + return T.table({ + headers = T.array(headers_schema()), + parts = T.array(part_schema()), + digest = T.string({ pattern = string.format('^%s$', string.rep('%x', 32)) }) + :doc({ summary = 'Message digest' }), + newlines = T.enum({ "cr", "lf", "crlf" }):doc({ summary = 'Newlines type' }), + size = T.integer():doc({ summary = 'Size of the message in bytes' }), envelope = envelope_schema() - } + }) end --[[[