Skip to content
Merged
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
2 changes: 2 additions & 0 deletions src/apiweb.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const HTML = @import("html/html.zig");
const Events = @import("events/event.zig");
const XHR = @import("xhr/xhr.zig");
const Storage = @import("storage/storage.zig");
const URL = @import("url/url.zig");

pub const HTMLDocument = @import("html/document.zig").HTMLDocument;

Expand All @@ -18,4 +19,5 @@ pub const Interfaces = generate.Tuple(.{
HTML.Interfaces,
XHR.Interfaces,
Storage.Interfaces,
URL.Interfaces,
});
93 changes: 6 additions & 87 deletions src/browser/mime.zig
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
const std = @import("std");
const testing = std.testing;

const strparser = @import("../str/parser.zig");
const Reader = strparser.Reader;
const trim = strparser.trim;

const Self = @This();

const MimeError = error{
Expand All @@ -21,91 +25,6 @@ pub const Empty = Self{ .mtype = "", .msubtype = "" };
pub const HTML = Self{ .mtype = "text", .msubtype = "html" };
pub const Javascript = Self{ .mtype = "application", .msubtype = "javascript" };

const reader = struct {
s: []const u8,
i: usize = 0,

fn until(self: *reader, c: u8) []const u8 {
const ln = self.s.len;
const start = self.i;
while (self.i < ln) {
if (c == self.s[self.i]) return self.s[start..self.i];
self.i += 1;
}

return self.s[start..self.i];
}

fn tail(self: *reader) []const u8 {
if (self.i > self.s.len) return "";
defer self.i = self.s.len;
return self.s[self.i..];
}

fn skip(self: *reader) bool {
if (self.i >= self.s.len) return false;
self.i += 1;
return true;
}
};

test "reader.skip" {
var r = reader{ .s = "foo" };
try testing.expect(r.skip());
try testing.expect(r.skip());
try testing.expect(r.skip());
try testing.expect(!r.skip());
try testing.expect(!r.skip());
}

test "reader.tail" {
var r = reader{ .s = "foo" };
try testing.expectEqualStrings("foo", r.tail());
try testing.expectEqualStrings("", r.tail());
}

test "reader.until" {
var r = reader{ .s = "foo.bar.baz" };
try testing.expectEqualStrings("foo", r.until('.'));
_ = r.skip();
try testing.expectEqualStrings("bar", r.until('.'));
_ = r.skip();
try testing.expectEqualStrings("baz", r.until('.'));

r = reader{ .s = "foo" };
try testing.expectEqualStrings("foo", r.until('.'));

r = reader{ .s = "" };
try testing.expectEqualStrings("", r.until('.'));
}

fn trim(s: []const u8) []const u8 {
const ln = s.len;
if (ln == 0) {
return "";
}
var start: usize = 0;
while (start < ln) {
if (!std.ascii.isWhitespace(s[start])) break;
start += 1;
}

var end: usize = ln;
while (end > 0) {
if (!std.ascii.isWhitespace(s[end - 1])) break;
end -= 1;
}

return s[start..end];
}

test "trim" {
try testing.expectEqualStrings("", trim(""));
try testing.expectEqualStrings("foo", trim("foo"));
try testing.expectEqualStrings("foo", trim(" \n\tfoo"));
try testing.expectEqualStrings("foo", trim("foo \n\t"));
}

// https://mimesniff.spec.whatwg.org/#http-token-code-point
fn isHTTPCodePoint(c: u8) bool {
return switch (c) {
Expand Down Expand Up @@ -133,7 +52,7 @@ pub fn parse(s: []const u8) Self.MimeError!Self {
if (ln > 255) return MimeError.TooBig;

var res = Self{ .mtype = "", .msubtype = "" };
var r = reader{ .s = s };
var r = Reader{ .s = s };

res.mtype = trim(r.until('/'));
if (res.mtype.len == 0) return MimeError.Invalid;
Expand All @@ -150,7 +69,7 @@ pub fn parse(s: []const u8) Self.MimeError!Self {

// parse well known parameters.
// don't check invalid parameter format.
var rp = reader{ .s = res.params };
var rp = Reader{ .s = res.params };
while (true) {
const name = trim(rp.until('='));
if (!rp.skip()) return res;
Expand Down
10 changes: 10 additions & 0 deletions src/run_tests.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const apiweb = @import("apiweb.zig");
const Window = @import("html/window.zig").Window;
const xhr = @import("xhr/xhr.zig");
const storage = @import("storage/storage.zig");
const url = @import("url/url.zig");
const urlquery = @import("url/query.zig");

const documentTestExecFn = @import("dom/document.zig").testExecFn;
const HTMLDocumentTestExecFn = @import("html/document.zig").testExecFn;
Expand All @@ -30,6 +32,7 @@ const EventTestExecFn = @import("events/event.zig").testExecFn;
const XHRTestExecFn = xhr.testExecFn;
const ProgressEventTestExecFn = @import("xhr/progress_event.zig").testExecFn;
const StorageTestExecFn = storage.testExecFn;
const URLTestExecFn = url.testExecFn;

pub const Types = jsruntime.reflect(apiweb.Interfaces);

Expand Down Expand Up @@ -95,6 +98,7 @@ fn testsAllExecFn(
ProgressEventTestExecFn,
ProcessingInstructionTestExecFn,
StorageTestExecFn,
URLTestExecFn,
};

inline for (testFns) |testFn| {
Expand Down Expand Up @@ -261,6 +265,9 @@ test {
const dumpTest = @import("browser/dump.zig");
std.testing.refAllDecls(dumpTest);

const mimeTest = @import("browser/mime.zig");
std.testing.refAllDecls(mimeTest);

const cssTest = @import("css/css.zig");
std.testing.refAllDecls(cssTest);

Expand All @@ -272,6 +279,9 @@ test {

const cssLibdomTest = @import("css/libdom_test.zig");
std.testing.refAllDecls(cssLibdomTest);

const queryTest = @import("url/query.zig");
std.testing.refAllDecls(queryTest);
}

fn testJSRuntime(alloc: std.mem.Allocator) !void {
Expand Down
88 changes: 88 additions & 0 deletions src/str/parser.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// some utils to parser strings.
const std = @import("std");
const testing = std.testing;

pub const Reader = struct {
s: []const u8,
i: usize = 0,

pub fn until(self: *Reader, c: u8) []const u8 {
const ln = self.s.len;
const start = self.i;
while (self.i < ln) {
if (c == self.s[self.i]) return self.s[start..self.i];
self.i += 1;
}

return self.s[start..self.i];
}

pub fn tail(self: *Reader) []const u8 {
if (self.i > self.s.len) return "";
defer self.i = self.s.len;
return self.s[self.i..];
}

pub fn skip(self: *Reader) bool {
if (self.i >= self.s.len) return false;
self.i += 1;
return true;
}
};

test "Reader.skip" {
var r = Reader{ .s = "foo" };
try testing.expect(r.skip());
try testing.expect(r.skip());
try testing.expect(r.skip());
try testing.expect(!r.skip());
try testing.expect(!r.skip());
}

test "Reader.tail" {
var r = Reader{ .s = "foo" };
try testing.expectEqualStrings("foo", r.tail());
try testing.expectEqualStrings("", r.tail());
}

test "Reader.until" {
var r = Reader{ .s = "foo.bar.baz" };
try testing.expectEqualStrings("foo", r.until('.'));
_ = r.skip();
try testing.expectEqualStrings("bar", r.until('.'));
_ = r.skip();
try testing.expectEqualStrings("baz", r.until('.'));

r = Reader{ .s = "foo" };
try testing.expectEqualStrings("foo", r.until('.'));

r = Reader{ .s = "" };
try testing.expectEqualStrings("", r.until('.'));
}

pub fn trim(s: []const u8) []const u8 {
const ln = s.len;
if (ln == 0) {
return "";
}
var start: usize = 0;
while (start < ln) {
if (!std.ascii.isWhitespace(s[start])) break;
start += 1;
}

var end: usize = ln;
while (end > 0) {
if (!std.ascii.isWhitespace(s[end - 1])) break;
end -= 1;
}

return s[start..end];
}

test "trim" {
try testing.expectEqualStrings("", trim(""));
try testing.expectEqualStrings("foo", trim("foo"));
try testing.expectEqualStrings("foo", trim(" \n\tfoo"));
try testing.expectEqualStrings("foo", trim("foo \n\t"));
}
Loading