From b09da93f0d9872521c59ca84e087d778ee8c6402 Mon Sep 17 00:00:00 2001 From: "Lucas F." Date: Sat, 3 Jan 2026 21:00:11 -0300 Subject: [PATCH] update: csrf_token and lorem --- src/parser.zig | 77 +++++++++++++++++++++++++++++++++++++++++++++ src/parser_test.zig | 66 ++++++++++++++++++++++++++++++++++++++ todo.md | 35 +++++++++++++++++++-- 3 files changed, 175 insertions(+), 3 deletions(-) diff --git a/src/parser.zig b/src/parser.zig index e4f5bd9..fdce959 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -19,6 +19,14 @@ pub const NodeType = enum { cycle, firstof, load, + csrf_token, + lorem, +}; + +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 }; pub const LoadNode = struct { @@ -147,6 +155,8 @@ pub const Node = struct { cycle: ?CycleNode = null, firstof: ?FirstOfNode = null, load: ?LoadNode = null, + lorem: ?LoremNode = null, + csrf_token: bool = false, pub fn deinit(self: Node, allocator: std.mem.Allocator) void { switch (self.type) { @@ -235,6 +245,12 @@ pub const Node = struct { for (l.libraries) |lib| allocator.free(lib); allocator.free(l.libraries); }, + .csrf_token => {}, + .lorem => if (self.lorem) |l| { + if (l.count) |c| allocator.free(c); + if (l.method) |m| allocator.free(m); + if (l.format) |f| allocator.free(f); + }, } } }; @@ -1090,6 +1106,48 @@ pub const Parser = struct { continue; } + if (std.mem.eql(u8, tag_name, "lorem")) { + const args = node.tag.?.args; + + var count: ?[]const u8 = null; + var method: ?[]const u8 = null; + var format: ?[]const u8 = null; + + var parts = std.mem.splitScalar(u8, args, ' '); + while (parts.next()) |part| { + const trimmed = std.mem.trim(u8, part, " \t\r\n"); + if (trimmed.len == 0) continue; + + const num: usize = std.fmt.parseInt(usize, trimmed, 10) catch 0; + if (num > 0) { + std.debug.print("trimmed: {s}\n", .{trimmed}); + count = try allocator.dupe(u8, trimmed); + } + + if (std.mem.eql(u8, trimmed, "p") or std.mem.eql(u8, trimmed, "w")) { + std.debug.print("trimmed: {s}\n", .{trimmed}); + method = try allocator.dupe(u8, trimmed); + } else if (std.mem.eql(u8, trimmed, "html")) { + std.debug.print("trimmed: {s}\n", .{trimmed}); + format = try allocator.dupe(u8, trimmed); + } + + } + + allocator.free(node.tag.?.name); + allocator.free(node.tag.?.args); + + try list.append(allocator, Node{ + .type = .lorem, + .lorem = .{ + .count = count, + .method = method, + .format = format, + }, + }); + continue; + } + if (std.mem.eql(u8, tag_name, "filter")) { const filters_raw = node.tag.?.args; const raw_open = node.tag.?.raw; @@ -1457,6 +1515,25 @@ pub const Parser = struct { continue; } + if (std.mem.eql(u8, tag_name, "csrf_token")) { + // Verifica se tem argumentos (não deve ter) + if (node.tag.?.args.len > 0 and !std.mem.allEqual(u8, node.tag.?.args, ' ')) { + return error.InvalidCsrfTokenArgs; + } + + allocator.free(node.tag.?.name); + allocator.free(node.tag.?.args); + + std.debug.print("3.0 - na real sou um csrf_token\n", .{}); + std.debug.print("===================================\n", .{}); + + try list.append(allocator, Node{ + .type = .csrf_token, + .csrf_token = true, + }); + continue; + } + // Para tags normais std.debug.print("===================================\n", .{}); try list.append(allocator, node); diff --git a/src/parser_test.zig b/src/parser_test.zig index a341d8e..8a47cdb 100644 --- a/src/parser_test.zig +++ b/src/parser_test.zig @@ -643,3 +643,69 @@ test "parse load com múltiplas" { try testing.expectEqualStrings("admin_urls", l.libraries[0]); try testing.expectEqualStrings("static", l.libraries[1]); } + +test "parse csrf_token simples" { + const allocator = testing.allocator; + const template = "
{% csrf_token %}
"; + const nodes = try parser.parse(allocator, template); + defer { + for (nodes) |node| node.deinit(allocator); + allocator.free(nodes); + } + + try testing.expectEqual(@as(usize, 3), nodes.len); + try testing.expect(nodes[0].type == .text); + try testing.expectEqualStrings("
", nodes[0].text.?.content); + + try testing.expect(nodes[1].type == .csrf_token); + + try testing.expect(nodes[2].type == .text); + try testing.expectEqualStrings("
", nodes[2].text.?.content); +} + +test "parse csrf_token sozinho" { + const allocator = testing.allocator; + const template = "{% csrf_token %}"; + const nodes = try parser.parse(allocator, template); + defer { + for (nodes) |node| node.deinit(allocator); + allocator.free(nodes); + } + + try testing.expectEqual(@as(usize, 1), nodes.len); + try testing.expect(nodes[0].type == .csrf_token); +} + +test "parse lorem padrão" { + const allocator = testing.allocator; + const template = "{% lorem %}"; + const nodes = try parser.parse(allocator, template); + defer { + for (nodes) |node| node.deinit(allocator); + allocator.free(nodes); + } + + try testing.expectEqual(@as(usize, 1), nodes.len); + try testing.expect(nodes[0].type == .lorem); + const l = nodes[0].lorem.?; + try testing.expect(l.count == null); + try testing.expect(l.method == null); + try testing.expect(l.format == null); +} + +test "parse lorem com argumentos" { + const allocator = testing.allocator; + const template = "{% lorem 5 p html %}"; + const nodes = try parser.parse(allocator, template); + defer { + for (nodes) |node| node.deinit(allocator); + allocator.free(nodes); + } + + try testing.expectEqual(@as(usize, 1), nodes.len); + try testing.expect(nodes[0].type == .lorem); + const l = nodes[0].lorem.?; + try testing.expectEqualStrings("5", l.count.?); + try testing.expectEqualStrings("p", l.method.?); + try testing.expectEqualStrings("html", l.format.?); +} diff --git a/todo.md b/todo.md index 5996198..6103185 100644 --- a/todo.md +++ b/todo.md @@ -3,7 +3,7 @@ - [x] autoescape - [x] block - [x] comment -- [ ] csrf_token +- [x] csrf_token - [x] cycle - [ ] debug - [x] extends @@ -14,7 +14,7 @@ - [x] ifchanged - [x] include - [x] load -- [ ] lorem +- [x] lorem - [x] now - [ ] partial - [ ] partialdef @@ -101,4 +101,33 @@ ___ - [x] cycle — alternar valores em loop - [x] firstof — fallback de variáveis - [x] load — para custom tags/filters (futuro) -- [ ] csrf_token — quando tiver web +- [x] csrf_token — quando tiver web + +--- + +## To do + +1 - Finalizar o parser — completar as tags que faltam da lista: +- [ ] debug +- [x] lorem +- [ ] partial / partialdef +- [ ] querystring +- [ ] regroup +- [ ] resetcycle +- [ ] templatetag +- [ ] widthratio + +2 - projetar o Context com calma: +- Estrutura hierárquica (escopos aninhados para with, for, etc.) +- Suporte a variáveis, listas, structs (models) +- Acesso por ponto (obj.atributo, lista.0, etc.) +- Fallback silencioso ou erro (como no Django) + +3 - Renderer — com: +- Resolução de variáveis +- Aplicação de filtros +- Herança com block.super +- Loops com forloop +- Tudo testado + +4 -Filtros