-
Notifications
You must be signed in to change notification settings - Fork 8
/
getJsdocSourceTokenCodeLocation.mjs
104 lines (89 loc) · 2.93 KB
/
getJsdocSourceTokenCodeLocation.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import CodeLocation from "./CodeLocation.mjs";
import CodePosition from "./CodePosition.mjs";
const JSDOC_SOURCE_TOKEN_ORDER = [
"start",
"delimiter",
"postDelimiter",
"tag",
"postTag",
"type",
"postType",
"name",
"postName",
"description",
"end",
"lineEnd",
];
const JSDOC_SOURCE_INFO_TOKENS = ["tag", "name", "type", "description"];
/**
* Gets a JSDoc comment code location a span of data, given parsed JSDoc
* source from `comment-parser` and a source token name. Empty lines at the
* start and end are excluded; particularly for descriptions.
* @kind function
* @name getJsdocSourceTokenCodeLocation
* @param {Array<object>} jsdocSource Parsed JSDoc source.
* @param {string} dataTokenName Name of a JSDoc source token that represents data (vs structural syntax such as delimiters and whitespace).
* @param {CodePosition} startCodePosition JSDoc comment start code position.
* @returns {CodeLocation} Code location.
* @ignore
*/
export default function getJsdocSourceTokenCodeLocation(
jsdocSource,
dataTokenName,
startCodePosition
) {
if (!Array.isArray(jsdocSource))
throw new TypeError("Argument 1 `jsdocSource` must be an array.");
if (typeof dataTokenName !== "string")
throw new TypeError("Argument 2 `dataTokenName` must be a string.");
if (!JSDOC_SOURCE_INFO_TOKENS.includes(dataTokenName))
throw new TypeError(
"Argument 2 `dataTokenName` must be a JSDoc source data token name."
);
if (!(startCodePosition instanceof CodePosition))
throw new TypeError(
"Argument 3 `startCodePosition` must be a `CodePosition` instance."
);
let start;
let end;
// Find the start, looping the source lines forwards.
for (let i = 0; i < jsdocSource.length; i++)
if (jsdocSource[i].tokens[dataTokenName]) {
start = {
line: jsdocSource[i].number,
column:
jsdocSource[i].number === startCodePosition.line
? startCodePosition.column
: 1,
};
for (const tokenName of JSDOC_SOURCE_TOKEN_ORDER) {
if (tokenName === dataTokenName) break;
start.column += jsdocSource[i].tokens[tokenName].length;
}
break;
}
// Find the end, looping the source lines backwards.
for (let i = jsdocSource.length; i--; )
if (jsdocSource[i].tokens[dataTokenName]) {
end = {
line: jsdocSource[i].number,
column:
jsdocSource[i].number === startCodePosition.line
? startCodePosition.column - 1
: 0,
};
for (const tokenName of JSDOC_SOURCE_TOKEN_ORDER) {
end.column += jsdocSource[i].tokens[tokenName].length;
if (tokenName === dataTokenName) break;
}
break;
}
if (!start || !end)
throw new Error(
`Unable to get a code location for JSDoc source token \`${dataTokenName}\`.`
);
return new CodeLocation(
new CodePosition(start.line, start.column),
new CodePosition(end.line, end.column)
);
}