teal-src/util/xtemplate.tl
author Kim Alvefur <zash@zash.se>
Sun, 27 Aug 2023 15:46:19 +0200
branch0.12
changeset 13258 a2ba3f06dcf4
parent 12217 dc9d63166488
permissions -rw-r--r--
util.prosodyctl.check: Correct modern replacement for 'disallow_s2s' The code would have suggested adding to modules_enabled instead of modules_disabled
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
12217
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     1
-- render(template, stanza) --> string
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     2
-- {path} --> stanza:find(path)
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     3
-- {{ns}name/child|each({ns}name){sub-template}}
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     4
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     5
--[[
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     6
template ::= "{" path ("|" name ("(" args ")")? (template)? )* "}"
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     7
path ::= defined by util.stanza
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     8
name ::= %w+
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     9
args ::= anything with balanced ( ) pairs
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    10
]]
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    11
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    12
local s_gsub = string.gsub;
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    13
local s_match = string.match;
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    14
local s_sub = string.sub;
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    15
local t_concat = table.concat;
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    16
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    17
local st = require "util.stanza";
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    18
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    19
local type escape_t = function (string) : string
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    20
local type filter_t = function (string, string | st.stanza_t, string) : string | st.stanza_t, boolean
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    21
local type filter_coll = { string : filter_t }
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    22
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    23
local function render(template : string, root : st.stanza_t, escape : escape_t, filters : filter_coll) : string
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    24
	escape = escape or st.xml_escape;
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    25
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    26
	return (s_gsub(template, "%b{}", function(block : string) : string
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    27
		local inner = s_sub(block, 2, -2);
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    28
		local path, pipe, pos = s_match(inner, "^([^|]+)(|?)()");
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    29
		if not path is string then return end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    30
		local value : string | st.stanza_t
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    31
		if path == "." then
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    32
			value = root;
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    33
		elseif path == "#" then
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    34
			value = root:get_text();
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    35
		else
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    36
			value = root:find(path);
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    37
		end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    38
		local is_escaped = false;
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    39
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    40
		while pipe == "|" do
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    41
			local func, args, tmpl, p = s_match(inner, "^(%w+)(%b())(%b{})()", pos as integer);
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    42
			if not func then func, args, p = s_match(inner, "^(%w+)(%b())()", pos as integer); end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    43
			if not func then func, tmpl, p = s_match(inner, "^(%w+)(%b{})()", pos as integer); end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    44
			if not func then func, p = s_match(inner, "^(%w+)()", pos as integer); end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    45
			if not func then break end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    46
			if tmpl then tmpl = s_sub(tmpl, 2, -2); end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    47
			if args then args = s_sub(args, 2, -2); end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    48
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    49
			if func == "each" and tmpl and st.is_stanza(value) then
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    50
				if not args then value, args = root, path; end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    51
				local ns, name = s_match(args, "^(%b{})(.*)$");
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    52
				if ns then ns = s_sub(ns, 2, -2); else name, ns = args, nil; end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    53
				if ns == "" then ns = nil; end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    54
				if name == "" then name = nil; end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    55
				local out, i = {}, 1;
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    56
				for c in (value as st.stanza_t):childtags(name, ns) do
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    57
					out[i], i = render(tmpl, c, escape, filters), i + 1;
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    58
				end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    59
				value = t_concat(out);
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    60
				is_escaped = true;
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    61
			elseif func == "and" and tmpl then
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    62
				local condition = value;
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    63
				if args then condition = root:find(args); end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    64
				if condition then
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    65
					value = render(tmpl, root, escape, filters);
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    66
					is_escaped = true;
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    67
				end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    68
			elseif func == "or" and tmpl then
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    69
				local condition = value;
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    70
				if args then condition = root:find(args); end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    71
				if not condition then
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    72
					value = render(tmpl, root, escape, filters);
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    73
					is_escaped = true;
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    74
				end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    75
			elseif filters and filters[func] then
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    76
				local f = filters[func];
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    77
				if args == nil then
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    78
					value, is_escaped = f(value, tmpl);
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    79
				else
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    80
					value, is_escaped = f(args, value, tmpl);
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    81
				end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    82
			else
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    83
				error("No such filter function: " .. func);
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    84
			end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    85
			pipe, pos = s_match(inner, "^(|?)()", p as integer);
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    86
		end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    87
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    88
		if value is string then
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    89
			if not is_escaped then value = escape(value); end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    90
			return value;
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    91
		elseif st.is_stanza(value) then
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    92
			value = value:get_text();
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    93
			if value then
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    94
				return escape(value);
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    95
			end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    96
		end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    97
		return "";
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    98
	end));
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    99
end
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   100
dc9d63166488 util.xtemplate: Yet another string template library
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   101
return { render = render };