Skip to content

Commit 3b2ea0a

Browse files
committed
introduce checking for valid HTML tag names
Use `--no-strict-tags` to disable this class of errors. This feature currently only supports HTML and SuperHTML.
1 parent 0c70bd8 commit 3b2ea0a

File tree

8 files changed

+265
-26
lines changed

8 files changed

+265
-26
lines changed

src/cli.zig

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,9 @@ fn fatalHelp() noreturn {
120120
\\ version Print Super's version and exit
121121
\\
122122
\\General Options:
123-
\\ --help, -h Print command specific usage
124-
\\
123+
\\ --help, -h Print command specific usage
124+
\\ --no-strict-tags Disable strict checking of tag names
125+
\\ in HTML and SuperHTML files.
125126
\\
126127
, .{});
127128
}

src/cli/check.zig

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !void {
1313
_ = try fr.interface.streamRemaining(&aw.writer);
1414
const in_bytes = try aw.toOwnedSliceSentinel(0);
1515

16-
try checkHtml(gpa, null, in_bytes);
16+
try checkHtml(gpa, null, in_bytes, cmd.strict);
1717
},
1818
.stdin_super => {
1919
var fr = std.fs.File.stdin().reader(&.{});
2020
var aw: std.Io.Writer.Allocating = .init(gpa);
2121
_ = try fr.interface.streamRemaining(&aw.writer);
2222
const in_bytes = try aw.toOwnedSliceSentinel(0);
2323

24-
try checkSuper(gpa, null, in_bytes);
24+
try checkSuper(gpa, null, in_bytes, cmd.strict);
2525
},
2626
.paths => |paths| {
2727
// checkFile will reset the arena at the end of each call
@@ -33,13 +33,15 @@ pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !void {
3333
path,
3434
path,
3535
&any_error,
36+
cmd.strict,
3637
) catch |err| switch (err) {
3738
error.IsDir, error.AccessDenied => {
3839
checkDir(
3940
gpa,
4041
&arena_impl,
4142
path,
4243
&any_error,
44+
cmd.strict,
4345
) catch |dir_err| {
4446
std.debug.print("Error walking dir '{s}': {t}\n", .{
4547
path,
@@ -69,6 +71,7 @@ fn checkDir(
6971
arena_impl: *std.heap.ArenaAllocator,
7072
path: []const u8,
7173
any_error: *bool,
74+
strict: bool,
7275
) !void {
7376
var dir = try std.fs.cwd().openDir(path, .{ .iterate = true });
7477
defer dir.close();
@@ -83,6 +86,7 @@ fn checkDir(
8386
item.basename,
8487
item.path,
8588
any_error,
89+
strict,
8690
);
8791
},
8892
else => {},
@@ -96,6 +100,7 @@ fn checkFile(
96100
sub_path: []const u8,
97101
full_path: []const u8,
98102
any_error: *bool,
103+
strict: bool,
99104
) !void {
100105
_ = any_error;
101106
defer _ = arena_impl.reset(.retain_capacity);
@@ -129,11 +134,13 @@ fn checkFile(
129134
arena,
130135
full_path,
131136
in_bytes,
137+
strict,
132138
),
133139
.super => try checkSuper(
134140
arena,
135141
full_path,
136142
in_bytes,
143+
strict,
137144
),
138145
}
139146
}
@@ -142,8 +149,9 @@ pub fn checkHtml(
142149
arena: std.mem.Allocator,
143150
path: ?[]const u8,
144151
code: [:0]const u8,
152+
strict: bool,
145153
) !void {
146-
const ast = try super.html.Ast.init(arena, code, .html);
154+
const ast = try super.html.Ast.init(arena, code, .html, strict);
147155
if (ast.errors.len > 0) {
148156
var stderr = std.fs.File.stderr().writer(&.{});
149157
try ast.printErrors(code, path, &stderr.interface);
@@ -155,8 +163,9 @@ fn checkSuper(
155163
arena: std.mem.Allocator,
156164
path: ?[]const u8,
157165
code: [:0]const u8,
166+
strict: bool,
158167
) !void {
159-
const html = try super.html.Ast.init(arena, code, .superhtml);
168+
const html = try super.html.Ast.init(arena, code, .superhtml, strict);
160169
if (html.errors.len > 0) {
161170
var stderr = std.fs.File.stderr().writer(&.{});
162171
try html.printErrors(code, path, &stderr.interface);
@@ -178,6 +187,7 @@ fn oom() noreturn {
178187

179188
const Command = struct {
180189
mode: Mode,
190+
strict: bool,
181191

182192
const Mode = union(enum) {
183193
stdin,
@@ -187,6 +197,7 @@ const Command = struct {
187197

188198
fn parse(args: []const []const u8) Command {
189199
var mode: ?Mode = null;
200+
var strict: ?bool = null;
190201

191202
var idx: usize = 0;
192203
while (idx < args.len) : (idx += 1) {
@@ -197,6 +208,11 @@ const Command = struct {
197208
fatalHelp();
198209
}
199210

211+
if (std.mem.eql(u8, arg, "--no-strict-tags")) {
212+
strict = false;
213+
continue;
214+
}
215+
200216
if (std.mem.startsWith(u8, arg, "-")) {
201217
if (std.mem.eql(u8, arg, "--stdin") or
202218
std.mem.eql(u8, arg, "-"))
@@ -245,7 +261,10 @@ const Command = struct {
245261
fatalHelp();
246262
};
247263

248-
return .{ .mode = m };
264+
return .{
265+
.mode = m,
266+
.strict = strict orelse true,
267+
};
249268
}
250269

251270
fn fatalHelp() noreturn {
@@ -266,6 +285,9 @@ const Command = struct {
266285
\\
267286
\\ --stdin-super Same as --stdin but for SuperHTML files.
268287
\\
288+
\\ --no-strict-tags Disable strict checking of tag names in HTML
289+
\\ and SuperHTML files.
290+
\\
269291
\\ --help, -h Prints this help and exits.
270292
, .{});
271293

src/cli/fmt.zig

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !void {
1313
_ = try fr.interface.streamRemaining(&aw.writer);
1414
const in_bytes = try aw.toOwnedSliceSentinel(0);
1515

16-
const out_bytes = try fmtHtml(gpa, null, in_bytes);
16+
const out_bytes = try fmtHtml(gpa, null, in_bytes, cmd.strict);
1717

1818
try std.fs.File.stdout().writeAll(out_bytes);
1919
},
@@ -23,7 +23,7 @@ pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !void {
2323
_ = try fr.interface.streamRemaining(&aw.writer);
2424
const in_bytes = try aw.toOwnedSliceSentinel(0);
2525

26-
const out_bytes = try fmtSuper(gpa, null, in_bytes);
26+
const out_bytes = try fmtSuper(gpa, null, in_bytes, cmd.strict);
2727
try std.fs.File.stdout().writeAll(out_bytes);
2828
},
2929
.paths => |paths| {
@@ -37,6 +37,7 @@ pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !void {
3737
path,
3838
path,
3939
&any_error,
40+
cmd.strict,
4041
) catch |err| switch (err) {
4142
error.IsDir, error.AccessDenied => {
4243
formatDir(
@@ -45,6 +46,7 @@ pub fn run(gpa: std.mem.Allocator, args: []const []const u8) !void {
4546
cmd.check,
4647
path,
4748
&any_error,
49+
cmd.strict,
4850
) catch |dir_err| {
4951
std.debug.print("Error walking dir '{s}': {s}\n", .{
5052
path,
@@ -75,6 +77,7 @@ fn formatDir(
7577
check: bool,
7678
path: []const u8,
7779
any_error: *bool,
80+
strict: bool,
7881
) !void {
7982
var dir = try std.fs.cwd().openDir(path, .{ .iterate = true });
8083
defer dir.close();
@@ -90,6 +93,7 @@ fn formatDir(
9093
item.basename,
9194
item.path,
9295
any_error,
96+
strict,
9397
);
9498
},
9599
else => {},
@@ -104,6 +108,7 @@ fn formatFile(
104108
sub_path: []const u8,
105109
full_path: []const u8,
106110
any_error: *bool,
111+
strict: bool,
107112
) !void {
108113
defer _ = arena_impl.reset(.retain_capacity);
109114
const arena = arena_impl.allocator();
@@ -136,11 +141,13 @@ fn formatFile(
136141
arena,
137142
full_path,
138143
in_bytes,
144+
strict,
139145
),
140146
.super => try fmtSuper(
141147
arena,
142148
full_path,
143149
in_bytes,
150+
strict,
144151
),
145152
};
146153

@@ -166,8 +173,9 @@ pub fn fmtHtml(
166173
arena: std.mem.Allocator,
167174
path: ?[]const u8,
168175
code: [:0]const u8,
176+
strict: bool,
169177
) ![]const u8 {
170-
const ast = try super.html.Ast.init(arena, code, .html);
178+
const ast = try super.html.Ast.init(arena, code, .html, strict);
171179
if (ast.errors.len > 0) {
172180
var ew = std.fs.File.stderr().writer(&.{});
173181
try ast.printErrors(code, path, &ew.interface);
@@ -181,8 +189,9 @@ fn fmtSuper(
181189
arena: std.mem.Allocator,
182190
path: ?[]const u8,
183191
code: [:0]const u8,
192+
strict: bool,
184193
) ![]const u8 {
185-
const ast = try super.html.Ast.init(arena, code, .superhtml);
194+
const ast = try super.html.Ast.init(arena, code, .superhtml, strict);
186195
if (ast.errors.len > 0) {
187196
var ew = std.fs.File.stderr().writer(&.{});
188197
try ast.printErrors(code, path, &ew.interface);
@@ -200,6 +209,7 @@ fn oom() noreturn {
200209
const Command = struct {
201210
check: bool,
202211
mode: Mode,
212+
strict: bool,
203213

204214
const Mode = union(enum) {
205215
stdin,
@@ -210,6 +220,7 @@ const Command = struct {
210220
fn parse(args: []const []const u8) Command {
211221
var check: bool = false;
212222
var mode: ?Mode = null;
223+
var strict: ?bool = null;
213224

214225
var idx: usize = 0;
215226
while (idx < args.len) : (idx += 1) {
@@ -221,15 +232,15 @@ const Command = struct {
221232
}
222233

223234
if (std.mem.eql(u8, arg, "--check")) {
224-
if (check) {
225-
std.debug.print("error: duplicate '--check' flag\n\n", .{});
226-
std.process.exit(1);
227-
}
228-
229235
check = true;
230236
continue;
231237
}
232238

239+
if (std.mem.eql(u8, arg, "--no-strict-tags")) {
240+
strict = true;
241+
continue;
242+
}
243+
233244
if (std.mem.startsWith(u8, arg, "-")) {
234245
if (std.mem.eql(u8, arg, "--stdin") or
235246
std.mem.eql(u8, arg, "-"))
@@ -278,7 +289,11 @@ const Command = struct {
278289
fatalHelp();
279290
};
280291

281-
return .{ .check = check, .mode = m };
292+
return .{
293+
.check = check,
294+
.mode = m,
295+
.strict = strict orelse true,
296+
};
282297
}
283298

284299
fn fatalHelp() noreturn {
@@ -302,6 +317,9 @@ const Command = struct {
302317
\\ --check List non-conforming files and exit with an
303318
\\ error if the list is not empty.
304319
\\
320+
\\ --no-strict-tags Disable strict checking of tag names in HTML
321+
\\ and SuperHTML files.
322+
\\
305323
\\ --help, -h Prints this help and exits.
306324
, .{});
307325

0 commit comments

Comments
 (0)