update: lorem
This commit is contained in:
parent
14e307f3dc
commit
24ecea0244
4 changed files with 853 additions and 201 deletions
338
src/lorem.zig
Normal file
338
src/lorem.zig
Normal file
|
|
@ -0,0 +1,338 @@
|
|||
const std = @import("std");
|
||||
const rand = std.crypto.random;
|
||||
|
||||
pub const LOREM_COMMON_P =
|
||||
\\Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||
\\tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
||||
\\veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
||||
\\commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
|
||||
\\velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
|
||||
\\occaecat cupidatat non proident, sunt in culpa qui officia deserunt
|
||||
\\mollit anim id est laborum.
|
||||
;
|
||||
|
||||
pub const LOREM_WORDS = [182][]const u8{
|
||||
"exercitationem",
|
||||
"perferendis",
|
||||
"perspiciatis",
|
||||
"laborum",
|
||||
"eveniet",
|
||||
"sunt",
|
||||
"iure",
|
||||
"nam",
|
||||
"nobis",
|
||||
"eum",
|
||||
"cum",
|
||||
"officiis",
|
||||
"excepturi",
|
||||
"odio",
|
||||
"consectetur",
|
||||
"quasi",
|
||||
"aut",
|
||||
"quisquam",
|
||||
"vel",
|
||||
"eligendi",
|
||||
"itaque",
|
||||
"non",
|
||||
"odit",
|
||||
"tempore",
|
||||
"quaerat",
|
||||
"dignissimos",
|
||||
"facilis",
|
||||
"neque",
|
||||
"nihil",
|
||||
"expedita",
|
||||
"vitae",
|
||||
"vero",
|
||||
"ipsum",
|
||||
"nisi",
|
||||
"animi",
|
||||
"cumque",
|
||||
"pariatur",
|
||||
"velit",
|
||||
"modi",
|
||||
"natus",
|
||||
"iusto",
|
||||
"eaque",
|
||||
"sequi",
|
||||
"illo",
|
||||
"sed",
|
||||
"ex",
|
||||
"et",
|
||||
"voluptatibus",
|
||||
"tempora",
|
||||
"veritatis",
|
||||
"ratione",
|
||||
"assumenda",
|
||||
"incidunt",
|
||||
"nostrum",
|
||||
"placeat",
|
||||
"aliquid",
|
||||
"fuga",
|
||||
"provident",
|
||||
"praesentium",
|
||||
"rem",
|
||||
"necessitatibus",
|
||||
"suscipit",
|
||||
"adipisci",
|
||||
"quidem",
|
||||
"possimus",
|
||||
"voluptas",
|
||||
"debitis",
|
||||
"sint",
|
||||
"accusantium",
|
||||
"unde",
|
||||
"sapiente",
|
||||
"voluptate",
|
||||
"qui",
|
||||
"aspernatur",
|
||||
"laudantium",
|
||||
"soluta",
|
||||
"amet",
|
||||
"quo",
|
||||
"aliquam",
|
||||
"saepe",
|
||||
"culpa",
|
||||
"libero",
|
||||
"ipsa",
|
||||
"dicta",
|
||||
"reiciendis",
|
||||
"nesciunt",
|
||||
"doloribus",
|
||||
"autem",
|
||||
"impedit",
|
||||
"minima",
|
||||
"maiores",
|
||||
"repudiandae",
|
||||
"ipsam",
|
||||
"obcaecati",
|
||||
"ullam",
|
||||
"enim",
|
||||
"totam",
|
||||
"delectus",
|
||||
"ducimus",
|
||||
"quis",
|
||||
"voluptates",
|
||||
"dolores",
|
||||
"molestiae",
|
||||
"harum",
|
||||
"dolorem",
|
||||
"quia",
|
||||
"voluptatem",
|
||||
"molestias",
|
||||
"magni",
|
||||
"distinctio",
|
||||
"omnis",
|
||||
"illum",
|
||||
"dolorum",
|
||||
"voluptatum",
|
||||
"ea",
|
||||
"quas",
|
||||
"quam",
|
||||
"corporis",
|
||||
"quae",
|
||||
"blanditiis",
|
||||
"atque",
|
||||
"deserunt",
|
||||
"laboriosam",
|
||||
"earum",
|
||||
"consequuntur",
|
||||
"hic",
|
||||
"cupiditate",
|
||||
"quibusdam",
|
||||
"accusamus",
|
||||
"ut",
|
||||
"rerum",
|
||||
"error",
|
||||
"minus",
|
||||
"eius",
|
||||
"ab",
|
||||
"ad",
|
||||
"nemo",
|
||||
"fugit",
|
||||
"officia",
|
||||
"at",
|
||||
"in",
|
||||
"id",
|
||||
"quos",
|
||||
"reprehenderit",
|
||||
"numquam",
|
||||
"iste",
|
||||
"fugiat",
|
||||
"sit",
|
||||
"inventore",
|
||||
"beatae",
|
||||
"repellendus",
|
||||
"magnam",
|
||||
"recusandae",
|
||||
"quod",
|
||||
"explicabo",
|
||||
"doloremque",
|
||||
"aperiam",
|
||||
"consequatur",
|
||||
"asperiores",
|
||||
"commodi",
|
||||
"optio",
|
||||
"dolor",
|
||||
"labore",
|
||||
"temporibus",
|
||||
"repellat",
|
||||
"veniam",
|
||||
"architecto",
|
||||
"est",
|
||||
"esse",
|
||||
"mollitia",
|
||||
"nulla",
|
||||
"a",
|
||||
"similique",
|
||||
"eos",
|
||||
"alias",
|
||||
"dolore",
|
||||
"tenetur",
|
||||
"deleniti",
|
||||
"porro",
|
||||
"facere",
|
||||
"maxime",
|
||||
"corrupti",
|
||||
};
|
||||
|
||||
pub const LOREM_COMMON_WORDS = [19][]const u8{
|
||||
"lorem",
|
||||
"ipsum",
|
||||
"dolor",
|
||||
"sit",
|
||||
"amet",
|
||||
"consectetur",
|
||||
"adipisicing",
|
||||
"elit",
|
||||
"sed",
|
||||
"do",
|
||||
"eiusmod",
|
||||
"tempor",
|
||||
"incididunt",
|
||||
"ut",
|
||||
"labore",
|
||||
"et",
|
||||
"dolore",
|
||||
"magna",
|
||||
"aliqua",
|
||||
};
|
||||
|
||||
pub fn sentence(allocator: std.mem.Allocator) ![]const u8 {
|
||||
const num_sections = rand.intRangeAtMost(u32, 1, 4);
|
||||
|
||||
var parts = std.ArrayList([]u8){};
|
||||
defer {
|
||||
for (parts.items) |p| allocator.free(p);
|
||||
parts.deinit(allocator);
|
||||
}
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < num_sections) : (i += 1) {
|
||||
const num_words = rand.intRangeAtMost(u32, 3, 12);
|
||||
|
||||
var wds = std.ArrayList([]const u8){};
|
||||
defer wds.deinit(allocator);
|
||||
try wds.ensureTotalCapacity(allocator, num_words);
|
||||
|
||||
var j: u32 = 0;
|
||||
while (j < num_words) : (j += 1) {
|
||||
const idx = rand.intRangeAtMost(usize, 0, LOREM_WORDS.len - 1);
|
||||
try wds.append(allocator, LOREM_WORDS[idx]);
|
||||
}
|
||||
|
||||
const section = try std.mem.join(allocator, " ", wds.items);
|
||||
try parts.append(allocator, section);
|
||||
}
|
||||
|
||||
const text = try std.mem.join(allocator, ", ", parts.items);
|
||||
defer allocator.free(text);
|
||||
|
||||
var result = try allocator.alloc(u8, text.len + 1);
|
||||
if (text.len > 0) {
|
||||
result[0] = std.ascii.toUpper(text[0]);
|
||||
@memcpy(result[1..text.len], text[1..]);
|
||||
}
|
||||
result[text.len] = if (rand.boolean()) '.' else '?';
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn paragraph(allocator: std.mem.Allocator) ![]const u8 {
|
||||
const num_sentences = rand.intRangeAtMost(u32, 1, 4);
|
||||
var sentences = std.ArrayList([]const u8){};
|
||||
defer sentences.deinit(allocator);
|
||||
|
||||
for (0..num_sentences) |_| {
|
||||
try sentences.append(allocator, try sentence(allocator));
|
||||
}
|
||||
|
||||
return try std.mem.join(allocator, ". ", sentences.items);
|
||||
}
|
||||
|
||||
pub fn paragraphs(allocator: std.mem.Allocator, count: u32, random: bool) ![]const u8 {
|
||||
var pa = std.ArrayList([]const u8){};
|
||||
defer pa.deinit(allocator);
|
||||
|
||||
if (count == 0) return "";
|
||||
|
||||
if (random == true) {
|
||||
for (0..count) |_| {
|
||||
const pg = try paragraph(allocator);
|
||||
if (pg.len > 0) {
|
||||
try pa.append(allocator, try std.fmt.allocPrint(allocator, "<p>{s}</p>", .{pg}));
|
||||
}
|
||||
}
|
||||
|
||||
return try std.mem.join(allocator, "\n", pa.items);
|
||||
}
|
||||
|
||||
const first = try std.fmt.allocPrint(allocator, "<p>{s}</p>", .{LOREM_COMMON_P});
|
||||
if (count == 1) {
|
||||
return first;
|
||||
}
|
||||
|
||||
const ncount: u32 = count - 1;
|
||||
try pa.append(allocator, first);
|
||||
|
||||
for (0..ncount) |_| {
|
||||
const pg = try paragraph(allocator);
|
||||
if (pg.len > 0) {
|
||||
try pa.append(allocator, try std.fmt.allocPrint(allocator, "<p>{s}</p>", .{pg}));
|
||||
}
|
||||
}
|
||||
|
||||
return try std.mem.join(allocator, "\n", pa.items);
|
||||
}
|
||||
|
||||
pub fn words(allocator: std.mem.Allocator, count: u32, random: bool) ![]const u8 {
|
||||
var wd = std.ArrayList([]const u8){};
|
||||
defer wd.deinit(allocator);
|
||||
|
||||
if (random == true) {
|
||||
for (0..count) |_| {
|
||||
const idx = rand.intRangeAtMost(usize, 0, LOREM_COMMON_WORDS.len - 1);
|
||||
try wd.append(allocator, LOREM_COMMON_WORDS[idx]);
|
||||
}
|
||||
return try std.mem.join(allocator, " ", wd.items);
|
||||
}
|
||||
|
||||
var inc: u32 = 0;
|
||||
|
||||
for (LOREM_COMMON_WORDS) |word| {
|
||||
try wd.append(allocator, word);
|
||||
inc += 1;
|
||||
if (inc >= count or inc >= 20) break;
|
||||
}
|
||||
|
||||
if (count >= 20) {
|
||||
const ncount = count - inc;
|
||||
|
||||
for (0..ncount) |_| {
|
||||
const idx = rand.intRangeAtMost(usize, 0, LOREM_COMMON_WORDS.len - 1);
|
||||
try wd.append(allocator, LOREM_COMMON_WORDS[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
return try std.mem.join(allocator, " ", wd.items);
|
||||
}
|
||||
|
|
@ -202,6 +202,7 @@ pub const FilterBlockNode = struct {
|
|||
|
||||
pub const FirstOfNode = struct {
|
||||
values: []const []const u8,
|
||||
fallback: []const u8,
|
||||
};
|
||||
|
||||
pub const ForNode = struct {
|
||||
|
|
@ -232,7 +233,7 @@ pub const LoadNode = struct {
|
|||
pub const LoremNode = struct {
|
||||
count: ?[]const u8 = null, // "3" ou null
|
||||
method: ?[]const u8 = null, // "p" ou "w" ou null
|
||||
format: ?[]const u8 = null, // "html" ou null
|
||||
random: bool = false,
|
||||
};
|
||||
|
||||
pub const NowNode = struct {
|
||||
|
|
@ -450,10 +451,12 @@ pub const Node = struct {
|
|||
values_copy[i] = try allocator.dupe(u8, f);
|
||||
}
|
||||
|
||||
const fallback_copy = try allocator.dupe(u8, self.tag.?.body.firstof.fallback);
|
||||
|
||||
return Node{ .type = .tag, .tag = .{
|
||||
.kind = .firstof,
|
||||
.args = try allocator.dupe(u8, self.tag.?.args),
|
||||
.body = .{ .firstof = .{ .values = values_copy } },
|
||||
.body = .{ .firstof = .{ .values = values_copy, .fallback = fallback_copy } },
|
||||
.raw = try allocator.dupe(u8, self.tag.?.raw),
|
||||
} };
|
||||
},
|
||||
|
|
@ -776,7 +779,7 @@ pub const Node = struct {
|
|||
.lorem = .{
|
||||
.count = if (self.tag.?.body.lorem.count) |c| try allocator.dupe(u8, c) else null,
|
||||
.method = if (self.tag.?.body.lorem.method) |m| try allocator.dupe(u8, m) else null,
|
||||
.format = if (self.tag.?.body.lorem.format) |f| try allocator.dupe(u8, f) else null,
|
||||
.random = self.tag.?.body.lorem.random,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1375,7 +1378,7 @@ pub const Parser = struct {
|
|||
if (tag_node.tag.?.kind == .comment) {
|
||||
try self.parseComment();
|
||||
continue;
|
||||
}else {
|
||||
} else {
|
||||
if (try self.parseTagContent(allocator, tag_node)) |tn| {
|
||||
tag.tag.?.body = tn;
|
||||
try body.append(allocator, tag);
|
||||
|
|
@ -1843,6 +1846,7 @@ pub const Parser = struct {
|
|||
var values = std.ArrayList([]const u8){};
|
||||
defer values.deinit(allocator);
|
||||
var i: usize = 0;
|
||||
var fallback: []const u8 = "";
|
||||
while (i < args.len) {
|
||||
while (i < args.len and std.ascii.isWhitespace(args[i])) : (i += 1) {}
|
||||
|
||||
|
|
@ -1870,12 +1874,17 @@ pub const Parser = struct {
|
|||
}
|
||||
|
||||
const value = std.mem.trim(u8, args[start..i], " \t\r\n\"'");
|
||||
if (in_quote) {
|
||||
fallback = value;
|
||||
} else {
|
||||
try values.append(allocator, value);
|
||||
}
|
||||
}
|
||||
|
||||
return TagNodeBody{
|
||||
.firstof = .{
|
||||
.values = try values.toOwnedSlice(allocator),
|
||||
.fallback = fallback,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
|
@ -1936,7 +1945,7 @@ pub const Parser = struct {
|
|||
const args = tag_node.tag.?.args;
|
||||
var count: ?[]const u8 = null;
|
||||
var method: ?[]const u8 = null;
|
||||
var format: ?[]const u8 = null;
|
||||
var random: bool = false;
|
||||
|
||||
var parts = std.mem.splitScalar(u8, args, ' ');
|
||||
while (parts.next()) |part| {
|
||||
|
|
@ -1950,8 +1959,8 @@ pub const Parser = struct {
|
|||
|
||||
if (std.mem.eql(u8, trimmed, "p") or std.mem.eql(u8, trimmed, "w")) {
|
||||
method = trimmed;
|
||||
} else if (std.mem.eql(u8, trimmed, "html") or std.mem.eql(u8, trimmed, "text")) {
|
||||
format = trimmed;
|
||||
} else if (std.mem.eql(u8, trimmed, "true")) {
|
||||
random = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1959,7 +1968,7 @@ pub const Parser = struct {
|
|||
.lorem = .{
|
||||
.count = count,
|
||||
.method = method,
|
||||
.format = format,
|
||||
.random = random,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
|
|
|||
264
src/renderer.zig
264
src/renderer.zig
|
|
@ -11,6 +11,7 @@ const FilterError = @import("filters.zig").FilterError;
|
|||
const parser = @import("parser.zig");
|
||||
const TemplateCache = @import("cache.zig").TemplateCache;
|
||||
const time = @import("time.zig");
|
||||
const lorem = @import("lorem.zig");
|
||||
|
||||
pub const RenderError = error{
|
||||
InvalidCharacter,
|
||||
|
|
@ -309,181 +310,91 @@ pub const Renderer = struct {
|
|||
|
||||
try writer.writeAll(std.fmt.allocPrint(alloc, "{d}", .{ratio}) catch "0");
|
||||
},
|
||||
.now =>{
|
||||
.now => {
|
||||
var format: []const u8 = node.tag.?.body.now.format;
|
||||
if (format.len == 0) format = "Y-m-d H:i:s";
|
||||
const datetime = try time.Time.now().toStringAlloc(alloc, format);
|
||||
try writer.writeAll(datetime);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
.csrf_token => {
|
||||
const token = self.context.get("csrf_token");
|
||||
if (token == null) return;
|
||||
try writer.writeAll(std.fmt.allocPrint(alloc, "<input type=\"hidden\" name=\"csrfmiddlewaretoken\" value=\"{s}\">", .{token.?.string}) catch "");
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn renderNode_old(self: *const Renderer, alloc: Allocator, nodes: []parser.Node, node: parser.Node, writer: anytype, context: ?*Context, parent_block_nodes: ?[]parser.Node) RenderError!void {
|
||||
switch (node.type) {
|
||||
.text => try writer.writeAll(node.text.?.content),
|
||||
.variable => {
|
||||
const var_name = node.variable.?.expr;
|
||||
var value: Value = Value.null;
|
||||
if (context != null) {
|
||||
value = context.?.get(var_name) orelse Value.null;
|
||||
} else {
|
||||
value = self.context.get(var_name) orelse Value.null;
|
||||
}
|
||||
|
||||
var is_safe = false;
|
||||
|
||||
for (node.variable.?.filters) |f| {
|
||||
const filter_fn = builtin_filters.get(f.name) orelse return error.UnknownFilter;
|
||||
|
||||
// const arg = if (f.arg) |a| Value{ .string = a } else null;
|
||||
var arg: Value = Value.null;
|
||||
if (f.arg) |a| {
|
||||
arg = Value{ .string = a };
|
||||
const result = try std.fmt.parseInt(i64, a, 10);
|
||||
if (std.math.maxInt(i64) < result) return error.Overflow;
|
||||
arg = Value{ .int = result };
|
||||
}
|
||||
value = try filter_fn(alloc, value, arg);
|
||||
|
||||
if (std.mem.eql(u8, f.name, "safe")) is_safe = true;
|
||||
}
|
||||
|
||||
if (!is_safe) {
|
||||
if (builtin_filters.get("escape")) |escape_fn| {
|
||||
value = try escape_fn(alloc, value, null);
|
||||
}
|
||||
}
|
||||
.firstof => {
|
||||
const values = node.tag.?.body.firstof.values;
|
||||
for (values) |value| {
|
||||
if (self.context.get(value)) |v| {
|
||||
if (!isTruthy(v)) continue;
|
||||
|
||||
var buf = ArrayListUnmanaged(u8){};
|
||||
defer buf.deinit(alloc);
|
||||
|
||||
try self.valueToString(alloc, &buf, value);
|
||||
try self.valueToString(alloc, &buf, v);
|
||||
|
||||
try writer.writeAll(buf.items);
|
||||
},
|
||||
.if_block => {
|
||||
const condition = try self.evaluateCondition(alloc, node.@"if".?.condition);
|
||||
|
||||
if (condition) {
|
||||
for (node.@"if".?.true_body) |child| {
|
||||
try self.renderNode(alloc, nodes, child, writer, null, null);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
for (node.@"if".?.false_body) |child| {
|
||||
try self.renderNode(alloc, nodes, child, writer, null, null);
|
||||
const check_value = self.resolveStringVariable(value).?;
|
||||
if (!isTruthy(check_value)) continue;
|
||||
|
||||
var buf = ArrayListUnmanaged(u8){};
|
||||
defer buf.deinit(alloc);
|
||||
|
||||
try self.valueToString(alloc, &buf, Value{ .string = value });
|
||||
try writer.writeAll(buf.items);
|
||||
return;
|
||||
}
|
||||
}
|
||||
try writer.writeAll(node.tag.?.body.firstof.fallback);
|
||||
},
|
||||
.include => {
|
||||
const included_template = try self.readTemplateFile(node.include.?.template_name);
|
||||
defer alloc.free(included_template);
|
||||
.lorem => {
|
||||
const count = node.tag.?.body.lorem.count;
|
||||
const method = node.tag.?.body.lorem.method;
|
||||
const random = node.tag.?.body.lorem.random;
|
||||
|
||||
var included_parser = parser.Parser.init(included_template);
|
||||
const included_nodes = try included_parser.parse(alloc);
|
||||
defer {
|
||||
for (included_nodes) |n| n.deinit(alloc);
|
||||
alloc.free(included_nodes);
|
||||
if (count == null and method == null) {
|
||||
if (random == false) {
|
||||
try writer.writeAll(lorem.LOREM_COMMON_P);
|
||||
return;
|
||||
}else {
|
||||
try writer.writeAll(try lorem.sentence(alloc));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Renderiza o include no contexto atual (sem novo contexto)
|
||||
for (included_nodes) |included_node| {
|
||||
try self.renderNode(alloc, nodes, included_node, writer, context, null);
|
||||
const ncount: u32 = std.fmt.parseInt(u32, count.?, 10) catch 1;
|
||||
if (std.mem.eql(u8, method.?, "p")) {
|
||||
const lorem_ = try lorem.paragraphs(alloc, ncount, random);
|
||||
try writer.writeAll(lorem_);
|
||||
return;
|
||||
} else {
|
||||
const lorem_ = try lorem.words(alloc, ncount, random);
|
||||
try writer.writeAll(lorem_);
|
||||
return;
|
||||
}
|
||||
},
|
||||
.for_block => {
|
||||
const list_value = self.context.get(node.@"for".?.iterable) orelse Value.null;
|
||||
const list = switch (list_value) {
|
||||
.list => |l| l,
|
||||
else => return,
|
||||
};
|
||||
|
||||
for (list) |item| {
|
||||
var ctx = Context.init(alloc);
|
||||
defer ctx.deinit();
|
||||
|
||||
try ctx.set(node.@"for".?.loop_var, item);
|
||||
|
||||
for (node.@"for".?.body) |child| {
|
||||
try self.renderNode(alloc, nodes, child, writer, &ctx, null);
|
||||
}
|
||||
|
||||
if (node.@"for".?.body.len == 0) {
|
||||
for (node.@"for".?.empty_body) |child| {
|
||||
try self.renderNode(alloc, nodes, child, writer, &ctx, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
.super => {
|
||||
if (parent_block_nodes) |parent| {
|
||||
for (parent) |child| {
|
||||
try self.renderNode(alloc, nodes, child, writer, null, null);
|
||||
}
|
||||
}
|
||||
},
|
||||
.block => {
|
||||
for (node.block.?.body) |child| {
|
||||
const parent_content = parent_block_nodes orelse node.block.?.body;
|
||||
try self.renderNode(alloc, nodes, child, writer, null, parent_content);
|
||||
}
|
||||
},
|
||||
.widthratio => {
|
||||
var divisor: Value = Value{ .float = 1.0 };
|
||||
var float_divisor: f64 = 1.0;
|
||||
|
||||
var value: Value = Value{ .float = 1.0 };
|
||||
var float_value: f64 = 1.0;
|
||||
|
||||
var max_value: Value = Value{ .float = 1.0 };
|
||||
var float_max_value: f64 = 1.0;
|
||||
|
||||
if (!std.mem.eql(u8, node.widthratio.?.value, "")) {
|
||||
value = Value{ .string = node.widthratio.?.value };
|
||||
if (self.context.get(node.widthratio.?.value)) |v| {
|
||||
value = v;
|
||||
}
|
||||
float_value = switch (value) {
|
||||
.int => @as(f64, @floatFromInt(value.int)),
|
||||
.float => value.float,
|
||||
.string => std.fmt.parseFloat(f64, value.string) catch 1.0,
|
||||
else => 1.0,
|
||||
};
|
||||
}
|
||||
|
||||
if (!std.mem.eql(u8, node.widthratio.?.max_value, "")) {
|
||||
max_value = Value{ .string = node.widthratio.?.max_value };
|
||||
if (self.context.get(node.widthratio.?.max_value)) |v| {
|
||||
max_value = v;
|
||||
}
|
||||
float_max_value = switch (max_value) {
|
||||
.int => @as(f64, @floatFromInt(max_value.int)),
|
||||
.float => max_value.float,
|
||||
.string => std.fmt.parseFloat(f64, max_value.string) catch 1.0,
|
||||
else => 1.0,
|
||||
};
|
||||
}
|
||||
|
||||
if (node.widthratio.?.divisor) |div| {
|
||||
divisor = Value{ .string = div };
|
||||
if (self.context.get(div)) |d| {
|
||||
divisor = d;
|
||||
}
|
||||
float_divisor = switch (divisor) {
|
||||
.int => @as(f64, @floatFromInt(divisor.int)),
|
||||
.float => divisor.float,
|
||||
.string => std.fmt.parseFloat(f64, divisor.string) catch 0.0,
|
||||
else => 1.0,
|
||||
};
|
||||
}
|
||||
|
||||
const ratio = (float_value / float_max_value) * float_divisor;
|
||||
|
||||
try writer.writeAll(std.fmt.allocPrint(alloc, "{d}", .{ratio}) catch "0");
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn resolveStringVariable(self: *const Renderer, value: []const u8) ?Value {
|
||||
_ = self;
|
||||
if (std.mem.eql(u8, value, "true")) return Value{ .bool = true };
|
||||
if (std.mem.eql(u8, value, "false")) return Value{ .bool = false };
|
||||
const is_int = std.fmt.parseInt(i64, value, 10) catch |err| switch (err) {
|
||||
error.InvalidCharacter => null,
|
||||
error.Overflow => null,
|
||||
};
|
||||
if (is_int != null) return Value{ .int = is_int.? };
|
||||
|
||||
const is_float = std.fmt.parseFloat(f64, value) catch |err| switch (err) {
|
||||
error.InvalidCharacter => null,
|
||||
};
|
||||
if (is_float != null) return Value{ .float = is_float.? };
|
||||
return Value{ .string = value };
|
||||
}
|
||||
|
||||
fn findChildBlock(self: *const Renderer, nodes: []parser.Node, name: []const u8) ?parser.BlockNode {
|
||||
|
|
@ -496,35 +407,26 @@ pub const Renderer = struct {
|
|||
return null;
|
||||
}
|
||||
|
||||
fn toValue(self: *Context, value: anytype) RenderError!Value {
|
||||
const T = @TypeOf(value);
|
||||
return switch (@typeInfo(T)) {
|
||||
.bool => Value{ .bool = value },
|
||||
.int, .comptime_int => Value{ .int = @intCast(value) },
|
||||
.float, .comptime_float => Value{ .float = @floatCast(value) },
|
||||
.pointer => Value{ .string = try std.fmt.allocPrint(self.allocator(), "{s}", .{value}) },
|
||||
.@"struct" => blk: {
|
||||
var dict = std.StringHashMapUnmanaged(Value){};
|
||||
inline for (std.meta.fields(T)) |field| {
|
||||
const field_val = @field(value, field.name);
|
||||
const converted = try self.toValue(field_val);
|
||||
try dict.put(self.allocator(), field.name, converted);
|
||||
}
|
||||
break :blk Value{ .dict = dict };
|
||||
},
|
||||
.array => blk: {
|
||||
var list = try self.allocator().alloc(Value, value.len);
|
||||
for (value, 0..) |item, i| {
|
||||
list[i] = try self.toValue(item);
|
||||
}
|
||||
break :blk Value{ .list = list };
|
||||
},
|
||||
.optional => if (value) |v| try self.toValue(v) else .null,
|
||||
.null => .null,
|
||||
// CASO ESPECIAL: o valor já é um Value (ex: lista de Value)
|
||||
.@"union" => if (T == Value) value else @compileError("Unsupported union type: " ++ @typeName(T)),
|
||||
else => @compileError("Unsupported type: " ++ @typeName(T)),
|
||||
fn escapeHtml(self: *const Renderer, value: Value) !Value {
|
||||
const s = switch (value) {
|
||||
.string => |str| str,
|
||||
else => return value,
|
||||
};
|
||||
|
||||
var result = std.ArrayList(u8){};
|
||||
|
||||
for (s) |c| {
|
||||
switch (c) {
|
||||
'&' => try result.appendSlice(self.allocator, "&"),
|
||||
'<' => try result.appendSlice(self.allocator, "<"),
|
||||
'>' => try result.appendSlice(self.allocator, ">"),
|
||||
'"' => try result.appendSlice(self.allocator, """),
|
||||
'\'' => try result.appendSlice(self.allocator, "'"),
|
||||
else => try result.append(self.allocator, c),
|
||||
}
|
||||
}
|
||||
|
||||
return Value{ .string = try result.toOwnedSlice(self.allocator) };
|
||||
}
|
||||
|
||||
fn valueToString(self: *const Renderer, alloc: Allocator, buf: *ArrayListUnmanaged(u8), value: Value) RenderError!void {
|
||||
|
|
|
|||
|
|
@ -652,8 +652,25 @@ test "renderer - now" {
|
|||
try ctx.set("idade", Value{ .int = 20 });
|
||||
|
||||
const template =
|
||||
// \\{% now \"Y-m-d H:i:s\" %}
|
||||
\\{% now %}
|
||||
\\{% now \"Y-m-d H:i:s\" %}
|
||||
\\{% now \"Y" %}
|
||||
\\{% now \"m\" %}
|
||||
\\{% now \"n\" %}
|
||||
\\{% now \"d\" %}
|
||||
\\{% now \"j\" %}
|
||||
\\{% now \"F\" %}
|
||||
\\{% now \"M\" %}
|
||||
\\{% now \"l\" %}
|
||||
\\{% now \"D\" %}
|
||||
\\{% now \"H:i:s\" %}
|
||||
\\{% now \"H\" %}
|
||||
\\{% now \"G\" %}
|
||||
\\{% now \"i\" %}
|
||||
\\{% now \"s\" %}
|
||||
\\{% now \"a\" %}
|
||||
\\{% now \"A\" %}
|
||||
\\{% now \"P\" %}
|
||||
;
|
||||
|
||||
var buf = std.ArrayList(u8){};
|
||||
|
|
@ -665,3 +682,389 @@ test "renderer - now" {
|
|||
|
||||
// try testing.expect(std.mem.indexOf(u8, buf.items, "Maior") != null);
|
||||
}
|
||||
|
||||
test "renderer - csrf_token in context" {
|
||||
std.debug.print("____________________________________________________\n", .{});
|
||||
std.debug.print("15 - csrf_token in context\n", .{});
|
||||
|
||||
const alloc = testing.allocator;
|
||||
var ctx = Context.init(alloc);
|
||||
defer ctx.deinit();
|
||||
|
||||
var cache = TemplateCache.init(alloc);
|
||||
defer cache.deinit();
|
||||
|
||||
const renderer = Renderer.init(&ctx, &cache);
|
||||
|
||||
const token: []const u8 = "zh5fyUSICjXNsDTtJCjl9A3O2dDSHhYFlIngAEO6PXK9NX56Z1XLEy7doYuPcE0u";
|
||||
|
||||
try ctx.set("csrf_token", token);
|
||||
const template =
|
||||
\\{% csrf_token %}
|
||||
;
|
||||
|
||||
const expected =
|
||||
\\<input type="hidden" name="csrfmiddlewaretoken" value="zh5fyUSICjXNsDTtJCjl9A3O2dDSHhYFlIngAEO6PXK9NX56Z1XLEy7doYuPcE0u">
|
||||
;
|
||||
var buf = std.ArrayList(u8){};
|
||||
defer buf.deinit(alloc);
|
||||
|
||||
try renderer.renderString(template, buf.writer(alloc));
|
||||
|
||||
std.debug.print("OUTPUT:\n\n{s}\n", .{buf.items});
|
||||
|
||||
try testing.expectEqualStrings(expected, buf.items);
|
||||
}
|
||||
|
||||
test "renderer - csrf_token not in context" {
|
||||
std.debug.print("____________________________________________________\n", .{});
|
||||
std.debug.print("16 - csrf_token not in context\n", .{});
|
||||
|
||||
const alloc = testing.allocator;
|
||||
var ctx = Context.init(alloc);
|
||||
defer ctx.deinit();
|
||||
|
||||
var cache = TemplateCache.init(alloc);
|
||||
defer cache.deinit();
|
||||
|
||||
const renderer = Renderer.init(&ctx, &cache);
|
||||
|
||||
const template =
|
||||
\\{% csrf_token %}
|
||||
;
|
||||
|
||||
const expected =
|
||||
\\
|
||||
;
|
||||
var buf = std.ArrayList(u8){};
|
||||
defer buf.deinit(alloc);
|
||||
|
||||
try renderer.renderString(template, buf.writer(alloc));
|
||||
|
||||
// std.debug.print("OUTPUT:\n\n{s}\n", .{buf.items});
|
||||
|
||||
try testing.expectEqualStrings(expected, buf.items);
|
||||
}
|
||||
|
||||
// TODO: add parse filters to variables
|
||||
test "renderer - firstof withtout fallback" {
|
||||
std.debug.print("____________________________________________________\n", .{});
|
||||
std.debug.print("17 - firstof without fallback\n", .{});
|
||||
|
||||
const alloc = testing.allocator;
|
||||
var ctx = Context.init(alloc);
|
||||
defer ctx.deinit();
|
||||
|
||||
var cache = TemplateCache.init(alloc);
|
||||
defer cache.deinit();
|
||||
|
||||
const renderer = Renderer.init(&ctx, &cache);
|
||||
|
||||
try ctx.set("var1", "");
|
||||
try ctx.set("var2", "baz");
|
||||
|
||||
const template =
|
||||
\\{% firstof var1 var2 %}
|
||||
;
|
||||
|
||||
const expected =
|
||||
\\baz
|
||||
;
|
||||
var buf = std.ArrayList(u8){};
|
||||
defer buf.deinit(alloc);
|
||||
|
||||
try renderer.renderString(template, buf.writer(alloc));
|
||||
|
||||
// std.debug.print("OUTPUT:\n\n{s}\n", .{buf.items});
|
||||
|
||||
try testing.expectEqualStrings(expected, buf.items);
|
||||
}
|
||||
|
||||
test "renderer - firstof with fallback" {
|
||||
std.debug.print("____________________________________________________\n", .{});
|
||||
std.debug.print("18 - firstof with fallback\n", .{});
|
||||
|
||||
const alloc = testing.allocator;
|
||||
var ctx = Context.init(alloc);
|
||||
defer ctx.deinit();
|
||||
|
||||
var cache = TemplateCache.init(alloc);
|
||||
defer cache.deinit();
|
||||
|
||||
const renderer = Renderer.init(&ctx, &cache);
|
||||
|
||||
try ctx.set("var1", "");
|
||||
try ctx.set("var2", 0);
|
||||
|
||||
const template =
|
||||
\\{% firstof var1 var2 "Oops no value!" %}
|
||||
;
|
||||
|
||||
const expected =
|
||||
\\Oops no value!
|
||||
;
|
||||
var buf = std.ArrayList(u8){};
|
||||
defer buf.deinit(alloc);
|
||||
|
||||
try renderer.renderString(template, buf.writer(alloc));
|
||||
|
||||
// std.debug.print("OUTPUT:\n\n{s}\n", .{buf.items});
|
||||
|
||||
try testing.expectEqualStrings(expected, buf.items);
|
||||
}
|
||||
|
||||
test "renderer - firstof without value in context" {
|
||||
std.debug.print("____________________________________________________\n", .{});
|
||||
std.debug.print("19 - firstof without value in context\n", .{});
|
||||
|
||||
const alloc = testing.allocator;
|
||||
var ctx = Context.init(alloc);
|
||||
defer ctx.deinit();
|
||||
|
||||
var cache = TemplateCache.init(alloc);
|
||||
defer cache.deinit();
|
||||
|
||||
const renderer = Renderer.init(&ctx, &cache);
|
||||
|
||||
const template =
|
||||
\\{% firstof 0 true "Oops no value!" %}
|
||||
;
|
||||
|
||||
const expected =
|
||||
\\true
|
||||
;
|
||||
var buf = std.ArrayList(u8){};
|
||||
defer buf.deinit(alloc);
|
||||
|
||||
try renderer.renderString(template, buf.writer(alloc));
|
||||
|
||||
// std.debug.print("OUTPUT:\n\n{s}\n", .{buf.items});
|
||||
|
||||
try testing.expectEqualStrings(expected, buf.items);
|
||||
}
|
||||
|
||||
test "renderer - firstof missing vars" {
|
||||
std.debug.print("____________________________________________________\n", .{});
|
||||
std.debug.print("20 - firstof missing vars\n", .{});
|
||||
|
||||
const alloc = testing.allocator;
|
||||
var ctx = Context.init(alloc);
|
||||
defer ctx.deinit();
|
||||
|
||||
var cache = TemplateCache.init(alloc);
|
||||
defer cache.deinit();
|
||||
|
||||
const renderer = Renderer.init(&ctx, &cache);
|
||||
|
||||
const template =
|
||||
\\{% firstof %}
|
||||
;
|
||||
|
||||
const expected =
|
||||
\\
|
||||
;
|
||||
var buf = std.ArrayList(u8){};
|
||||
defer buf.deinit(alloc);
|
||||
|
||||
try renderer.renderString(template, buf.writer(alloc));
|
||||
|
||||
// std.debug.print("OUTPUT:\n\n{s}\n", .{buf.items});
|
||||
|
||||
try testing.expectEqualStrings(expected, buf.items);
|
||||
}
|
||||
|
||||
test "renderer - firstof missing vars with fallback" {
|
||||
std.debug.print("____________________________________________________\n", .{});
|
||||
std.debug.print("21 - firstof missing vars with fallback\n", .{});
|
||||
|
||||
const alloc = testing.allocator;
|
||||
var ctx = Context.init(alloc);
|
||||
defer ctx.deinit();
|
||||
|
||||
var cache = TemplateCache.init(alloc);
|
||||
defer cache.deinit();
|
||||
|
||||
const renderer = Renderer.init(&ctx, &cache);
|
||||
|
||||
const template =
|
||||
\\{% firstof "nothing here" %}
|
||||
;
|
||||
|
||||
const expected =
|
||||
\\nothing here
|
||||
;
|
||||
var buf = std.ArrayList(u8){};
|
||||
defer buf.deinit(alloc);
|
||||
|
||||
try renderer.renderString(template, buf.writer(alloc));
|
||||
|
||||
// std.debug.print("OUTPUT:\n\n{s}\n", .{buf.items});
|
||||
|
||||
try testing.expectEqualStrings(expected, buf.items);
|
||||
}
|
||||
|
||||
test "renderer - lorem" {
|
||||
std.debug.print("____________________________________________________\n", .{});
|
||||
std.debug.print("22 - lorem\n", .{});
|
||||
|
||||
const alloc = testing.allocator;
|
||||
var ctx = Context.init(alloc);
|
||||
defer ctx.deinit();
|
||||
|
||||
var cache = TemplateCache.init(alloc);
|
||||
defer cache.deinit();
|
||||
|
||||
const renderer = Renderer.init(&ctx, &cache);
|
||||
|
||||
const template =
|
||||
\\{% lorem %}
|
||||
;
|
||||
|
||||
var buf = std.ArrayList(u8){};
|
||||
defer buf.deinit(alloc);
|
||||
|
||||
try renderer.renderString(template, buf.writer(alloc));
|
||||
|
||||
std.debug.print("OUTPUT:\n\n{s}\n", .{buf.items});
|
||||
|
||||
try testing.expect(std.mem.indexOf(u8, buf.items, "Lorem ipsum") != null);
|
||||
}
|
||||
|
||||
test "renderer - lorem with count and method words" {
|
||||
std.debug.print("____________________________________________________\n", .{});
|
||||
std.debug.print("23 - lorem with count and method words\n", .{});
|
||||
|
||||
const alloc = testing.allocator;
|
||||
var ctx = Context.init(alloc);
|
||||
defer ctx.deinit();
|
||||
|
||||
var cache = TemplateCache.init(alloc);
|
||||
defer cache.deinit();
|
||||
|
||||
const renderer = Renderer.init(&ctx, &cache);
|
||||
|
||||
const template =
|
||||
\\{% lorem 3 w %}
|
||||
;
|
||||
|
||||
var buf = std.ArrayList(u8){};
|
||||
defer buf.deinit(alloc);
|
||||
|
||||
try renderer.renderString(template, buf.writer(alloc));
|
||||
|
||||
std.debug.print("OUTPUT:\n\n{s}\n", .{buf.items});
|
||||
|
||||
try testing.expectEqualStrings("lorem ipsum dolor", buf.items);
|
||||
}
|
||||
|
||||
test "renderer - lorem with count and method paragraphs" {
|
||||
std.debug.print("____________________________________________________\n", .{});
|
||||
std.debug.print("24 - lorem with count and method paragraphs\n", .{});
|
||||
|
||||
const alloc = testing.allocator;
|
||||
var ctx = Context.init(alloc);
|
||||
defer ctx.deinit();
|
||||
|
||||
var cache = TemplateCache.init(alloc);
|
||||
defer cache.deinit();
|
||||
|
||||
const renderer = Renderer.init(&ctx, &cache);
|
||||
|
||||
const template =
|
||||
\\{% lorem 5 p %}
|
||||
;
|
||||
|
||||
var buf = std.ArrayList(u8){};
|
||||
defer buf.deinit(alloc);
|
||||
|
||||
try renderer.renderString(template, buf.writer(alloc));
|
||||
|
||||
std.debug.print("OUTPUT:\n\n{s}\n", .{buf.items});
|
||||
|
||||
const qty = std.mem.count(u8, buf.items, "<p>");
|
||||
try testing.expect(std.mem.indexOf(u8, buf.items, "Lorem ipsum dolor") != null);
|
||||
try testing.expect(qty == 5);
|
||||
}
|
||||
|
||||
test "renderer - lorem only random" {
|
||||
std.debug.print("____________________________________________________\n", .{});
|
||||
std.debug.print("25 - lorem only random\n", .{});
|
||||
|
||||
const alloc = testing.allocator;
|
||||
var ctx = Context.init(alloc);
|
||||
defer ctx.deinit();
|
||||
|
||||
var cache = TemplateCache.init(alloc);
|
||||
defer cache.deinit();
|
||||
|
||||
const renderer = Renderer.init(&ctx, &cache);
|
||||
|
||||
const template =
|
||||
\\{% lorem true %}
|
||||
;
|
||||
|
||||
var buf = std.ArrayList(u8){};
|
||||
defer buf.deinit(alloc);
|
||||
|
||||
try renderer.renderString(template, buf.writer(alloc));
|
||||
|
||||
std.debug.print("OUTPUT:\n\n{s}\n", .{buf.items});
|
||||
|
||||
try testing.expect(buf.items.len > 0);
|
||||
}
|
||||
|
||||
test "renderer - lorem words random" {
|
||||
std.debug.print("____________________________________________________\n", .{});
|
||||
std.debug.print("26 - lorem words random\n", .{});
|
||||
|
||||
const alloc = testing.allocator;
|
||||
var ctx = Context.init(alloc);
|
||||
defer ctx.deinit();
|
||||
|
||||
var cache = TemplateCache.init(alloc);
|
||||
defer cache.deinit();
|
||||
|
||||
const renderer = Renderer.init(&ctx, &cache);
|
||||
|
||||
const template =
|
||||
\\{% lorem 6 w true %}
|
||||
;
|
||||
|
||||
var buf = std.ArrayList(u8){};
|
||||
defer buf.deinit(alloc);
|
||||
|
||||
try renderer.renderString(template, buf.writer(alloc));
|
||||
|
||||
std.debug.print("OUTPUT:\n\n{s}\n", .{buf.items});
|
||||
|
||||
const spaces = std.mem.count(u8, buf.items, " ");
|
||||
try testing.expect(spaces == 5);
|
||||
}
|
||||
|
||||
test "renderer - lorem paragraphs random" {
|
||||
std.debug.print("____________________________________________________\n", .{});
|
||||
std.debug.print("26 - lorem paragraphs random\n", .{});
|
||||
|
||||
const alloc = testing.allocator;
|
||||
var ctx = Context.init(alloc);
|
||||
defer ctx.deinit();
|
||||
|
||||
var cache = TemplateCache.init(alloc);
|
||||
defer cache.deinit();
|
||||
|
||||
const renderer = Renderer.init(&ctx, &cache);
|
||||
|
||||
const template =
|
||||
\\{% lorem 3 p true %}
|
||||
;
|
||||
|
||||
var buf = std.ArrayList(u8){};
|
||||
defer buf.deinit(alloc);
|
||||
|
||||
try renderer.renderString(template, buf.writer(alloc));
|
||||
|
||||
std.debug.print("OUTPUT:\n\n{s}\n", .{buf.items});
|
||||
|
||||
const spaces = std.mem.count(u8, buf.items, "<p>");
|
||||
try testing.expect(spaces == 3);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue