Skip to content
This repository was archived by the owner on Apr 16, 2025. It is now read-only.

Commit fa8a767

Browse files
ggereenglercj
authored andcommitted
Support objects in complex types, Fixes: englercj#65 (englercj#71)
1 parent 1c5c10a commit fa8a767

File tree

3 files changed

+76
-8
lines changed

3 files changed

+76
-8
lines changed

src/type_resolve_helpers.ts

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { warn } from './logger';
44
import { PropTree, IPropDesc } from './PropTree';
55
import { type } from 'os';
66

7-
const rgxObjectTokenize = /(<|>|,|\(|\)|\|)/;
7+
const rgxObjectTokenize = /(<|>|,|\(|\)|\||\{|\}|:)/;
88
const rgxCommaAll = /,/g;
99
const rgxParensAll = /\(|\)/g;
1010

@@ -17,6 +17,7 @@ enum ENodeType {
1717
FUNCTION, // function() has arguments for children
1818
TUPLE, // [a,b] has types for children
1919
TYPE, // string, X has no children
20+
OBJECT, // {a:b, c:d} has name value pairs for children
2021
}
2122
class StringTreeNode {
2223
children: StringTreeNode[] = [];
@@ -45,6 +46,8 @@ class StringTreeNode {
4546
return 'TUPLE';
4647
case ENodeType.TYPE:
4748
return 'TYPE';
49+
case ENodeType.OBJECT:
50+
return 'OBJECT';
4851
default:
4952
return 'UNKNOWN'
5053
}
@@ -86,7 +89,7 @@ function generateTree(name: string, parent: StringTreeNode | null = null) : Stri
8689
const matchingIndex = findMatchingBracket(parts, i + 1, '<', '>');
8790
if (matchingIndex === -1)
8891
{
89-
warn(`error`);
92+
warn(`Unable to find matching '<', '>' brackets in '${part}', defaulting to \`any\``, name);
9093
return anyNode;
9194
}
9295

@@ -107,7 +110,7 @@ function generateTree(name: string, parent: StringTreeNode | null = null) : Stri
107110
const matchingIndex = findMatchingBracket(parts, i, '(', ')');
108111
if (matchingIndex === -1)
109112
{
110-
warn(`error`);
113+
warn(`Unable to find matching '(', ')' brackets in '${part}', defaulting to \`any\``, name);
111114
return anyNode;
112115
}
113116

@@ -121,12 +124,32 @@ function generateTree(name: string, parent: StringTreeNode | null = null) : Stri
121124
continue;
122125
}
123126

127+
// Object
128+
if (part === '{')
129+
{
130+
const matchingIndex = findMatchingBracket(parts, i, '{', '}');
131+
if (matchingIndex === -1)
132+
{
133+
warn(`Unable to find matching '{', '}' brackets in '${part}', defaulting to \`any\``, name);
134+
return anyNode;
135+
}
136+
137+
const node = new StringTreeNode('Object', ENodeType.OBJECT, parent);
138+
generateTree(parts.slice(i + 1, matchingIndex).join(''), node);
139+
if (!parent)
140+
return node;
141+
142+
parent.children.push(node);
143+
i = matchingIndex + 1;
144+
continue;
145+
}
146+
124147
// TODO: Function?
125148

126149
// TODO: Tuples?
127150

128151
// skip separators, our handling below takes them into account
129-
if (part === '|' || part === ',' )
152+
if (part === '|' || part === ',' || part === ':')
130153
{
131154
continue;
132155
}
@@ -181,6 +204,37 @@ function resolveTree(node: StringTreeNode, parentTypes: ts.TypeNode[] | null = n
181204
// resolve our type, do this for our parent (add our type to its children), or return our type if we have no parent (we are the root)
182205
switch (node.type)
183206
{
207+
case ENodeType.OBJECT:
208+
const objectProperties: ts.TypeElement[] = [];
209+
210+
for (var i = 0; i < node.children.length; i = i + 2)
211+
{
212+
let valType = childTypes[i + 1];
213+
if (!valType)
214+
{
215+
warn('Unable to resolve object value type, this is likely due to invalid JSDoc. Defaulting to \`any\`.', node);
216+
valType = anyTypeNode;
217+
}
218+
219+
const property = ts.createPropertySignature(
220+
undefined, //modifiers
221+
ts.createIdentifier(node.children[i].name),
222+
undefined, //question token
223+
valType,
224+
undefined //initializer
225+
)
226+
227+
objectProperties.push(property);
228+
}
229+
230+
const objectNode = ts.createTypeLiteralNode(objectProperties);
231+
ts.setEmitFlags(objectNode, ts.EmitFlags.SingleLine);
232+
233+
if (!parentTypes)
234+
return objectNode;
235+
236+
parentTypes.push(objectNode);
237+
break;
184238
case ENodeType.GENERIC:
185239
let genericNode: ts.TypeNode;
186240
if (upperName === 'OBJECT')
@@ -229,7 +283,7 @@ function resolveTree(node: StringTreeNode, parentTypes: ts.TypeNode[] | null = n
229283

230284
if (!valType)
231285
{
232-
warn('Unable to resolve array value type, defaulting to \`any\`.', parent);
286+
warn('Unable to resolve array value type, defaulting to \`any\`.', node);
233287
valType = anyTypeNode;
234288
}
235289

@@ -241,7 +295,7 @@ function resolveTree(node: StringTreeNode, parentTypes: ts.TypeNode[] | null = n
241295

242296
if (!valType)
243297
{
244-
warn('Unable to resolve class value type, defaulting to \`any\`.', parent);
298+
warn('Unable to resolve class value type, defaulting to \`any\`.', node);
245299
valType = anyTypeNode;
246300
}
247301

@@ -252,7 +306,7 @@ function resolveTree(node: StringTreeNode, parentTypes: ts.TypeNode[] | null = n
252306
{
253307
if (childTypes.length === 0 )
254308
{
255-
warn('Unable to resolve generic type, defaulting to \`any\`.', parent);
309+
warn('Unable to resolve generic type, defaulting to \`any\`.', node);
256310
childTypes.push(anyTypeNode);
257311
}
258312

@@ -276,7 +330,7 @@ function resolveTree(node: StringTreeNode, parentTypes: ts.TypeNode[] | null = n
276330
case ENodeType.UNION:
277331
if (childTypes.length === 0 )
278332
{
279-
warn('Unable to resolve any types for union, defaulting to \`any\`.', parent);
333+
warn('Unable to resolve any types for union, defaulting to \`any\`.', node);
280334
childTypes.push(anyTypeNode);
281335
}
282336

test/expected/class_all.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,12 @@ declare module "util" {
175175
* @return {Promise<Array.<*>|Object|number|string>} The Promise
176176
*/
177177
promiseFoo(): Promise<any[] | object | number | string>;
178+
/**
179+
* Gets a Promise that will resolve with an object with complex properties
180+
*
181+
* @return {Promise<{newChannels: Channel[], foo: Bar}>} The Promise
182+
*/
183+
promiseBar(): Promise<{ newChannels: Channel[]; foo: Bar; }>;
178184
/**
179185
*
180186
* @param {GitGraphOptions} options - GitGraph options

test/fixtures/class_all.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,14 @@ class MyThing extends OtherThing {
188188
promiseFoo() {
189189
}
190190

191+
/**
192+
* Gets a Promise that will resolve with an object with complex properties
193+
*
194+
* @return {Promise<{newChannels: Channel[], foo: Bar}>} The Promise
195+
*/
196+
promiseBar() {
197+
}
198+
191199
/**
192200
*
193201
* @param {GitGraphOptions} options - GitGraph options

0 commit comments

Comments
 (0)