Skip to content
This repository was archived by the owner on Mar 24, 2022. It is now read-only.

Commit 269ef1c

Browse files
committed
refactor: Move ErrorReportingParserMixin into parser
1 parent 54e1feb commit 269ef1c

3 files changed

Lines changed: 74 additions & 108 deletions

File tree

packages/parse5/lib/extensions/error-reporting/parser-mixin.ts

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

packages/parse5/lib/extensions/location-info/parser-mixin.ts

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
import { CommentToken, DoctypeToken, CharacterToken } from '../../common/token';
22
import { Mixin } from '../../utils/mixin.js';
33
import { TAG_NAMES as $, NAMESPACES as NS } from '../../common/html.js';
4-
import type { TreeAdapter, TreeAdapterTypeMap, ElementLocation } from '../../tree-adapters/interface';
4+
import type { TreeAdapterTypeMap, ElementLocation } from '../../tree-adapters/interface';
55
import type { Parser } from '../../parser/index.js';
66
import { TokenType, Token, TagToken } from '../../common/token.js';
77

88
export class LocationInfoParserMixin<T extends TreeAdapterTypeMap> extends Mixin<Parser<T>> {
9-
treeAdapter: TreeAdapter<T>;
109
lastStartTagToken: null | TagToken = null;
1110
lastFosterParentingLocation: null | ReturnType<Parser<T>['_findFosterParentingLocation']> = null;
1211
currentToken: Token | null = null;
1312

14-
constructor(parser: Parser<T>) {
13+
constructor(private parser: Parser<T>) {
1514
super(parser);
16-
17-
this.treeAdapter = parser.treeAdapter;
1815
}
1916

2017
_setStartLocation(element: T['element']) {
@@ -27,34 +24,32 @@ export class LocationInfoParserMixin<T extends TreeAdapterTypeMap> extends Mixin
2724
};
2825
}
2926

30-
this.treeAdapter.setNodeSourceCodeLocation(element, loc);
27+
this.parser.treeAdapter.setNodeSourceCodeLocation(element, loc);
3128
}
3229

3330
_setEndLocation(element: T['element'], closingToken: Token) {
34-
const loc = this.treeAdapter.getNodeSourceCodeLocation(element);
35-
36-
if (loc) {
37-
if (closingToken.location) {
38-
const ctLoc = closingToken.location;
39-
const tn = this.treeAdapter.getTagName(element);
40-
41-
// NOTE: For cases like <p> <p> </p> - First 'p' closes without a closing
42-
// tag and for cases like <td> <p> </td> - 'p' closes without a closing tag.
43-
const isClosingEndTag = closingToken.type === TokenType.END_TAG && tn === closingToken.tagName;
44-
const endLoc: Partial<ElementLocation> = {};
45-
if (isClosingEndTag) {
46-
endLoc.endTag = { ...ctLoc };
47-
endLoc.endLine = ctLoc.endLine;
48-
endLoc.endCol = ctLoc.endCol;
49-
endLoc.endOffset = ctLoc.endOffset;
50-
} else {
51-
endLoc.endLine = ctLoc.startLine;
52-
endLoc.endCol = ctLoc.startCol;
53-
endLoc.endOffset = ctLoc.startOffset;
54-
}
55-
56-
this.treeAdapter.updateNodeSourceCodeLocation(element, endLoc);
31+
const loc = this.parser.treeAdapter.getNodeSourceCodeLocation(element);
32+
33+
if (loc && closingToken.location) {
34+
const ctLoc = closingToken.location;
35+
const tn = this.parser.treeAdapter.getTagName(element);
36+
37+
// NOTE: For cases like <p> <p> </p> - First 'p' closes without a closing
38+
// tag and for cases like <td> <p> </td> - 'p' closes without a closing tag.
39+
const isClosingEndTag = closingToken.type === TokenType.END_TAG && tn === closingToken.tagName;
40+
const endLoc: Partial<ElementLocation> = {};
41+
if (isClosingEndTag) {
42+
endLoc.endTag = { ...ctLoc };
43+
endLoc.endLine = ctLoc.endLine;
44+
endLoc.endCol = ctLoc.endCol;
45+
endLoc.endOffset = ctLoc.endOffset;
46+
} else {
47+
endLoc.endLine = ctLoc.startLine;
48+
endLoc.endCol = ctLoc.startCol;
49+
endLoc.endOffset = ctLoc.startOffset;
5750
}
51+
52+
this.parser.treeAdapter.updateNodeSourceCodeLocation(element, endLoc);
5853
}
5954
}
6055

packages/parse5/lib/parser/index.ts

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@ import { Tokenizer, TokenizerMode } from '../tokenizer/index.js';
22
import { OpenElementStack } from './open-element-stack.js';
33
import { FormattingElementList, ElementEntry, EntryType } from './formatting-element-list.js';
44
import { LocationInfoParserMixin } from '../extensions/location-info/parser-mixin.js';
5-
import { ErrorReportingParserMixin } from '../extensions/error-reporting/parser-mixin.js';
65
import { Mixin } from '../utils/mixin.js';
76
import * as defaultTreeAdapter from '../tree-adapters/default.js';
87
import * as doctype from '../common/doctype.js';
98
import * as foreignContent from '../common/foreign-content.js';
10-
import { ERR } from '../common/error-codes.js';
9+
import { ERR, ParserErrorHandler } from '../common/error-codes.js';
1110
import * as unicode from '../common/unicode.js';
1211
import {
1312
TAG_NAMES as $,
@@ -18,7 +17,6 @@ import {
1817
isNumberedHeader,
1918
} from '../common/html.js';
2019
import type { TreeAdapter, TreeAdapterTypeMap } from '../tree-adapters/interface.js';
21-
import type { ParserError } from '../common/error-codes.js';
2220
import {
2321
TokenType,
2422
getTokenAttr,
@@ -89,6 +87,15 @@ const TEMPLATE_INSERTION_MODE_SWITCH_MAP = new Map<string, InsertionMode>([
8987
[$.TH, InsertionMode.IN_ROW],
9088
]);
9189

90+
const BASE_LOC = {
91+
startLine: -1,
92+
startCol: -1,
93+
startOffset: -1,
94+
endLine: -1,
95+
endCol: -1,
96+
endOffset: -1,
97+
};
98+
9299
const TABLE_STRUCTURE_TAGS = new Set<string>([$.TABLE, $.TBODY, $.TFOOT, $.THEAD, $.TR]);
93100

94101
export interface ParserOptions<T extends TreeAdapterTypeMap> {
@@ -124,14 +131,15 @@ export interface ParserOptions<T extends TreeAdapterTypeMap> {
124131
*
125132
* @default `null`
126133
*/
127-
onParseError?: ((err: ParserError) => void) | null;
134+
onParseError?: ParserErrorHandler | null;
128135
}
129136

130137
//Parser
131138
export class Parser<T extends TreeAdapterTypeMap> {
132139
options: ParserOptions<T>;
133140
treeAdapter: TreeAdapter<T>;
134141
pendingScript: null | T['element'];
142+
private onParseError: ParserErrorHandler | null;
135143

136144
constructor(options?: ParserOptions<T>) {
137145
this.options = {
@@ -145,8 +153,9 @@ export class Parser<T extends TreeAdapterTypeMap> {
145153
this.treeAdapter = this.options.treeAdapter!;
146154
this.pendingScript = null;
147155

156+
this.onParseError = this.options.onParseError ?? null;
157+
148158
if (this.options.onParseError) {
149-
Mixin.install(this, ErrorReportingParserMixin as any, { onParseError: this.options.onParseError });
150159
this.options.sourceCodeLocationInfo = true;
151160
}
152161

@@ -255,8 +264,21 @@ export class Parser<T extends TreeAdapterTypeMap> {
255264
}
256265

257266
//Errors
258-
_err(_err: ERR, _opts?: { beforeToken: boolean }) {
259-
// NOTE: err reporting is noop by default. Enabled by mixin.
267+
_err(token: Token, code: ERR, beforeToken?: boolean) {
268+
if (!this.onParseError) return;
269+
270+
const loc = token.location ?? BASE_LOC;
271+
const err = {
272+
code,
273+
startLine: loc.startLine,
274+
startCol: loc.startCol,
275+
startOffset: loc.startOffset,
276+
endLine: beforeToken ? loc.startLine : loc.endLine,
277+
endCol: beforeToken ? loc.startCol : loc.endCol,
278+
endOffset: beforeToken ? loc.startOffset : loc.endOffset,
279+
};
280+
281+
this.onParseError(err);
260282
}
261283

262284
//Parsing loop
@@ -572,7 +594,7 @@ export class Parser<T extends TreeAdapterTypeMap> {
572594
}
573595

574596
if (token.type === TokenType.START_TAG && token.selfClosing && !token.ackSelfClosing) {
575-
this._err(ERR.nonVoidHtmlElementStartTagWithTrailingSolidus);
597+
this._err(token, ERR.nonVoidHtmlElementStartTagWithTrailingSolidus);
576598
}
577599
}
578600

@@ -911,8 +933,8 @@ function callAdoptionAgency<T extends TreeAdapterTypeMap>(p: Parser<T>, token: T
911933
//Generic token handlers
912934
//------------------------------------------------------------------
913935

914-
function misplacedDoctype<T extends TreeAdapterTypeMap>(p: Parser<T>) {
915-
p._err(ERR.misplacedDoctype);
936+
function misplacedDoctype<T extends TreeAdapterTypeMap>(p: Parser<T>, token: DoctypeToken) {
937+
p._err(token, ERR.misplacedDoctype);
916938
}
917939

918940
function appendComment<T extends TreeAdapterTypeMap>(p: Parser<T>, token: CommentToken) {
@@ -949,7 +971,7 @@ function doctypeInInitialMode<T extends TreeAdapterTypeMap>(p: Parser<T>, token:
949971
const mode = token.forceQuirks ? DOCUMENT_MODE.QUIRKS : doctype.getDocumentMode(token);
950972

951973
if (!doctype.isConforming(token)) {
952-
p._err(ERR.nonConformingDoctype);
974+
p._err(token, ERR.nonConformingDoctype);
953975
}
954976

955977
p.treeAdapter.setDocumentMode(p.document, mode);
@@ -958,7 +980,7 @@ function doctypeInInitialMode<T extends TreeAdapterTypeMap>(p: Parser<T>, token:
958980
}
959981

960982
function tokenInInitialMode<T extends TreeAdapterTypeMap>(p: Parser<T>, token: Token) {
961-
p._err(ERR.missingDoctype, { beforeToken: true });
983+
p._err(token, ERR.missingDoctype, true);
962984
p.treeAdapter.setDocumentMode(p.document, DOCUMENT_MODE.QUIRKS);
963985
p.insertionMode = InsertionMode.BEFORE_HTML;
964986
p._processToken(token);
@@ -1009,7 +1031,7 @@ function modeBeforeHead<T extends TreeAdapterTypeMap>(p: Parser<T>, token: Token
10091031
} else if (token.type === TokenType.COMMENT) {
10101032
appendComment(p, token);
10111033
} else if (token.type === TokenType.DOCTYPE) {
1012-
misplacedDoctype(p);
1034+
misplacedDoctype(p, token);
10131035
} else if (token.type === TokenType.START_TAG) {
10141036
startTagBeforeHead(p, token);
10151037
} else if (token.type === TokenType.END_TAG) {
@@ -1037,7 +1059,7 @@ function endTagBeforeHead<T extends TreeAdapterTypeMap>(p: Parser<T>, token: Tag
10371059
if (tn === $.HEAD || tn === $.BODY || tn === $.HTML || tn === $.BR) {
10381060
tokenBeforeHead(p, token);
10391061
} else {
1040-
p._err(ERR.endTagWithoutMatchingOpenElement);
1062+
p._err(token, ERR.endTagWithoutMatchingOpenElement);
10411063
}
10421064
}
10431065

@@ -1058,7 +1080,7 @@ function modeInHead<T extends TreeAdapterTypeMap>(p: Parser<T>, token: Token) {
10581080
} else if (token.type === TokenType.COMMENT) {
10591081
appendComment(p, token);
10601082
} else if (token.type === TokenType.DOCTYPE) {
1061-
misplacedDoctype(p);
1083+
misplacedDoctype(p, token);
10621084
} else if (token.type === TokenType.START_TAG) {
10631085
startTagInHead(p, token);
10641086
} else if (token.type === TokenType.END_TAG) {
@@ -1094,7 +1116,7 @@ function startTagInHead<T extends TreeAdapterTypeMap>(p: Parser<T>, token: TagTo
10941116
p.insertionMode = InsertionMode.IN_TEMPLATE;
10951117
p.tmplInsertionModeStack.unshift(InsertionMode.IN_TEMPLATE);
10961118
} else if (tn === $.HEAD) {
1097-
p._err(ERR.misplacedStartTagForHeadElement);
1119+
p._err(token, ERR.misplacedStartTagForHeadElement);
10981120
} else {
10991121
tokenInHead(p, token);
11001122
}
@@ -1113,18 +1135,18 @@ function endTagInHead<T extends TreeAdapterTypeMap>(p: Parser<T>, token: TagToke
11131135
p.openElements.generateImpliedEndTagsThoroughly();
11141136

11151137
if (p.openElements.currentTagName !== $.TEMPLATE) {
1116-
p._err(ERR.closingOfElementWithOpenChildElements);
1138+
p._err(token, ERR.closingOfElementWithOpenChildElements);
11171139
}
11181140

11191141
p.openElements.popUntilTagNamePopped($.TEMPLATE);
11201142
p.activeFormattingElements.clearToLastMarker();
11211143
p.tmplInsertionModeStack.shift();
11221144
p._resetInsertionMode();
11231145
} else {
1124-
p._err(ERR.endTagWithoutMatchingOpenElement);
1146+
p._err(token, ERR.endTagWithoutMatchingOpenElement);
11251147
}
11261148
} else {
1127-
p._err(ERR.endTagWithoutMatchingOpenElement);
1149+
p._err(token, ERR.endTagWithoutMatchingOpenElement);
11281150
}
11291151
}
11301152

@@ -1144,7 +1166,7 @@ function modeInHeadNoScript<T extends TreeAdapterTypeMap>(p: Parser<T>, token: T
11441166
} else if (token.type === TokenType.COMMENT) {
11451167
appendComment(p, token);
11461168
} else if (token.type === TokenType.DOCTYPE) {
1147-
misplacedDoctype(p);
1169+
misplacedDoctype(p, token);
11481170
} else if (token.type === TokenType.START_TAG) {
11491171
startTagInHeadNoScript(p, token);
11501172
} else if (token.type === TokenType.END_TAG) {
@@ -1168,7 +1190,7 @@ function startTagInHeadNoScript<T extends TreeAdapterTypeMap>(p: Parser<T>, toke
11681190
) {
11691191
startTagInHead(p, token);
11701192
} else if (tn === $.NOSCRIPT) {
1171-
p._err(ERR.nestedNoscriptInHead);
1193+
p._err(token, ERR.nestedNoscriptInHead);
11721194
} else {
11731195
tokenInHeadNoScript(p, token);
11741196
}
@@ -1183,14 +1205,14 @@ function endTagInHeadNoScript<T extends TreeAdapterTypeMap>(p: Parser<T>, token:
11831205
} else if (tn === $.BR) {
11841206
tokenInHeadNoScript(p, token);
11851207
} else {
1186-
p._err(ERR.endTagWithoutMatchingOpenElement);
1208+
p._err(token, ERR.endTagWithoutMatchingOpenElement);
11871209
}
11881210
}
11891211

11901212
function tokenInHeadNoScript<T extends TreeAdapterTypeMap>(p: Parser<T>, token: Token) {
11911213
const errCode = token.type === TokenType.EOF ? ERR.openElementsLeftAfterEof : ERR.disallowedContentInNoscriptInHead;
11921214

1193-
p._err(errCode);
1215+
p._err(token, errCode);
11941216
p.openElements.pop();
11951217
p.insertionMode = InsertionMode.IN_HEAD;
11961218
p._processToken(token);
@@ -1206,7 +1228,7 @@ function modeAfterHead<T extends TreeAdapterTypeMap>(p: Parser<T>, token: Token)
12061228
} else if (token.type === TokenType.COMMENT) {
12071229
appendComment(p, token);
12081230
} else if (token.type === TokenType.DOCTYPE) {
1209-
misplacedDoctype(p);
1231+
misplacedDoctype(p, token);
12101232
} else if (token.type === TokenType.START_TAG) {
12111233
startTagAfterHead(p, token);
12121234
} else if (token.type === TokenType.END_TAG) {
@@ -1240,12 +1262,12 @@ function startTagAfterHead<T extends TreeAdapterTypeMap>(p: Parser<T>, token: Ta
12401262
p._insertElement(token, NS.HTML);
12411263
p.insertionMode = InsertionMode.IN_FRAMESET;
12421264
} else if (ABANDONED_HEAD_ELEMENT_CHILDS.has(tn)) {
1243-
p._err(ERR.abandonedHeadElementChild);
1265+
p._err(token, ERR.abandonedHeadElementChild);
12441266
p.openElements.push(p.headElement!);
12451267
startTagInHead(p, token);
12461268
p.openElements.remove(p.headElement!);
12471269
} else if (tn === $.HEAD) {
1248-
p._err(ERR.misplacedStartTagForHeadElement);
1270+
p._err(token, ERR.misplacedStartTagForHeadElement);
12491271
} else {
12501272
tokenAfterHead(p, token);
12511273
}
@@ -1259,7 +1281,7 @@ function endTagAfterHead<T extends TreeAdapterTypeMap>(p: Parser<T>, token: TagT
12591281
} else if (tn === $.TEMPLATE) {
12601282
endTagInHead(p, token);
12611283
} else {
1262-
p._err(ERR.endTagWithoutMatchingOpenElement);
1284+
p._err(token, ERR.endTagWithoutMatchingOpenElement);
12631285
}
12641286
}
12651287

@@ -2126,7 +2148,7 @@ function endTagInText<T extends TreeAdapterTypeMap>(p: Parser<T>, token: TagToke
21262148
}
21272149

21282150
function eofInText<T extends TreeAdapterTypeMap>(p: Parser<T>, token: Token) {
2129-
p._err(ERR.eofInElementThatCanContainOnlyText);
2151+
p._err(token, ERR.eofInElementThatCanContainOnlyText);
21302152
p.openElements.pop();
21312153
p.insertionMode = p.originalInsertionMode;
21322154
p._processToken(token);

0 commit comments

Comments
 (0)