Skip to content

Commit 8e57eee

Browse files
authored
Fix handle CRLF (#15)
1 parent d05b17e commit 8e57eee

File tree

8 files changed

+414
-16
lines changed

8 files changed

+414
-16
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<div
2+
id="foo"
3+
style="bar"
4+
bool
5+
>
6+
</div>
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
import { TokenTypes } from "../../../constants";
2+
3+
export default [
4+
{
5+
type: TokenTypes.OpenTagStart,
6+
range: [0, 4],
7+
loc: {
8+
start: {
9+
column: 0,
10+
line: 1,
11+
},
12+
end: {
13+
column: 4,
14+
line: 1,
15+
},
16+
},
17+
value: "<div",
18+
},
19+
{
20+
type: TokenTypes.AttributeKey,
21+
range: [8, 10],
22+
value: "id",
23+
loc: {
24+
start: {
25+
line: 2,
26+
column: 2,
27+
},
28+
end: {
29+
line: 2,
30+
column: 4,
31+
},
32+
},
33+
},
34+
{
35+
type: TokenTypes.AttributeAssignment,
36+
range: [10, 11],
37+
value: "=",
38+
loc: {
39+
start: {
40+
line: 2,
41+
column: 4,
42+
},
43+
end: {
44+
line: 2,
45+
column: 5,
46+
},
47+
},
48+
},
49+
{
50+
type: TokenTypes.AttributeValueWrapperStart,
51+
value: '"',
52+
range: [11, 12],
53+
loc: {
54+
start: {
55+
line: 2,
56+
column: 5,
57+
},
58+
end: {
59+
line: 2,
60+
column: 6,
61+
},
62+
},
63+
},
64+
{
65+
type: TokenTypes.AttributeValue,
66+
value: "foo",
67+
range: [12, 15],
68+
loc: {
69+
start: {
70+
line: 2,
71+
column: 6,
72+
},
73+
end: {
74+
line: 2,
75+
column: 9,
76+
},
77+
},
78+
},
79+
{
80+
type: TokenTypes.AttributeValueWrapperEnd,
81+
value: '"',
82+
range: [15, 16],
83+
loc: {
84+
start: {
85+
line: 2,
86+
column: 9,
87+
},
88+
end: {
89+
line: 2,
90+
column: 10,
91+
},
92+
},
93+
},
94+
{
95+
type: TokenTypes.AttributeKey,
96+
value: "style",
97+
range: [20, 25],
98+
loc: {
99+
start: {
100+
line: 3,
101+
column: 2,
102+
},
103+
end: {
104+
line: 3,
105+
column: 7,
106+
},
107+
},
108+
},
109+
{
110+
type: TokenTypes.AttributeAssignment,
111+
value: "=",
112+
range: [25, 26],
113+
loc: {
114+
start: {
115+
line: 3,
116+
column: 7,
117+
},
118+
end: {
119+
line: 3,
120+
column: 8,
121+
},
122+
},
123+
},
124+
{
125+
type: TokenTypes.AttributeValueWrapperStart,
126+
value: '"',
127+
range: [26, 27],
128+
loc: {
129+
start: {
130+
line: 3,
131+
column: 8,
132+
},
133+
end: {
134+
line: 3,
135+
column: 9,
136+
},
137+
},
138+
},
139+
{
140+
type: TokenTypes.AttributeValue,
141+
value: "bar",
142+
range: [27, 30],
143+
loc: {
144+
start: {
145+
line: 3,
146+
column: 9,
147+
},
148+
end: {
149+
line: 3,
150+
column: 12,
151+
},
152+
},
153+
},
154+
{
155+
type: TokenTypes.AttributeValueWrapperEnd,
156+
value: '"',
157+
range: [30, 31],
158+
loc: {
159+
start: {
160+
line: 3,
161+
column: 12,
162+
},
163+
end: {
164+
line: 3,
165+
column: 13,
166+
},
167+
},
168+
},
169+
{
170+
type: TokenTypes.AttributeKey,
171+
value: "bool",
172+
range: [35, 39],
173+
loc: {
174+
start: {
175+
line: 4,
176+
column: 2,
177+
},
178+
end: {
179+
line: 4,
180+
column: 6,
181+
},
182+
},
183+
},
184+
{
185+
type: TokenTypes.OpenTagEnd,
186+
value: ">",
187+
range: [41, 42],
188+
loc: {
189+
start: {
190+
line: 5,
191+
column: 0,
192+
},
193+
end: {
194+
line: 5,
195+
column: 1,
196+
},
197+
},
198+
},
199+
{
200+
type: TokenTypes.Text,
201+
value: "\r\n",
202+
range: [42, 44],
203+
loc: {
204+
start: {
205+
line: 5,
206+
column: 1,
207+
},
208+
end: {
209+
line: 6,
210+
column: 0,
211+
},
212+
},
213+
},
214+
{
215+
type: TokenTypes.CloseTag,
216+
value: "</div>",
217+
range: [44, 50],
218+
loc: {
219+
start: {
220+
line: 6,
221+
column: 0,
222+
},
223+
end: {
224+
line: 6,
225+
column: 6,
226+
},
227+
},
228+
},
229+
{
230+
type: TokenTypes.Text,
231+
value: "\r\n",
232+
range: [50, 52],
233+
loc: {
234+
start: {
235+
line: 6,
236+
column: 6,
237+
},
238+
end: {
239+
line: 7,
240+
column: 0,
241+
},
242+
},
243+
},
244+
];

src/tokenizer/__tests__/tokenize.spec.ts

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import TAGS_REGISTER from "./__output__/tags-register";
1818
import VOID_TAGS from "./__output__/void-tags";
1919
import EMPTY from "./__output__/empty";
2020
import SVG from "./__output__/svg";
21+
import ATTRIBUTES_MULTILINE_CRLF from "./__output__/attributes-multiline-crlf";
2122

2223
describe("tokenize", () => {
2324
test.each(
@@ -107,12 +108,31 @@ describe("tokenize", () => {
107108
"Svg",
108109
"svg.html",
109110
SVG,
111+
],
112+
[
113+
"Attributes multiline CRLF",
114+
"attributes-multiline.html",
115+
ATTRIBUTES_MULTILINE_CRLF,
116+
(html: string) => {
117+
return html.replace(/\n/gi, "\r\n");
118+
}
110119
]
111120
]
112-
)("%s", (name, input, output) => {
113-
const inputPath = path.join(__dirname, "__input__", input);
114-
const html = fs.readFileSync(inputPath, "utf-8");
115-
const { tokens } = tokenize(html, undefined);
116-
expect(tokens).toEqual(output);
117-
});
121+
)(
122+
"%s",
123+
(
124+
name,
125+
input,
126+
output,
127+
process: null | ((html: string) => string) = null
128+
) => {
129+
const inputPath = path.join(__dirname, "__input__", input);
130+
let html = fs.readFileSync(inputPath, "utf-8");
131+
if (process) {
132+
html = process(html);
133+
}
134+
const { tokens } = tokenize(html, undefined);
135+
expect(tokens).toEqual(output);
136+
}
137+
);
118138
});

src/tokenizer/handlers/attribute-key.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { TokenizerContextTypes } from "../../constants";
22
import { TokenTypes } from "../../constants/token-types";
3-
import { calculateTokenPosition } from "../../utils";
3+
import { calculateTokenPosition, isWhitespace } from "../../utils";
44
import { AnyToken, TokenizerState } from "../../types";
55

66
export function parse(
@@ -18,14 +18,7 @@ export function parse(
1818
}
1919

2020
function isKeyBreak(chars: string): boolean {
21-
return (
22-
chars === "=" ||
23-
chars === " " ||
24-
chars === "\n" ||
25-
chars === "\t" ||
26-
chars === "/" ||
27-
chars === ">"
28-
);
21+
return chars === "=" || chars === "/" || chars === ">" || isWhitespace(chars);
2922
}
3023

3124
function parseKeyEnd(state: TokenizerState, tokens: AnyToken[]) {

src/tokenizer/handlers/open-tag-start.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export function parse(
2020
if (chars === ">" || chars === "/") {
2121
return parseTagEnd(state, tokens);
2222
}
23+
2324
if (isWhitespace(chars)) {
2425
return parseWhitespace(state, tokens);
2526
}

0 commit comments

Comments
 (0)