@cjser/parse5 8.0.1-cjser.2 → 8.1.0-cjser.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/parser/index.d.ts +12 -7
- package/dist/parser/index.js +50 -21
- package/dist/tokenizer/index.d.ts +34 -7
- package/dist/tokenizer/index.js +263 -67
- package/dist/tokenizer/preprocessor.d.ts +3 -0
- package/dist/tokenizer/preprocessor.js +14 -5
- package/dist/tree-adapters/interface.d.ts +17 -0
- package/dist-cjser/index.cjs +312 -104
- package/package.json +9 -5
package/dist/index.d.ts
CHANGED
|
@@ -16,8 +16,8 @@ export declare namespace DefaultTreeAdapterTypes {
|
|
|
16
16
|
type Node = DefaultTreeAdapter.Node;
|
|
17
17
|
type DefaultTreeAdapterMap = DefaultTreeAdapter.DefaultTreeAdapterMap;
|
|
18
18
|
}
|
|
19
|
-
export type { TreeAdapter, TreeAdapterTypeMap } from './tree-adapters/interface.js';
|
|
20
|
-
export { type ParserOptions, /** @internal */ Parser } from './parser/index.js';
|
|
19
|
+
export type { ElementCreationContext, TreeAdapter, TreeAdapterTypeMap } from './tree-adapters/interface.js';
|
|
20
|
+
export { type ParserOptions, /** @internal */ Parser, InsertionMode } from './parser/index.js';
|
|
21
21
|
export { serialize, serializeOuter, type SerializerOptions } from './serializer/index.js';
|
|
22
22
|
export { ERR as ErrorCodes, type ParserError, type ParserErrorHandler } from './common/error-codes.js';
|
|
23
23
|
/** @internal */
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Parser } from './parser/index.js';
|
|
2
2
|
export { defaultTreeAdapter } from './tree-adapters/default.js';
|
|
3
|
-
export { /** @internal */ Parser } from './parser/index.js';
|
|
3
|
+
export { /** @internal */ Parser, InsertionMode } from './parser/index.js';
|
|
4
4
|
export { serialize, serializeOuter } from './serializer/index.js';
|
|
5
5
|
export { ERR as ErrorCodes } from './common/error-codes.js';
|
|
6
6
|
/** @internal */
|
package/dist/parser/index.d.ts
CHANGED
|
@@ -4,8 +4,8 @@ import { FormattingElementList } from './formatting-element-list.js';
|
|
|
4
4
|
import { ERR, type ParserErrorHandler } from '../common/error-codes.js';
|
|
5
5
|
import { TAG_ID as $, NS } from '../common/html.js';
|
|
6
6
|
import type { TreeAdapter, TreeAdapterTypeMap } from '../tree-adapters/interface.js';
|
|
7
|
-
import { type Token, type CommentToken, type CharacterToken, type TagToken, type DoctypeToken, type EOFToken, type LocationWithAttributes } from '../common/token.js';
|
|
8
|
-
declare enum InsertionMode {
|
|
7
|
+
import { type Token, type CommentToken, type CharacterToken, type TagToken, type DoctypeToken, type EOFToken, type LocationWithAttributes, type Attribute } from '../common/token.js';
|
|
8
|
+
export declare enum InsertionMode {
|
|
9
9
|
INITIAL = 0,
|
|
10
10
|
BEFORE_HTML = 1,
|
|
11
11
|
BEFORE_HEAD = 2,
|
|
@@ -30,6 +30,10 @@ declare enum InsertionMode {
|
|
|
30
30
|
AFTER_AFTER_BODY = 21,
|
|
31
31
|
AFTER_AFTER_FRAMESET = 22
|
|
32
32
|
}
|
|
33
|
+
interface InsertionLocation<T extends TreeAdapterTypeMap> {
|
|
34
|
+
parent: T['parentNode'];
|
|
35
|
+
beforeElement: T['element'] | null;
|
|
36
|
+
}
|
|
33
37
|
export interface ParserOptions<T extends TreeAdapterTypeMap> {
|
|
34
38
|
/**
|
|
35
39
|
* The [scripting flag](https://html.spec.whatwg.org/multipage/parsing.html#scripting-flag). If set
|
|
@@ -134,7 +138,11 @@ export declare class Parser<T extends TreeAdapterTypeMap> implements TokenHandle
|
|
|
134
138
|
/** @protected */
|
|
135
139
|
_setDocumentType(token: DoctypeToken): void;
|
|
136
140
|
/** @protected */
|
|
137
|
-
_attachElementToTree(element: T['element'], location: LocationWithAttributes | null): void;
|
|
141
|
+
_attachElementToTree(element: T['element'], location: LocationWithAttributes | null, insertionLocation: InsertionLocation<T>): void;
|
|
142
|
+
/** @protected */
|
|
143
|
+
_getInsertionLocation(): InsertionLocation<T>;
|
|
144
|
+
/** @protected */
|
|
145
|
+
_createElement(tagName: string, namespaceURI: NS, attrs: Attribute[], intendedParent: T['parentNode']): T['element'];
|
|
138
146
|
/**
|
|
139
147
|
* For self-closing tags. Add an element to the tree, but skip adding it
|
|
140
148
|
* to the stack.
|
|
@@ -177,10 +185,7 @@ export declare class Parser<T extends TreeAdapterTypeMap> implements TokenHandle
|
|
|
177
185
|
/** @protected */
|
|
178
186
|
_shouldFosterParentOnInsertion(): boolean;
|
|
179
187
|
/** @protected */
|
|
180
|
-
_findFosterParentingLocation():
|
|
181
|
-
parent: T['parentNode'];
|
|
182
|
-
beforeElement: T['element'] | null;
|
|
183
|
-
};
|
|
188
|
+
_findFosterParentingLocation(): InsertionLocation<T>;
|
|
184
189
|
/** @protected */
|
|
185
190
|
_fosterParentElement(element: T['element']): void;
|
|
186
191
|
/** @protected */
|
package/dist/parser/index.js
CHANGED
|
@@ -14,7 +14,7 @@ const HIDDEN_INPUT_TYPE = 'hidden';
|
|
|
14
14
|
const AA_OUTER_LOOP_ITER = 8;
|
|
15
15
|
const AA_INNER_LOOP_ITER = 3;
|
|
16
16
|
//Insertion modes
|
|
17
|
-
var InsertionMode;
|
|
17
|
+
export var InsertionMode;
|
|
18
18
|
(function (InsertionMode) {
|
|
19
19
|
InsertionMode[InsertionMode["INITIAL"] = 0] = "INITIAL";
|
|
20
20
|
InsertionMode[InsertionMode["BEFORE_HTML"] = 1] = "BEFORE_HTML";
|
|
@@ -273,7 +273,7 @@ export class Parser {
|
|
|
273
273
|
}
|
|
274
274
|
}
|
|
275
275
|
/** @protected */
|
|
276
|
-
_attachElementToTree(element, location) {
|
|
276
|
+
_attachElementToTree(element, location, insertionLocation) {
|
|
277
277
|
if (this.options.sourceCodeLocationInfo) {
|
|
278
278
|
const loc = location && {
|
|
279
279
|
...location,
|
|
@@ -281,13 +281,34 @@ export class Parser {
|
|
|
281
281
|
};
|
|
282
282
|
this.treeAdapter.setNodeSourceCodeLocation(element, loc);
|
|
283
283
|
}
|
|
284
|
-
if (
|
|
285
|
-
this.
|
|
284
|
+
if (insertionLocation.beforeElement) {
|
|
285
|
+
this.treeAdapter.insertBefore(insertionLocation.parent, element, insertionLocation.beforeElement);
|
|
286
286
|
}
|
|
287
287
|
else {
|
|
288
|
-
|
|
289
|
-
|
|
288
|
+
this.treeAdapter.appendChild(insertionLocation.parent, element);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/** @protected */
|
|
292
|
+
_getInsertionLocation() {
|
|
293
|
+
var _a;
|
|
294
|
+
if (this._shouldFosterParentOnInsertion()) {
|
|
295
|
+
return this._findFosterParentingLocation();
|
|
290
296
|
}
|
|
297
|
+
return {
|
|
298
|
+
parent: (_a = this.openElements.currentTmplContentOrNode) !== null && _a !== void 0 ? _a : this.document,
|
|
299
|
+
beforeElement: null,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
/** @protected */
|
|
303
|
+
_createElement(tagName, namespaceURI, attrs, intendedParent) {
|
|
304
|
+
var _a, _b;
|
|
305
|
+
const element = this.treeAdapter.createElement(tagName, namespaceURI, attrs);
|
|
306
|
+
(_b = (_a = this.treeAdapter).onElementCreated) === null || _b === void 0 ? void 0 : _b.call(_a, element, {
|
|
307
|
+
intendedParent,
|
|
308
|
+
formElement: this.formElement,
|
|
309
|
+
isInTemplate: this.openElements.tmplCount > 0,
|
|
310
|
+
});
|
|
311
|
+
return element;
|
|
291
312
|
}
|
|
292
313
|
/**
|
|
293
314
|
* For self-closing tags. Add an element to the tree, but skip adding it
|
|
@@ -295,37 +316,41 @@ export class Parser {
|
|
|
295
316
|
*/
|
|
296
317
|
/** @protected */
|
|
297
318
|
_appendElement(token, namespaceURI) {
|
|
298
|
-
const
|
|
299
|
-
this.
|
|
319
|
+
const insertionLocation = this._getInsertionLocation();
|
|
320
|
+
const element = this._createElement(token.tagName, namespaceURI, token.attrs, insertionLocation.parent);
|
|
321
|
+
this._attachElementToTree(element, token.location, insertionLocation);
|
|
300
322
|
}
|
|
301
323
|
/** @protected */
|
|
302
324
|
_insertElement(token, namespaceURI) {
|
|
303
|
-
const
|
|
304
|
-
this.
|
|
325
|
+
const insertionLocation = this._getInsertionLocation();
|
|
326
|
+
const element = this._createElement(token.tagName, namespaceURI, token.attrs, insertionLocation.parent);
|
|
327
|
+
this._attachElementToTree(element, token.location, insertionLocation);
|
|
305
328
|
this.openElements.push(element, token.tagID);
|
|
306
329
|
}
|
|
307
330
|
/** @protected */
|
|
308
331
|
_insertFakeElement(tagName, tagID) {
|
|
309
|
-
const
|
|
310
|
-
this.
|
|
332
|
+
const insertionLocation = this._getInsertionLocation();
|
|
333
|
+
const element = this._createElement(tagName, NS.HTML, [], insertionLocation.parent);
|
|
334
|
+
this._attachElementToTree(element, null, insertionLocation);
|
|
311
335
|
this.openElements.push(element, tagID);
|
|
312
336
|
}
|
|
313
337
|
/** @protected */
|
|
314
338
|
_insertTemplate(token) {
|
|
315
|
-
const
|
|
339
|
+
const insertionLocation = this._getInsertionLocation();
|
|
340
|
+
const tmpl = this._createElement(token.tagName, NS.HTML, token.attrs, insertionLocation.parent);
|
|
316
341
|
const content = this.treeAdapter.createDocumentFragment();
|
|
317
342
|
this.treeAdapter.setTemplateContent(tmpl, content);
|
|
318
|
-
this._attachElementToTree(tmpl, token.location);
|
|
343
|
+
this._attachElementToTree(tmpl, token.location, insertionLocation);
|
|
319
344
|
this.openElements.push(tmpl, token.tagID);
|
|
320
345
|
if (this.options.sourceCodeLocationInfo)
|
|
321
346
|
this.treeAdapter.setNodeSourceCodeLocation(content, null);
|
|
322
347
|
}
|
|
323
348
|
/** @protected */
|
|
324
349
|
_insertFakeRootElement() {
|
|
325
|
-
const element = this.
|
|
350
|
+
const element = this._createElement(TN.HTML, NS.HTML, [], this.document);
|
|
326
351
|
if (this.options.sourceCodeLocationInfo)
|
|
327
352
|
this.treeAdapter.setNodeSourceCodeLocation(element, null);
|
|
328
|
-
this.treeAdapter.appendChild(this.
|
|
353
|
+
this.treeAdapter.appendChild(this.document, element);
|
|
329
354
|
this.openElements.push(element, $.HTML);
|
|
330
355
|
}
|
|
331
356
|
/** @protected */
|
|
@@ -1217,6 +1242,7 @@ function aaObtainFurthestBlock(p, formattingElementEntry) {
|
|
|
1217
1242
|
function aaInnerLoop(p, furthestBlock, formattingElement) {
|
|
1218
1243
|
let lastElement = furthestBlock;
|
|
1219
1244
|
let nextElement = p.openElements.getCommonAncestor(furthestBlock);
|
|
1245
|
+
const intendedParent = p.openElements.getCommonAncestor(formattingElement);
|
|
1220
1246
|
for (let i = 0, element = nextElement; element !== formattingElement; i++, element = nextElement) {
|
|
1221
1247
|
//NOTE: store the next element for the next loop iteration (it may be deleted from the stack by step 9.5)
|
|
1222
1248
|
nextElement = p.openElements.getCommonAncestor(element);
|
|
@@ -1230,7 +1256,7 @@ function aaInnerLoop(p, furthestBlock, formattingElement) {
|
|
|
1230
1256
|
p.openElements.remove(element);
|
|
1231
1257
|
}
|
|
1232
1258
|
else {
|
|
1233
|
-
element = aaRecreateElementFromEntry(p, elementEntry);
|
|
1259
|
+
element = aaRecreateElementFromEntry(p, elementEntry, intendedParent);
|
|
1234
1260
|
if (lastElement === furthestBlock) {
|
|
1235
1261
|
p.activeFormattingElements.bookmark = elementEntry;
|
|
1236
1262
|
}
|
|
@@ -1242,9 +1268,9 @@ function aaInnerLoop(p, furthestBlock, formattingElement) {
|
|
|
1242
1268
|
return lastElement;
|
|
1243
1269
|
}
|
|
1244
1270
|
//Step 13.7 of the algorithm
|
|
1245
|
-
function aaRecreateElementFromEntry(p, elementEntry) {
|
|
1271
|
+
function aaRecreateElementFromEntry(p, elementEntry, intendedParent) {
|
|
1246
1272
|
const ns = p.treeAdapter.getNamespaceURI(elementEntry.element);
|
|
1247
|
-
const newElement = p.
|
|
1273
|
+
const newElement = p._createElement(elementEntry.token.tagName, ns, elementEntry.token.attrs, intendedParent);
|
|
1248
1274
|
p.openElements.replace(elementEntry.element, newElement);
|
|
1249
1275
|
elementEntry.element = newElement;
|
|
1250
1276
|
return newElement;
|
|
@@ -1268,7 +1294,7 @@ function aaInsertLastNodeInCommonAncestor(p, commonAncestor, lastElement) {
|
|
|
1268
1294
|
function aaReplaceFormattingElement(p, furthestBlock, formattingElementEntry) {
|
|
1269
1295
|
const ns = p.treeAdapter.getNamespaceURI(formattingElementEntry.element);
|
|
1270
1296
|
const { token } = formattingElementEntry;
|
|
1271
|
-
const newElement = p.
|
|
1297
|
+
const newElement = p._createElement(token.tagName, ns, token.attrs, furthestBlock);
|
|
1272
1298
|
p._adoptNodes(furthestBlock, newElement);
|
|
1273
1299
|
p.treeAdapter.appendChild(furthestBlock, newElement);
|
|
1274
1300
|
p.activeFormattingElements.insertElementAfterBookmark(newElement, token);
|
|
@@ -2227,7 +2253,10 @@ function genericEndTagInBody(p, token) {
|
|
|
2227
2253
|
const element = p.openElements.items[i];
|
|
2228
2254
|
const elementId = p.openElements.tagIDs[i];
|
|
2229
2255
|
// Compare the tag name here, as the tag might not be a known tag with an ID.
|
|
2230
|
-
|
|
2256
|
+
// Only HTML elements match; a foreign element falls through to the special-element check.
|
|
2257
|
+
if (tid === elementId &&
|
|
2258
|
+
p.treeAdapter.getNamespaceURI(element) === NS.HTML &&
|
|
2259
|
+
(tid !== $.UNKNOWN || p.treeAdapter.getTagName(element) === tn)) {
|
|
2231
2260
|
p.openElements.generateImpliedEndTagsWithExclusion(tid);
|
|
2232
2261
|
if (p.openElements.stackTop >= i)
|
|
2233
2262
|
p.openElements.shortenToLength(i);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Preprocessor } from './preprocessor.js';
|
|
2
2
|
import { type Token, type CharacterToken, type DoctypeToken, type TagToken, type EOFToken, type CommentToken, type Attribute, type Location } from '../common/token.js';
|
|
3
|
-
import {
|
|
3
|
+
import { HtmlEntityDecoder } from '@cjser/entities/decode';
|
|
4
4
|
import { ERR, type ParserErrorHandler } from '../common/error-codes.js';
|
|
5
5
|
declare const enum State {
|
|
6
6
|
DATA = 0,
|
|
@@ -118,9 +118,9 @@ export declare class Tokenizer {
|
|
|
118
118
|
state: State;
|
|
119
119
|
protected returnState: State;
|
|
120
120
|
/**
|
|
121
|
-
* We use `entities`' `
|
|
121
|
+
* We use `entities`' `HtmlEntityDecoder` to parse character references.
|
|
122
122
|
*
|
|
123
|
-
* All of the following states are handled by the `
|
|
123
|
+
* All of the following states are handled by the `HtmlEntityDecoder`:
|
|
124
124
|
*
|
|
125
125
|
* - Named character reference state
|
|
126
126
|
* - Numeric character reference state
|
|
@@ -129,17 +129,28 @@ export declare class Tokenizer {
|
|
|
129
129
|
* - Decimal character reference state
|
|
130
130
|
* - Numeric character reference end state
|
|
131
131
|
*/
|
|
132
|
-
protected entityDecoder:
|
|
132
|
+
protected entityDecoder: HtmlEntityDecoder;
|
|
133
133
|
protected entityStartPos: number;
|
|
134
134
|
protected consumedAfterSnapshot: number;
|
|
135
135
|
protected currentLocation: Location | null;
|
|
136
136
|
protected currentCharacterToken: CharacterToken | null;
|
|
137
137
|
protected currentToken: Token | null;
|
|
138
138
|
protected currentAttr: Attribute;
|
|
139
|
+
private currentAttrLocation;
|
|
140
|
+
/**
|
|
141
|
+
* `[start, end)` of `preprocessor.html` still to be appended to the attribute value, comment data or character
|
|
142
|
+
* token being built (`_flushRun`): input that is used as is is appended as one slice, not a code point at a time.
|
|
143
|
+
*/
|
|
144
|
+
protected runStart: number;
|
|
145
|
+
protected runEnd: number;
|
|
139
146
|
constructor(options: TokenizerOptions, handler: TokenHandler);
|
|
140
147
|
protected _err(code: ERR, cpOffset?: number): void;
|
|
141
148
|
protected getCurrentLocation(offset: number): Location | null;
|
|
142
149
|
protected _runParsingLoop(): void;
|
|
150
|
+
/** Emit buffered character tokens without completing the current token or emitting EOF. */
|
|
151
|
+
flushCharacters(): void;
|
|
152
|
+
private getCharacterTokenEndLocation;
|
|
153
|
+
private getCharacterTokenEndOffset;
|
|
143
154
|
pause(): void;
|
|
144
155
|
resume(writeCallback?: () => void): void;
|
|
145
156
|
write(chunk: string, isLastChunk: boolean, writeCallback?: () => void): void;
|
|
@@ -152,19 +163,35 @@ export declare class Tokenizer {
|
|
|
152
163
|
protected _createEndTagToken(): void;
|
|
153
164
|
protected _createCommentToken(offset: number): void;
|
|
154
165
|
protected _createDoctypeToken(initialName: string | null): void;
|
|
155
|
-
protected _createCharacterToken(type: CharacterToken['type']
|
|
166
|
+
protected _createCharacterToken(type: CharacterToken['type']): void;
|
|
156
167
|
protected _createAttr(attrNameFirstCh: string): void;
|
|
157
168
|
protected _leaveAttrName(): void;
|
|
158
169
|
protected _leaveAttrValue(): void;
|
|
170
|
+
/**
|
|
171
|
+
* Append the pending run and `text` to the attribute value, comment data or character token being built.
|
|
172
|
+
* The run is a string of its own: V8 copies a slice of fewer than 13 characters but lets a longer one share
|
|
173
|
+
* the input's buffer, which would keep that buffer alive for as long as any attribute value or text cut from
|
|
174
|
+
* it is; a concatenation is flattened into a buffer of its own when it is sliced.
|
|
175
|
+
*/
|
|
176
|
+
protected _flushRun(text: string): void;
|
|
177
|
+
/** Extend the pending run by the current input code point, read as `cp`, or flush it and start a new one. */
|
|
178
|
+
protected _extendRun(cp: number): void;
|
|
179
|
+
/**
|
|
180
|
+
* Extend the pending run by `text`, the input that ends `cpOffset` code points after the current one, or flush
|
|
181
|
+
* the run and append `text` where the input differs (a NUL replacement, a decoded reference, a dropped chunk).
|
|
182
|
+
*/
|
|
183
|
+
protected _extendRunWith(text: string, cpOffset: number): void;
|
|
159
184
|
protected prepareToken(ct: Token): void;
|
|
160
185
|
protected emitCurrentTagToken(): void;
|
|
161
186
|
protected emitCurrentComment(ct: CommentToken): void;
|
|
162
187
|
protected emitCurrentDoctype(ct: DoctypeToken): void;
|
|
163
188
|
protected _emitCurrentCharacterToken(nextLocation: Location | null): void;
|
|
164
189
|
protected _emitEOFToken(): void;
|
|
165
|
-
|
|
190
|
+
/** Make the current character token one of `type`, emitting the current one if it has another type. */
|
|
191
|
+
protected _ensureCharacterToken(type: CharacterToken['type']): void;
|
|
192
|
+
/** Emit the current input code point, read as `cp`. */
|
|
166
193
|
protected _emitCodePoint(cp: number): void;
|
|
167
|
-
protected _emitChars(ch: string): void;
|
|
194
|
+
protected _emitChars(ch: string, cpOffset?: number): void;
|
|
168
195
|
protected _startCharacterReference(): void;
|
|
169
196
|
protected _isCharacterReferenceInAttribute(): boolean;
|
|
170
197
|
protected _flushCodePointConsumedAsCharacterReference(cp: number): void;
|