-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
43081j
committed
Aug 13, 2022
1 parent
17c8022
commit d30b5ad
Showing
1 changed file
with
170 additions
and
77 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,80 +1,173 @@ | ||
# parse5-tools | ||
# @parse5/tools | ||
|
||
A set of tools for interacting with and manipulating a parse5 AST. | ||
|
||
# WIP | ||
|
||
This is a work in progress until we achieve the same functionality dom5 and modernweb have. | ||
|
||
## Suggested interface | ||
|
||
* Tree interaction | ||
* replaceWith | ||
* Attributes | ||
* setAttribute | ||
* getAttribute | ||
* hasAttribute | ||
* removeAttribute | ||
* getAttributeIndex | ||
* getAttributes | ||
* Node interaction | ||
* getTextContent | ||
* setTextContent | ||
* normalizeNode | ||
* Traversal | ||
* query | ||
* queryAll | ||
* treeMap | ||
* ancestors | ||
* previousSiblings | ||
* nextSiblings | ||
* prior | ||
* walk | ||
|
||
## dom5 | ||
|
||
* Mutation | ||
* [x] replaceNode | ||
* [x] removeNodeSaveChildren - use `replaceWith` | ||
* [ ] removeFakeRootElements | ||
* Iteration | ||
* [x] treeMap | ||
* [x] depthFirst | ||
* [x] depthFirstReversed | ||
* [x] depthFirstIncludingTemplates | ||
* [x] ancestors | ||
* [x] previousSiblings | ||
* [x] prior | ||
* [x] query | ||
* [x] queryAll | ||
* Utilities | ||
* [x] getTextContent | ||
* [x] getAttribute | ||
* [x] getAttributeIndex | ||
* [x] hasAttribute | ||
* [x] setAttribute | ||
* [x] removeAttribute | ||
* [x] normalize | ||
* [x] setTextContent | ||
|
||
Many of the iteration functions use a predicate concept to allow filtering. | ||
|
||
## modernweb | ||
|
||
* Mutation | ||
* [ ] createScript - use `createElement` instead | ||
* [x] setAttribute | ||
* [ ] setAttributes - use `setAttribute` instead | ||
* [x] removeAttribute | ||
* [ ] prependToDocument | ||
* [ ] appendToDocument | ||
* Utilities | ||
* [ ] isHtmlFragment | ||
* [x] hasAttribute | ||
* [x] getAttribute | ||
* [x] getAttributes | ||
* Iteration | ||
* [x] findNode | ||
* [x] findNodes | ||
* [ ] findElement - use `findNode` with a type guard | ||
* [ ] findElements - use `findNodes` with a type guard | ||
## Why? | ||
|
||
The parse5 tree adapter architecture can make AST types, traversal and | ||
manipulation difficult due to its customisability. | ||
|
||
This package introduces some assumptions (i.e. removes some customisability) | ||
in order to provide a more trivial interface to the parse5 AST for the common | ||
use case. | ||
|
||
Due to this, the types in various places are also simplified and improved. | ||
|
||
## Tools | ||
|
||
### Node type guards | ||
|
||
A full set of node type guard functions are availabile: | ||
|
||
* `isDocument` | ||
* `isDocumentFragment` | ||
* `isTemplateNode` | ||
* `isElementNode` | ||
* `isCommentNode` | ||
* `isDocumentTypeNode` | ||
* `isTextNode` | ||
|
||
Each of these consumes a `Node` and acts as a TypeScript type guard: | ||
|
||
```ts | ||
if (isDocument(node)) { | ||
// access document-specific properties | ||
} | ||
``` | ||
|
||
### Parent/child type guards | ||
|
||
These help with determining if a given node can have children, or can be | ||
a child. | ||
|
||
* `isChildNode` | ||
* `isParentNode` | ||
|
||
These too are TypeScript type guards: | ||
|
||
```ts | ||
if (isChildNode(node)) { | ||
// interact with node.parentNode | ||
} | ||
|
||
if (isParentNode(node)) { | ||
// interact with node.childNodes | ||
} | ||
``` | ||
|
||
### Child manipulation | ||
|
||
If you need to mutate a child: | ||
|
||
* `replaceWith(node, ...replacements)` - replaces a given node with one or more | ||
nodes | ||
* `spliceChildren(node, start, deleteCount[, ...children])` - splices the | ||
children of a node just the same as `Array#splice` | ||
|
||
### Attributes | ||
|
||
For interacting with and mutating attributes of an element: | ||
|
||
* `setAttribute(node, name, value)` | ||
* `getAttribute(node, name)` | ||
* `hasAttribute(node, name)` | ||
* `removeAttribute(node, name)` | ||
* `getAttributeIndex(node, name)` | ||
|
||
### Text manipulation | ||
|
||
For dealing with text content of nodes: | ||
|
||
* `getTextContent(node)` | ||
* `setTextContent(node, str)` | ||
|
||
### Traversal | ||
|
||
Unless otherwise specified, all traversal functions are _depth first_. | ||
|
||
Additionally, all capable of returning multiple nodes are iterators. | ||
|
||
#### `query(node, condition)` | ||
|
||
From a given node, this queries for a child at any depth which matches the | ||
condition. | ||
|
||
For example, to find the first document fragment: | ||
|
||
```ts | ||
query( | ||
node, | ||
(node) => isDocumentFragment(node) | ||
); | ||
``` | ||
|
||
### `queryAll(node[, condition])` | ||
|
||
From a given node, this queries for all children at any depth which match | ||
the condition. | ||
|
||
For example, to find all elements: | ||
|
||
```ts | ||
const elements = query( | ||
node, | ||
(node) => isElementNode(node) | ||
); | ||
|
||
for (const element of elements) { | ||
// do something | ||
} | ||
``` | ||
|
||
### `ancestors(node)` | ||
|
||
Discovers all parents of the specified node until the root document. | ||
|
||
### `walkChildren(node)` | ||
|
||
Discovers all children of the specified node, depth-first. | ||
|
||
### `previousSiblings(node)` | ||
|
||
Discovers all previous siblings of the specified node. | ||
|
||
### `nextSiblings(node)` | ||
|
||
Discovers all next siblings of the specified node. | ||
|
||
### `traverse` | ||
|
||
The traverse function allows you to specify a visitor which will be called | ||
for each matching type encountered while traversing the tree depth-first. | ||
|
||
For example: | ||
|
||
```ts | ||
traverse(node, { | ||
text: (textNode) => { | ||
// do something with a text node | ||
} | ||
}); | ||
``` | ||
|
||
Each node type can have a visitor (e.g. you could have an `element` function). | ||
|
||
#### `pre:node` | ||
|
||
There is one special visit function: `pre:node`. | ||
|
||
This is called before visiting any node and will prevent traversing into | ||
the current node's children if it returns false. | ||
|
||
For example: | ||
|
||
```ts | ||
traverse(node, { | ||
'pre:node': (node) => { | ||
return isElement(node); | ||
} | ||
}); | ||
``` | ||
|
||
This example would traverse into the children of only element nodes as all | ||
others would have returned false. |