Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/Ast.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,7 @@ test "basics" {
std.testing.allocator,
case,
.superhtml,
html.Ast.ElementValidationMode.off,
);
defer html_ast.deinit(std.testing.allocator);
const tree = try Ast.init(std.testing.allocator, html_ast, case);
Expand Down Expand Up @@ -1119,6 +1120,7 @@ test "text/html - errors" {
std.testing.allocator,
case,
.superhtml,
html.Ast.ElementValidationMode.off,
);
defer html_ast.deinit(std.testing.allocator);
const tree = try Ast.init(std.testing.allocator, html_ast, case);
Expand All @@ -1143,6 +1145,7 @@ test "siblings" {
std.testing.allocator,
case,
.superhtml,
html.Ast.ElementValidationMode.off,
);
defer html_ast.deinit(std.testing.allocator);
const tree = try Ast.init(std.testing.allocator, html_ast, case);
Expand Down Expand Up @@ -1177,6 +1180,7 @@ test "nesting" {
std.testing.allocator,
case,
.superhtml,
html.Ast.ElementValidationMode.off,
);
defer html_ast.deinit(std.testing.allocator);
const tree = try Ast.init(std.testing.allocator, html_ast, case);
Expand Down Expand Up @@ -1213,6 +1217,7 @@ test "deeper nesting" {
std.testing.allocator,
case,
.superhtml,
html.Ast.ElementValidationMode.off,
);
defer html_ast.deinit(std.testing.allocator);
const tree = try Ast.init(std.testing.allocator, html_ast, case);
Expand Down Expand Up @@ -1254,6 +1259,7 @@ test "complex example" {
std.testing.allocator,
case,
.superhtml,
html.Ast.ElementValidationMode.off,
);
defer html_ast.deinit(std.testing.allocator);
const tree = try Ast.init(std.testing.allocator, html_ast, case);
Expand Down Expand Up @@ -1300,6 +1306,7 @@ test "if-else-loop errors" {
std.testing.allocator,
case,
.superhtml,
html.Ast.ElementValidationMode.off,
);
defer html_ast.deinit(std.testing.allocator);
const tree = try Ast.init(std.testing.allocator, html_ast, case);
Expand Down Expand Up @@ -1329,6 +1336,7 @@ test "super" {
std.testing.allocator,
case,
.superhtml,
html.Ast.ElementValidationMode.off,
);
defer html_ast.deinit(std.testing.allocator);
const tree = try Ast.init(std.testing.allocator, html_ast, case);
Expand Down
58 changes: 42 additions & 16 deletions src/cli/check.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const std = @import("std");
const super = @import("superhtml");
const ElementValidationMode = super.html.Ast.ElementValidationMode;

const FileType = enum { html, super };

Expand All @@ -12,14 +13,14 @@ pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !void {
try std.io.getStdIn().reader().readAllArrayList(&buf, super.max_size);
const in_bytes = try buf.toOwnedSliceSentinel(0);

try checkHtml(gpa, null, in_bytes);
try checkHtml(gpa, null, in_bytes, cmd.validationMode);
},
.stdin_super => {
var buf = std.ArrayList(u8).init(gpa);
try std.io.getStdIn().reader().readAllArrayList(&buf, super.max_size);
const in_bytes = try buf.toOwnedSliceSentinel(0);

try checkSuper(gpa, null, in_bytes);
try checkSuper(gpa, null, in_bytes, cmd.validationMode);
},
.paths => |paths| {
// checkFile will reset the arena at the end of each call
Expand All @@ -31,13 +32,15 @@ pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !void {
path,
path,
&any_error,
cmd.validationMode,
) catch |err| switch (err) {
error.IsDir, error.AccessDenied => {
checkDir(
gpa,
&arena_impl,
path,
&any_error,
cmd.validationMode,
) catch |dir_err| {
std.debug.print("Error walking dir '{s}': {s}\n", .{
path,
Expand Down Expand Up @@ -67,6 +70,7 @@ fn checkDir(
arena_impl: *std.heap.ArenaAllocator,
path: []const u8,
any_error: *bool,
validation_mode: ElementValidationMode,
) !void {
var dir = try std.fs.cwd().openDir(path, .{ .iterate = true });
defer dir.close();
Expand All @@ -81,6 +85,7 @@ fn checkDir(
item.basename,
item.path,
any_error,
validation_mode,
);
},
else => {},
Expand All @@ -94,6 +99,7 @@ fn checkFile(
sub_path: []const u8,
full_path: []const u8,
any_error: *bool,
validation_mode: ElementValidationMode,
) !void {
_ = any_error;
defer _ = arena_impl.reset(.retain_capacity);
Expand Down Expand Up @@ -128,25 +134,18 @@ fn checkFile(
const in_bytes = try buf.toOwnedSliceSentinel(0);

switch (file_type) {
.html => try checkHtml(
arena,
full_path,
in_bytes,
),
.super => try checkSuper(
arena,
full_path,
in_bytes,
),
.html => try checkHtml(arena, full_path, in_bytes, validation_mode),
.super => try checkSuper(arena, full_path, in_bytes, validation_mode),
}
}

pub fn checkHtml(
arena: std.mem.Allocator,
path: ?[]const u8,
code: [:0]const u8,
validation_mode: ElementValidationMode,
) !void {
const ast = try super.html.Ast.init(arena, code, .html);
const ast = try super.html.Ast.init(arena, code, .html, validation_mode);
if (ast.errors.len > 0) {
try ast.printErrors(code, path, std.io.getStdErr().writer());
std.process.exit(1);
Expand All @@ -157,8 +156,9 @@ fn checkSuper(
arena: std.mem.Allocator,
path: ?[]const u8,
code: [:0]const u8,
validation_mode: ElementValidationMode,
) !void {
const html = try super.html.Ast.init(arena, code, .superhtml);
const html = try super.html.Ast.init(arena, code, .superhtml, validation_mode);
if (html.errors.len > 0) {
try html.printErrors(code, path, std.io.getStdErr().writer());
std.process.exit(1);
Expand All @@ -178,6 +178,7 @@ fn oom() noreturn {

const Command = struct {
mode: Mode,
validationMode: ElementValidationMode,

const Mode = union(enum) {
stdin,
Expand All @@ -187,6 +188,7 @@ const Command = struct {

fn parse(args: []const []const u8) Command {
var mode: ?Mode = null;
var element_validation_mode = ElementValidationMode.off;

var idx: usize = 0;
while (idx < args.len) : (idx += 1) {
Expand All @@ -196,6 +198,21 @@ const Command = struct {
{
fatalHelp();
}
if (std.mem.startsWith(u8, arg, "--element-validation=")) {
const value = arg["--element-validation=".len..];
if (std.mem.eql(u8, value, "off")) {
element_validation_mode = .off;
} else if (std.mem.eql(u8, value, "standard")) {
element_validation_mode = .standard;
} else if (std.mem.eql(u8, value, "web-components")) {
element_validation_mode = .webComponents;
} else {
std.debug.print("invalid value for --element-validation: '{s}'\n", .{value});
std.debug.print("valid values are: off, standard, web-components\n", .{});
std.process.exit(1);
}
continue;
}

if (std.mem.startsWith(u8, arg, "-")) {
if (std.mem.eql(u8, arg, "--stdin") or
Expand Down Expand Up @@ -236,7 +253,9 @@ const Command = struct {
}

const paths = args[paths_start .. idx + 1];
mode = .{ .paths = paths };
mode = .{
.paths = paths,
};
}
}

Expand All @@ -245,7 +264,7 @@ const Command = struct {
fatalHelp();
};

return .{ .mode = m };
return .{ .mode = m, .validationMode = element_validation_mode };
}

fn fatalHelp() noreturn {
Expand All @@ -264,6 +283,13 @@ const Command = struct {
\\ --stdin Format bytes from stdin and output to stdout.
\\ Mutually exclusive with other input arguments.
\\
\\ --element-validation=MODE
\\ Control HTML element validation mode:
\\ off - No validation (default)
\\ standard - Only allow standard HTML tags
\\ web-components - Allow standard tags
\\ and web components
\\
\\ --stdin-super Same as --stdin but for SuperHTML files.
\\
\\ --help, -h Prints this help and exits.
Expand Down
15 changes: 13 additions & 2 deletions src/cli/fmt.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const std = @import("std");
const super = @import("superhtml");
const ElementValidationMode = super.html.Ast.ElementValidationMode;

const FileType = enum { html, super };

Expand Down Expand Up @@ -168,7 +169,12 @@ pub fn fmtHtml(
path: ?[]const u8,
code: [:0]const u8,
) ![]const u8 {
const ast = try super.html.Ast.init(arena, code, .html);
const ast = try super.html.Ast.init(
arena,
code,
.html,
ElementValidationMode.off,
);
if (ast.errors.len > 0) {
try ast.printErrors(code, path, std.io.getStdErr().writer());
std.process.exit(1);
Expand All @@ -182,7 +188,12 @@ fn fmtSuper(
path: ?[]const u8,
code: [:0]const u8,
) ![]const u8 {
const ast = try super.html.Ast.init(arena, code, .superhtml);
const ast = try super.html.Ast.init(
arena,
code,
.superhtml,
ElementValidationMode.off,
);
if (ast.errors.len > 0) {
try ast.printErrors(code, path, std.io.getStdErr().writer());
std.process.exit(1);
Expand Down
8 changes: 7 additions & 1 deletion src/cli/interface.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const std = @import("std");
const super = @import("superhtml");
const ElementValidationMode = super.html.Ast.ElementValidationMode;

const FileType = enum { html, super };

Expand Down Expand Up @@ -73,7 +74,12 @@ fn renderInterface(
path: ?[]const u8,
code: [:0]const u8,
) ![]const u8 {
const html_ast = try super.html.Ast.init(arena, code, .superhtml);
const html_ast = try super.html.Ast.init(
arena,
code,
.superhtml,
ElementValidationMode.off,
);
if (html_ast.errors.len > 0) {
try html_ast.printErrors(code, path, std.io.getStdErr().writer());
std.process.exit(1);
Expand Down
8 changes: 7 additions & 1 deletion src/cli/lsp/Document.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const Document = @This();
const std = @import("std");
const assert = std.debug.assert;
const super = @import("superhtml");
const ElementValidationMode = super.html.Ast.ElementValidationMode;

const log = std.log.scoped(.lsp_document);

Expand All @@ -24,7 +25,12 @@ pub fn init(
var doc: Document = .{
.src = src,
.language = language,
.html = try super.html.Ast.init(gpa, src, language),
.html = try super.html.Ast.init(
gpa,
src,
language,
ElementValidationMode.off,
),
};
errdefer doc.html.deinit(gpa);

Expand Down
7 changes: 6 additions & 1 deletion src/fuzz.zig
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ test "afl++ fuzz cases" {

for (cases) |c| {
// std.debug.print("test: \n\n{s}\n\n", .{c});
const ast = try super.html.Ast.init(std.testing.allocator, c, .html);
const ast = try super.html.Ast.init(
std.testing.allocator,
c,
.html,
super.html.Ast.ElementValidationMode.off,
);
defer ast.deinit(std.testing.allocator);
if (ast.errors.len == 0) {
try ast.render(c, std.io.null_writer);
Expand Down
Loading