Skip to content

Commit 4e8ac8b

Browse files
committed
Merge remote-tracking branch 'upstream/master'
2 parents 9770094 + ef8a617 commit 4e8ac8b

File tree

83 files changed

+1735
-386
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+1735
-386
lines changed

.devcontainer/Dockerfile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
FROM mcr.microsoft.com/devcontainers/base:debian
2+
3+
# Install deno
4+
ENV DENO_INSTALL=/deno
5+
RUN mkdir -p /deno \
6+
&& curl -fsSL https://deno.land/install.sh | sh \
7+
&& chown -R vscode /deno
8+
9+
ENV PATH=${DENO_INSTALL}/bin:${PATH} \
10+
DENO_DIR=${DENO_INSTALL}/.cache/deno

.devcontainer/devcontainer.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "Deno",
3+
"build": {
4+
"dockerfile": "Dockerfile"
5+
},
6+
"customizations": {
7+
"vscode": {
8+
"settings": {
9+
"editor.defaultFormatter": "denoland.vscode-deno",
10+
"deno.lint": true,
11+
"deno.enable": true
12+
},
13+
"extensions": ["denoland.vscode-deno"]
14+
},
15+
"remoteUser": "vscode"
16+
}
17+
}

.github/workflows/deno-dom.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,11 @@ jobs:
2828
- name: Check code formatting
2929
run: deno fmt --check --unstable
3030

31+
# We check in a separate step because dynamic imports
32+
# no longer type check at runtime which we need for
33+
# invoking the unit tests
34+
- name: Check TypeScript types
35+
run: deno task type-check
36+
3137
- name: Run tests
32-
run: deno test --allow-read --allow-net wasm.test.ts
38+
run: deno test --no-check --allow-read --allow-net wasm.test.ts

.github/workflows/main.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,9 @@ jobs:
9494
rustup target add "$target"
9595
9696
# Add ARM64 Ubuntu repos
97-
sed -E '/^deb/!d; s|.+/|deb [arch=arm64] http://ports.ubuntu.com/|' /etc/apt/sources.list | sudo tee /etc/apt/sources.list.d/sources-arm64.list
97+
sed -E '/^deb/!d; s|.+/([^/]+\.txt)?|deb [arch=arm64] http://ports.ubuntu.com/|' /etc/apt/sources.list | sudo tee /etc/apt/sources.list.d/sources-arm64.list
98+
# Mark existing repos as x86_64 only
99+
sudo sed -i -E 's/^deb/deb [arch=amd64]/' /etc/apt/sources.list
98100
sudo dpkg --add-architecture arm64
99101
sudo bash -c 'apt update; true'
100102

README.md

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,18 @@ Rust, WASM, and obviously, Deno/TypeScript.
66
## Example
77

88
```typescript
9-
import {
10-
DOMParser,
11-
Element,
12-
} from "https://deno.land/x/deno_dom/deno-dom-wasm.ts";
9+
import { DOMParser, Element } from "jsr:@b-fuze/deno-dom";
10+
11+
// non-JSR wasm url import: https://deno.land/x/deno_dom/deno-dom-wasm.ts
12+
// non-JSR native url import: https://deno.land/x/deno_dom/deno-dom-native.ts
1313

1414
const doc = new DOMParser().parseFromString(
1515
`
16-
<h1>Hello World!</h1>
17-
<p>Hello from <a href="https://deno.land/">Deno!</a></p>
18-
`,
16+
<h1>Hello World!</h1>
17+
<p>Hello from <a href="https://deno.land/">Deno!</a></p>
18+
`,
1919
"text/html",
20-
)!;
20+
);
2121

2222
const p = doc.querySelector("p")!;
2323

@@ -31,8 +31,11 @@ console.log(p.children[0].outerHTML); // "<b>Deno</b>"
3131
Deno DOM has **two** backends, WASM and native using Deno native plugins. Both
3232
APIs are **identical**, the difference being only in performance. The WASM
3333
backend works with all Deno restrictions, but the native backend requires the
34-
`--unstable --allow-ffi` flags. You can switch between them by importing either
35-
`deno-dom-wasm.ts` or `deno-dom-native.ts`.
34+
`--unstable-ffi --allow-ffi --allow-env --allow-read --allow-net=deno.land`
35+
flags. A shorter version could be `--unstable-ffi -A`, but that allows all
36+
permissions so you'd have to assess your risk and requirements. You can switch
37+
between them by importing either `jsr:@b-fuze/deno-dom` for WASM or
38+
`jsr:@b-fuze/deno-dom/native` for the native binary.
3639

3740
Deno DOM is still under development, but is fairly usable for basic HTML
3841
manipulation needs.
@@ -42,23 +45,19 @@ manipulation needs.
4245
Deno suffers an initial startup penalty in Deno DOM WASM due to Top Level Await
4346
(TLA) preparing the WASM parser. As an alternative to running the initiation on
4447
startup, you can initialize Deno DOM's parser on-demand yourself when you need
45-
it by importing from `deno-dom-wasm-noinit.ts`. Example:
48+
it by importing from `jsr:@b-fuze/deno-dom/wasm-noinit`. Example:
4649

4750
```typescript
48-
// Note: -wasm-noinit.ts and not -wasm.ts
49-
import {
50-
DOMParser,
51-
initParser,
52-
} from "https://deno.land/x/deno_dom/deno-dom-wasm-noinit.ts";
51+
import { DOMParser, initParser } from "jsr:@b-fuze/deno-dom/wasm-noinit";
5352

5453
// ...and when you need Deno DOM make sure you initialize the parser...
5554
await initParser();
5655

5756
// Then you can use Deno DOM as you would normally
5857
const doc = new DOMParser().parseFromString(
5958
`
60-
<h1>Lorem ipsum dolor...</h1>
61-
`,
59+
<h1>Lorem ipsum dolor...</h1>
60+
`,
6261
"text/html",
6362
);
6463
```
@@ -74,7 +73,7 @@ inconsistencies (that aren't a result of legacy APIs) file an issue.
7473
- Fast
7574
- Mirror _most_ supported DOM APIs as closely as possible
7675
- Provide specific APIs in addition to DOM APIs to make certain operations more
77-
efficient, like controlling Shadow DOM (see Open Questions)
76+
efficient, like controlling Shadow DOM
7877
- Use cutting-edge JS features like private class members, optional chaining,
7978
etc
8079

build/deno-wasm/deno-wasm.d.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
export function parse(html: string): string;
88
/**
99
* @param {string} html
10+
* @param {string} context_local_name
1011
* @returns {string}
1112
*/
12-
export function parse_frag(html: string): string;
13+
export function parse_frag(html: string, context_local_name: string): string;
1314

1415
export type InitInput =
1516
| RequestInfo
@@ -21,7 +22,13 @@ export type InitInput =
2122
export interface InitOutput {
2223
readonly memory: WebAssembly.Memory;
2324
readonly parse: (a: number, b: number, c: number) => void;
24-
readonly parse_frag: (a: number, b: number, c: number) => void;
25+
readonly parse_frag: (
26+
a: number,
27+
b: number,
28+
c: number,
29+
d: number,
30+
e: number,
31+
) => void;
2532
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
2633
readonly __wbindgen_malloc: (a: number) => number;
2734
readonly __wbindgen_realloc: (a: number, b: number, c: number) => number;

build/deno-wasm/deno-wasm.js

Lines changed: 22 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/deno-wasm/deno-wasm_bg.js

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,18 @@ const lTextEncoder = typeof TextEncoder === "undefined"
1919

2020
let cachedTextEncoder = new lTextEncoder("utf-8");
2121

22-
const encodeString =
23-
(typeof cachedTextEncoder.encodeInto === "function"
24-
? function (arg, view) {
25-
return cachedTextEncoder.encodeInto(arg, view);
26-
}
27-
: function (arg, view) {
28-
const buf = cachedTextEncoder.encode(arg);
29-
view.set(buf);
30-
return {
31-
read: arg.length,
32-
written: buf.length,
33-
};
34-
});
22+
const encodeString = typeof cachedTextEncoder.encodeInto === "function"
23+
? function (arg, view) {
24+
return cachedTextEncoder.encodeInto(arg, view);
25+
}
26+
: function (arg, view) {
27+
const buf = cachedTextEncoder.encode(arg);
28+
view.set(buf);
29+
return {
30+
read: arg.length,
31+
written: buf.length,
32+
};
33+
};
3534

3635
function passStringToWasm0(arg, malloc, realloc) {
3736
if (realloc === undefined) {

build/deno-wasm/deno-wasm_bg.wasm

79 KB
Binary file not shown.

build/deno-wasm/package.json

Lines changed: 0 additions & 15 deletions
This file was deleted.

deno-dom-native.ts

Lines changed: 91 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,38 @@
1-
import { Plug } from "https://deno.land/x/plug/mod.ts";
1+
/**
2+
* @module
3+
*
4+
* This module exposes the Deno DOM API with the native binary backend.
5+
* Unlike the WASM backend the native backend requires more permissions
6+
* due to the nature of how native bindings work. They include:
7+
*
8+
* - `--unstable-ffi`
9+
* - `--allow-ffi`
10+
* - `--allow-env`
11+
* - `--allow-read`
12+
* - `--allow-net=deno.land`
13+
*
14+
* @example
15+
* ```ts
16+
* import { DOMParser, initParser } from "jsr:@b-fuze/deno-dom/native";
17+
*
18+
* // ...and when you need Deno DOM make sure you initialize the parser...
19+
* await initParser();
20+
*
21+
* // Then you can use Deno DOM as you would normally
22+
* const doc = new DOMParser().parseFromString(
23+
* `
24+
* <h1>Hello World!</h1>
25+
* <p>Hello from <a href="https://deno.land/">Deno!</a></p>
26+
* `,
27+
* "text/html",
28+
* );
29+
*
30+
* const p = doc.querySelector("p")!;
31+
* console.log(p.textContent); // "Hello from Deno!"
32+
* ```
33+
*/
34+
35+
import { dlopen } from "jsr:@denosaurs/plug@1.0.3";
236
import { register } from "./src/parser.ts";
337

438
const nativeEnv = "DENO_DOM_PLUGIN";
@@ -18,7 +52,7 @@ const _symbols = {
1852
result: "void",
1953
},
2054
deno_dom_parse_frag_sync: {
21-
parameters: ["buffer", "usize", "buffer"],
55+
parameters: ["buffer", "usize", "buffer", "usize", "buffer"],
2256
result: "void",
2357
},
2458
deno_dom_is_big_endian: { parameters: [], result: "u32" },
@@ -32,11 +66,30 @@ if (denoNativePluginPath) {
3266
// Load the plugin locally
3367
dylib = Deno.dlopen(denoNativePluginPath, symbols);
3468
} else {
69+
const host = `${Deno.build.os}-${Deno.build.arch}` as const;
70+
let name = "";
71+
72+
switch (host) {
73+
case "linux-x86_64":
74+
case "darwin-x86_64":
75+
case "windows-x86_64":
76+
name = "plugin";
77+
break;
78+
79+
case "linux-aarch64":
80+
name = "plugin-linux-aarch64";
81+
break;
82+
83+
default:
84+
console.error(`deno-dom-native: host ${host} has no supported backend`);
85+
Deno.exit(1);
86+
}
87+
3588
// Download the plugin
36-
dylib = await Plug.prepare({
37-
name: "plugin",
89+
dylib = await dlopen({
90+
name,
3891
url:
39-
"https://github.com/b-fuze/deno-dom/releases/download/v0.1.23-alpha-artifacts/",
92+
"https://github.com/b-fuze/deno-dom/releases/download/v0.1.41-alpha-artifacts/",
4093
}, symbols);
4194
}
4295

@@ -55,16 +108,41 @@ const dylibParseFragSync = dylib.symbols.deno_dom_parse_frag_sync.bind(
55108
const returnBufSizeLenRaw = new ArrayBuffer(usizeBytes * 2);
56109
const returnBufSizeLen = new Uint8Array(returnBufSizeLenRaw);
57110

111+
type DocumentParser = (
112+
srcBuf: Uint8Array,
113+
srcLength: bigint,
114+
returnBuf: Uint8Array,
115+
) => void;
116+
type FragmentParser = (
117+
srcBuf: Uint8Array,
118+
srcLength: bigint,
119+
contextLocalNameBuf: Uint8Array,
120+
contextLocalNameLength: bigint,
121+
returnBuf: Uint8Array,
122+
) => void;
123+
58124
function genericParse(
59-
parser: (
60-
srcBuf: Uint8Array,
61-
srcLength: number,
62-
returnBuf: Uint8Array,
63-
) => void,
125+
parser: DocumentParser | FragmentParser,
64126
srcHtml: string,
127+
contextLocalName?: string,
65128
): string {
66129
const encodedHtml = utf8Encoder.encode(srcHtml);
67-
parser(encodedHtml, encodedHtml.length, returnBufSizeLen);
130+
if (contextLocalName) {
131+
const encodedContextLocalName = utf8Encoder.encode(contextLocalName);
132+
(parser as FragmentParser)(
133+
encodedHtml,
134+
BigInt(encodedHtml.length),
135+
encodedContextLocalName,
136+
BigInt(encodedContextLocalName.length),
137+
returnBufSizeLen,
138+
);
139+
} else {
140+
(parser as DocumentParser)(
141+
encodedHtml,
142+
BigInt(encodedHtml.length),
143+
returnBufSizeLen,
144+
);
145+
}
68146

69147
const outBufSize = Number(
70148
new DataView(returnBufSizeLenRaw).getBigUint64(0, !isBigEndian),
@@ -79,8 +157,8 @@ function parse(html: string): string {
79157
return genericParse(dylibParseSync, html);
80158
}
81159

82-
function parseFrag(html: string): string {
83-
return genericParse(dylibParseFragSync, html);
160+
function parseFrag(html: string, contextLocalName?: string): string {
161+
return genericParse(dylibParseFragSync, html, contextLocalName);
84162
}
85163

86164
// Register parse function

deno-dom-wasm-noinit.ts

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,45 @@
1+
/**
2+
* @module
3+
*
4+
* This module exposes the Deno DOM API with the WASM (Web Assembly) backend.
5+
* This module is different from the primary WASM module because it allows
6+
* you to control when the WASM HTML parsing engine loads (which is a
7+
* relatively slow process). You can't use any of the parsing functions
8+
* of Deno DOM until you invoke the async `initParser()` export.
9+
*
10+
* @example
11+
* ```ts
12+
* import { DOMParser, initParser } from "jsr:@b-fuze/deno-dom/wasm-noinit";
13+
*
14+
* // ...and when you need Deno DOM's parser make sure you initialize it...
15+
* await initParser();
16+
*
17+
* // Then you can use Deno DOM as you would normally
18+
* const doc = new DOMParser().parseFromString(
19+
* `
20+
* <h1>Hello World!</h1>
21+
* <p>Hello from <a href="https://deno.land/">Deno!</a></p>
22+
* `,
23+
* "text/html",
24+
* );
25+
*
26+
* const p = doc.querySelector("p")!;
27+
* console.log(p.textContent); // "Hello from Deno!"
28+
* ```
29+
*/
30+
131
import initWasm, {
232
parse,
333
parse_frag as parseFrag,
434
} from "./build/deno-wasm/deno-wasm.js";
5-
import { register } from "./src/parser.ts";
35+
import { type Parser, register } from "./src/parser.ts";
636

737
export async function initParser() {
838
await initWasm();
9-
register(parse, parseFrag);
39+
register(
40+
parse,
41+
parseFrag as Parser,
42+
);
1043
}
1144

1245
export * from "./src/api.ts";

0 commit comments

Comments
 (0)