-
Notifications
You must be signed in to change notification settings - Fork 45
Expand file tree
/
Copy pathparseList.mjs
More file actions
133 lines (110 loc) · 3.93 KB
/
parseList.mjs
File metadata and controls
133 lines (110 loc) · 3.93 KB
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import {
DEFAULT_EXPRESSION,
LEADING_HYPHEN,
NAME_EXPRESSION,
TYPE_EXPRESSION,
} from '../constants.mjs';
import parseSignature from './parseSignature.mjs';
import { leftHandAssign } from '../../../utils/generators.mjs';
import createQueries from '../../../utils/queries/index.mjs';
import { transformNodesToString } from '../../../utils/unist.mjs';
/**
* Modifies type references in a string by replacing template syntax (`<...>`) with curly braces `{...}`
* and normalizing formatting.
* @param {string} string
* @returns {string}
*/
export function transformTypeReferences(string) {
return string.replace(/`<([^>]+)>`/g, '{$1}').replaceAll('} | {', '|');
}
/**
* Extracts and removes a specific pattern from a text string while storing the result in a key of the `current` object.
* @param {string} text
* @param {RegExp} pattern
* @param {string} key
* @param {Object} current
* @returns {string}
*/
export const extractPattern = (text, pattern, key, current) => {
const match = text.match(pattern)?.[1]?.trim().replace(/\.$/, '');
if (!match) {
return text;
}
current[key] = match;
return text.replace(pattern, '');
};
/**
* Parses an individual list item node to extract its properties
*
* @param {import('@types/mdast').ListItem} child
* @returns {import('../types').ParameterList}
*/
export function parseListItem(child) {
const current = {};
const subList = child.children.find(createQueries.UNIST.isLooselyTypedList);
// Extract and clean raw text from the node, excluding nested lists
current.textRaw = transformTypeReferences(
transformNodesToString(child.children.filter(node => node !== subList))
.replace(/\s+/g, ' ')
.replace(/<!--.*?-->/gs, '')
);
let text = current.textRaw;
// Identify return items or extract key properties (name, type, default) from the text
const starter = text.match(createQueries.QUERIES.typedListStarters);
if (starter) {
current.name =
starter[1] === 'Returns' ? 'return' : starter[1].toLowerCase();
text = text.slice(starter[0].length);
} else {
text = extractPattern(text, NAME_EXPRESSION, 'name', current);
}
text = extractPattern(text, TYPE_EXPRESSION, 'type', current);
text = extractPattern(text, DEFAULT_EXPRESSION, 'default', current);
// Set the remaining text as the description, removing any leading hyphen
current.desc = text.replace(LEADING_HYPHEN, '').trim() || undefined;
// Parse nested lists (options) recursively if present
if (subList) {
current.options = subList.children.map(parseListItem);
}
return current;
}
/**
* Parses a list of nodes and updates the corresponding section object with the extracted information.
* Handles different section types such as methods, properties, and events differently.
* @param {import('../types').Section} section
* @param {import('@types/mdast').RootContent[]} nodes
*/
export function parseList(section, nodes) {
const listIdx = nodes.findIndex(createQueries.UNIST.isStronglyTypedList);
const list = nodes[listIdx];
const values = list ? list.children.map(parseListItem) : [];
let removeList = true;
// Update the section based on its type and parsed values
switch (section.type) {
case 'ctor':
// Constructors are their own signatures
leftHandAssign(section, parseSignature(section.textRaw, values));
break;
case 'classMethod':
case 'method':
// For methods and constructors, parse and attach signatures
section.signatures = [parseSignature(section.textRaw, values)];
break;
case 'property':
// For properties, update type and other details if values exist
if (values.length) {
delete values[0].name;
Object.assign(section, values[0]);
}
break;
case 'event':
// For events, assign parsed values as parameters
section.params = values;
break;
default:
removeList = false;
}
if (removeList && list) {
nodes.splice(listIdx, 1);
}
}