Genearte .zig verions of templates to use in production.
This commit is contained in:
369
src/compile_tpls.zig
Normal file
369
src/compile_tpls.zig
Normal file
@@ -0,0 +1,369 @@
|
||||
// Build step for compiling Pug templates at build time
|
||||
//
|
||||
// Usage in build.zig:
|
||||
// const pugz = @import("pugz");
|
||||
// const compile_step = pugz.addCompileStep(b, .{
|
||||
// .name = "compile-templates",
|
||||
// .source_dirs = &.{"src/views", "src/pages"},
|
||||
// .output_dir = "generated",
|
||||
// });
|
||||
// exe.step.dependOn(&compile_step.step);
|
||||
|
||||
const std = @import("std");
|
||||
const fs = std.fs;
|
||||
const mem = std.mem;
|
||||
const Build = std.Build;
|
||||
const Step = Build.Step;
|
||||
const GeneratedFile = Build.GeneratedFile;
|
||||
|
||||
const zig_codegen = @import("tpl_compiler/zig_codegen.zig");
|
||||
const view_engine = @import("view_engine.zig");
|
||||
const mixin = @import("mixin.zig");
|
||||
|
||||
pub const CompileOptions = struct {
|
||||
/// Name for the compile step
|
||||
name: []const u8 = "compile-pug-templates",
|
||||
|
||||
/// Source directories containing .pug files (can be multiple)
|
||||
source_dirs: []const []const u8,
|
||||
|
||||
/// Output directory for generated .zig files
|
||||
output_dir: []const u8,
|
||||
|
||||
/// Base directory for resolving includes/extends
|
||||
/// If not specified, automatically inferred as the common parent of all source_dirs
|
||||
/// e.g., ["views/pages", "views/partials"] -> "views"
|
||||
views_root: ?[]const u8 = null,
|
||||
};
|
||||
|
||||
pub const CompileStep = struct {
|
||||
step: Step,
|
||||
options: CompileOptions,
|
||||
output_file: GeneratedFile,
|
||||
|
||||
pub fn create(owner: *Build, options: CompileOptions) *CompileStep {
|
||||
const self = owner.allocator.create(CompileStep) catch @panic("OOM");
|
||||
|
||||
self.* = .{
|
||||
.step = Step.init(.{
|
||||
.id = .custom,
|
||||
.name = options.name,
|
||||
.owner = owner,
|
||||
.makeFn = make,
|
||||
}),
|
||||
.options = options,
|
||||
.output_file = .{ .step = &self.step },
|
||||
};
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
fn make(step: *Step, options: Step.MakeOptions) !void {
|
||||
_ = options;
|
||||
const self: *CompileStep = @fieldParentPtr("step", step);
|
||||
const b = step.owner;
|
||||
const allocator = b.allocator;
|
||||
|
||||
// Use output_dir relative to project root (not zig-out/)
|
||||
const output_path = b.pathFromRoot(self.options.output_dir);
|
||||
try fs.cwd().makePath(output_path);
|
||||
|
||||
var arena = std.heap.ArenaAllocator.init(allocator);
|
||||
defer arena.deinit();
|
||||
const arena_allocator = arena.allocator();
|
||||
|
||||
// Track all compiled templates
|
||||
var all_templates = std.StringHashMap([]const u8).init(allocator);
|
||||
defer {
|
||||
var iter = all_templates.iterator();
|
||||
while (iter.next()) |entry| {
|
||||
allocator.free(entry.key_ptr.*);
|
||||
allocator.free(entry.value_ptr.*);
|
||||
}
|
||||
all_templates.deinit();
|
||||
}
|
||||
|
||||
// Determine views_root (common parent directory for all templates)
|
||||
const views_root = if (self.options.views_root) |root|
|
||||
b.pathFromRoot(root)
|
||||
else if (self.options.source_dirs.len > 0) blk: {
|
||||
// Infer common parent from all source_dirs
|
||||
// e.g., ["views/pages", "views/partials"] -> "views"
|
||||
const first_dir = b.pathFromRoot(self.options.source_dirs[0]);
|
||||
const common_parent = fs.path.dirname(first_dir) orelse first_dir;
|
||||
|
||||
// Verify all source_dirs share this parent
|
||||
for (self.options.source_dirs) |dir| {
|
||||
const abs_dir = b.pathFromRoot(dir);
|
||||
if (!mem.startsWith(u8, abs_dir, common_parent)) {
|
||||
// Dirs don't share common parent, use first dir's parent
|
||||
break :blk common_parent;
|
||||
}
|
||||
}
|
||||
|
||||
break :blk common_parent;
|
||||
} else b.pathFromRoot(".");
|
||||
|
||||
// Compile each source directory
|
||||
for (self.options.source_dirs) |source_dir| {
|
||||
const abs_source_dir = b.pathFromRoot(source_dir);
|
||||
|
||||
std.debug.print("Compiling templates from {s}...\n", .{source_dir});
|
||||
|
||||
try compileDirectory(
|
||||
allocator,
|
||||
arena_allocator,
|
||||
abs_source_dir,
|
||||
views_root,
|
||||
output_path,
|
||||
&all_templates,
|
||||
);
|
||||
}
|
||||
|
||||
// Generate root.zig
|
||||
try generateRootZig(allocator, output_path, &all_templates);
|
||||
|
||||
// Copy helpers.zig
|
||||
try copyHelpersZig(allocator, output_path);
|
||||
|
||||
std.debug.print("Compiled {d} templates to {s}/root.zig\n", .{ all_templates.count(), output_path });
|
||||
|
||||
// Set the output file path
|
||||
self.output_file.path = try fs.path.join(allocator, &.{ output_path, "root.zig" });
|
||||
}
|
||||
|
||||
pub fn getOutput(self: *CompileStep) Build.LazyPath {
|
||||
return .{ .generated = .{ .file = &self.output_file } };
|
||||
}
|
||||
};
|
||||
|
||||
fn compileDirectory(
|
||||
allocator: mem.Allocator,
|
||||
arena_allocator: mem.Allocator,
|
||||
input_dir: []const u8,
|
||||
views_root: []const u8,
|
||||
output_dir: []const u8,
|
||||
template_map: *std.StringHashMap([]const u8),
|
||||
) !void {
|
||||
// Find all .pug files recursively
|
||||
const pug_files = try findPugFiles(arena_allocator, input_dir);
|
||||
|
||||
// Initialize ViewEngine with views_root for resolving includes/extends
|
||||
var engine = view_engine.ViewEngine.init(.{
|
||||
.views_dir = views_root,
|
||||
});
|
||||
defer engine.deinit();
|
||||
|
||||
// Initialize mixin registry
|
||||
var registry = mixin.MixinRegistry.init(arena_allocator);
|
||||
defer registry.deinit();
|
||||
|
||||
// Compile each file
|
||||
for (pug_files) |pug_file| {
|
||||
compileSingleFile(
|
||||
allocator,
|
||||
arena_allocator,
|
||||
&engine,
|
||||
®istry,
|
||||
pug_file,
|
||||
views_root,
|
||||
output_dir,
|
||||
template_map,
|
||||
) catch |err| {
|
||||
std.debug.print(" ERROR: Failed to compile {s}: {}\n", .{ pug_file, err });
|
||||
continue;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn compileSingleFile(
|
||||
allocator: mem.Allocator,
|
||||
arena_allocator: mem.Allocator,
|
||||
engine: *view_engine.ViewEngine,
|
||||
registry: *mixin.MixinRegistry,
|
||||
pug_file: []const u8,
|
||||
views_root: []const u8,
|
||||
output_dir: []const u8,
|
||||
template_map: *std.StringHashMap([]const u8),
|
||||
) !void {
|
||||
// Get relative path from views_root (for template resolution)
|
||||
const views_rel = if (mem.startsWith(u8, pug_file, views_root))
|
||||
pug_file[views_root.len..]
|
||||
else
|
||||
pug_file;
|
||||
|
||||
// Skip leading slash
|
||||
const trimmed_views = if (views_rel.len > 0 and views_rel[0] == '/')
|
||||
views_rel[1..]
|
||||
else
|
||||
views_rel;
|
||||
|
||||
// Remove .pug extension for template name (used by ViewEngine)
|
||||
const template_name = if (mem.endsWith(u8, trimmed_views, ".pug"))
|
||||
trimmed_views[0 .. trimmed_views.len - 4]
|
||||
else
|
||||
trimmed_views;
|
||||
|
||||
// Parse template with full resolution
|
||||
const final_ast = try engine.parseWithIncludes(arena_allocator, template_name, registry);
|
||||
|
||||
// Extract field names
|
||||
const fields = try zig_codegen.extractFieldNames(arena_allocator, final_ast);
|
||||
|
||||
// Generate Zig code
|
||||
var codegen = zig_codegen.Codegen.init(arena_allocator);
|
||||
defer codegen.deinit();
|
||||
|
||||
const zig_code = try codegen.generate(final_ast, "render", fields);
|
||||
|
||||
// Create flat filename from views-relative path to avoid collisions
|
||||
// e.g., "pages/404.pug" → "pages_404.zig"
|
||||
const flat_name = try makeFlatFileName(allocator, trimmed_views);
|
||||
defer allocator.free(flat_name);
|
||||
|
||||
const output_path = try fs.path.join(allocator, &.{ output_dir, flat_name });
|
||||
defer allocator.free(output_path);
|
||||
|
||||
try fs.cwd().writeFile(.{ .sub_path = output_path, .data = zig_code });
|
||||
|
||||
// Track for root.zig (use same naming convention for both)
|
||||
const name = try makeTemplateName(allocator, trimmed_views);
|
||||
const output_copy = try allocator.dupe(u8, flat_name);
|
||||
try template_map.put(name, output_copy);
|
||||
}
|
||||
|
||||
fn findPugFiles(allocator: mem.Allocator, dir_path: []const u8) ![][]const u8 {
|
||||
var results: std.ArrayListUnmanaged([]const u8) = .{};
|
||||
errdefer {
|
||||
for (results.items) |item| allocator.free(item);
|
||||
results.deinit(allocator);
|
||||
}
|
||||
|
||||
try findPugFilesRecursive(allocator, dir_path, &results);
|
||||
return results.toOwnedSlice(allocator);
|
||||
}
|
||||
|
||||
fn findPugFilesRecursive(allocator: mem.Allocator, dir_path: []const u8, results: *std.ArrayListUnmanaged([]const u8)) !void {
|
||||
var dir = try fs.cwd().openDir(dir_path, .{ .iterate = true });
|
||||
defer dir.close();
|
||||
|
||||
var iter = dir.iterate();
|
||||
while (try iter.next()) |entry| {
|
||||
const full_path = try fs.path.join(allocator, &.{ dir_path, entry.name });
|
||||
errdefer allocator.free(full_path);
|
||||
|
||||
switch (entry.kind) {
|
||||
.file => {
|
||||
if (mem.endsWith(u8, entry.name, ".pug")) {
|
||||
try results.append(allocator, full_path);
|
||||
} else {
|
||||
allocator.free(full_path);
|
||||
}
|
||||
},
|
||||
.directory => {
|
||||
try findPugFilesRecursive(allocator, full_path, results);
|
||||
allocator.free(full_path);
|
||||
},
|
||||
else => {
|
||||
allocator.free(full_path);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn makeTemplateName(allocator: mem.Allocator, path: []const u8) ![]const u8 {
|
||||
const without_ext = if (mem.endsWith(u8, path, ".pug"))
|
||||
path[0 .. path.len - 4]
|
||||
else
|
||||
path;
|
||||
|
||||
var result: std.ArrayListUnmanaged(u8) = .{};
|
||||
defer result.deinit(allocator);
|
||||
|
||||
for (without_ext) |c| {
|
||||
if (c == '/' or c == '-' or c == '.') {
|
||||
try result.append(allocator, '_');
|
||||
} else {
|
||||
try result.append(allocator, c);
|
||||
}
|
||||
}
|
||||
|
||||
return result.toOwnedSlice(allocator);
|
||||
}
|
||||
|
||||
fn makeFlatFileName(allocator: mem.Allocator, path: []const u8) ![]const u8 {
|
||||
// Convert "pages/404.pug" → "pages_404.zig"
|
||||
const without_ext = if (mem.endsWith(u8, path, ".pug"))
|
||||
path[0 .. path.len - 4]
|
||||
else
|
||||
path;
|
||||
|
||||
var result: std.ArrayListUnmanaged(u8) = .{};
|
||||
defer result.deinit(allocator);
|
||||
|
||||
for (without_ext) |c| {
|
||||
if (c == '/' or c == '-') {
|
||||
try result.append(allocator, '_');
|
||||
} else {
|
||||
try result.append(allocator, c);
|
||||
}
|
||||
}
|
||||
|
||||
try result.appendSlice(allocator, ".zig");
|
||||
|
||||
return result.toOwnedSlice(allocator);
|
||||
}
|
||||
|
||||
fn generateRootZig(allocator: mem.Allocator, output_dir: []const u8, template_map: *std.StringHashMap([]const u8)) !void {
|
||||
var output: std.ArrayListUnmanaged(u8) = .{};
|
||||
defer output.deinit(allocator);
|
||||
|
||||
try output.appendSlice(allocator, "// Auto-generated by Pugz build step\n");
|
||||
try output.appendSlice(allocator, "// This file exports all compiled templates\n\n");
|
||||
|
||||
// Sort template names
|
||||
var names: std.ArrayListUnmanaged([]const u8) = .{};
|
||||
defer names.deinit(allocator);
|
||||
|
||||
var iter = template_map.keyIterator();
|
||||
while (iter.next()) |key| {
|
||||
try names.append(allocator, key.*);
|
||||
}
|
||||
|
||||
std.mem.sort([]const u8, names.items, {}, struct {
|
||||
fn lessThan(_: void, a: []const u8, b: []const u8) bool {
|
||||
return std.mem.lessThan(u8, a, b);
|
||||
}
|
||||
}.lessThan);
|
||||
|
||||
// Generate exports
|
||||
for (names.items) |name| {
|
||||
const file_path = template_map.get(name).?;
|
||||
// file_path is already the flat filename like "pages_404.zig"
|
||||
const import_path = file_path[0 .. file_path.len - 4]; // Remove .zig to get "pages_404"
|
||||
|
||||
try output.appendSlice(allocator, "pub const ");
|
||||
try output.appendSlice(allocator, name);
|
||||
try output.appendSlice(allocator, " = @import(\"");
|
||||
try output.appendSlice(allocator, import_path);
|
||||
try output.appendSlice(allocator, ".zig\");\n");
|
||||
}
|
||||
|
||||
const root_path = try fs.path.join(allocator, &.{ output_dir, "root.zig" });
|
||||
defer allocator.free(root_path);
|
||||
|
||||
try fs.cwd().writeFile(.{ .sub_path = root_path, .data = output.items });
|
||||
}
|
||||
|
||||
fn copyHelpersZig(allocator: mem.Allocator, output_dir: []const u8) !void {
|
||||
const helpers_source = @embedFile("tpl_compiler/helpers_template.zig");
|
||||
const output_path = try fs.path.join(allocator, &.{ output_dir, "helpers.zig" });
|
||||
defer allocator.free(output_path);
|
||||
|
||||
try fs.cwd().writeFile(.{ .sub_path = output_path, .data = helpers_source });
|
||||
}
|
||||
|
||||
/// Convenience function to add a compile step to the build
|
||||
pub fn addCompileStep(b: *Build, options: CompileOptions) *CompileStep {
|
||||
return CompileStep.create(b, options);
|
||||
}
|
||||
@@ -131,6 +131,7 @@ pub const Token = struct {
|
||||
key: TokenValue = .none, // string for each
|
||||
code: TokenValue = .none, // string for each/eachOf
|
||||
name: TokenValue = .none, // string for attribute
|
||||
quoted: TokenValue = .none, // boolean for attribute values (true if originally quoted)
|
||||
|
||||
/// Helper to get val as string
|
||||
pub fn getVal(self: Token) ?[]const u8 {
|
||||
@@ -147,6 +148,11 @@ pub const Token = struct {
|
||||
return self.must_escape.getBool() orelse true;
|
||||
}
|
||||
|
||||
/// Helper to check if value was originally quoted
|
||||
pub fn isQuoted(self: Token) bool {
|
||||
return self.quoted.getBool() orelse false;
|
||||
}
|
||||
|
||||
/// Helper to get mode as string
|
||||
pub fn getMode(self: Token) ?[]const u8 {
|
||||
return self.mode.getString();
|
||||
@@ -2182,8 +2188,21 @@ pub const Lexer = struct {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
attr_token.val = TokenValue.fromString(str[val_start..i]);
|
||||
// Strip outer quotes from attribute value if present
|
||||
var val_str = str[val_start..i];
|
||||
var was_quoted = false;
|
||||
if (val_str.len >= 2) {
|
||||
const first = val_str[0];
|
||||
const last = val_str[val_str.len - 1];
|
||||
if ((first == '"' and last == '"') or (first == '\'' and last == '\'')) {
|
||||
val_str = val_str[1 .. val_str.len - 1];
|
||||
was_quoted = true;
|
||||
}
|
||||
}
|
||||
|
||||
attr_token.val = TokenValue.fromString(val_str);
|
||||
attr_token.must_escape = TokenValue.fromBool(must_escape);
|
||||
attr_token.quoted = TokenValue.fromBool(was_quoted);
|
||||
} else {
|
||||
// Boolean attribute
|
||||
attr_token.val = TokenValue.fromBool(true);
|
||||
|
||||
@@ -579,3 +579,22 @@ test "evaluateStringConcat - basic" {
|
||||
defer allocator.free(result2);
|
||||
try std.testing.expectEqualStrings("btn btn-primary", result2);
|
||||
}
|
||||
|
||||
test "bindArguments - with default value in param" {
|
||||
const allocator = std.testing.allocator;
|
||||
|
||||
var bindings = std.StringHashMapUnmanaged([]const u8){};
|
||||
defer bindings.deinit(allocator);
|
||||
|
||||
// This is how it appears: params have default, args are the call args
|
||||
try bindArguments(allocator, "text, type=\"primary\"", "\"Click Me\", \"primary\"", &bindings);
|
||||
|
||||
std.debug.print("\nBindings:\n", .{});
|
||||
var iter = bindings.iterator();
|
||||
while (iter.next()) |entry| {
|
||||
std.debug.print(" {s} = '{s}'\n", .{ entry.key_ptr.*, entry.value_ptr.* });
|
||||
}
|
||||
|
||||
try std.testing.expectEqualStrings("Click Me", bindings.get("text").?);
|
||||
try std.testing.expectEqualStrings("primary", bindings.get("type").?);
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ pub const Attribute = struct {
|
||||
filename: ?[]const u8,
|
||||
must_escape: bool,
|
||||
val_owned: bool = false, // true if val was allocated and needs to be freed
|
||||
quoted: bool = false, // true if val was originally quoted (static string)
|
||||
};
|
||||
|
||||
pub const AttributeBlock = struct {
|
||||
@@ -1425,14 +1426,9 @@ pub const Parser = struct {
|
||||
}
|
||||
try attribute_names.append(self.allocator, "id");
|
||||
}
|
||||
// Create quoted value
|
||||
// Class/id values from shorthand are always static strings
|
||||
const val_str = tok.val.getString() orelse "";
|
||||
var quoted_val = std.ArrayListUnmanaged(u8){};
|
||||
defer quoted_val.deinit(self.allocator);
|
||||
try quoted_val.append(self.allocator, '\'');
|
||||
try quoted_val.appendSlice(self.allocator, val_str);
|
||||
try quoted_val.append(self.allocator, '\'');
|
||||
const final_val = try self.allocator.dupe(u8, quoted_val.items);
|
||||
const final_val = try self.allocator.dupe(u8, val_str);
|
||||
|
||||
try tag.attrs.append(self.allocator, .{
|
||||
.name = if (tok.type == .id) "id" else "class",
|
||||
@@ -1442,6 +1438,7 @@ pub const Parser = struct {
|
||||
.filename = self.filename,
|
||||
.must_escape = false,
|
||||
.val_owned = true, // We allocated this string
|
||||
.quoted = true, // Shorthand class/id are always static
|
||||
});
|
||||
},
|
||||
.start_attributes => {
|
||||
@@ -1573,6 +1570,7 @@ pub const Parser = struct {
|
||||
.column = tok.loc.start.column,
|
||||
.filename = self.filename,
|
||||
.must_escape = tok.shouldEscape(),
|
||||
.quoted = tok.isQuoted(),
|
||||
});
|
||||
tok = self.advance();
|
||||
}
|
||||
|
||||
21
src/root.zig
21
src/root.zig
@@ -5,10 +5,21 @@
|
||||
// const engine = pugz.ViewEngine.init(.{ .views_dir = "views" });
|
||||
// const html = try engine.render(allocator, "index", .{ .title = "Home" });
|
||||
|
||||
const builtin = @import("builtin");
|
||||
|
||||
pub const pug = @import("pug.zig");
|
||||
pub const view_engine = @import("view_engine.zig");
|
||||
pub const template = @import("template.zig");
|
||||
pub const parser = @import("parser.zig");
|
||||
pub const mixin = @import("mixin.zig");
|
||||
pub const runtime = @import("runtime.zig");
|
||||
pub const codegen = @import("codegen.zig");
|
||||
|
||||
// Build step for compiling templates (only available in build scripts)
|
||||
pub const compile_tpls = if (builtin.is_test or @import("builtin").output_mode == .Obj)
|
||||
void
|
||||
else
|
||||
@import("compile_tpls.zig");
|
||||
|
||||
// Re-export main types
|
||||
pub const ViewEngine = view_engine.ViewEngine;
|
||||
@@ -22,3 +33,13 @@ pub const CompileError = pug.CompileError;
|
||||
|
||||
// Convenience function for inline templates with data
|
||||
pub const renderTemplate = template.renderWithData;
|
||||
|
||||
// Build step convenience exports (only available in build context)
|
||||
pub const addCompileStep = if (@TypeOf(compile_tpls) == type and compile_tpls != void)
|
||||
compile_tpls.addCompileStep
|
||||
else
|
||||
void;
|
||||
pub const CompileTplsOptions = if (@TypeOf(compile_tpls) == type and compile_tpls != void)
|
||||
compile_tpls.CompileOptions
|
||||
else
|
||||
void;
|
||||
|
||||
308
src/tests/benchmarks/bench.zig
Normal file
308
src/tests/benchmarks/bench.zig
Normal file
@@ -0,0 +1,308 @@
|
||||
//! Pugz Benchmark - Template Rendering
|
||||
//!
|
||||
//! Three benchmark modes (best of 5 runs each):
|
||||
//! 1. Cached AST: Parse once, render many times (matches Pug.js behavior)
|
||||
//! 2. No Cache: Parse + render on every iteration
|
||||
//! 3. Compiled: Pre-compiled templates to Zig code (zero parse overhead)
|
||||
//!
|
||||
//! Run: zig build bench
|
||||
|
||||
const std = @import("std");
|
||||
const pugz = @import("pugz");
|
||||
const compiled = @import("bench_compiled");
|
||||
|
||||
const iterations: usize = 2000;
|
||||
const runs: usize = 5; // Best of 5
|
||||
const templates_dir = "benchmarks/templates";
|
||||
|
||||
// Data structures matching JSON files
|
||||
const SubFriend = struct {
|
||||
id: i64,
|
||||
name: []const u8,
|
||||
};
|
||||
|
||||
const Friend = struct {
|
||||
name: []const u8,
|
||||
balance: []const u8,
|
||||
age: i64,
|
||||
address: []const u8,
|
||||
picture: []const u8,
|
||||
company: []const u8,
|
||||
email: []const u8,
|
||||
emailHref: []const u8,
|
||||
about: []const u8,
|
||||
tags: []const []const u8,
|
||||
friends: []const SubFriend,
|
||||
};
|
||||
|
||||
const Account = struct {
|
||||
balance: i64,
|
||||
balanceFormatted: []const u8,
|
||||
status: []const u8,
|
||||
negative: bool,
|
||||
};
|
||||
|
||||
const Project = struct {
|
||||
name: []const u8,
|
||||
url: []const u8,
|
||||
description: []const u8,
|
||||
};
|
||||
|
||||
const SearchRecord = struct {
|
||||
imgUrl: []const u8,
|
||||
viewItemUrl: []const u8,
|
||||
title: []const u8,
|
||||
description: []const u8,
|
||||
featured: bool,
|
||||
sizes: ?[]const []const u8,
|
||||
};
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
defer _ = gpa.deinit();
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
// Load JSON data
|
||||
var data_arena = std.heap.ArenaAllocator.init(allocator);
|
||||
defer data_arena.deinit();
|
||||
const data_alloc = data_arena.allocator();
|
||||
|
||||
const simple0 = try loadJson(struct { name: []const u8 }, data_alloc, "simple-0.json");
|
||||
const simple1 = try loadJson(struct {
|
||||
name: []const u8,
|
||||
messageCount: i64,
|
||||
colors: []const []const u8,
|
||||
primary: bool,
|
||||
}, data_alloc, "simple-1.json");
|
||||
const simple2 = try loadJson(struct {
|
||||
header: []const u8,
|
||||
header2: []const u8,
|
||||
header3: []const u8,
|
||||
header4: []const u8,
|
||||
header5: []const u8,
|
||||
header6: []const u8,
|
||||
list: []const []const u8,
|
||||
}, data_alloc, "simple-2.json");
|
||||
const if_expr = try loadJson(struct { accounts: []const Account }, data_alloc, "if-expression.json");
|
||||
const projects = try loadJson(struct {
|
||||
title: []const u8,
|
||||
text: []const u8,
|
||||
projects: []const Project,
|
||||
}, data_alloc, "projects-escaped.json");
|
||||
const search = try loadJson(struct { searchRecords: []const SearchRecord }, data_alloc, "search-results.json");
|
||||
const friends_data = try loadJson(struct { friends: []const Friend }, data_alloc, "friends.json");
|
||||
|
||||
// Load template sources
|
||||
const simple0_tpl = try loadTemplate(data_alloc, "simple-0.pug");
|
||||
const simple1_tpl = try loadTemplate(data_alloc, "simple-1.pug");
|
||||
const simple2_tpl = try loadTemplate(data_alloc, "simple-2.pug");
|
||||
const if_expr_tpl = try loadTemplate(data_alloc, "if-expression.pug");
|
||||
const projects_tpl = try loadTemplate(data_alloc, "projects-escaped.pug");
|
||||
const search_tpl = try loadTemplate(data_alloc, "search-results.pug");
|
||||
const friends_tpl = try loadTemplate(data_alloc, "friends.pug");
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// Benchmark 1: Cached AST (parse once, render many)
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
std.debug.print("\n", .{});
|
||||
std.debug.print("╔═══════════════════════════════════════════════════════════════╗\n", .{});
|
||||
std.debug.print("║ Pugz Benchmark - CACHED AST ({d} iterations, best of {d}) ║\n", .{ iterations, runs });
|
||||
std.debug.print("║ Mode: Parse once, render many (like Pug.js) ║\n", .{});
|
||||
std.debug.print("╚═══════════════════════════════════════════════════════════════╝\n", .{});
|
||||
|
||||
std.debug.print("\nParsing templates...\n", .{});
|
||||
|
||||
const simple0_ast = try pugz.template.parse(data_alloc, simple0_tpl);
|
||||
const simple1_ast = try pugz.template.parse(data_alloc, simple1_tpl);
|
||||
const simple2_ast = try pugz.template.parse(data_alloc, simple2_tpl);
|
||||
const if_expr_ast = try pugz.template.parse(data_alloc, if_expr_tpl);
|
||||
const projects_ast = try pugz.template.parse(data_alloc, projects_tpl);
|
||||
const search_ast = try pugz.template.parse(data_alloc, search_tpl);
|
||||
const friends_ast = try pugz.template.parse(data_alloc, friends_tpl);
|
||||
|
||||
std.debug.print("Starting benchmark (render only)...\n\n", .{});
|
||||
|
||||
var total_cached: f64 = 0;
|
||||
total_cached += try benchCached("simple-0", allocator, simple0_ast, simple0);
|
||||
total_cached += try benchCached("simple-1", allocator, simple1_ast, simple1);
|
||||
total_cached += try benchCached("simple-2", allocator, simple2_ast, simple2);
|
||||
total_cached += try benchCached("if-expression", allocator, if_expr_ast, if_expr);
|
||||
total_cached += try benchCached("projects-escaped", allocator, projects_ast, projects);
|
||||
total_cached += try benchCached("search-results", allocator, search_ast, search);
|
||||
total_cached += try benchCached("friends", allocator, friends_ast, friends_data);
|
||||
|
||||
std.debug.print("\n", .{});
|
||||
std.debug.print(" {s:<20} => {d:>7.1}ms\n", .{ "TOTAL (cached)", total_cached });
|
||||
std.debug.print("\n", .{});
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// Benchmark 2: No Cache (parse + render every time)
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
std.debug.print("\n", .{});
|
||||
std.debug.print("╔═══════════════════════════════════════════════════════════════╗\n", .{});
|
||||
std.debug.print("║ Pugz Benchmark - NO CACHE ({d} iterations, best of {d}) ║\n", .{ iterations, runs });
|
||||
std.debug.print("║ Mode: Parse + render every iteration ║\n", .{});
|
||||
std.debug.print("╚═══════════════════════════════════════════════════════════════╝\n", .{});
|
||||
|
||||
std.debug.print("\nStarting benchmark (parse + render)...\n\n", .{});
|
||||
|
||||
var total_nocache: f64 = 0;
|
||||
total_nocache += try benchNoCache("simple-0", allocator, simple0_tpl, simple0);
|
||||
total_nocache += try benchNoCache("simple-1", allocator, simple1_tpl, simple1);
|
||||
total_nocache += try benchNoCache("simple-2", allocator, simple2_tpl, simple2);
|
||||
total_nocache += try benchNoCache("if-expression", allocator, if_expr_tpl, if_expr);
|
||||
total_nocache += try benchNoCache("projects-escaped", allocator, projects_tpl, projects);
|
||||
total_nocache += try benchNoCache("search-results", allocator, search_tpl, search);
|
||||
total_nocache += try benchNoCache("friends", allocator, friends_tpl, friends_data);
|
||||
|
||||
std.debug.print("\n", .{});
|
||||
std.debug.print(" {s:<20} => {d:>7.1}ms\n", .{ "TOTAL (no cache)", total_nocache });
|
||||
std.debug.print("\n", .{});
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// Benchmark 3: Compiled Templates (zero parse overhead)
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
std.debug.print("\n", .{});
|
||||
std.debug.print("╔═══════════════════════════════════════════════════════════════╗\n", .{});
|
||||
std.debug.print("║ Pugz Benchmark - COMPILED ({d} iterations, best of {d}) ║\n", .{ iterations, runs });
|
||||
std.debug.print("║ Mode: Pre-compiled .pug → .zig (no parse overhead) ║\n", .{});
|
||||
std.debug.print("╚═══════════════════════════════════════════════════════════════╝\n", .{});
|
||||
|
||||
std.debug.print("\nStarting benchmark (compiled templates)...\n\n", .{});
|
||||
|
||||
var total_compiled: f64 = 0;
|
||||
total_compiled += try benchCompiled("simple-0", allocator, compiled.simple_0);
|
||||
total_compiled += try benchCompiled("simple-1", allocator, compiled.simple_1);
|
||||
total_compiled += try benchCompiled("simple-2", allocator, compiled.simple_2);
|
||||
total_compiled += try benchCompiled("if-expression", allocator, compiled.if_expression);
|
||||
total_compiled += try benchCompiled("projects-escaped", allocator, compiled.projects_escaped);
|
||||
total_compiled += try benchCompiled("search-results", allocator, compiled.search_results);
|
||||
total_compiled += try benchCompiled("friends", allocator, compiled.friends);
|
||||
|
||||
std.debug.print("\n", .{});
|
||||
std.debug.print(" {s:<20} => {d:>7.1}ms\n", .{ "TOTAL (compiled)", total_compiled });
|
||||
std.debug.print("\n", .{});
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// Summary
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
std.debug.print("╔═══════════════════════════════════════════════════════════════╗\n", .{});
|
||||
std.debug.print("║ SUMMARY ║\n", .{});
|
||||
std.debug.print("╚═══════════════════════════════════════════════════════════════╝\n", .{});
|
||||
std.debug.print(" Cached AST (render only): {d:>7.1}ms\n", .{total_cached});
|
||||
std.debug.print(" No Cache (parse+render): {d:>7.1}ms\n", .{total_nocache});
|
||||
if (total_compiled > 0) {
|
||||
std.debug.print(" Compiled (zero parse): {d:>7.1}ms\n", .{total_compiled});
|
||||
}
|
||||
std.debug.print("\n", .{});
|
||||
std.debug.print(" Parse overhead: {d:>7.1}ms ({d:.1}%)\n", .{
|
||||
total_nocache - total_cached,
|
||||
((total_nocache - total_cached) / total_nocache) * 100.0,
|
||||
});
|
||||
if (total_compiled > 0) {
|
||||
std.debug.print(" Cached vs Compiled: {d:>7.1}ms ({d:.1}x faster)\n", .{
|
||||
total_cached - total_compiled,
|
||||
total_cached / total_compiled,
|
||||
});
|
||||
}
|
||||
std.debug.print("\n", .{});
|
||||
}
|
||||
|
||||
fn loadJson(comptime T: type, alloc: std.mem.Allocator, comptime filename: []const u8) !T {
|
||||
const path = templates_dir ++ "/" ++ filename;
|
||||
const content = try std.fs.cwd().readFileAlloc(alloc, path, 10 * 1024 * 1024);
|
||||
const parsed = try std.json.parseFromSlice(T, alloc, content, .{});
|
||||
return parsed.value;
|
||||
}
|
||||
|
||||
fn loadTemplate(alloc: std.mem.Allocator, comptime filename: []const u8) ![]const u8 {
|
||||
const path = templates_dir ++ "/" ++ filename;
|
||||
return try std.fs.cwd().readFileAlloc(alloc, path, 1 * 1024 * 1024);
|
||||
}
|
||||
|
||||
// Benchmark with cached AST (render only) - Best of 5 runs
|
||||
fn benchCached(
|
||||
name: []const u8,
|
||||
allocator: std.mem.Allocator,
|
||||
ast: *pugz.parser.Node,
|
||||
data: anytype,
|
||||
) !f64 {
|
||||
var arena = std.heap.ArenaAllocator.init(allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
var best_ms: f64 = std.math.inf(f64);
|
||||
|
||||
for (0..runs) |_| {
|
||||
_ = arena.reset(.retain_capacity);
|
||||
var timer = try std.time.Timer.start();
|
||||
for (0..iterations) |_| {
|
||||
_ = arena.reset(.retain_capacity);
|
||||
_ = pugz.template.renderAst(arena.allocator(), ast, data) catch |err| {
|
||||
std.debug.print(" {s:<20} => ERROR: {}\n", .{ name, err });
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
const ms = @as(f64, @floatFromInt(timer.read())) / 1_000_000.0;
|
||||
if (ms < best_ms) best_ms = ms;
|
||||
}
|
||||
|
||||
std.debug.print(" {s:<20} => {d:>7.1}ms\n", .{ name, best_ms });
|
||||
return best_ms;
|
||||
}
|
||||
|
||||
// Benchmark without cache (parse + render every iteration) - Best of 5 runs
|
||||
fn benchNoCache(
|
||||
name: []const u8,
|
||||
allocator: std.mem.Allocator,
|
||||
source: []const u8,
|
||||
data: anytype,
|
||||
) !f64 {
|
||||
var best_ms: f64 = std.math.inf(f64);
|
||||
|
||||
for (0..runs) |_| {
|
||||
var timer = try std.time.Timer.start();
|
||||
for (0..iterations) |_| {
|
||||
var arena = std.heap.ArenaAllocator.init(allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
_ = pugz.template.renderWithData(arena.allocator(), source, data) catch |err| {
|
||||
std.debug.print(" {s:<20} => ERROR: {}\n", .{ name, err });
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
const ms = @as(f64, @floatFromInt(timer.read())) / 1_000_000.0;
|
||||
if (ms < best_ms) best_ms = ms;
|
||||
}
|
||||
|
||||
std.debug.print(" {s:<20} => {d:>7.1}ms\n", .{ name, best_ms });
|
||||
return best_ms;
|
||||
}
|
||||
|
||||
// Benchmark compiled templates (zero parse overhead) - Best of 5 runs
|
||||
fn benchCompiled(
|
||||
name: []const u8,
|
||||
allocator: std.mem.Allocator,
|
||||
comptime tpl: type,
|
||||
) !f64 {
|
||||
var arena = std.heap.ArenaAllocator.init(allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
var best_ms: f64 = std.math.inf(f64);
|
||||
|
||||
for (0..runs) |_| {
|
||||
_ = arena.reset(.retain_capacity);
|
||||
var timer = try std.time.Timer.start();
|
||||
for (0..iterations) |_| {
|
||||
_ = arena.reset(.retain_capacity);
|
||||
_ = tpl.render(arena.allocator(), .{}) catch |err| {
|
||||
std.debug.print(" {s:<20} => ERROR: {}\n", .{ name, err });
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
const ms = @as(f64, @floatFromInt(timer.read())) / 1_000_000.0;
|
||||
if (ms < best_ms) best_ms = ms;
|
||||
}
|
||||
|
||||
std.debug.print(" {s:<20} => {d:>7.1}ms\n", .{ name, best_ms });
|
||||
return best_ms;
|
||||
}
|
||||
91
src/tests/benchmarks/pugjs/bench.js
Normal file
91
src/tests/benchmarks/pugjs/bench.js
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* Pug.js Benchmark - Comparison with Pugz
|
||||
*
|
||||
* Run: npm install && npm run bench
|
||||
*
|
||||
* Both Pug.js and Pugz benchmarks read from the same files:
|
||||
* ../templates/*.pug (templates)
|
||||
* ../templates/*.json (data)
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const pug = require('pug');
|
||||
|
||||
const iterations = 2000;
|
||||
const templatesDir = path.join(__dirname, '..', 'templates');
|
||||
|
||||
const benchmarks = [
|
||||
'simple-0',
|
||||
'simple-1',
|
||||
'simple-2',
|
||||
'if-expression',
|
||||
'projects-escaped',
|
||||
'search-results',
|
||||
'friends',
|
||||
];
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// Load templates and data from shared files BEFORE benchmarking
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
console.log("");
|
||||
console.log("Loading templates and data...");
|
||||
|
||||
const templates = {};
|
||||
const data = {};
|
||||
|
||||
for (const name of benchmarks) {
|
||||
templates[name] = fs.readFileSync(path.join(templatesDir, `${name}.pug`), 'utf8');
|
||||
data[name] = JSON.parse(fs.readFileSync(path.join(templatesDir, `${name}.json`), 'utf8'));
|
||||
}
|
||||
|
||||
// Compile all templates BEFORE benchmarking
|
||||
const compiled = {};
|
||||
for (const name of benchmarks) {
|
||||
compiled[name] = pug.compile(templates[name], { pretty: true });
|
||||
}
|
||||
|
||||
console.log("Templates compiled. Starting benchmark...\n");
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// Benchmark (Best of 5 runs)
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
console.log("╔═══════════════════════════════════════════════════════════════╗");
|
||||
console.log(`║ Pug.js Benchmark (${iterations} iterations, best of 5) ║`);
|
||||
console.log("║ Templates: benchmarks/templates/*.pug ║");
|
||||
console.log("║ Data: benchmarks/templates/*.json ║");
|
||||
console.log("╚═══════════════════════════════════════════════════════════════╝");
|
||||
|
||||
const runs = 5;
|
||||
let total = 0;
|
||||
|
||||
for (const name of benchmarks) {
|
||||
const compiledFn = compiled[name];
|
||||
const templateData = data[name];
|
||||
|
||||
// Warmup
|
||||
for (let i = 0; i < 100; i++) {
|
||||
compiledFn(templateData);
|
||||
}
|
||||
|
||||
// Run 5 times and take best
|
||||
let bestMs = Infinity;
|
||||
for (let run = 0; run < runs; run++) {
|
||||
const start = process.hrtime.bigint();
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
compiledFn(templateData);
|
||||
}
|
||||
const end = process.hrtime.bigint();
|
||||
const ms = Number(end - start) / 1_000_000;
|
||||
if (ms < bestMs) bestMs = ms;
|
||||
}
|
||||
|
||||
total += bestMs;
|
||||
console.log(` ${name.padEnd(20)} => ${bestMs.toFixed(1).padStart(7)}ms`);
|
||||
}
|
||||
|
||||
console.log("");
|
||||
console.log(` ${"TOTAL".padEnd(20)} => ${total.toFixed(1).padStart(7)}ms`);
|
||||
console.log("");
|
||||
576
src/tests/benchmarks/pugjs/package-lock.json
generated
Normal file
576
src/tests/benchmarks/pugjs/package-lock.json
generated
Normal file
@@ -0,0 +1,576 @@
|
||||
{
|
||||
"name": "pugjs-benchmark",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pugjs-benchmark",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"pug": "^3.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-string-parser": {
|
||||
"version": "7.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
|
||||
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-identifier": {
|
||||
"version": "7.28.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
|
||||
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz",
|
||||
"integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.28.6"
|
||||
},
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz",
|
||||
"integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.27.1",
|
||||
"@babel/helper-validator-identifier": "^7.28.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "7.4.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
||||
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/asap": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
|
||||
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/assert-never": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.4.0.tgz",
|
||||
"integrity": "sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/babel-walk": {
|
||||
"version": "3.0.0-canary-5",
|
||||
"resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz",
|
||||
"integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.9.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bind-apply-helpers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bound": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
|
||||
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
"get-intrinsic": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/character-parser": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz",
|
||||
"integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-regex": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/constantinople": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz",
|
||||
"integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.6.0",
|
||||
"@babel/types": "^7.6.1"
|
||||
}
|
||||
},
|
||||
"node_modules/doctypes": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz",
|
||||
"integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
"es-define-property": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.1.1",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-proto": "^1.0.1",
|
||||
"gopd": "^1.2.0",
|
||||
"has-symbols": "^1.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"math-intrinsics": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-tostringtag": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/is-core-module": {
|
||||
"version": "2.16.1",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
||||
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"hasown": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-expression": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz",
|
||||
"integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"acorn": "^7.1.1",
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/is-promise": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
|
||||
"integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-regex": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
|
||||
"integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"gopd": "^1.2.0",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"hasown": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/js-stringify": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz",
|
||||
"integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/jstransformer": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz",
|
||||
"integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-promise": "^2.0.0",
|
||||
"promise": "^7.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/path-parse": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/promise": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
|
||||
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asap": "~2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/pug": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/pug/-/pug-3.0.3.tgz",
|
||||
"integrity": "sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pug-code-gen": "^3.0.3",
|
||||
"pug-filters": "^4.0.0",
|
||||
"pug-lexer": "^5.0.1",
|
||||
"pug-linker": "^4.0.0",
|
||||
"pug-load": "^3.0.0",
|
||||
"pug-parser": "^6.0.0",
|
||||
"pug-runtime": "^3.0.1",
|
||||
"pug-strip-comments": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pug-attrs": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz",
|
||||
"integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"constantinople": "^4.0.1",
|
||||
"js-stringify": "^1.0.2",
|
||||
"pug-runtime": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pug-code-gen": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.3.tgz",
|
||||
"integrity": "sha512-cYQg0JW0w32Ux+XTeZnBEeuWrAY7/HNE6TWnhiHGnnRYlCgyAUPoyh9KzCMa9WhcJlJ1AtQqpEYHc+vbCzA+Aw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"constantinople": "^4.0.1",
|
||||
"doctypes": "^1.1.0",
|
||||
"js-stringify": "^1.0.2",
|
||||
"pug-attrs": "^3.0.0",
|
||||
"pug-error": "^2.1.0",
|
||||
"pug-runtime": "^3.0.1",
|
||||
"void-elements": "^3.1.0",
|
||||
"with": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pug-error": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.1.0.tgz",
|
||||
"integrity": "sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pug-filters": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz",
|
||||
"integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"constantinople": "^4.0.1",
|
||||
"jstransformer": "1.0.0",
|
||||
"pug-error": "^2.0.0",
|
||||
"pug-walk": "^2.0.0",
|
||||
"resolve": "^1.15.1"
|
||||
}
|
||||
},
|
||||
"node_modules/pug-lexer": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz",
|
||||
"integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"character-parser": "^2.2.0",
|
||||
"is-expression": "^4.0.0",
|
||||
"pug-error": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pug-linker": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz",
|
||||
"integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pug-error": "^2.0.0",
|
||||
"pug-walk": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pug-load": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz",
|
||||
"integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"object-assign": "^4.1.1",
|
||||
"pug-walk": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pug-parser": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz",
|
||||
"integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pug-error": "^2.0.0",
|
||||
"token-stream": "1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pug-runtime": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz",
|
||||
"integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pug-strip-comments": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz",
|
||||
"integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pug-error": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pug-walk": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz",
|
||||
"integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.11",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
|
||||
"integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.16.1",
|
||||
"path-parse": "^1.0.7",
|
||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"resolve": "bin/resolve"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-preserve-symlinks-flag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/token-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/void-elements": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
|
||||
"integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/with": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz",
|
||||
"integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.9.6",
|
||||
"@babel/types": "^7.9.6",
|
||||
"assert-never": "^1.2.1",
|
||||
"babel-walk": "3.0.0-canary-5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
src/tests/benchmarks/pugjs/package.json
Normal file
12
src/tests/benchmarks/pugjs/package.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "pugjs-benchmark",
|
||||
"version": "1.0.0",
|
||||
"description": "Pug.js benchmark for comparison with Pugz",
|
||||
"main": "bench.js",
|
||||
"scripts": {
|
||||
"bench": "node bench.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"pug": "^3.0.3"
|
||||
}
|
||||
}
|
||||
3064
src/tests/benchmarks/templates/friends.json
Normal file
3064
src/tests/benchmarks/templates/friends.json
Normal file
File diff suppressed because it is too large
Load Diff
30
src/tests/benchmarks/templates/friends.pug
Normal file
30
src/tests/benchmarks/templates/friends.pug
Normal file
@@ -0,0 +1,30 @@
|
||||
doctype html
|
||||
html(lang="en")
|
||||
head
|
||||
meta(charset="UTF-8")
|
||||
title Friends
|
||||
body
|
||||
div.friends
|
||||
each friend in friends
|
||||
div.friend
|
||||
ul
|
||||
li Name: #{friend.name}
|
||||
li Balance: #{friend.balance}
|
||||
li Age: #{friend.age}
|
||||
li Address: #{friend.address}
|
||||
li Image:
|
||||
img(src=friend.picture)
|
||||
li Company: #{friend.company}
|
||||
li Email:
|
||||
a(href=friend.emailHref) #{friend.email}
|
||||
li About: #{friend.about}
|
||||
if friend.tags
|
||||
li Tags:
|
||||
ul
|
||||
each tag in friend.tags
|
||||
li #{tag}
|
||||
if friend.friends
|
||||
li Friends:
|
||||
ul
|
||||
each subFriend in friend.friends
|
||||
li #{subFriend.name} (#{subFriend.id})
|
||||
28
src/tests/benchmarks/templates/if-expression.json
Normal file
28
src/tests/benchmarks/templates/if-expression.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"accounts": [
|
||||
{
|
||||
"balance": 0,
|
||||
"balanceFormatted": "$0.00",
|
||||
"status": "open",
|
||||
"negative": false
|
||||
},
|
||||
{
|
||||
"balance": 10,
|
||||
"balanceFormatted": "$10.00",
|
||||
"status": "closed",
|
||||
"negative": false
|
||||
},
|
||||
{
|
||||
"balance": -100,
|
||||
"balanceFormatted": "$-100.00",
|
||||
"status": "suspended",
|
||||
"negative": true
|
||||
},
|
||||
{
|
||||
"balance": 999,
|
||||
"balanceFormatted": "$999.00",
|
||||
"status": "open",
|
||||
"negative": false
|
||||
}
|
||||
]
|
||||
}
|
||||
13
src/tests/benchmarks/templates/if-expression.pug
Normal file
13
src/tests/benchmarks/templates/if-expression.pug
Normal file
@@ -0,0 +1,13 @@
|
||||
each account in accounts
|
||||
div
|
||||
if account.status == "closed"
|
||||
div Your account has been closed!
|
||||
if account.status == "suspended"
|
||||
div Your account has been temporarily suspended
|
||||
if account.status == "open"
|
||||
div
|
||||
| Bank balance:
|
||||
if account.negative
|
||||
span.negative= account.balanceFormatted
|
||||
else
|
||||
span.positive= account.balanceFormatted
|
||||
41
src/tests/benchmarks/templates/projects-escaped.json
Normal file
41
src/tests/benchmarks/templates/projects-escaped.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"title": "Projects",
|
||||
"text": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>",
|
||||
"projects": [
|
||||
{
|
||||
"name": "<strong>Facebook</strong>",
|
||||
"url": "http://facebook.com",
|
||||
"description": "Social network"
|
||||
},
|
||||
{
|
||||
"name": "<strong>Google</strong>",
|
||||
"url": "http://google.com",
|
||||
"description": "Search engine"
|
||||
},
|
||||
{
|
||||
"name": "<strong>Twitter</strong>",
|
||||
"url": "http://twitter.com",
|
||||
"description": "Microblogging service"
|
||||
},
|
||||
{
|
||||
"name": "<strong>Amazon</strong>",
|
||||
"url": "http://amazon.com",
|
||||
"description": "Online retailer"
|
||||
},
|
||||
{
|
||||
"name": "<strong>eBay</strong>",
|
||||
"url": "http://ebay.com",
|
||||
"description": "Online auction"
|
||||
},
|
||||
{
|
||||
"name": "<strong>Wikipedia</strong>",
|
||||
"url": "http://wikipedia.org",
|
||||
"description": "A free encyclopedia"
|
||||
},
|
||||
{
|
||||
"name": "<strong>LiveJournal</strong>",
|
||||
"url": "http://livejournal.com",
|
||||
"description": "Blogging platform"
|
||||
}
|
||||
]
|
||||
}
|
||||
11
src/tests/benchmarks/templates/projects-escaped.pug
Normal file
11
src/tests/benchmarks/templates/projects-escaped.pug
Normal file
@@ -0,0 +1,11 @@
|
||||
doctype html
|
||||
html
|
||||
head
|
||||
title #{title}
|
||||
body
|
||||
p #{text}
|
||||
each project in projects
|
||||
a(href=project.url) #{project.name}
|
||||
p #{project.description}
|
||||
else
|
||||
p No projects
|
||||
278
src/tests/benchmarks/templates/search-results.json
Normal file
278
src/tests/benchmarks/templates/search-results.json
Normal file
@@ -0,0 +1,278 @@
|
||||
{
|
||||
"searchRecords": [
|
||||
{
|
||||
"imgUrl": "img1.jpg",
|
||||
"viewItemUrl": "http://foo/1",
|
||||
"title": "Namebox",
|
||||
"description": "Duis laborum nostrud consectetur exercitation minim ad laborum velit adipisicing.",
|
||||
"featured": true,
|
||||
"sizes": [
|
||||
"S",
|
||||
"M",
|
||||
"L",
|
||||
"XL",
|
||||
"XXL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"imgUrl": "img2.jpg",
|
||||
"viewItemUrl": "http://foo/2",
|
||||
"title": "Arctiq",
|
||||
"description": "Incididunt ea mollit commodo velit officia. Enim officia occaecat nulla aute.",
|
||||
"featured": false,
|
||||
"sizes": [
|
||||
"S",
|
||||
"M",
|
||||
"L",
|
||||
"XL",
|
||||
"XXL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"imgUrl": "img3.jpg",
|
||||
"viewItemUrl": "http://foo/3",
|
||||
"title": "Niquent",
|
||||
"description": "Aliquip Lorem consequat sunt ipsum dolor amet amet cupidatat deserunt eiusmod.",
|
||||
"featured": true,
|
||||
"sizes": [
|
||||
"S",
|
||||
"M",
|
||||
"L",
|
||||
"XL",
|
||||
"XXL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"imgUrl": "img4.jpg",
|
||||
"viewItemUrl": "http://foo/4",
|
||||
"title": "Remotion",
|
||||
"description": "Est ad amet irure veniam dolore velit amet irure fugiat ut elit.",
|
||||
"featured": true,
|
||||
"sizes": [
|
||||
"S",
|
||||
"M",
|
||||
"L",
|
||||
"XL",
|
||||
"XXL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"imgUrl": "img5.jpg",
|
||||
"viewItemUrl": "http://foo/5",
|
||||
"title": "Octocore",
|
||||
"description": "Sunt ex magna culpa cillum esse irure consequat Lorem aliquip enim sit.",
|
||||
"featured": true,
|
||||
"sizes": [
|
||||
"S",
|
||||
"M",
|
||||
"L",
|
||||
"XL",
|
||||
"XXL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"imgUrl": "img6.jpg",
|
||||
"viewItemUrl": "http://foo/6",
|
||||
"title": "Spherix",
|
||||
"description": "Duis laborum nostrud consectetur exercitation minim ad laborum velit adipisicing.",
|
||||
"featured": true,
|
||||
"sizes": [
|
||||
"S",
|
||||
"M",
|
||||
"L",
|
||||
"XL",
|
||||
"XXL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"imgUrl": "img7.jpg",
|
||||
"viewItemUrl": "http://foo/7",
|
||||
"title": "Quarex",
|
||||
"description": "Incididunt ea mollit commodo velit officia. Enim officia occaecat nulla aute.",
|
||||
"featured": true,
|
||||
"sizes": [
|
||||
"S",
|
||||
"M",
|
||||
"L",
|
||||
"XL",
|
||||
"XXL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"imgUrl": "img8.jpg",
|
||||
"viewItemUrl": "http://foo/8",
|
||||
"title": "Supremia",
|
||||
"description": "Aliquip Lorem consequat sunt ipsum dolor amet amet cupidatat deserunt eiusmod.",
|
||||
"featured": false,
|
||||
"sizes": [
|
||||
"S",
|
||||
"M",
|
||||
"L",
|
||||
"XL",
|
||||
"XXL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"imgUrl": "img9.jpg",
|
||||
"viewItemUrl": "http://foo/9",
|
||||
"title": "Amtap",
|
||||
"description": "Est ad amet irure veniam dolore velit amet irure fugiat ut elit.",
|
||||
"featured": false,
|
||||
"sizes": [
|
||||
"S",
|
||||
"M",
|
||||
"L",
|
||||
"XL",
|
||||
"XXL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"imgUrl": "img10.jpg",
|
||||
"viewItemUrl": "http://foo/10",
|
||||
"title": "Qiao",
|
||||
"description": "Sunt ex magna culpa cillum esse irure consequat Lorem aliquip enim sit.",
|
||||
"featured": false,
|
||||
"sizes": [
|
||||
"S",
|
||||
"M",
|
||||
"L",
|
||||
"XL",
|
||||
"XXL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"imgUrl": "img11.jpg",
|
||||
"viewItemUrl": "http://foo/11",
|
||||
"title": "Pushcart",
|
||||
"description": "Duis laborum nostrud consectetur exercitation minim ad laborum velit adipisicing.",
|
||||
"featured": true,
|
||||
"sizes": [
|
||||
"S",
|
||||
"M",
|
||||
"L",
|
||||
"XL",
|
||||
"XXL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"imgUrl": "img12.jpg",
|
||||
"viewItemUrl": "http://foo/12",
|
||||
"title": "Eweville",
|
||||
"description": "Incididunt ea mollit commodo velit officia. Enim officia occaecat nulla aute.",
|
||||
"featured": false,
|
||||
"sizes": [
|
||||
"S",
|
||||
"M",
|
||||
"L",
|
||||
"XL",
|
||||
"XXL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"imgUrl": "img13.jpg",
|
||||
"viewItemUrl": "http://foo/13",
|
||||
"title": "Senmei",
|
||||
"description": "Aliquip Lorem consequat sunt ipsum dolor amet amet cupidatat deserunt eiusmod.",
|
||||
"featured": true,
|
||||
"sizes": [
|
||||
"S",
|
||||
"M",
|
||||
"L",
|
||||
"XL",
|
||||
"XXL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"imgUrl": "img14.jpg",
|
||||
"viewItemUrl": "http://foo/14",
|
||||
"title": "Maximind",
|
||||
"description": "Est ad amet irure veniam dolore velit amet irure fugiat ut elit.",
|
||||
"featured": true,
|
||||
"sizes": [
|
||||
"S",
|
||||
"M",
|
||||
"L",
|
||||
"XL",
|
||||
"XXL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"imgUrl": "img15.jpg",
|
||||
"viewItemUrl": "http://foo/15",
|
||||
"title": "Blurrybus",
|
||||
"description": "Sunt ex magna culpa cillum esse irure consequat Lorem aliquip enim sit.",
|
||||
"featured": true,
|
||||
"sizes": [
|
||||
"S",
|
||||
"M",
|
||||
"L",
|
||||
"XL",
|
||||
"XXL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"imgUrl": "img16.jpg",
|
||||
"viewItemUrl": "http://foo/16",
|
||||
"title": "Virva",
|
||||
"description": "Duis laborum nostrud consectetur exercitation minim ad laborum velit adipisicing.",
|
||||
"featured": true,
|
||||
"sizes": [
|
||||
"S",
|
||||
"M",
|
||||
"L",
|
||||
"XL",
|
||||
"XXL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"imgUrl": "img17.jpg",
|
||||
"viewItemUrl": "http://foo/17",
|
||||
"title": "Centregy",
|
||||
"description": "Incididunt ea mollit commodo velit officia. Enim officia occaecat nulla aute.",
|
||||
"featured": true,
|
||||
"sizes": [
|
||||
"S",
|
||||
"M",
|
||||
"L",
|
||||
"XL",
|
||||
"XXL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"imgUrl": "img18.jpg",
|
||||
"viewItemUrl": "http://foo/18",
|
||||
"title": "Dancerity",
|
||||
"description": "Aliquip Lorem consequat sunt ipsum dolor amet amet cupidatat deserunt eiusmod.",
|
||||
"featured": true,
|
||||
"sizes": [
|
||||
"S",
|
||||
"M",
|
||||
"L",
|
||||
"XL",
|
||||
"XXL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"imgUrl": "img19.jpg",
|
||||
"viewItemUrl": "http://foo/19",
|
||||
"title": "Oceanica",
|
||||
"description": "Est ad amet irure veniam dolore velit amet irure fugiat ut elit.",
|
||||
"featured": true,
|
||||
"sizes": [
|
||||
"S",
|
||||
"M",
|
||||
"L",
|
||||
"XL",
|
||||
"XXL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"imgUrl": "img20.jpg",
|
||||
"viewItemUrl": "http://foo/20",
|
||||
"title": "Synkgen",
|
||||
"description": "Sunt ex magna culpa cillum esse irure consequat Lorem aliquip enim sit.",
|
||||
"featured": false,
|
||||
"sizes": null
|
||||
}
|
||||
]
|
||||
}
|
||||
17
src/tests/benchmarks/templates/search-results.pug
Normal file
17
src/tests/benchmarks/templates/search-results.pug
Normal file
@@ -0,0 +1,17 @@
|
||||
.search-results.view-gallery
|
||||
each searchRecord in searchRecords
|
||||
.search-item
|
||||
.search-item-container.drop-shadow
|
||||
.img-container
|
||||
img(src=searchRecord.imgUrl)
|
||||
h4.title
|
||||
a(href=searchRecord.viewItemUrl)= searchRecord.title
|
||||
| #{searchRecord.description}
|
||||
if searchRecord.featured
|
||||
div Featured!
|
||||
if searchRecord.sizes
|
||||
div
|
||||
| Sizes available:
|
||||
ul
|
||||
each size in searchRecord.sizes
|
||||
li= size
|
||||
3
src/tests/benchmarks/templates/simple-0.json
Normal file
3
src/tests/benchmarks/templates/simple-0.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"name": "John"
|
||||
}
|
||||
1
src/tests/benchmarks/templates/simple-0.pug
Normal file
1
src/tests/benchmarks/templates/simple-0.pug
Normal file
@@ -0,0 +1 @@
|
||||
h1 Hello, #{name}
|
||||
19
src/tests/benchmarks/templates/simple-1.json
Normal file
19
src/tests/benchmarks/templates/simple-1.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "George Washington",
|
||||
"messageCount": 999,
|
||||
"colors": [
|
||||
"red",
|
||||
"green",
|
||||
"blue",
|
||||
"yellow",
|
||||
"orange",
|
||||
"pink",
|
||||
"black",
|
||||
"white",
|
||||
"beige",
|
||||
"brown",
|
||||
"cyan",
|
||||
"magenta"
|
||||
],
|
||||
"primary": true
|
||||
}
|
||||
14
src/tests/benchmarks/templates/simple-1.pug
Normal file
14
src/tests/benchmarks/templates/simple-1.pug
Normal file
@@ -0,0 +1,14 @@
|
||||
.simple-1(style="background-color: blue; border: 1px solid black")
|
||||
.colors
|
||||
span.hello Hello #{name}!
|
||||
strong You have #{messageCount} messages!
|
||||
if colors
|
||||
ul
|
||||
each color in colors
|
||||
li.color= color
|
||||
else
|
||||
div No colors!
|
||||
if primary
|
||||
button(type="button" class="primary") Click me!
|
||||
else
|
||||
button(type="button" class="secondary") Click me!
|
||||
20
src/tests/benchmarks/templates/simple-2.json
Normal file
20
src/tests/benchmarks/templates/simple-2.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"header": "Header",
|
||||
"header2": "Header2",
|
||||
"header3": "Header3",
|
||||
"header4": "Header4",
|
||||
"header5": "Header5",
|
||||
"header6": "Header6",
|
||||
"list": [
|
||||
"1000000000",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
"10"
|
||||
]
|
||||
}
|
||||
10
src/tests/benchmarks/templates/simple-2.pug
Normal file
10
src/tests/benchmarks/templates/simple-2.pug
Normal file
@@ -0,0 +1,10 @@
|
||||
div
|
||||
h1.header #{header}
|
||||
h2.header2 #{header2}
|
||||
h3.header3 #{header3}
|
||||
h4.header4 #{header4}
|
||||
h5.header5 #{header5}
|
||||
h6.header6 #{header6}
|
||||
ul.list
|
||||
each item in list
|
||||
li.item #{item}
|
||||
6
src/tests/check_list/attrs-data.html
Normal file
6
src/tests/check_list/attrs-data.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<foo data-user="{"name":"tobi"}"></foo>
|
||||
<foo data-items="[1,2,3]"></foo>
|
||||
<foo data-username="tobi"></foo>
|
||||
<foo data-escaped="{"message":"Let's rock!"}"></foo>
|
||||
<foo data-ampersand="{"message":"a quote: &quot; this & that"}"></foo>
|
||||
<foo data-epoc="1970-01-01T00:00:00.000Z"></foo>
|
||||
7
src/tests/check_list/attrs-data.pug
Normal file
7
src/tests/check_list/attrs-data.pug
Normal file
@@ -0,0 +1,7 @@
|
||||
- var user = { name: 'tobi' }
|
||||
foo(data-user=user)
|
||||
foo(data-items=[1,2,3])
|
||||
foo(data-username='tobi')
|
||||
foo(data-escaped={message: "Let's rock!"})
|
||||
foo(data-ampersand={message: "a quote: " this & that"})
|
||||
foo(data-epoc=new Date(0))
|
||||
4
src/tests/check_list/attrs.colon.html
Normal file
4
src/tests/check_list/attrs.colon.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<div :my-var="model"></div>
|
||||
<span v-for="item in items" :key="item.id" :value="item.name"></span>
|
||||
<span v-for="item in items" :key="item.id" :value="item.name"></span>
|
||||
<a :link="goHere" value="static" :my-value="dynamic" @click="onClick()" :another="more">Click Me!</a>
|
||||
9
src/tests/check_list/attrs.colon.pug
Normal file
9
src/tests/check_list/attrs.colon.pug
Normal file
@@ -0,0 +1,9 @@
|
||||
//- Tests for using a colon-prefexed attribute (typical when using short-cut for Vue.js `v-bind`)
|
||||
div(:my-var="model")
|
||||
span(v-for="item in items" :key="item.id" :value="item.name")
|
||||
span(
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
:value="item.name"
|
||||
)
|
||||
a(:link="goHere" value="static" :my-value="dynamic" @click="onClick()" :another="more") Click Me!
|
||||
20
src/tests/check_list/attrs.html
Normal file
20
src/tests/check_list/attrs.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<a href="/contact">contact</a><a class="button" href="/save">save</a><a foo="foo" bar="bar" baz="baz"></a><a foo="foo, bar, baz" bar="1"></a><a foo="((foo))" bar="1"></a>
|
||||
<select>
|
||||
<option value="foo" selected="selected">Foo</option>
|
||||
<option selected="selected" value="bar">Bar</option>
|
||||
</select><a foo="class:"></a>
|
||||
<input pattern="\S+"/><a href="/contact">contact</a><a class="button" href="/save">save</a><a foo="foo" bar="bar" baz="baz"></a><a foo="foo, bar, baz" bar="1"></a><a foo="((foo))" bar="1"></a>
|
||||
<select>
|
||||
<option value="foo" selected="selected">Foo</option>
|
||||
<option selected="selected" value="bar">Bar</option>
|
||||
</select><a foo="class:"></a>
|
||||
<input pattern="\S+"/>
|
||||
<foo terse="true"></foo>
|
||||
<foo date="1970-01-01T00:00:00.000Z"></foo>
|
||||
<foo abc="abc" def="def"></foo>
|
||||
<foo abc="abc" def="def"></foo>
|
||||
<foo abc="abc" def="def"></foo>
|
||||
<foo abc="abc" def="def"></foo>
|
||||
<foo abc="abc" def="def"></foo>
|
||||
<foo abc="abc" def="def"></foo>
|
||||
<div foo="bar" bar="<baz>"></div><a foo="foo" bar="bar"></a><a foo="foo" bar="bar"></a>
|
||||
5
src/tests/check_list/attrs.js.html
Normal file
5
src/tests/check_list/attrs.js.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<a class="button" href="/user/5"></a><a class="button" href="/user/5"></a>
|
||||
<meta key="answer" value="42"/><a class="class1 class2"></a><a class="tag-class class1 class2"></a><a class="button" href="/user/5"></a><a class="button" href="/user/5"></a>
|
||||
<meta key="answer" value="42"/><a class="class1 class2"></a><a class="tag-class class1 class2"></a>
|
||||
<div id="5" foo="bar"></div>
|
||||
<div baz="baz"></div>
|
||||
17
src/tests/check_list/attrs.js.pug
Normal file
17
src/tests/check_list/attrs.js.pug
Normal file
@@ -0,0 +1,17 @@
|
||||
- var id = 5
|
||||
- function answer() { return 42; }
|
||||
a(href='/user/' + id, class='button')
|
||||
a(href = '/user/' + id, class = 'button')
|
||||
meta(key='answer', value=answer())
|
||||
a(class = ['class1', 'class2'])
|
||||
a.tag-class(class = ['class1', 'class2'])
|
||||
|
||||
a(href='/user/' + id class='button')
|
||||
a(href = '/user/' + id class = 'button')
|
||||
meta(key='answer' value=answer())
|
||||
a(class = ['class1', 'class2'])
|
||||
a.tag-class(class = ['class1', 'class2'])
|
||||
|
||||
div(id=id)&attributes({foo: 'bar'})
|
||||
- var bar = null
|
||||
div(foo=null bar=bar)&attributes({baz: 'baz'})
|
||||
43
src/tests/check_list/attrs.pug
Normal file
43
src/tests/check_list/attrs.pug
Normal file
@@ -0,0 +1,43 @@
|
||||
a(href='/contact') contact
|
||||
a(href='/save').button save
|
||||
a(foo, bar, baz)
|
||||
a(foo='foo, bar, baz', bar=1)
|
||||
a(foo='((foo))', bar= (1) ? 1 : 0 )
|
||||
select
|
||||
option(value='foo', selected) Foo
|
||||
option(selected, value='bar') Bar
|
||||
a(foo="class:")
|
||||
input(pattern='\\S+')
|
||||
|
||||
a(href='/contact') contact
|
||||
a(href='/save').button save
|
||||
a(foo bar baz)
|
||||
a(foo='foo, bar, baz' bar=1)
|
||||
a(foo='((foo))' bar= (1) ? 1 : 0 )
|
||||
select
|
||||
option(value='foo' selected) Foo
|
||||
option(selected value='bar') Bar
|
||||
a(foo="class:")
|
||||
input(pattern='\\S+')
|
||||
foo(terse="true")
|
||||
foo(date=new Date(0))
|
||||
|
||||
foo(abc
|
||||
,def)
|
||||
foo(abc,
|
||||
def)
|
||||
foo(abc,
|
||||
def)
|
||||
foo(abc
|
||||
,def)
|
||||
foo(abc
|
||||
def)
|
||||
foo(abc
|
||||
def)
|
||||
|
||||
- var attrs = {foo: 'bar', bar: '<baz>'}
|
||||
|
||||
div&attributes(attrs)
|
||||
|
||||
a(foo='foo' "bar"="bar")
|
||||
a(foo='foo' 'bar'='bar')
|
||||
5
src/tests/check_list/attrs.unescaped.html
Normal file
5
src/tests/check_list/attrs.unescaped.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<script type="text/x-template">
|
||||
<div id="user-<%= user.id %>">
|
||||
<h1><%= user.title %></h1>
|
||||
</div>
|
||||
</script>
|
||||
3
src/tests/check_list/attrs.unescaped.pug
Normal file
3
src/tests/check_list/attrs.unescaped.pug
Normal file
@@ -0,0 +1,3 @@
|
||||
script(type='text/x-template')
|
||||
div(id!='user-<%= user.id %>')
|
||||
h1 <%= user.title %>
|
||||
1
src/tests/check_list/auxiliary/1794-extends.pug
Normal file
1
src/tests/check_list/auxiliary/1794-extends.pug
Normal file
@@ -0,0 +1 @@
|
||||
block content
|
||||
4
src/tests/check_list/auxiliary/1794-include.pug
Normal file
4
src/tests/check_list/auxiliary/1794-include.pug
Normal file
@@ -0,0 +1,4 @@
|
||||
mixin test()
|
||||
.test&attributes(attributes)
|
||||
|
||||
+test()
|
||||
@@ -0,0 +1,8 @@
|
||||
doctype html
|
||||
html
|
||||
head
|
||||
title Default title
|
||||
body
|
||||
block body
|
||||
.container
|
||||
block content
|
||||
6
src/tests/check_list/auxiliary/dialog.pug
Normal file
6
src/tests/check_list/auxiliary/dialog.pug
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
extends window.pug
|
||||
|
||||
block window-content
|
||||
.dialog
|
||||
block content
|
||||
2
src/tests/check_list/auxiliary/empty-block.pug
Normal file
2
src/tests/check_list/auxiliary/empty-block.pug
Normal file
@@ -0,0 +1,2 @@
|
||||
block test
|
||||
|
||||
3
src/tests/check_list/auxiliary/escapes.html
Normal file
3
src/tests/check_list/auxiliary/escapes.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<script>
|
||||
console.log("foo\nbar")
|
||||
</script>
|
||||
5
src/tests/check_list/auxiliary/extends-empty-block-1.pug
Normal file
5
src/tests/check_list/auxiliary/extends-empty-block-1.pug
Normal file
@@ -0,0 +1,5 @@
|
||||
extends empty-block.pug
|
||||
|
||||
block test
|
||||
div test1
|
||||
|
||||
5
src/tests/check_list/auxiliary/extends-empty-block-2.pug
Normal file
5
src/tests/check_list/auxiliary/extends-empty-block-2.pug
Normal file
@@ -0,0 +1,5 @@
|
||||
extends empty-block.pug
|
||||
|
||||
block test
|
||||
div test2
|
||||
|
||||
4
src/tests/check_list/auxiliary/extends-from-root.pug
Normal file
4
src/tests/check_list/auxiliary/extends-from-root.pug
Normal file
@@ -0,0 +1,4 @@
|
||||
extends /auxiliary/layout.pug
|
||||
|
||||
block content
|
||||
include /auxiliary/include-from-root.pug
|
||||
4
src/tests/check_list/auxiliary/extends-relative.pug
Normal file
4
src/tests/check_list/auxiliary/extends-relative.pug
Normal file
@@ -0,0 +1,4 @@
|
||||
extends ../../cases/auxiliary/layout
|
||||
|
||||
block content
|
||||
include ../../cases/auxiliary/include-from-root
|
||||
8
src/tests/check_list/auxiliary/filter-in-include.pug
Normal file
8
src/tests/check_list/auxiliary/filter-in-include.pug
Normal file
@@ -0,0 +1,8 @@
|
||||
html
|
||||
head
|
||||
style(type="text/css")
|
||||
:less
|
||||
@pad: 15px;
|
||||
body {
|
||||
padding: @pad;
|
||||
}
|
||||
8
src/tests/check_list/auxiliary/includable.js
Normal file
8
src/tests/check_list/auxiliary/includable.js
Normal file
@@ -0,0 +1,8 @@
|
||||
var STRING_SUBSTITUTIONS = {
|
||||
// table of character substitutions
|
||||
'\t': '\\t',
|
||||
'\r': '\\r',
|
||||
'\n': '\\n',
|
||||
'"': '\\"',
|
||||
'\\': '\\\\',
|
||||
};
|
||||
1
src/tests/check_list/auxiliary/include-from-root.pug
Normal file
1
src/tests/check_list/auxiliary/include-from-root.pug
Normal file
@@ -0,0 +1 @@
|
||||
h1 hello
|
||||
@@ -0,0 +1,11 @@
|
||||
mixin article()
|
||||
article
|
||||
block
|
||||
|
||||
html
|
||||
head
|
||||
title My Application
|
||||
block head
|
||||
body
|
||||
+article
|
||||
block content
|
||||
@@ -0,0 +1,2 @@
|
||||
h1 grand-grandparent
|
||||
block grand-grandparent
|
||||
@@ -0,0 +1,6 @@
|
||||
extends inheritance.extend.recursive-grand-grandparent.pug
|
||||
|
||||
block grand-grandparent
|
||||
h2 grandparent
|
||||
block grandparent
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
extends inheritance.extend.recursive-grandparent.pug
|
||||
|
||||
block grandparent
|
||||
h3 parent
|
||||
block parent
|
||||
7
src/tests/check_list/auxiliary/layout.include.pug
Normal file
7
src/tests/check_list/auxiliary/layout.include.pug
Normal file
@@ -0,0 +1,7 @@
|
||||
html
|
||||
head
|
||||
title My Application
|
||||
block head
|
||||
body
|
||||
block content
|
||||
include window.pug
|
||||
6
src/tests/check_list/auxiliary/layout.pug
Normal file
6
src/tests/check_list/auxiliary/layout.pug
Normal file
@@ -0,0 +1,6 @@
|
||||
html
|
||||
head
|
||||
title My Application
|
||||
block head
|
||||
body
|
||||
block content
|
||||
3
src/tests/check_list/auxiliary/mixin-at-end-of-file.pug
Normal file
3
src/tests/check_list/auxiliary/mixin-at-end-of-file.pug
Normal file
@@ -0,0 +1,3 @@
|
||||
mixin slide
|
||||
section.slide
|
||||
block
|
||||
3
src/tests/check_list/auxiliary/mixins.pug
Normal file
3
src/tests/check_list/auxiliary/mixins.pug
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
mixin foo()
|
||||
p bar
|
||||
3
src/tests/check_list/auxiliary/pet.pug
Normal file
3
src/tests/check_list/auxiliary/pet.pug
Normal file
@@ -0,0 +1,3 @@
|
||||
.pet
|
||||
h1 {{name}}
|
||||
p {{name}} is a {{species}} that is {{age}} old
|
||||
1
src/tests/check_list/auxiliary/smile.html
Normal file
1
src/tests/check_list/auxiliary/smile.html
Normal file
@@ -0,0 +1 @@
|
||||
<p>:)</p>
|
||||
4
src/tests/check_list/auxiliary/window.pug
Normal file
4
src/tests/check_list/auxiliary/window.pug
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
.window
|
||||
a(href='#').close Close
|
||||
block window-content
|
||||
10
src/tests/check_list/auxiliary/yield-nested.pug
Normal file
10
src/tests/check_list/auxiliary/yield-nested.pug
Normal file
@@ -0,0 +1,10 @@
|
||||
html
|
||||
head
|
||||
title
|
||||
body
|
||||
h1 Page
|
||||
#content
|
||||
#content-wrapper
|
||||
yield
|
||||
#footer
|
||||
stuff
|
||||
5
src/tests/check_list/basic.html
Normal file
5
src/tests/check_list/basic.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
<h1>Title</h1>
|
||||
</body>
|
||||
</html>
|
||||
3
src/tests/check_list/basic.pug
Normal file
3
src/tests/check_list/basic.pug
Normal file
@@ -0,0 +1,3 @@
|
||||
html
|
||||
body
|
||||
h1 Title
|
||||
5
src/tests/check_list/blanks.html
Normal file
5
src/tests/check_list/blanks.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<ul>
|
||||
<li>foo</li>
|
||||
<li>bar</li>
|
||||
<li>baz</li>
|
||||
</ul>
|
||||
8
src/tests/check_list/blanks.pug
Normal file
8
src/tests/check_list/blanks.pug
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
ul
|
||||
li foo
|
||||
|
||||
li bar
|
||||
|
||||
li baz
|
||||
5
src/tests/check_list/block-expansion.html
Normal file
5
src/tests/check_list/block-expansion.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<ul>
|
||||
<li><a href="#">foo</a></li>
|
||||
<li><a href="#">bar</a></li>
|
||||
</ul>
|
||||
<p>baz</p>
|
||||
5
src/tests/check_list/block-expansion.pug
Normal file
5
src/tests/check_list/block-expansion.pug
Normal file
@@ -0,0 +1,5 @@
|
||||
ul
|
||||
li: a(href='#') foo
|
||||
li: a(href='#') bar
|
||||
|
||||
p baz
|
||||
5
src/tests/check_list/block-expansion.shorthands.html
Normal file
5
src/tests/check_list/block-expansion.shorthands.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<ul>
|
||||
<li class="list-item">
|
||||
<div class="foo"><div id="bar">baz</div></div>
|
||||
</li>
|
||||
</ul>
|
||||
2
src/tests/check_list/block-expansion.shorthands.pug
Normal file
2
src/tests/check_list/block-expansion.shorthands.pug
Normal file
@@ -0,0 +1,2 @@
|
||||
ul
|
||||
li.list-item: .foo: #bar baz
|
||||
4
src/tests/check_list/blockquote.html
Normal file
4
src/tests/check_list/blockquote.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<figure>
|
||||
<blockquote>Try to define yourself by what you do, and you’ll burnout every time. You are. That is enough. I rest in that.</blockquote>
|
||||
<figcaption>from @thefray at 1:43pm on May 10</figcaption>
|
||||
</figure>
|
||||
4
src/tests/check_list/blockquote.pug
Normal file
4
src/tests/check_list/blockquote.pug
Normal file
@@ -0,0 +1,4 @@
|
||||
figure
|
||||
blockquote
|
||||
| Try to define yourself by what you do, and you’ll burnout every time. You are. That is enough. I rest in that.
|
||||
figcaption from @thefray at 1:43pm on May 10
|
||||
9
src/tests/check_list/blocks-in-blocks.html
Normal file
9
src/tests/check_list/blocks-in-blocks.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Default title</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Page 2</h1>
|
||||
</body>
|
||||
</html>
|
||||
4
src/tests/check_list/blocks-in-blocks.pug
Normal file
4
src/tests/check_list/blocks-in-blocks.pug
Normal file
@@ -0,0 +1,4 @@
|
||||
extends ./auxiliary/blocks-in-blocks-layout.pug
|
||||
|
||||
block body
|
||||
h1 Page 2
|
||||
1
src/tests/check_list/blocks-in-if.html
Normal file
1
src/tests/check_list/blocks-in-if.html
Normal file
@@ -0,0 +1 @@
|
||||
<p>ajax contents</p>
|
||||
19
src/tests/check_list/blocks-in-if.pug
Normal file
19
src/tests/check_list/blocks-in-if.pug
Normal file
@@ -0,0 +1,19 @@
|
||||
//- see https://github.com/pugjs/pug/issues/1589
|
||||
|
||||
-var ajax = true
|
||||
|
||||
-if( ajax )
|
||||
//- return only contents if ajax requests
|
||||
block contents
|
||||
p ajax contents
|
||||
|
||||
-else
|
||||
//- return all html
|
||||
doctype html
|
||||
html
|
||||
head
|
||||
meta( charset='utf8' )
|
||||
title sample
|
||||
body
|
||||
block contents
|
||||
p all contetns
|
||||
5
src/tests/check_list/case-blocks.html
Normal file
5
src/tests/check_list/case-blocks.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>you have a friend</p>
|
||||
</body>
|
||||
</html>
|
||||
10
src/tests/check_list/case-blocks.pug
Normal file
10
src/tests/check_list/case-blocks.pug
Normal file
@@ -0,0 +1,10 @@
|
||||
html
|
||||
body
|
||||
- var friends = 1
|
||||
case friends
|
||||
when 0
|
||||
p you have no friends
|
||||
when 1
|
||||
p you have a friend
|
||||
default
|
||||
p you have #{friends} friends
|
||||
8
src/tests/check_list/case.html
Normal file
8
src/tests/check_list/case.html
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
<html>
|
||||
<body>
|
||||
<p>you have a friend</p>
|
||||
<p>you have very few friends</p>
|
||||
<p>Friend is a string</p>
|
||||
</body>
|
||||
</html>
|
||||
19
src/tests/check_list/case.pug
Normal file
19
src/tests/check_list/case.pug
Normal file
@@ -0,0 +1,19 @@
|
||||
html
|
||||
body
|
||||
- var friends = 1
|
||||
case friends
|
||||
when 0: p you have no friends
|
||||
when 1: p you have a friend
|
||||
default: p you have #{friends} friends
|
||||
- var friends = 0
|
||||
case friends
|
||||
when 0
|
||||
when 1
|
||||
p you have very few friends
|
||||
default
|
||||
p you have #{friends} friends
|
||||
|
||||
- var friend = 'Tim:G'
|
||||
case friend
|
||||
when 'Tim:G': p Friend is a string
|
||||
when {tim: 'g'}: p Friend is an object
|
||||
3
src/tests/check_list/classes-empty.html
Normal file
3
src/tests/check_list/classes-empty.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<a></a>
|
||||
<a></a>
|
||||
<a></a>
|
||||
3
src/tests/check_list/classes-empty.pug
Normal file
3
src/tests/check_list/classes-empty.pug
Normal file
@@ -0,0 +1,3 @@
|
||||
a(class='')
|
||||
a(class=null)
|
||||
a(class=undefined)
|
||||
1
src/tests/check_list/classes.html
Normal file
1
src/tests/check_list/classes.html
Normal file
@@ -0,0 +1 @@
|
||||
<a class="foo bar baz"></a><a class="foo bar baz"></a><a class="foo-bar_baz"></a><a class="foo baz"></a>
|
||||
11
src/tests/check_list/classes.pug
Normal file
11
src/tests/check_list/classes.pug
Normal file
@@ -0,0 +1,11 @@
|
||||
a(class=['foo', 'bar', 'baz'])
|
||||
|
||||
|
||||
|
||||
a.foo(class='bar').baz
|
||||
|
||||
|
||||
|
||||
a.foo-bar_baz
|
||||
|
||||
a(class={foo: true, bar: false, baz: true})
|
||||
11
src/tests/check_list/code.conditionals.html
Normal file
11
src/tests/check_list/code.conditionals.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<p>foo</p>
|
||||
<p>foo</p>
|
||||
<p>foo</p>
|
||||
<p>bar</p>
|
||||
<p>baz</p>
|
||||
<p>bar</p>
|
||||
<p>yay</p>
|
||||
<div class="bar"></div>
|
||||
<div class="bar"></div>
|
||||
<div class="bing"></div>
|
||||
<div class="foo"></div>
|
||||
43
src/tests/check_list/code.conditionals.pug
Normal file
43
src/tests/check_list/code.conditionals.pug
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
- if (true)
|
||||
p foo
|
||||
- else
|
||||
p bar
|
||||
|
||||
- if (true) {
|
||||
p foo
|
||||
- } else {
|
||||
p bar
|
||||
- }
|
||||
|
||||
if true
|
||||
p foo
|
||||
p bar
|
||||
p baz
|
||||
else
|
||||
p bar
|
||||
|
||||
unless true
|
||||
p foo
|
||||
else
|
||||
p bar
|
||||
|
||||
if 'nested'
|
||||
if 'works'
|
||||
p yay
|
||||
|
||||
//- allow empty blocks
|
||||
if false
|
||||
else
|
||||
.bar
|
||||
if true
|
||||
.bar
|
||||
else
|
||||
.bing
|
||||
|
||||
if false
|
||||
.bing
|
||||
else if false
|
||||
.bar
|
||||
else
|
||||
.foo
|
||||
2
src/tests/check_list/code.escape.html
Normal file
2
src/tests/check_list/code.escape.html
Normal file
@@ -0,0 +1,2 @@
|
||||
<p><script></p>
|
||||
<p><script></p>
|
||||
2
src/tests/check_list/code.escape.pug
Normal file
2
src/tests/check_list/code.escape.pug
Normal file
@@ -0,0 +1,2 @@
|
||||
p= '<script>'
|
||||
p!= '<script>'
|
||||
10
src/tests/check_list/code.html
Normal file
10
src/tests/check_list/code.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<p></p>
|
||||
<p></p>
|
||||
<p></p>
|
||||
<p>0</p>
|
||||
<p>false</p>
|
||||
<p></p>
|
||||
<p></p>
|
||||
<p foo=""></p>
|
||||
<p foo="0"></p>
|
||||
<p></p>
|
||||
36
src/tests/check_list/code.iteration.html
Normal file
36
src/tests/check_list/code.iteration.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<ul>
|
||||
<li>1</li>
|
||||
<li>2</li>
|
||||
<li>3</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li class="item-0">1</li>
|
||||
<li class="item-1">2</li>
|
||||
<li class="item-2">3</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>1</li>
|
||||
<li>2</li>
|
||||
<li>3</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>1</li>
|
||||
<li>2</li>
|
||||
<li>3</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>1: a</li>
|
||||
<li>2: a</li>
|
||||
<li>3: a</li>
|
||||
<li>1: b</li>
|
||||
<li>2: b</li>
|
||||
<li>3: b</li>
|
||||
<li>1: c</li>
|
||||
<li>2: c</li>
|
||||
<li>3: c</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>1</li>
|
||||
<li>2</li>
|
||||
<li>3</li>
|
||||
</ul>
|
||||
35
src/tests/check_list/code.iteration.pug
Normal file
35
src/tests/check_list/code.iteration.pug
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
- var items = [1,2,3]
|
||||
|
||||
ul
|
||||
- items.forEach(function(item){
|
||||
li= item
|
||||
- })
|
||||
|
||||
- var items = [1,2,3]
|
||||
|
||||
ul
|
||||
for item, i in items
|
||||
li(class='item-' + i)= item
|
||||
|
||||
ul
|
||||
each item, i in items
|
||||
li= item
|
||||
|
||||
ul
|
||||
each $item in items
|
||||
li= $item
|
||||
|
||||
- var nums = [1, 2, 3]
|
||||
- var letters = ['a', 'b', 'c']
|
||||
|
||||
ul
|
||||
for l in letters
|
||||
for n in nums
|
||||
li #{n}: #{l}
|
||||
|
||||
- var count = 1
|
||||
- var counter = function() { return [count++, count++, count++] }
|
||||
ul
|
||||
for n in counter()
|
||||
li #{n}
|
||||
10
src/tests/check_list/code.pug
Normal file
10
src/tests/check_list/code.pug
Normal file
@@ -0,0 +1,10 @@
|
||||
p= null
|
||||
p= undefined
|
||||
p= ''
|
||||
p= 0
|
||||
p= false
|
||||
p(foo=null)
|
||||
p(foo=undefined)
|
||||
p(foo='')
|
||||
p(foo=0)
|
||||
p(foo=false)
|
||||
6
src/tests/check_list/comments-in-case.html
Normal file
6
src/tests/check_list/comments-in-case.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<p>It's this!</p>
|
||||
</body>
|
||||
</html>
|
||||
10
src/tests/check_list/comments-in-case.pug
Normal file
10
src/tests/check_list/comments-in-case.pug
Normal file
@@ -0,0 +1,10 @@
|
||||
doctype html
|
||||
html
|
||||
body
|
||||
- var s = 'this'
|
||||
case s
|
||||
//- Comment
|
||||
when 'this'
|
||||
p It's this!
|
||||
when 'that'
|
||||
p It's that!
|
||||
32
src/tests/check_list/comments.html
Normal file
32
src/tests/check_list/comments.html
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
<!-- foo-->
|
||||
<ul>
|
||||
<!-- bar-->
|
||||
<li>one</li>
|
||||
<!-- baz-->
|
||||
<li>two</li>
|
||||
</ul>
|
||||
<!--
|
||||
ul
|
||||
li foo
|
||||
|
||||
-->
|
||||
<!-- block
|
||||
// inline follow
|
||||
li three
|
||||
|
||||
-->
|
||||
<!-- block
|
||||
// inline followed by tags
|
||||
ul
|
||||
li four
|
||||
|
||||
-->
|
||||
<!--if IE lt 9
|
||||
// inline
|
||||
script(src='/lame.js')
|
||||
// end-inline
|
||||
|
||||
-->
|
||||
<p>five</p>
|
||||
<div class="foo">// not a comment</div>
|
||||
29
src/tests/check_list/comments.pug
Normal file
29
src/tests/check_list/comments.pug
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
// foo
|
||||
ul
|
||||
// bar
|
||||
li one
|
||||
// baz
|
||||
li two
|
||||
|
||||
//
|
||||
ul
|
||||
li foo
|
||||
|
||||
// block
|
||||
// inline follow
|
||||
li three
|
||||
|
||||
// block
|
||||
// inline followed by tags
|
||||
ul
|
||||
li four
|
||||
|
||||
//if IE lt 9
|
||||
// inline
|
||||
script(src='/lame.js')
|
||||
// end-inline
|
||||
|
||||
p five
|
||||
|
||||
.foo // not a comment
|
||||
0
src/tests/check_list/comments.source.html
Normal file
0
src/tests/check_list/comments.source.html
Normal file
9
src/tests/check_list/comments.source.pug
Normal file
9
src/tests/check_list/comments.source.pug
Normal file
@@ -0,0 +1,9 @@
|
||||
//-
|
||||
s/s.
|
||||
|
||||
//- test/cases/comments.source.pug
|
||||
|
||||
//-
|
||||
test/cases/comments.source.pug
|
||||
when
|
||||
()
|
||||
1
src/tests/check_list/doctype.custom.html
Normal file
1
src/tests/check_list/doctype.custom.html
Normal file
@@ -0,0 +1 @@
|
||||
<!DOCTYPE custom stuff>
|
||||
1
src/tests/check_list/doctype.custom.pug
Normal file
1
src/tests/check_list/doctype.custom.pug
Normal file
@@ -0,0 +1 @@
|
||||
doctype custom stuff
|
||||
6
src/tests/check_list/doctype.default.html
Normal file
6
src/tests/check_list/doctype.default.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<h1>Title</h1>
|
||||
</body>
|
||||
</html>
|
||||
4
src/tests/check_list/doctype.default.pug
Normal file
4
src/tests/check_list/doctype.default.pug
Normal file
@@ -0,0 +1,4 @@
|
||||
doctype
|
||||
html
|
||||
body
|
||||
h1 Title
|
||||
1
src/tests/check_list/doctype.keyword.html
Normal file
1
src/tests/check_list/doctype.keyword.html
Normal file
@@ -0,0 +1 @@
|
||||
<!DOCTYPE html>
|
||||
1
src/tests/check_list/doctype.keyword.pug
Normal file
1
src/tests/check_list/doctype.keyword.pug
Normal file
@@ -0,0 +1 @@
|
||||
doctype html
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user