-
Notifications
You must be signed in to change notification settings - Fork 46
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
TreeWalker #37
base: master
Are you sure you want to change the base?
TreeWalker #37
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,3 +5,4 @@ node_modules | |
/target | ||
*~ | ||
/.vim | ||
/.vscode |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
import { setLock, getLock } from "../constructor-lock.ts"; | ||
import { Node, NodeType, Text, Comment } from "./node.ts"; | ||
import { NodeList, nodeListMutatorSym } from "./node-list.ts"; | ||
import { Filter } from "./node-filter.ts"; | ||
import { Element } from "./element.ts"; | ||
import { TreeWalker } from "./treewalker.ts" | ||
import { DOM as NWAPI } from "./nwsapi-types.ts"; | ||
|
||
export class DOMImplementation { | ||
|
@@ -165,6 +167,10 @@ export class Document extends Node { | |
return child; | ||
} | ||
|
||
createComment(data?: string): Comment { | ||
return new Comment(data); | ||
} | ||
|
||
createElement(tagName: string, options?: ElementCreationOptions): Element { | ||
tagName = tagName.toUpperCase(); | ||
|
||
|
@@ -191,8 +197,8 @@ export class Document extends Node { | |
return new Text(data); | ||
} | ||
|
||
createComment(data?: string): Comment { | ||
return new Comment(data); | ||
createTreeWalker(root: Node, whatToShow?: number, filter?: Filter): TreeWalker { | ||
return new TreeWalker(root, whatToShow, filter); | ||
} | ||
|
||
querySelector(selectors: string): Element | null { | ||
|
@@ -289,7 +295,7 @@ export class Document extends Node { | |
|
||
export class HTMLDocument extends Document { | ||
constructor() { | ||
let lock = getLock(); | ||
const lock = getLock(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please revert this |
||
super(); | ||
|
||
if (lock) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { Node } from "./node.ts"; | ||
|
||
export enum NodeFilter { | ||
FILTER_ACCEPT = 1, | ||
FILTER_REJECT, | ||
FILTER_SKIP, | ||
|
||
// staticants for whatToShow | ||
SHOW_ALL = -1, | ||
SHOW_ELEMENT = 0x1, | ||
SHOW_ATTRIBUTE = 0x2, | ||
SHOW_TEXT = 0x4, | ||
SHOW_CDATA_SECTION = 0x8, | ||
SHOW_ENTITY_REFERENCE = 0x10, // legacy | ||
SHOW_ENTITY = 0x20, // legacy | ||
SHOW_PROCESSING_INSTRUCTION = 0x40, | ||
SHOW_COMMENT = 0x80, | ||
SHOW_DOCUMENT = 0x100, | ||
SHOW_DOCUMENT_TYPE = 0x200, | ||
SHOW_DOCUMENT_FRAGMENT = 0x400, | ||
SHOW_NOTATION = 0x800, // legacy | ||
} | ||
|
||
export interface Filter { | ||
acceptNode(node: Node): number; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please move this to |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -102,7 +102,7 @@ export class Node extends EventTarget { | |
this._setOwnerDocument(newParent.#ownerDocument); | ||
|
||
// Add parent chain to ancestors | ||
let parent: Node | null = newParent; | ||
const parent: Node | null = newParent; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please revert this whole file, it is unrelated to the PR. If you want to submit this, please do it as a separate PR. |
||
this._ancestors = new Set(newParent._ancestors); | ||
this._ancestors.add(newParent); | ||
} else { | ||
|
@@ -287,7 +287,7 @@ export class Node extends EventTarget { | |
} | ||
|
||
const index = parent._getChildNodesMutator().indexOf(this); | ||
let next: Node | null = this.childNodes[index + 1] || null; | ||
const next: Node | null = this.childNodes[index + 1] || null; | ||
|
||
return next; | ||
} | ||
|
@@ -300,7 +300,7 @@ export class Node extends EventTarget { | |
} | ||
|
||
const index = parent._getChildNodesMutator().indexOf(this); | ||
let prev: Node | null = this.childNodes[index - 1] || null; | ||
const prev: Node | null = this.childNodes[index - 1] || null; | ||
|
||
return prev; | ||
} | ||
|
@@ -337,7 +337,7 @@ export class Text extends CharacterData { | |
constructor( | ||
text: string = "", | ||
) { | ||
let oldLock = getLock(); | ||
const oldLock = getLock(); | ||
setLock(false); | ||
super( | ||
text, | ||
|
@@ -359,7 +359,7 @@ export class Comment extends CharacterData { | |
constructor( | ||
text: string = "", | ||
) { | ||
let oldLock = getLock(); | ||
const oldLock = getLock(); | ||
setLock(false); | ||
super( | ||
text, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { NodeFilter, Filter } from "./node-filter.ts"; | ||
import { Node } from "./node.ts"; | ||
|
||
export abstract class Traverser { | ||
public readonly root: Node; | ||
public readonly whatToShow: number; | ||
public readonly filter: Filter | undefined; | ||
private activeFlag = false; | ||
|
||
protected constructor(root: Node, whatToShow?: number, filter?: Filter) { | ||
this.root = root; | ||
this.whatToShow = whatToShow || -1; | ||
this.filter = filter; | ||
} | ||
|
||
protected accept(node: Node): number { | ||
if (this.activeFlag) { | ||
throw new Error("DOMException: InvalidStateError"); | ||
} | ||
|
||
if (!((1 << (node.nodeType-1)) & this.whatToShow)) { | ||
return NodeFilter.FILTER_SKIP; | ||
} | ||
|
||
if (!this.filter) { | ||
return NodeFilter.FILTER_ACCEPT; | ||
} | ||
|
||
this.activeFlag = true; | ||
let result: number; | ||
try { | ||
result = this.filter.acceptNode(node); | ||
} catch (error) { | ||
this.activeFlag = false; | ||
throw error; | ||
} | ||
|
||
this.activeFlag = false; | ||
return result; | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please move this to |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
import { Node } from "./node.ts"; | ||
import { NodeFilter, Filter } from "./node-filter.ts"; | ||
import { Traverser } from "./traverser.ts"; | ||
|
||
|
||
export class TreeWalker extends Traverser { | ||
public currentNode: Node; | ||
|
||
constructor(root: Node, whatToShow?: number, filter?: Filter) { | ||
super(root, whatToShow, filter); | ||
this.currentNode = root; | ||
} | ||
|
||
parentNode(): Node | null { | ||
let node: Node | null = this.currentNode; | ||
while (node && node != this.root) { | ||
node = node.parentNode; | ||
if (node && this.accept(node) === NodeFilter.FILTER_ACCEPT) { | ||
this.currentNode = node; | ||
return node; | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
|
||
firstChild(): Node | null { | ||
return this.traverseChildren(new Forwards()); | ||
} | ||
|
||
lastChild(): Node | null { | ||
return this.traverseChildren(new Backwards()); | ||
} | ||
|
||
previousSibling(): Node | null { | ||
return this.traverseSiblings(new Backwards()); | ||
} | ||
|
||
nextSibling(): Node | null { | ||
return this.traverseSiblings(new Forwards()); | ||
} | ||
|
||
previousNode(): Node | null { | ||
let node: Node = this.currentNode; | ||
let tmp: Node | null; | ||
while (node != this.root) { | ||
while (tmp = node.previousSibling) { | ||
node = tmp; | ||
const result = this.accept(node); | ||
if (result === NodeFilter.FILTER_REJECT) { | ||
continue; | ||
} | ||
while (tmp = node.lastChild) { | ||
node = tmp; | ||
const result = this.accept(node); | ||
if (result === NodeFilter.FILTER_REJECT) { | ||
break; | ||
} | ||
} | ||
if (result === NodeFilter.FILTER_ACCEPT) { | ||
this.currentNode = node; | ||
return node; | ||
} | ||
} | ||
if (node === this.root) { | ||
return null; | ||
} | ||
if (tmp = node.parentNode) { | ||
node = tmp; | ||
const result = this.accept(node); | ||
if (result === NodeFilter.FILTER_ACCEPT) { | ||
this.currentNode = node; | ||
return node; | ||
} | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
|
||
nextNode(): Node | null { | ||
let tmp: Node | null; | ||
let node: Node = this.currentNode; | ||
loop: while (true) { | ||
while (tmp = node.firstChild) { | ||
node = tmp; | ||
const result = this.accept(node); | ||
if (result === NodeFilter.FILTER_ACCEPT) { | ||
this.currentNode = node; | ||
return node; | ||
} | ||
if (result === NodeFilter.FILTER_REJECT) { | ||
break; | ||
} | ||
} | ||
while (tmp = node.nextSibling) { | ||
node = tmp; | ||
const result = this.accept(node); | ||
if (result === NodeFilter.FILTER_ACCEPT) { | ||
this.currentNode = node; | ||
return node; | ||
} | ||
if (result === NodeFilter.FILTER_SKIP) { | ||
continue loop; | ||
} | ||
} | ||
break; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
private traverseChildren(strategy: Strategy): Node | null { | ||
let node: Node; | ||
let tmp: Node | null = strategy.first(this.currentNode); | ||
|
||
while (tmp) { | ||
node = tmp; | ||
const result = this.accept(node); | ||
if (result === NodeFilter.FILTER_ACCEPT) { | ||
this.currentNode = node; | ||
return node; | ||
} | ||
if (result === NodeFilter.FILTER_SKIP && (tmp = strategy.first(node))) { | ||
continue; | ||
} | ||
do { | ||
if (tmp = strategy.next(node)) { | ||
break; | ||
} | ||
tmp = node.parentNode; | ||
if (!tmp || tmp === this.root || tmp === this.currentNode) { | ||
return null; | ||
} | ||
node = tmp; | ||
} while (tmp); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
private traverseSiblings(strategy: Strategy): Node | null { | ||
let node: Node = this.currentNode; | ||
|
||
if (node === this.root) { | ||
return null; | ||
} | ||
|
||
let tmp: Node | null; | ||
while (true) { | ||
while (tmp = strategy.next(node)) { | ||
node = tmp; | ||
const result = this.accept(node); | ||
if (result === NodeFilter.FILTER_ACCEPT) { | ||
this.currentNode = node; | ||
return node; | ||
} | ||
if (!(tmp = strategy.first(tmp)) || (result === NodeFilter.FILTER_REJECT)) { | ||
tmp = strategy.next(node); | ||
} | ||
} | ||
if ((tmp = node.parentNode) && (tmp != this.root)) { | ||
node = tmp; | ||
const result = this.accept(node); | ||
if (result === NodeFilter.FILTER_ACCEPT) { | ||
return null; | ||
} | ||
} else { | ||
return null; | ||
} | ||
} | ||
} | ||
} | ||
|
||
interface Strategy { | ||
next(node: Node): Node | null; | ||
first(node: Node): Node | null; | ||
} | ||
|
||
class Forwards implements Strategy { | ||
next(node: Node): Node | null { | ||
return node.nextSibling; | ||
} | ||
first(node: Node): Node | null { | ||
return node.firstChild; | ||
} | ||
} | ||
|
||
class Backwards implements Strategy { | ||
next(node: Node): Node | null { | ||
return node.previousSibling; | ||
} | ||
first(node: Node): Node | null { | ||
return node.lastChild; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,9 @@ | ||
import { dirname, join } from "https://deno.land/[email protected]/path/mod.ts"; | ||
|
||
const unitDir = join(dirname(new URL(import.meta.url).pathname), "units"); | ||
let unitDir = join(dirname(new URL(import.meta.url).pathname), "units"); | ||
if (Deno.build.os === "windows") { | ||
unitDir = unitDir.slice(1); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this for? |
||
const units = Array.from(Deno.readDirSync(unitDir)) | ||
.filter(file => file.isFile && file.name.endsWith(".ts")) | ||
.map(file => join("units", file.name)); | ||
|
@@ -12,4 +15,3 @@ Deno.chdir(unitDir); | |
for (const file of units) { | ||
await import("./" + file); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,7 @@ export type Backend = "wasm" | "native"; | |
export async function run(path: string, root: string, backend: Backend) { | ||
const html = await Deno.readTextFile(path); | ||
const doc = parser.parseFromString(html, "text/html")!; | ||
let scripts = Array.from(doc.querySelectorAll("script")).map(scriptNode => { | ||
const scripts = Array.from(doc.querySelectorAll("script")).map(scriptNode => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please revert this file |
||
const scriptElement = scriptNode as Element; | ||
let script = scriptElement.getAttribute("src")!; | ||
let scriptContents: string; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why was this moved?