• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3const assert = require('assert');
4const parse5 = require('../lib');
5const generateLocationInfoParserTests = require('../../../test/utils/generate-location-info-parser-tests');
6const {
7    assertStartTagLocation,
8    assertNodeLocation
9} = require('../../../test/utils/generate-location-info-parser-tests');
10const { generateTestsForEachTreeAdapter, treeAdapters } = require('../../../test/utils/common');
11
12generateLocationInfoParserTests(module.exports, 'Parser', (input, opts) => ({
13    node: parse5.parse(input, opts)
14}));
15
16generateTestsForEachTreeAdapter(module.exports, (_test, treeAdapter) => {
17    _test['Regression - Incorrect LocationInfo.endOffset for implicitly closed <p> element (GH-109)'] = function() {
18        const html = '<p>1<p class="2">3';
19
20        const opts = {
21            treeAdapter: treeAdapter,
22            sourceCodeLocationInfo: true
23        };
24
25        const fragment = parse5.parseFragment(html, opts);
26        const firstP = treeAdapter.getChildNodes(fragment)[0];
27        const firstPLocation = treeAdapter.getNodeSourceCodeLocation(firstP);
28
29        assert.strictEqual(html.substring(firstPLocation.startOffset, firstPLocation.endOffset), '<p>1');
30    };
31
32    _test['Regression - Incorrect LocationInfo.endOffset for element with closing tag (GH-159)'] = function() {
33        const html = '<i>1</i>2';
34
35        const opts = {
36            treeAdapter: treeAdapter,
37            sourceCodeLocationInfo: true
38        };
39
40        const fragment = parse5.parseFragment(html, opts);
41        const firstChild = treeAdapter.getChildNodes(fragment)[0];
42        const location = treeAdapter.getNodeSourceCodeLocation(firstChild);
43
44        assert.strictEqual(html.substring(location.startOffset, location.endOffset), '<i>1</i>');
45    };
46
47    _test['Regression - Location info not exposed with parseFragment (GH-82)'] = function() {
48        const html = '<html><head></head><body>foo</body></html>';
49
50        const opts = {
51            treeAdapter: treeAdapter,
52            sourceCodeLocationInfo: true
53        };
54
55        const fragment = parse5.parseFragment(html, opts);
56        const firstChild = treeAdapter.getChildNodes(fragment)[0];
57
58        assert.ok(treeAdapter.getNodeSourceCodeLocation(firstChild));
59    };
60
61    _test['Regression - location info mixin error when parsing <template> elements (GH-90)'] = function() {
62        const html = '<template>hello</template>';
63
64        const opts = {
65            treeAdapter: treeAdapter,
66            sourceCodeLocationInfo: true
67        };
68
69        assert.doesNotThrow(() => {
70            parse5.parseFragment(html, opts);
71        });
72    };
73
74    _test['Regression - location info not attached for empty attributes (GH-96)'] = function() {
75        const html = '<div test-attr></div>';
76
77        const opts = {
78            treeAdapter: treeAdapter,
79            sourceCodeLocationInfo: true
80        };
81
82        const fragment = parse5.parseFragment(html, opts);
83        const firstChild = treeAdapter.getChildNodes(fragment)[0];
84
85        assert.ok(treeAdapter.getNodeSourceCodeLocation(firstChild).attrs['test-attr']);
86    };
87
88    _test['Regression - location line incorrect when a character is unconsumed (GH-151)'] = function() {
89        const html = [
90            '<html><body><script>',
91            '  var x = window.scrollY <',
92            '      100;',
93            '</script>',
94            '</body></html>'
95        ].join('\n');
96
97        const opts = {
98            treeAdapter: treeAdapter,
99            sourceCodeLocationInfo: true
100        };
101
102        const document = parse5.parse(html, opts);
103        const htmlEl = treeAdapter.getChildNodes(document)[0];
104        const bodyEl = treeAdapter.getChildNodes(htmlEl)[1];
105        const scriptEl = treeAdapter.getChildNodes(bodyEl)[0];
106        const scriptLocation = treeAdapter.getNodeSourceCodeLocation(scriptEl);
107
108        assert.strictEqual(treeAdapter.getTagName(scriptEl), 'script');
109        assert.equal(scriptLocation.endTag.startLine, 4);
110    };
111
112    _test['Regression - location.startTag should be available if end tag is missing (GH-181)'] = function() {
113        const html = '<p>test';
114
115        const opts = {
116            treeAdapter: treeAdapter,
117            sourceCodeLocationInfo: true
118        };
119
120        const fragment = parse5.parseFragment(html, opts);
121        const p = treeAdapter.getChildNodes(fragment)[0];
122        const location = treeAdapter.getNodeSourceCodeLocation(p);
123
124        assertNodeLocation(location, html, html, [html]);
125        assertStartTagLocation(location, html, html, [html]);
126
127        assert.ok(!location.endTag);
128    };
129});
130
131exports['Updating node source code location (GH-314)'] = function() {
132    const sourceCodeLocationSetter = {
133        setNodeSourceCodeLocation(node, location) {
134            if (location === null) {
135                node.sourceCodeLocation = null;
136            } else {
137                node.sourceCodeLocation = {
138                    start: {
139                        line: location.startLine,
140                        column: location.startCol,
141                        offset: location.startOffset
142                    },
143                    end: {
144                        line: location.endLine,
145                        column: location.endCol,
146                        offset: location.endOffset
147                    }
148                };
149            }
150        },
151        updateNodeSourceCodeLocation(node, endLocation) {
152            node.sourceCodeLocation = {
153                start: node.sourceCodeLocation.start,
154                end: {
155                    line: endLocation.endLine,
156                    column: endLocation.endCol,
157                    offset: endLocation.endOffset
158                }
159            };
160        }
161    };
162    const adapter = Object.assign(treeAdapters.default, sourceCodeLocationSetter);
163    const document = parse5.parse('<!doctype><body>Testing location</body>', { adapter, sourceCodeLocationInfo: true });
164    const [doctype, html] = document.childNodes;
165    const [head, body] = html.childNodes;
166    const [text] = body.childNodes;
167
168    assert.deepEqual(doctype.sourceCodeLocation, {
169        start: { line: 1, column: 1, offset: 0 },
170        end: { line: 1, column: 11, offset: 10 }
171    });
172    assert.strictEqual(html.sourceCodeLocation, null);
173    assert.strictEqual(head.sourceCodeLocation, null);
174    assert.deepEqual(body.sourceCodeLocation, {
175        start: { line: 1, column: 11, offset: 10 },
176        end: { line: 1, column: 40, offset: 39 }
177    });
178    assert.deepEqual(text.sourceCodeLocation, {
179        start: { line: 1, column: 17, offset: 16 },
180        end: { line: 1, column: 33, offset: 32 }
181    });
182};
183