Skip to content

Commit

Permalink
fix: pass context local name when setting innerHTML (closes #146)
Browse files Browse the repository at this point in the history
  • Loading branch information
b-fuze committed Oct 7, 2023
1 parent bbb4f93 commit f05a381
Show file tree
Hide file tree
Showing 15 changed files with 125 additions and 48 deletions.
11 changes: 9 additions & 2 deletions build/deno-wasm/deno-wasm.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
export function parse(html: string): string;
/**
* @param {string} html
* @param {string} context_local_name
* @returns {string}
*/
export function parse_frag(html: string): string;
export function parse_frag(html: string, context_local_name: string): string;

export type InitInput =
| RequestInfo
Expand All @@ -21,7 +22,13 @@ export type InitInput =
export interface InitOutput {
readonly memory: WebAssembly.Memory;
readonly parse: (a: number, b: number, c: number) => void;
readonly parse_frag: (a: number, b: number, c: number) => void;
readonly parse_frag: (
a: number,
b: number,
c: number,
d: number,
e: number,
) => void;
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
readonly __wbindgen_malloc: (a: number) => number;
readonly __wbindgen_realloc: (a: number, b: number, c: number) => number;
Expand Down
13 changes: 10 additions & 3 deletions build/deno-wasm/deno-wasm.js

Large diffs are not rendered by default.

Binary file modified build/deno-wasm/deno-wasm_bg.wasm
Binary file not shown.
15 changes: 0 additions & 15 deletions build/deno-wasm/package.json

This file was deleted.

43 changes: 34 additions & 9 deletions deno-dom-native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const _symbols = {
result: "void",
},
deno_dom_parse_frag_sync: {
parameters: ["buffer", "usize", "buffer"],
parameters: ["buffer", "usize", "buffer", "usize", "buffer"],
result: "void",
},
deno_dom_is_big_endian: { parameters: [], result: "u32" },
Expand Down Expand Up @@ -74,16 +74,41 @@ const dylibParseFragSync = dylib.symbols.deno_dom_parse_frag_sync.bind(
const returnBufSizeLenRaw = new ArrayBuffer(usizeBytes * 2);
const returnBufSizeLen = new Uint8Array(returnBufSizeLenRaw);

type DocumentParser = (
srcBuf: Uint8Array,
srcLength: number,
returnBuf: Uint8Array,
) => void;
type FragmentParser = (
srcBuf: Uint8Array,
srcLength: number,
contextLocalNameBuf: Uint8Array,
contextLocalNameLength: number,
returnBuf: Uint8Array,
) => void;

function genericParse(
parser: (
srcBuf: Uint8Array,
srcLength: number,
returnBuf: Uint8Array,
) => void,
parser: DocumentParser | FragmentParser,
srcHtml: string,
contextLocalName?: string,
): string {
const encodedHtml = utf8Encoder.encode(srcHtml);
parser(encodedHtml, encodedHtml.length, returnBufSizeLen);
if (contextLocalName) {
const encodedContextLocalName = utf8Encoder.encode(contextLocalName);
(parser as FragmentParser)(
encodedHtml,
encodedHtml.length,
encodedContextLocalName,
encodedContextLocalName.length,
returnBufSizeLen,
);
} else {
(parser as DocumentParser)(
encodedHtml,
encodedHtml.length,
returnBufSizeLen,
);
}

const outBufSize = Number(
new DataView(returnBufSizeLenRaw).getBigUint64(0, !isBigEndian),
Expand All @@ -98,8 +123,8 @@ function parse(html: string): string {
return genericParse(dylibParseSync, html);
}

function parseFrag(html: string): string {
return genericParse(dylibParseFragSync, html);
function parseFrag(html: string, contextLocalName?: string): string {
return genericParse(dylibParseFragSync, html, contextLocalName);
}

// Register parse function
Expand Down
8 changes: 7 additions & 1 deletion deno-dom-wasm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import init, { parse, parse_frag } from "./build/deno-wasm/deno-wasm.js";
import { register } from "./src/parser.ts";

await init();
register(parse, parse_frag);
register(
parse,
parse_frag as unknown as (
html: string,
context_local_name?: string,
) => string,
);

export * from "./src/api.ts";
17 changes: 11 additions & 6 deletions html-parser/cli-test/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@ enum Method {

fn main() {
let mut method = Method::Document;
let mut context_local_name = "div".to_string();

for arg in args() {
match arg.as_str() {
"fragment" => {
method = Method::Fragment;
},
_ => {},
if let Method::Document = method {
match arg.as_str() {
"fragment" => {
method = Method::Fragment;
},
_ => {},
}
} else {
context_local_name = arg;
}
}

Expand All @@ -25,7 +30,7 @@ fn main() {
if let Method::Document = method {
println!("{}", parse(buf));
} else {
println!("{}", parse_frag(buf));
println!("{}", parse_frag(buf, context_local_name));
}
}

4 changes: 2 additions & 2 deletions html-parser/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub fn parse(html: String) -> String {
dom_to_string(len, &dom)
}

pub fn parse_frag(html: String) -> String {
pub fn parse_frag(html: String, context_local_name: String) -> String {
let len = html.len();
let sink: RcDom = Default::default();
let parser = parse_fragment(
Expand All @@ -46,7 +46,7 @@ pub fn parse_frag(html: String) -> String {
QualName::new(
None,
ns!(html),
LocalName::from("div"),
LocalName::from(context_local_name),
),
vec![],
);
Expand Down
14 changes: 12 additions & 2 deletions html-parser/plugin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,32 @@ pub extern "C" fn deno_dom_parse_sync(src_buf: *mut u8, src_len: usize, dest_buf
}

#[no_mangle]
pub extern "C" fn deno_dom_parse_frag_sync(src_buf: *mut u8, src_len: usize, dest_buf_size_ptr: *mut usize) {
pub extern "C" fn deno_dom_parse_frag_sync(
src_buf: *mut u8,
src_len: usize,
context_local_name_buf: *mut u8,
context_local_name_len: usize,
dest_buf_size_ptr: *mut usize
) {
let src_html = unsafe {
String::from_raw_parts(src_buf, src_len, src_len)
};
let context_local_name = unsafe {
String::from_raw_parts(context_local_name_buf, context_local_name_len, context_local_name_len)
};
let dest_buf_meta = unsafe {
std::slice::from_raw_parts_mut(
dest_buf_size_ptr,
std::mem::size_of::<usize>() * 2,
)
};

let parsed = Box::new(parse_frag(src_html.clone()));
let parsed = Box::new(parse_frag(src_html.clone(), context_local_name.clone()));
dest_buf_meta[0] = parsed.len();
dest_buf_meta[1] = Box::into_raw(parsed) as usize;

std::mem::forget(src_html);
std::mem::forget(context_local_name);
std::mem::forget(dest_buf_meta);
}

Expand Down
4 changes: 2 additions & 2 deletions html-parser/wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub fn parse(html: &str) -> String {
}

#[wasm_bindgen]
pub fn parse_frag(html: &str) -> String {
parse_frag_rs(html.into())
pub fn parse_frag(html: &str, context_local_name: &str) -> String {
parse_frag_rs(html.into(), context_local_name.into())
}

7 changes: 5 additions & 2 deletions src/deserialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ export function nodesFromString(html: string): Node {
return node;
}

export function fragmentNodesFromString(html: string): Node {
const parsed = JSON.parse(parseFrag(html));
export function fragmentNodesFromString(
html: string,
contextLocalName: string,
): Node {
const parsed = JSON.parse(parseFrag(html, contextLocalName));
const node = nodeFromArray(parsed, null);

return node;
Expand Down
2 changes: 1 addition & 1 deletion src/dom/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,7 @@ export class Element extends Node {

// Parse HTML into new children
if (html.length) {
const parsed = fragmentNodesFromString(html);
const parsed = fragmentNodesFromString(html, this.localName);
for (const child of parsed.childNodes[0].childNodes) {
mutator.push(child);
}
Expand Down
2 changes: 1 addition & 1 deletion src/dom/elements/html-template-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export class HTMLTemplateElement extends Element {

// Parse HTML into new children
if (html.length) {
const parsed = fragmentNodesFromString(html);
const parsed = fragmentNodesFromString(html, this.localName);
mutator.push(...parsed.childNodes[0].childNodes);

for (const child of content.childNodes) {
Expand Down
4 changes: 2 additions & 2 deletions src/parser.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/**
* Parser interface
*/
export type Parser = (html: string) => string;
export type Parser = (html: string, contextLocalName?: string) => string;
export let parse: Parser = (_html) => {
console.error("Error: deno-dom: No parser registered");
Deno.exit(1);
};

export let parseFrag: Parser = (_html) => {
export let parseFrag: Parser = (_html, _contextLocalName) => {
console.error("Error: deno-dom: No parser registered");
Deno.exit(1);
};
Expand Down
29 changes: 29 additions & 0 deletions test/units/Element-set-innerHTML.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,32 @@ Deno.test("setting Element.innerHTML yields children with correct .parentNode's"

assertEquals(child.parentNode, parent, "parentNode is the parent");
});

Deno.test(
"Element.innerHTML includes context",
() => {
const doc = new DOMParser().parseFromString(
`
<table><tr id=parent-row></tr></table>
<div id=parent-div></div>
`,
"text/html",
)!;

const parentRow = doc.querySelector("#parent-row")!;
parentRow.innerHTML = "<th>This is a header</th>";

assertEquals(
parentRow.innerHTML,
"<th>This is a header</th>",
);

const parentDiv = doc.querySelector("#parent-div")!;
parentDiv.innerHTML = "<th>This is a header</th>";

assertEquals(
parentDiv.innerHTML,
"This is a header",
);
},
);

0 comments on commit f05a381

Please sign in to comment.