Skip to content

Commit 823deb9

Browse files
committed
Support indexed access type param ranges
1 parent bc15b19 commit 823deb9

9 files changed

Lines changed: 183 additions & 0 deletions

lib/parse/ParameterLoader.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,12 @@ export class ParameterLoader {
439439
qualifiedPath: this.getQualifiedPath(typeNode.exprName.left),
440440
origin: classLoaded,
441441
};
442+
case AST_NODE_TYPES.TSIndexedAccessType:
443+
return {
444+
type: 'indexed',
445+
object: this.getRangeFromTypeNode(classLoaded, typeNode.objectType, errorIdentifier),
446+
index: this.getRangeFromTypeNode(classLoaded, typeNode.indexType, errorIdentifier),
447+
};
442448
}
443449
this.throwOrWarn(new Error(`Could not understand parameter type ${typeNode.type} of ${errorIdentifier
444450
} in ${classLoaded.localName} at ${classLoaded.fileName}`));
@@ -531,6 +537,7 @@ export class ParameterLoader {
531537
case 'interface':
532538
case 'genericTypeReference':
533539
case 'typeof':
540+
case 'indexed':
534541
// Replace these types
535542
return override;
536543
case 'undefined':
@@ -803,6 +810,10 @@ export type ParameterRangeUnresolved = {
803810
* The place from which the interface was referenced.
804811
*/
805812
origin: ClassReferenceLoaded;
813+
} | {
814+
type: 'indexed';
815+
object: ParameterRangeUnresolved;
816+
index: ParameterRangeUnresolved;
806817
};
807818

808819
export type ParameterRangeResolved = {
@@ -853,6 +864,10 @@ export type ParameterRangeResolved = {
853864
} | {
854865
type: 'typeof';
855866
value: ParameterRangeResolved;
867+
} | {
868+
type: 'indexed';
869+
object: ParameterRangeResolved;
870+
index: ParameterRangeResolved;
856871
};
857872

858873
/**

lib/parse/ParameterResolver.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,14 @@ export class ParameterResolver {
313313
};
314314
case 'typeof':
315315
throw new Error(`Detected typeof of unsupported value ${range.value} in ${owningClass.fileName}`);
316+
case 'indexed':
317+
return {
318+
type: 'indexed',
319+
object: await this
320+
.resolveRange(range.object, owningClass, genericTypeRemappings, getNestedFields, handlingInterfaces),
321+
index: await this
322+
.resolveRange(range.index, owningClass, genericTypeRemappings, getNestedFields, handlingInterfaces),
323+
};
316324
}
317325
}
318326

@@ -343,6 +351,8 @@ export class ParameterResolver {
343351
return `${range.type}:[${this.hashParameterRangeUnresolved(range.value)}]`;
344352
case 'hash':
345353
return `hash:${JSON.stringify(range.value)}`;
354+
case 'indexed':
355+
return `${range.type}:[${this.hashParameterRangeUnresolved(range.object)};${this.hashParameterRangeUnresolved(range.index)}]`;
346356
}
347357
}
348358

lib/resolution/ExternalModulesLoader.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ export class ExternalModulesLoader {
120120
case 'typeof':
121121
this.indexParameterRangeInExternalPackage(parameterRange.value, externalPackages);
122122
break;
123+
case 'indexed':
124+
this.indexParameterRangeInExternalPackage(parameterRange.object, externalPackages);
125+
this.indexParameterRangeInExternalPackage(parameterRange.index, externalPackages);
126+
break;
123127
}
124128
}
125129

lib/serialize/ComponentConstructor.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,14 @@ export class ComponentConstructor {
788788
'@type': 'ParameterRangeGenericTypeReference',
789789
parameterRangeGenericType: this.genericNameToId(context, range.origin, range.value),
790790
};
791+
case 'indexed':
792+
return {
793+
'@type': 'ParameterRangeIndexed',
794+
parameterRangeIndexedObject: await this
795+
.constructParameterRange(range.object, context, externalContextsCallback, fieldId),
796+
parameterRangeIndexedIndex: await this
797+
.constructParameterRange(range.index, context, externalContextsCallback, fieldId),
798+
};
791799
}
792800
}
793801

lib/serialize/ComponentDefinitions.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ export type ParameterDefinitionRange = string | { '@id': string; parameters: Par
7373
'@type': 'ParameterRangeGenericComponent';
7474
component: string;
7575
genericTypeInstances: ParameterDefinitionRange[];
76+
} | {
77+
'@type': 'ParameterRangeIndexed';
78+
parameterRangeIndexedObject: ParameterDefinitionRange;
79+
parameterRangeIndexedIndex: ParameterDefinitionRange;
7680
};
7781

7882
export type ConstructorArgumentDefinition = string | { '@id': string } | {

test/parse/ParameterLoader.test.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,6 +1999,30 @@ export interface A{
19991999
origin: expect.anything(),
20002000
});
20012001
});
2002+
2003+
it('should get the range of a static indexed access field type', async() => {
2004+
expect(await getFieldRange('fieldA: MyClass["field"]', {}))
2005+
.toEqual({
2006+
type: 'indexed',
2007+
object: { type: 'interface', value: 'MyClass', origin: expect.anything() },
2008+
index: { type: 'literal', value: 'field' },
2009+
});
2010+
});
2011+
2012+
it('should get the range of a dynamic indexed access field type', async() => {
2013+
expect(await getFieldRange('fieldA: MyClass["fieldA" | "fieldB"]', {}))
2014+
.toEqual({
2015+
type: 'indexed',
2016+
object: { type: 'interface', value: 'MyClass', origin: expect.anything() },
2017+
index: {
2018+
type: 'union',
2019+
elements: [
2020+
{ type: 'literal', value: 'fieldA' },
2021+
{ type: 'literal', value: 'fieldB' },
2022+
],
2023+
},
2024+
});
2025+
});
20022026
});
20032027

20042028
describe('overrideRawRange', () => {
@@ -2099,6 +2123,23 @@ export interface A{
20992123
});
21002124
});
21012125

2126+
it('should override an indexed range', () => {
2127+
expect(loader.overrideRawRange(
2128+
{
2129+
type: 'indexed',
2130+
object: <any> {},
2131+
index: <any> {},
2132+
},
2133+
{
2134+
type: 'raw',
2135+
value: 'boolean',
2136+
},
2137+
)).toEqual({
2138+
type: 'raw',
2139+
value: 'boolean',
2140+
});
2141+
});
2142+
21022143
it('should override a hash range', () => {
21032144
expect(loader.overrideRawRange(
21042145
{

test/parse/ParameterResolver.test.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,15 @@ describe('ParameterResolver', () => {
646646
}))
647647
.toEqual('hash:{"a":"b"}');
648648
});
649+
650+
it('should hash index', () => {
651+
expect(loader.hashParameterRangeUnresolved({
652+
type: 'indexed',
653+
object: { type: 'raw', value: 'boolean' },
654+
index: { type: 'raw', value: 'string' },
655+
}))
656+
.toEqual('indexed:[raw:boolean;raw:string]');
657+
});
649658
});
650659

651660
describe('resolveRange', () => {
@@ -1388,6 +1397,49 @@ class MyInnerClass<AInner, BInner> {
13881397
],
13891398
});
13901399
});
1400+
1401+
it('should handle an indexed range over a generic', async() => {
1402+
expect(await loader.resolveRange({
1403+
type: 'indexed',
1404+
object: {
1405+
type: 'genericTypeReference',
1406+
value: 'AOuter',
1407+
},
1408+
index: { type: 'literal', value: 'keya' },
1409+
}, classReference, {}, true, new Set())).toMatchObject({
1410+
type: 'indexed',
1411+
object: {
1412+
type: 'genericTypeReference',
1413+
value: 'AOuter',
1414+
},
1415+
index: { type: 'literal', value: 'keya' },
1416+
});
1417+
});
1418+
1419+
it('should handle an indexed range over a class', async() => {
1420+
resolutionContext.contentsOverrides = {
1421+
'A.d.ts': `export * from './MyClass'`,
1422+
'MyClass.d.ts': `export class MyClass{}`,
1423+
};
1424+
1425+
expect(await loader.resolveRange({
1426+
type: 'indexed',
1427+
object: {
1428+
type: 'interface',
1429+
value: 'MyClass',
1430+
genericTypeParameterInstantiations: [],
1431+
origin: classReference,
1432+
},
1433+
index: { type: 'literal', value: 'keya' },
1434+
}, classReference, {}, true, new Set())).toMatchObject({
1435+
type: 'indexed',
1436+
object: {
1437+
type: 'class',
1438+
value: { localName: 'MyClass', fileName: 'MyClass' },
1439+
},
1440+
index: { type: 'literal', value: 'keya' },
1441+
});
1442+
});
13911443
});
13921444

13931445
describe('resolveRangeInterface', () => {

test/resolution/ExternalModulesLoader.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,38 @@ describe('ExternalModulesLoader', () => {
575575
expect(loader.findExternalPackages({}, constructors))
576576
.toEqual([ 'package1' ]);
577577
});
578+
579+
it('should handle indexed constructor parameters', () => {
580+
const constructors: ClassIndex<ConstructorData<ParameterRangeResolved>> = <any> {
581+
Class1: {
582+
parameters: [
583+
{
584+
range: {
585+
type: 'indexed',
586+
object: {
587+
type: 'class',
588+
value: {
589+
type: 'class',
590+
localName: 'Class1',
591+
packageName: 'package1',
592+
},
593+
},
594+
index: {
595+
type: 'class',
596+
value: {
597+
type: 'class',
598+
localName: 'Class2',
599+
packageName: 'package2',
600+
},
601+
},
602+
},
603+
},
604+
],
605+
},
606+
};
607+
expect(loader.findExternalPackages({}, constructors))
608+
.toEqual([ 'package1', 'package2' ]);
609+
});
578610
});
579611

580612
describe('buildModuleStateSelective', () => {

test/serialize/ComponentConstructor.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2648,6 +2648,23 @@ describe('ComponentConstructor', () => {
26482648
parameterRangeValue: 'xsd:boolean',
26492649
});
26502650
});
2651+
2652+
it('should construct an indexed parameter range', async() => {
2653+
expect(await ctor.constructParameterRange(
2654+
{
2655+
type: 'indexed',
2656+
object: { type: 'raw', value: 'boolean' },
2657+
index: { type: 'raw', value: 'boolean' },
2658+
},
2659+
context,
2660+
externalContextsCallback,
2661+
'mp:a/b/file-param#MyClass_field',
2662+
)).toEqual({
2663+
'@type': 'ParameterRangeIndexed',
2664+
parameterRangeIndexedObject: 'xsd:boolean',
2665+
parameterRangeIndexedIndex: 'xsd:boolean',
2666+
});
2667+
});
26512668
});
26522669

26532670
describe('populateOptionalParameterFields', () => {

0 commit comments

Comments
 (0)