Skip to content

Commit c3223ab

Browse files
author
Robert Jackson
committed
Make doctype delegate methods optional
This allows the change to be non-breaking.
1 parent cfdb371 commit c3223ab

File tree

3 files changed

+150
-22
lines changed

3 files changed

+150
-22
lines changed

src/evented-tokenizer.ts

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ export default class EventedTokenizer {
196196
this.consume();
197197
this.consume();
198198
this.transitionTo(TokenizerState.doctype);
199-
this.delegate.beginDoctype();
199+
if (this.delegate.beginDoctype) this.delegate.beginDoctype();
200200
}
201201
}
202202
},
@@ -216,7 +216,7 @@ export default class EventedTokenizer {
216216
return;
217217
} else {
218218
this.transitionTo(TokenizerState.doctypeName);
219-
this.delegate.appendToDoctypeName(char.toLowerCase());
219+
if (this.delegate.appendToDoctypeName) this.delegate.appendToDoctypeName(char.toLowerCase());
220220
}
221221
},
222222

@@ -226,10 +226,10 @@ export default class EventedTokenizer {
226226
if (isSpace(char)) {
227227
this.transitionTo(TokenizerState.afterDoctypeName);
228228
} else if (char === '>') {
229-
this.delegate.endDoctype();
229+
if (this.delegate.endDoctype) this.delegate.endDoctype();
230230
this.transitionTo(TokenizerState.beforeData);
231231
} else {
232-
this.delegate.appendToDoctypeName(char.toLowerCase());
232+
if (this.delegate.appendToDoctypeName) this.delegate.appendToDoctypeName(char.toLowerCase());
233233
}
234234
},
235235

@@ -239,7 +239,7 @@ export default class EventedTokenizer {
239239
if (isSpace(char)) {
240240
return;
241241
} else if (char === '>') {
242-
this.delegate.endDoctype();
242+
if (this.delegate.endDoctype) this.delegate.endDoctype();
243243
this.transitionTo(TokenizerState.beforeData);
244244
} else {
245245
let nextSixChars = char.toUpperCase() + this.input.substring(this.index, this.index + 5).toUpperCase();
@@ -278,7 +278,7 @@ export default class EventedTokenizer {
278278
this.consume();
279279
} else if (char === '>') {
280280
this.consume();
281-
this.delegate.endDoctype();
281+
if (this.delegate.endDoctype) this.delegate.endDoctype();
282282
this.transitionTo(TokenizerState.beforeData);
283283
}
284284
},
@@ -289,10 +289,10 @@ export default class EventedTokenizer {
289289
if (char === '"') {
290290
this.transitionTo(TokenizerState.afterDoctypePublicIdentifier);
291291
} else if (char === '>') {
292-
this.delegate.endDoctype();
292+
if (this.delegate.endDoctype) this.delegate.endDoctype();
293293
this.transitionTo(TokenizerState.beforeData);
294294
} else {
295-
this.delegate.appendToDoctypePublicIdentifier(char);
295+
if (this.delegate.appendToDoctypePublicIdentifier) this.delegate.appendToDoctypePublicIdentifier(char);
296296
}
297297
},
298298

@@ -302,10 +302,10 @@ export default class EventedTokenizer {
302302
if (char === "'") {
303303
this.transitionTo(TokenizerState.afterDoctypePublicIdentifier);
304304
} else if (char === '>') {
305-
this.delegate.endDoctype();
305+
if (this.delegate.endDoctype) this.delegate.endDoctype();
306306
this.transitionTo(TokenizerState.beforeData);
307307
} else {
308-
this.delegate.appendToDoctypePublicIdentifier(char);
308+
if (this.delegate.appendToDoctypePublicIdentifier) this.delegate.appendToDoctypePublicIdentifier(char);
309309
}
310310
},
311311

@@ -315,7 +315,7 @@ export default class EventedTokenizer {
315315
if (isSpace(char)) {
316316
this.transitionTo(TokenizerState.betweenDoctypePublicAndSystemIdentifiers);
317317
} else if (char === '>') {
318-
this.delegate.endDoctype();
318+
if (this.delegate.endDoctype) this.delegate.endDoctype();
319319
this.transitionTo(TokenizerState.beforeData);
320320
} else if (char === '"') {
321321
this.transitionTo(TokenizerState.doctypeSystemIdentifierDoubleQuoted);
@@ -330,7 +330,7 @@ export default class EventedTokenizer {
330330
if (isSpace(char)) {
331331
return;
332332
} else if (char === '>') {
333-
this.delegate.endDoctype();
333+
if (this.delegate.endDoctype) this.delegate.endDoctype();
334334
this.transitionTo(TokenizerState.beforeData);
335335
} else if (char === '"') {
336336
this.transitionTo(TokenizerState.doctypeSystemIdentifierDoubleQuoted);
@@ -345,10 +345,10 @@ export default class EventedTokenizer {
345345
if (char === '"') {
346346
this.transitionTo(TokenizerState.afterDoctypeSystemIdentifier);
347347
} else if (char === '>') {
348-
this.delegate.endDoctype();
348+
if (this.delegate.endDoctype) this.delegate.endDoctype();
349349
this.transitionTo(TokenizerState.beforeData);
350350
} else {
351-
this.delegate.appendToDoctypeSystemIdentifier(char);
351+
if (this.delegate.appendToDoctypeSystemIdentifier) this.delegate.appendToDoctypeSystemIdentifier(char);
352352
}
353353
},
354354

@@ -358,10 +358,10 @@ export default class EventedTokenizer {
358358
if (char === "'") {
359359
this.transitionTo(TokenizerState.afterDoctypeSystemIdentifier);
360360
} else if (char === '>') {
361-
this.delegate.endDoctype();
361+
if (this.delegate.endDoctype) this.delegate.endDoctype();
362362
this.transitionTo(TokenizerState.beforeData);
363363
} else {
364-
this.delegate.appendToDoctypeSystemIdentifier(char);
364+
if (this.delegate.appendToDoctypeSystemIdentifier) this.delegate.appendToDoctypeSystemIdentifier(char);
365365
}
366366
},
367367

@@ -371,7 +371,7 @@ export default class EventedTokenizer {
371371
if (isSpace(char)) {
372372
return;
373373
} else if (char === '>') {
374-
this.delegate.endDoctype();
374+
if (this.delegate.endDoctype) this.delegate.endDoctype();
375375
this.transitionTo(TokenizerState.beforeData);
376376
}
377377
},

src/types.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,12 @@ export interface TokenizerDelegate {
7777
finishData(): void;
7878
tagOpen(): void;
7979

80-
beginDoctype(): void;
81-
appendToDoctypeName(char: string): void;
82-
appendToDoctypePublicIdentifier(char: string): void;
83-
appendToDoctypeSystemIdentifier(char: string): void;
84-
endDoctype(): void;
80+
// TODO: make these non-optional in preparation for the next major version release
81+
beginDoctype?(): void;
82+
appendToDoctypeName?(char: string): void;
83+
appendToDoctypePublicIdentifier?(char: string): void;
84+
appendToDoctypeSystemIdentifier?(char: string): void;
85+
endDoctype?(): void;
8586

8687
beginData(): void;
8788
appendToData(char: string): void;

tests/tokenizer-tests.ts

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import {
22
tokenize,
3+
EventedTokenizer,
4+
TokenizerDelegate,
5+
EntityParser,
36
Doctype,
47
StartTag,
58
EndTag,
@@ -12,6 +15,130 @@ import {
1215

1316
QUnit.module('simple-html-tokenizer - tokenizer');
1417

18+
QUnit.test('does not fail if delegate does not include doctype methods', function(assert) {
19+
let steps: Array<string[]> = [];
20+
21+
class MissingDoctypeTokenizerDelegate implements TokenizerDelegate {
22+
reset() {
23+
steps.push(['reset']);
24+
}
25+
finishData() {
26+
steps.push(['finishData']);
27+
}
28+
tagOpen() {
29+
steps.push(['tagOpen']);
30+
}
31+
32+
beginData() {
33+
steps.push(['beginData']);
34+
}
35+
36+
appendToData(char: string) {
37+
steps.push(['appendToData', char]);
38+
}
39+
40+
beginStartTag() {
41+
steps.push(['beginStartTag']);
42+
}
43+
appendToTagName(char: string) {
44+
steps.push(['appendToTagName', char]);
45+
}
46+
47+
beginAttribute() {
48+
steps.push(['beginAttribute']);
49+
}
50+
appendToAttributeName(char: string) {
51+
steps.push(['appendToAttributeName', char]);
52+
}
53+
beginAttributeValue(quoted: boolean) {
54+
steps.push(['beginAttributeValue', `${quoted}`]);
55+
}
56+
57+
appendToAttributeValue(char: string) {
58+
steps.push(['appendToAttributeValue', char]);
59+
}
60+
finishAttributeValue() {
61+
steps.push(['finishAttributeValue']);
62+
}
63+
64+
markTagAsSelfClosing() {
65+
steps.push(['markTagAsSelfClosing']);
66+
}
67+
68+
beginEndTag() {
69+
steps.push(['beginEndTag']);
70+
}
71+
finishTag() {
72+
steps.push(['finishTag']);
73+
}
74+
75+
beginComment() {
76+
steps.push(['beginComment']);
77+
}
78+
appendToCommentData(char: string) {
79+
steps.push(['appendToCommentData', char]);
80+
}
81+
finishComment() {
82+
steps.push(['finishComment']);
83+
}
84+
85+
reportSyntaxError(error: string) {
86+
steps.push(['reportSyntaxError', error]);
87+
}
88+
}
89+
90+
let delegate = new MissingDoctypeTokenizerDelegate();
91+
let tokenizer = new EventedTokenizer(delegate, new EntityParser({}));
92+
93+
tokenizer.tokenize('\n<!-- comment here --><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<!-- comment here -->');
94+
95+
assert.deepEqual(steps, [
96+
[ "reset" ],
97+
[ "reset" ],
98+
[ "beginData" ],
99+
[ "appendToData", "\n" ],
100+
[ "finishData" ],
101+
[ "tagOpen" ],
102+
[ "beginComment" ],
103+
[ "appendToCommentData", " " ],
104+
[ "appendToCommentData", "c" ],
105+
[ "appendToCommentData", "o" ],
106+
[ "appendToCommentData", "m" ],
107+
[ "appendToCommentData", "m" ],
108+
[ "appendToCommentData", "e" ],
109+
[ "appendToCommentData", "n" ],
110+
[ "appendToCommentData", "t" ],
111+
[ "appendToCommentData", " " ],
112+
[ "appendToCommentData", "h" ],
113+
[ "appendToCommentData", "e" ],
114+
[ "appendToCommentData", "r" ],
115+
[ "appendToCommentData", "e" ],
116+
[ "appendToCommentData", " " ],
117+
[ "finishComment" ],
118+
[ "tagOpen" ],
119+
[ "beginData" ],
120+
[ "appendToData", "\n" ],
121+
[ "finishData" ],
122+
[ "tagOpen" ],
123+
[ "beginComment" ],
124+
[ "appendToCommentData", " " ],
125+
[ "appendToCommentData", "c" ],
126+
[ "appendToCommentData", "o" ],
127+
[ "appendToCommentData", "m" ],
128+
[ "appendToCommentData", "m" ],
129+
[ "appendToCommentData", "e" ],
130+
[ "appendToCommentData", "n" ],
131+
[ "appendToCommentData", "t" ],
132+
[ "appendToCommentData", " " ],
133+
[ "appendToCommentData", "h" ],
134+
[ "appendToCommentData", "e" ],
135+
[ "appendToCommentData", "r" ],
136+
[ "appendToCommentData", "e" ],
137+
[ "appendToCommentData", " " ],
138+
[ "finishComment" ]
139+
]);
140+
});
141+
15142
QUnit.test('Doctype', function(assert) {
16143
let tokens = tokenize('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">');
17144
assert.deepEqual(tokens, [ doctype('-//W3C//DTD HTML 4.01//EN', 'http://www.w3.org/TR/html4/strict.dtd') ], 'Standard HTML 4.01 Strict doctype');

0 commit comments

Comments
 (0)