217 lines
4.5 KiB
Markdown
217 lines
4.5 KiB
Markdown
# Tags
|
|
|
|
- [x] autoescape
|
|
- [x] block
|
|
- [x] comment
|
|
- [x] csrf_token
|
|
- [x] cycle
|
|
- [x] debug
|
|
- [x] extends
|
|
- [x] filter
|
|
- [x] firstof
|
|
- [x] for
|
|
- [x] if
|
|
- [x] ifchanged
|
|
- [x] include
|
|
- [x] load
|
|
- [x] lorem
|
|
- [x] now
|
|
- [x] partial
|
|
- [x] partialdef
|
|
- [x] querystring
|
|
- [x] regroup
|
|
- [x] resetcycle
|
|
- [x] spaceless
|
|
- [x] templatetag
|
|
- [x] url
|
|
- [x] verbatim
|
|
- [x] widthratio
|
|
- [x] with
|
|
|
|
|
|
# Filters
|
|
|
|
- [x] add
|
|
- [x] addslashes
|
|
- [x] capfirst
|
|
- [x] center
|
|
- [x] cut
|
|
- [ ] date
|
|
- [x] default
|
|
- [x] default_if_none
|
|
- [x] dictsort
|
|
- [x] dictsortreversed
|
|
- [x] divisibleby
|
|
- [x] escape
|
|
- [x] escapejs
|
|
- [x] escapeseq
|
|
- [x] filesizeformat
|
|
- [x] first
|
|
- [x] floatformat
|
|
- [x] force_escape
|
|
- [x] get_digit
|
|
- [x] iriencode
|
|
- [x] join
|
|
- [x] json_script
|
|
- [x] last
|
|
- [x] length
|
|
- [x] linebreaks
|
|
- [x] linebreaksbr
|
|
- [x] linenumbers
|
|
- [x] ljust
|
|
- [x] lower
|
|
- [x] make_list
|
|
- [x] phone2numeric
|
|
- [x] pluralize
|
|
- [x] pprint
|
|
- [x] random
|
|
- [x] rjust
|
|
- [x] safe
|
|
- [x] safeseq
|
|
- [x] slice
|
|
- [x] slugify
|
|
- [x] stringformat
|
|
- [x] striptags
|
|
- [ ] time
|
|
- [ ] timesince
|
|
- [ ] timeuntil
|
|
- [x] title
|
|
- [x] truncatechars
|
|
- [-] truncatechars_html
|
|
- [x] truncatewords
|
|
- [-] truncatewords_html
|
|
- [x] unordered_list
|
|
- [x] upper
|
|
- [x] urlencode
|
|
- [x] urlize
|
|
- [x] urlizetrunc
|
|
- [x] wordcount
|
|
- [x] wordwrap
|
|
- [x] yesno
|
|
|
|
___
|
|
|
|
## Doing
|
|
|
|
- [x] filter — super útil (ex.: {{ var|upper }})
|
|
- [x] autoescape — segurança importante
|
|
- [x] spaceless — remove espaços em branco
|
|
- [x] verbatim — como raw
|
|
- [x] url — reverse de URLs (quando tiver routing)
|
|
- [x] cycle — alternar valores em loop
|
|
- [x] firstof — fallback de variáveis
|
|
- [x] load — para custom tags/filters (futuro)
|
|
- [x] csrf_token — quando tiver web
|
|
|
|
---
|
|
|
|
## To do
|
|
|
|
1 - Finalizar o parser — completar as tags que faltam da lista:
|
|
- [x] debug
|
|
- [x] lorem
|
|
- [x] partial / partialdef
|
|
- [x] querystring
|
|
- [x] regroup
|
|
- [x] resetcycle
|
|
- [x] templatetag
|
|
- [x] 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
|
|
|
|
|
|
|
|
|
|
|
|
na verdade o pushScope não tava não, a versão final que vc me mandou depois que se inspirou no tokamak foi essa:
|
|
```
|
|
const std = @import("std");
|
|
|
|
pub const Value = union(enum) {
|
|
null,
|
|
bool: bool,
|
|
int: i64,
|
|
float: f64,
|
|
string: []const u8,
|
|
list: []const Value,
|
|
dict: std.StringHashMapUnmanaged(Value),
|
|
|
|
pub fn deinit(self: Value) void {
|
|
_ = self; // nada — a arena libera tudo
|
|
}
|
|
};
|
|
|
|
pub const Context = struct {
|
|
arena: std.heap.ArenaAllocator,
|
|
map: std.StringHashMapUnmanaged(Value),
|
|
|
|
pub fn init(child_allocator: std.mem.Allocator) Context {
|
|
const arena = std.heap.ArenaAllocator.init(child_allocator);
|
|
return .{
|
|
.arena = arena,
|
|
.map = .{},
|
|
};
|
|
}
|
|
|
|
pub fn allocator(self: *Context) std.mem.Allocator {
|
|
return self.arena.allocator();
|
|
}
|
|
|
|
pub fn deinit(self: *Context) void {
|
|
self.arena.deinit();
|
|
}
|
|
|
|
pub fn set(self: *Context, key: []const u8, value: Value) !void {
|
|
const gop = try self.map.getOrPut(self.allocator(), key);
|
|
if (gop.found_existing) {
|
|
// opcional: deinit value antigo se necessário
|
|
// mas como arena libera tudo, não precisa
|
|
} else {
|
|
gop.key_ptr.* = try self.allocator().dupe(u8, key);
|
|
}
|
|
gop.value_ptr.* = value;
|
|
}
|
|
|
|
pub fn get(self: *const Context, key: []const u8) ?Value {
|
|
return self.map.get(key);
|
|
}
|
|
};
|
|
|
|
```
|
|
ao colocar isso ordered_dict: []struct { key: []const u8, val: Value }, vc ferrou em todos os switches de Value que agora tem que prever o que fazer com orderdered_dict
|
|
|
|
Conclusão sobre o getA melhor abordagem, considerando Zig, é:
|
|
Manter o get(comptime T: type, key) — é seguro, performático, e em uso real fica natural
|
|
|
|
```zig
|
|
const idade: i64 = ctx.get("idade") orelse 0;
|
|
const nome: []const u8 = ctx.get("nome") orelse "Desconhecido";
|
|
```
|
|
|
|
É verboso no teste, mas em código real é claro e seguro.Ou podemos fazer uma versão com optional:
|
|
|
|
```zig
|
|
pub fn get(self: *const Context, comptime T: type, key: []const u8) ?T {
|
|
const value = self.map.get(key) orelse return null;
|
|
return value.as(T) catch null;
|
|
}
|
|
```
|
|
|
|
Aí fica:
|
|
|
|
```zig
|
|
const idade = ctx.get(i64, "idade") orelse 0;
|
|
```
|