Skip to content

Commit

Permalink
Add updateNodeSourceCodeLocation to the tree adapter (#315)
Browse files Browse the repository at this point in the history
* Add updateNodeSourceCodeLocation to the tree adapter

* Add updateNodeSourceCodeLocation to the tree adapter documentation

* Renamed updateNodeSourceCodeLocation parameter location to endLocation

* Use updateNodeSourceCodeLocation to update the end location of tokens

* Update tree adapter updateNodeSourceCodeLocation documentation to reflect updating the source code location of nodes not just elements

* Add test for updating node source code location
  • Loading branch information
DMartens authored Apr 15, 2020
1 parent 9c7556e commit e36bd98
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 14 deletions.
4 changes: 4 additions & 0 deletions packages/parse5-htmlparser2-tree-adapter/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -342,3 +342,7 @@ exports.setNodeSourceCodeLocation = function(node, location) {
exports.getNodeSourceCodeLocation = function(node) {
return node.sourceCodeLocation;
};

exports.updateNodeSourceCodeLocation = function(node, endLocation) {
node.sourceCodeLocation = Object.assign(node.sourceCodeLocation, endLocation);
};
48 changes: 48 additions & 0 deletions packages/parse5/docs/source-code-location/end-location.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Interface: EndLocation

### Properties

* [endCol](#endcol)
* [endOffset](#endoffset)
* [endLine](#endline)
* [endTag](#endtag)

---

## Properties

<a id="endcol"></a>

### endCol

**● endCol**: *`number`*

One-based column index of the last character

___
<a id="endoffset"></a>

### endOffset

**● endOffset**: *`number`*

Zero-based last character index

___
<a id="endline"></a>

### endLine

**● endLine**: *`number`*

One-based line index of the last character

___
<a id="endtag"></a>

### endTag

**● endTag**: *[Location](location.md)|undefined*

Element's end tag location info.
This property is undefined, if the element has no closing tag.
19 changes: 17 additions & 2 deletions packages/parse5/docs/tree-adapter/interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Tree adapter is a set of utility functions that provides minimal required abstra
* [setDocumentType](#setdocumenttype)
* [setNodeSourceCodeLocation](#setnodesourcecodelocation)
* [setTemplateContent](#settemplatecontent)

* [updateNodeSourceCodeLocation](#updatenodesourcecodelocation)
---

## Methods
Expand Down Expand Up @@ -588,6 +588,21 @@ Sets the `<template>` element content element.
| contentElement | DocumentFragment | Content element. |

**Returns:** `void`

___
<a id="updatenodesourcecodelocation"></a>

### updateNodeSourceCodeLocation

**updateNodeSourceCodeLocation**(node: *Node*, endLocation: *[EndLocation](../source-code-location/end-location.md)*): `void`

Updates the source code location of nodes.

**Parameters:**

| Param | Type | Description |
| ------ | ------ | ------ |
| node | Node | Node. |
| endLocation | [EndLocation](../source-code-location/end-location.md) | Source code location information of the end of the node. |

**Returns:** `void`
___
23 changes: 12 additions & 11 deletions packages/parse5/lib/extensions/location-info/parser-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,19 @@ class LocationInfoParserMixin extends Mixin {
// NOTE: For cases like <p> <p> </p> - First 'p' closes without a closing
// tag and for cases like <td> <p> </td> - 'p' closes without a closing tag.
const isClosingEndTag = closingToken.type === Tokenizer.END_TAG_TOKEN && tn === closingToken.tagName;

const endLoc = {};
if (isClosingEndTag) {
loc.endTag = Object.assign({}, ctLoc);
loc.endLine = ctLoc.endLine;
loc.endCol = ctLoc.endCol;
loc.endOffset = ctLoc.endOffset;
endLoc.endTag = Object.assign({}, ctLoc);
endLoc.endLine = ctLoc.endLine;
endLoc.endCol = ctLoc.endCol;
endLoc.endOffset = ctLoc.endOffset;
} else {
loc.endLine = ctLoc.startLine;
loc.endCol = ctLoc.startCol;
loc.endOffset = ctLoc.startOffset;
endLoc.endLine = ctLoc.startLine;
endLoc.endCol = ctLoc.startCol;
endLoc.endOffset = ctLoc.startOffset;
}

this.treeAdapter.updateNodeSourceCodeLocation(element, endLoc);
}
}
}
Expand Down Expand Up @@ -208,9 +210,8 @@ class LocationInfoParserMixin extends Mixin {
const tnLoc = this.treeAdapter.getNodeSourceCodeLocation(textNode);

if (tnLoc) {
tnLoc.endLine = token.location.endLine;
tnLoc.endCol = token.location.endCol;
tnLoc.endOffset = token.location.endOffset;
const { endLine, endCol, endOffset } = token.location;
this.treeAdapter.updateNodeSourceCodeLocation(textNode, { endLine, endCol, endOffset });
} else {
this.treeAdapter.setNodeSourceCodeLocation(textNode, token.location);
}
Expand Down
4 changes: 4 additions & 0 deletions packages/parse5/lib/tree-adapters/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,7 @@ exports.setNodeSourceCodeLocation = function(node, location) {
exports.getNodeSourceCodeLocation = function(node) {
return node.sourceCodeLocation;
};

exports.updateNodeSourceCodeLocation = function(node, endLocation) {
node.sourceCodeLocation = Object.assign(node.sourceCodeLocation, endLocation);
};
55 changes: 54 additions & 1 deletion packages/parse5/test/location-info-parser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const {
assertStartTagLocation,
assertNodeLocation
} = require('../../../test/utils/generate-location-info-parser-tests');
const { generateTestsForEachTreeAdapter } = require('../../../test/utils/common');
const { generateTestsForEachTreeAdapter, treeAdapters } = require('../../../test/utils/common');

generateLocationInfoParserTests(module.exports, 'Parser', (input, opts) => ({
node: parse5.parse(input, opts)
Expand Down Expand Up @@ -127,3 +127,56 @@ generateTestsForEachTreeAdapter(module.exports, (_test, treeAdapter) => {
assert.ok(!location.endTag);
};
});

exports['Updating node source code location (GH-314)'] = function() {
const sourceCodeLocationSetter = {
setNodeSourceCodeLocation(node, location) {
if (location === null) {
node.sourceCodeLocation = null;
} else {
node.sourceCodeLocation = {
start: {
line: location.startLine,
column: location.startCol,
offset: location.startOffset
},
end: {
line: location.endLine,
column: location.endCol,
offset: location.endOffset
}
};
}
},
updateNodeSourceCodeLocation(node, endLocation) {
node.sourceCodeLocation = {
start: node.sourceCodeLocation.start,
end: {
line: endLocation.endLine,
column: endLocation.endCol,
offset: endLocation.endOffset
}
};
}
};
const adapter = Object.assign(treeAdapters.default, sourceCodeLocationSetter);
const document = parse5.parse('<!doctype><body>Testing location</body>', { adapter, sourceCodeLocationInfo: true });
const [doctype, html] = document.childNodes;
const [head, body] = html.childNodes;
const [text] = body.childNodes;

assert.deepEqual(doctype.sourceCodeLocation, {
start: { line: 1, column: 1, offset: 0 },
end: { line: 1, column: 11, offset: 10 }
});
assert.strictEqual(html.sourceCodeLocation, null);
assert.strictEqual(head.sourceCodeLocation, null);
assert.deepEqual(body.sourceCodeLocation, {
start: { line: 1, column: 11, offset: 10 },
end: { line: 1, column: 40, offset: 39 }
});
assert.deepEqual(text.sourceCodeLocation, {
start: { line: 1, column: 17, offset: 16 },
end: { line: 1, column: 33, offset: 32 }
});
};

0 comments on commit e36bd98

Please sign in to comment.