Skip to content

Commit 54e0017

Browse files
rklfssblakeembrey
authored andcommitted
Support for multidimensional arrays (TypeStrong#491)
1 parent 2509112 commit 54e0017

File tree

29 files changed

+394
-139
lines changed

29 files changed

+394
-139
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"minimatch": "^3.0.0",
4646
"progress": "^2.0.0",
4747
"shelljs": "^0.7.0",
48-
"typedoc-default-themes": "^0.4.2",
48+
"typedoc-default-themes": "^0.4.4",
4949
"typescript": "2.3.2"
5050
},
5151
"devDependencies": {

src/lib/converter/plugins/TypePlugin.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {Reflection, ReflectionKind, Decorator, DeclarationReflection, DeclarationHierarchy} from '../../models/reflections/index';
2-
import {Type, ReferenceType, TupleType, UnionType, IntersectionType} from '../../models/types/index';
2+
import {Type, ReferenceType, TupleType, UnionType, IntersectionType, ArrayType} from '../../models/types/index';
33
import {Component, ConverterComponent} from '../components';
44
import {Converter} from '../converter';
55
import {Context} from '../context';
@@ -113,6 +113,8 @@ export class TypePlugin extends ConverterComponent {
113113
for (let index = 0, count = unionOrIntersectionType.types.length; index < count; index++) {
114114
resolveType(reflection, unionOrIntersectionType.types[index]);
115115
}
116+
} else if (type instanceof ArrayType) {
117+
resolveType(reflection, type.elementType);
116118
}
117119
}
118120
}

src/lib/converter/types/array.ts

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
import * as ts from 'typescript';
22

3-
import {Type, IntrinsicType} from '../../models/index';
4-
import {Component, ConverterTypeComponent, TypeNodeConverter} from '../components';
3+
import {Type, ArrayType} from '../../models/index';
4+
import {Component, ConverterTypeComponent, TypeConverter} from '../components';
55
import {Context} from '../context';
66

77
@Component({name: 'type:array'})
8-
export class ArrayConverter extends ConverterTypeComponent implements TypeNodeConverter<ts.Type, ts.ArrayTypeNode> {
8+
export class ArrayConverter extends ConverterTypeComponent implements TypeConverter<ts.TypeReference, ts.ArrayTypeNode> {
99
/**
1010
* Test whether this converter can handle the given TypeScript node.
1111
*/
1212
supportsNode(context: Context, node: ts.ArrayTypeNode): boolean {
1313
return node.kind === ts.SyntaxKind.ArrayType;
1414
}
1515

16+
/**
17+
* Test whether this converter can handle the given TypeScript type.
18+
*/
19+
supportsType(context: Context, type: ts.TypeReference): boolean {
20+
// Is there a better way to detect the {"type":"reference","name":"Array","typeArguments":{...}} types that are in fact arrays?
21+
return !!(type.flags & ts.TypeFlags.Object) && !!type.symbol && type.symbol.name === 'Array' && !type.symbol.parent && !!type.typeArguments && type.typeArguments.length === 1;
22+
}
23+
1624
/**
1725
* Convert the given array type node to its type reflection.
1826
*
@@ -27,14 +35,28 @@ export class ArrayConverter extends ConverterTypeComponent implements TypeNodeCo
2735
* @returns The type reflection representing the given array type node.
2836
*/
2937
convertNode(context: Context, node: ts.ArrayTypeNode): Type {
30-
let result = this.owner.convertType(context, node.elementType);
38+
const result = this.owner.convertType(context, node.elementType);
3139

32-
if (result) {
33-
result.isArray = true;
34-
} else {
35-
result = new IntrinsicType('Array');
36-
}
40+
return new ArrayType(result);
41+
}
42+
43+
/**
44+
* Convert the given type reference to its type reflection.
45+
*
46+
* This is a type based converter, see [[convertTypeReference]] for the node equivalent.
47+
*
48+
* ```
49+
* class SomeClass { }
50+
* let someValue: SomeClass;
51+
* ```
52+
*
53+
* @param context The context object describing the current state the converter is in.
54+
* @param type The type reference that should be converted.
55+
* @returns The type reflection representing the given type reference.
56+
*/
57+
convertType(context: Context, type: ts.TypeReference): Type {
58+
const result = this.owner.convertType(context, null, type.typeArguments[0]);
3759

38-
return result;
60+
return new ArrayType(result);
3961
}
4062
}

src/lib/models/types/abstract.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@
44
* Instances of this class are also used to represent the type `void`.
55
*/
66
export abstract class Type {
7-
/**
8-
* Is this an array type?
9-
*/
10-
isArray = false;
117

128
/**
139
* The type name identifier.
@@ -38,10 +34,6 @@ export abstract class Type {
3834
let result: any = {};
3935
result.type = this.type;
4036

41-
if (this.isArray) {
42-
result.isArray = this.isArray;
43-
}
44-
4537
return result;
4638
}
4739

src/lib/models/types/array.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import {Type, UnionType, IntersectionType} from './index';
2+
3+
/**
4+
* Represents an array type.
5+
*
6+
* ~~~
7+
* let value: string[];
8+
* ~~~
9+
*/
10+
export class ArrayType extends Type {
11+
12+
/**
13+
* The type of the array elements.
14+
*/
15+
elementType: Type;
16+
17+
/**
18+
* The type name identifier.
19+
*/
20+
readonly type: string = 'array';
21+
22+
/**
23+
* Create a new TupleType instance.
24+
*
25+
* @param elementType The type of the array's elements.
26+
*/
27+
constructor(elementType: Type) {
28+
super();
29+
this.elementType = elementType;
30+
}
31+
32+
/**
33+
* Clone this type.
34+
*
35+
* @return A clone of this type.
36+
*/
37+
clone(): Type {
38+
return new ArrayType(this.elementType);
39+
}
40+
41+
/**
42+
* Test whether this type equals the given type.
43+
*
44+
* @param type The type that should be checked for equality.
45+
* @returns TRUE if the given type equals this type, FALSE otherwise.
46+
*/
47+
equals(type: Type): boolean {
48+
if (!(type instanceof ArrayType)) {
49+
return false;
50+
}
51+
return type.elementType.equals(this.elementType);
52+
}
53+
54+
/**
55+
* Return a raw object representation of this type.
56+
*/
57+
toObject(): any {
58+
const result: any = super.toObject();
59+
result.elementType = this.elementType.toObject();
60+
61+
return result;
62+
}
63+
64+
/**
65+
* Return a string representation of this type.
66+
*/
67+
toString() {
68+
const elementTypeStr = this.elementType.toString();
69+
if (this.elementType instanceof UnionType || this.elementType instanceof IntersectionType) {
70+
return '(' + elementTypeStr + ')[]';
71+
} else {
72+
return elementTypeStr + '[]';
73+
}
74+
}
75+
}

src/lib/models/types/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export {Type} from './abstract';
2+
export {ArrayType} from './array';
23
export {IntrinsicType} from './intrinsic';
34
export {IntersectionType} from './intersection';
45
export {ReferenceType} from './reference';

src/lib/models/types/intersection.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@ export class IntersectionType extends Type {
3434
* @return A clone of this type.
3535
*/
3636
clone(): Type {
37-
const clone = new IntersectionType(this.types);
38-
clone.isArray = this.isArray;
39-
return clone;
37+
return new IntersectionType(this.types);
4038
}
4139

4240
/**
@@ -49,9 +47,6 @@ export class IntersectionType extends Type {
4947
if (!(type instanceof IntersectionType)) {
5048
return false;
5149
}
52-
if (type.isArray !== this.isArray) {
53-
return false;
54-
}
5550
return Type.isTypeListSimiliar(type.types, this.types);
5651
}
5752

src/lib/models/types/intrinsic.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@ export class IntrinsicType extends Type {
3434
* @return A clone of this type.
3535
*/
3636
clone(): Type {
37-
const clone = new IntrinsicType(this.name);
38-
clone.isArray = this.isArray;
39-
return clone;
37+
return new IntrinsicType(this.name);
4038
}
4139

4240
/**
@@ -47,7 +45,6 @@ export class IntrinsicType extends Type {
4745
*/
4846
equals(type: IntrinsicType): boolean {
4947
return type instanceof IntrinsicType &&
50-
type.isArray === this.isArray &&
5148
type.name === this.name;
5249
}
5350

@@ -64,6 +61,6 @@ export class IntrinsicType extends Type {
6461
* Return a string representation of this type.
6562
*/
6663
toString() {
67-
return this.name + (this.isArray ? '[]' : '');
64+
return this.name;
6865
}
6966
}

src/lib/models/types/reference.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ export class ReferenceType extends Type {
7373
*/
7474
clone(): Type {
7575
const clone = new ReferenceType(this.name, this.symbolID, this.reflection);
76-
clone.isArray = this.isArray;
7776
clone.typeArguments = this.typeArguments;
7877
return clone;
7978
}
@@ -86,7 +85,6 @@ export class ReferenceType extends Type {
8685
*/
8786
equals(type: ReferenceType): boolean {
8887
return type instanceof ReferenceType &&
89-
type.isArray === this.isArray &&
9088
(type.symbolID === this.symbolID || type.reflection === this.reflection);
9189
}
9290

@@ -114,14 +112,13 @@ export class ReferenceType extends Type {
114112
*/
115113
toString() {
116114
const name = this.reflection ? this.reflection.name : this.name;
117-
const arraySuffix = this.isArray ? '[]' : '';
118115
let typeArgs = '';
119116
if (this.typeArguments) {
120117
typeArgs += '<';
121118
typeArgs += this.typeArguments.map(arg => arg.toString()).join(', ');
122119
typeArgs += '>';
123120
}
124121

125-
return name + typeArgs + arraySuffix;
122+
return name + typeArgs;
126123
}
127124
}

src/lib/models/types/reflection.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,7 @@ export class ReflectionType extends Type {
3535
* @return A clone of this type.
3636
*/
3737
clone(): Type {
38-
const clone = new ReflectionType(this.declaration);
39-
clone.isArray = this.isArray;
40-
return clone;
38+
return new ReflectionType(this.declaration);
4139
}
4240

4341
/**

0 commit comments

Comments
 (0)