1 | import { last, pathOr } from 'ramda';
|
---|
2 | import { isNumber } from 'ramda-adjunct';
|
---|
3 | import { hasElementSourceMap } from "../predicates/index.mjs";
|
---|
4 | import { visit } from "./visitor.mjs";
|
---|
5 | import toValue from "../transformers/serializers/value/index.mjs";
|
---|
6 | class Visitor {
|
---|
7 | result;
|
---|
8 | offset;
|
---|
9 | includeRightBound;
|
---|
10 | constructor({
|
---|
11 | offset = 0,
|
---|
12 | includeRightBound = false
|
---|
13 | } = {}) {
|
---|
14 | this.result = [];
|
---|
15 | this.offset = offset;
|
---|
16 | this.includeRightBound = includeRightBound;
|
---|
17 | }
|
---|
18 | enter(element) {
|
---|
19 | if (!hasElementSourceMap(element)) {
|
---|
20 | return undefined; // dive in
|
---|
21 | }
|
---|
22 | const sourceMapElement = element.getMetaProperty('sourceMap');
|
---|
23 | const charStart = toValue(sourceMapElement.positionStart.get(2));
|
---|
24 | const charEnd = toValue(sourceMapElement.positionEnd.get(2));
|
---|
25 | const isWithinOffsetRange = this.offset >= charStart && (this.offset < charEnd || this.includeRightBound && this.offset <= charEnd);
|
---|
26 | if (isWithinOffsetRange) {
|
---|
27 | this.result.push(element);
|
---|
28 | return undefined; // push to stack and dive in
|
---|
29 | }
|
---|
30 | return false; // skip entire sub-tree
|
---|
31 | }
|
---|
32 | }
|
---|
33 | // Finds the most inner node at the given offset.
|
---|
34 | // If includeRightBound is set, also finds nodes that end at the given offset.
|
---|
35 | // findAtOffset :: Number -> Element -> Element | Undefined
|
---|
36 | const findAtOffset = (options, element) => {
|
---|
37 | let offset;
|
---|
38 | let includeRightBound;
|
---|
39 | if (isNumber(options)) {
|
---|
40 | offset = options;
|
---|
41 | includeRightBound = false;
|
---|
42 | } else {
|
---|
43 | offset = pathOr(0, ['offset'], options);
|
---|
44 | includeRightBound = pathOr(false, ['includeRightBound'], options);
|
---|
45 | }
|
---|
46 | const visitor = new Visitor({
|
---|
47 | offset,
|
---|
48 | includeRightBound
|
---|
49 | });
|
---|
50 | visit(element, visitor);
|
---|
51 | return last(visitor.result);
|
---|
52 | };
|
---|
53 | export default findAtOffset; |
---|