Skip to content

Commit 72e262f

Browse files
committed
feat(parser): support inner union types and multi-parameters in generics
1 parent 0753220 commit 72e262f

2 files changed

Lines changed: 77 additions & 14 deletions

File tree

src/utils/parser/__tests__/index.test.mjs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,27 @@ describe('transformTypeToReferenceLink', () => {
4444
'`<CustomType>`&lt;[`<string>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type)&gt;'
4545
);
4646
});
47+
48+
it('should transform a Generic type with an inner union like {Promise<string|boolean>}', () => {
49+
strictEqual(
50+
transformTypeToReferenceLink('{Promise<string|boolean>}', {}),
51+
'[`<Promise>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)&lt;[`<string>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) | [`<boolean>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#boolean_type)&gt;'
52+
);
53+
});
54+
55+
it('should transform multi-parameter generics like {Map<string, number>}', () => {
56+
strictEqual(
57+
transformTypeToReferenceLink('{Map<string, number>}', {}),
58+
'[`<Map>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)&lt;[`<string>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type), [`<number>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#number_type)&gt;'
59+
);
60+
});
61+
62+
it('should handle outer unions with generics like {Promise<string|number> | boolean}', () => {
63+
strictEqual(
64+
transformTypeToReferenceLink('{Promise<string|number> | boolean}', {}),
65+
'[`<Promise>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)&lt;[`<string>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) | [`<number>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#number_type)&gt; | [`<boolean>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#boolean_type)'
66+
);
67+
});
4768
});
4869

4970
describe('normalizeYamlSyntax', () => {

src/utils/parser/index.mjs

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ export const transformTypeToReferenceLink = (type, record) => {
101101

102102
// Transform Node.js type/module references into Markdown links
103103
// that refer to other API docs pages within the Node.js API docs
104-
if (lookupPiece in record) {
104+
if (record && lookupPiece in record) {
105105
return record[lookupPiece];
106106
}
107107

@@ -118,6 +118,7 @@ export const transformTypeToReferenceLink = (type, record) => {
118118

119119
/**
120120
* Attempts to parse and format a basic Generic type (e.g., Promise<string>).
121+
* It also supports union and multi-parameter types within the generic brackets.
121122
*
122123
* @param {string} typePiece The plain type piece to be evaluated
123124
* @returns {string|null} The formatted Markdown link, or null if no match is found
@@ -130,26 +131,67 @@ export const transformTypeToReferenceLink = (type, record) => {
130131
const innerType = genericMatch[2].trim();
131132

132133
const baseResult = transformType(baseType.replace('[]', ''));
133-
const innerResult = transformType(innerType.replace('[]', ''));
134-
135-
// If at least one part is mapped successfully, format as a Generic Markdown link
136-
if (baseResult || innerResult) {
137-
const baseFormatted = baseResult
138-
? `[\`<${baseType}>\`](${baseResult})`
139-
: `\`<${baseType}>\``;
134+
const baseFormatted = baseResult
135+
? `[\`<${baseType}>\`](${baseResult})`
136+
: `\`<${baseType}>\``;
137+
138+
// Split while capturing delimiters (| or ,) to preserve original syntax
139+
const parts = innerType.split(/([|,])/);
140+
141+
const innerFormatted = parts
142+
.map(part => {
143+
const trimmed = part.trim();
144+
// If it is a delimiter, return it as is
145+
if (trimmed === '|') {
146+
return ' | ';
147+
}
148+
149+
if (trimmed === ',') {
150+
return ', ';
151+
}
152+
153+
const innerRes = transformType(trimmed.replace('[]', ''));
154+
return innerRes
155+
? `[\`<${trimmed}>\`](${innerRes})`
156+
: `\`<${trimmed}>\``;
157+
})
158+
.join('');
159+
160+
return `${baseFormatted}&lt;${innerFormatted}&gt;`;
161+
}
140162

141-
const innerFormatted = innerResult
142-
? `[\`<${innerType}>\`](${innerResult})`
143-
: `\`<${innerType}>\``;
163+
return null;
164+
};
144165

145-
return `${baseFormatted}&lt;${innerFormatted}&gt;`;
166+
/**
167+
* Safely splits the string by `|`, ignoring pipes that are inside `< >`
168+
*
169+
* @param {string} str The type string to split
170+
* @returns {string[]} An array of type pieces
171+
*/
172+
const splitByOuterUnion = str => {
173+
const result = [];
174+
let current = '';
175+
let depth = 0;
176+
177+
for (const char of str) {
178+
if (char === '<') {
179+
depth++;
180+
} else if (char === '>') {
181+
depth--;
182+
} else if (char === '|' && depth === 0) {
183+
result.push(current);
184+
current = '';
185+
continue;
146186
}
187+
current += char;
147188
}
148189

149-
return null;
190+
result.push(current);
191+
return result;
150192
};
151193

152-
const typePieces = typeInput.split('|').map(piece => {
194+
const typePieces = splitByOuterUnion(typeInput).map(piece => {
153195
// This is the content to render as the text of the Markdown link
154196
const trimmedPiece = piece.trim();
155197

0 commit comments

Comments
 (0)