Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add remove() and isRemoved in HTMLRewriterTypes.Doctype interface #16031

Merged
merged 3 commits into from
Dec 29, 2024
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 packages/bun-types/html-rewriter.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ declare namespace HTMLRewriterTypes {
readonly name: string | null;
readonly publicId: string | null;
readonly systemId: string | null;
readonly removed: boolean;
remove(): Doctype;
}

interface DocumentEnd {
Expand Down
7 changes: 7 additions & 0 deletions src/bun.js/api/html_rewriter.classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ export default [
getter: "publicId",
cache: true,
},
remove: {
fn: "remove",
length: 0,
},
removed: {
getter: "removed",
},
},
}),
define({
Expand Down
20 changes: 20 additions & 0 deletions src/bun.js/api/html_rewriter.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1157,6 +1157,26 @@ pub const DocType = struct {
return JSValue.jsNull();
return ZigString.init(str).toJS(globalObject);
}

pub fn remove(
this: *DocType,
_: *JSGlobalObject,
callFrame: *JSC.CallFrame,
) bun.JSError!JSValue {
if (this.doctype == null)
return JSValue.jsUndefined();
this.doctype.?.remove();
return callFrame.this();
}

pub fn removed(
this: *DocType,
_: *JSGlobalObject,
) JSValue {
if (this.doctype == null)
return JSValue.jsUndefined();
return JSValue.jsBoolean(this.doctype.?.isRemoved());
}
};

pub const DocEnd = struct {
Expand Down
10 changes: 10 additions & 0 deletions src/deps/lol-html.zig
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,8 @@ pub const DocType = opaque {
extern fn lol_html_doctype_system_id_get(doctype: *const DocType) HTMLString;
extern fn lol_html_doctype_user_data_set(doctype: *const DocType, user_data: ?*anyopaque) void;
extern fn lol_html_doctype_user_data_get(doctype: *const DocType) ?*anyopaque;
extern fn lol_html_doctype_remove(doctype: *DocType) void;
extern fn lol_html_doctype_is_removed(doctype: *const DocType) bool;

pub const Callback = *const fn (*DocType, ?*anyopaque) callconv(.C) Directive;

Expand All @@ -811,6 +813,14 @@ pub const DocType = opaque {
auto_disable();
return this.lol_html_doctype_system_id_get();
}
pub fn remove(this: *DocType) void {
auto_disable();
return this.lol_html_doctype_remove();
}
pub fn isRemoved(this: *const DocType) bool {
auto_disable();
return this.lol_html_doctype_is_removed();
}
};

pub const Encoding = enum {
Expand Down
24 changes: 24 additions & 0 deletions test/js/web/html/html-rewriter-doctype.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { expect, test, describe } from "bun:test";

describe("HTMLRewriter DOCTYPE handler", () => {
test("remove and removed property work on DOCTYPE", () => {
const html = "<!DOCTYPE html><html><head></head><body>Hello</body></html>";
let sawDoctype = false;
let wasRemoved = false;

const rewriter = new HTMLRewriter().onDocument({
doctype(doctype) {
sawDoctype = true;
doctype.remove();
wasRemoved = doctype.removed;
},
});

const result = rewriter.transform(html);

expect(sawDoctype).toBe(true);
expect(wasRemoved).toBe(true);
expect(result).not.toContain("<!DOCTYPE");
expect(result).toContain("<html>");
});
});