Skip to content

Commit 5ec6fdc

Browse files
committed
add utils to typescript rpdk
1 parent 3f85ca0 commit 5ec6fdc

File tree

2 files changed

+155
-0
lines changed

2 files changed

+155
-0
lines changed

src/utils.ts

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import {
2+
LogGroupName,
3+
LogicalResourceId,
4+
NextToken,
5+
} from 'aws-sdk/clients/cloudformation';
6+
import { allArgsConstructor } from 'tombok';
7+
import {
8+
Action,
9+
BaseResourceHandlerRequest,
10+
BaseResourceModel,
11+
Credentials,
12+
RequestContext,
13+
} from './interface';
14+
15+
16+
export type Constructor<T = {}> = new (...args: any[]) => T;
17+
18+
/**
19+
* Convert minutes to a valid scheduling expression to be used in the AWS Events
20+
*
21+
* @param {number} minutes Minutes to be converted
22+
*/
23+
export function minToCron(minutes: number): string {
24+
const date = new Date(Date.now());
25+
// add another minute, as per java implementation
26+
date.setMinutes(date.getMinutes() + minutes + 1);
27+
return `cron(${date.getMinutes()} ${date.getHours()} ${date.getDate()} ${date.getMonth()} ? ${date.getFullYear()})`;
28+
}
29+
30+
@allArgsConstructor
31+
export class TestEvent {
32+
credentials: Credentials;
33+
action: Action;
34+
request: Map<string, any>;
35+
callbackContext: Map<string, any>;
36+
region?: string;
37+
38+
constructor(...args: any[]) {}
39+
}
40+
41+
@allArgsConstructor
42+
export class RequestData<T = Map<string, any>> {
43+
callerCredentials?: Credentials;
44+
platformCredentials?: Credentials;
45+
providerCredentials?: Credentials;
46+
providerLogGroupName: LogGroupName;
47+
logicalResourceId: LogicalResourceId;
48+
resourceProperties: T;
49+
previousResourceProperties?: T;
50+
systemTags: { [index: string]: string };
51+
stackTags?: { [index: string]: string };
52+
previousStackTags?: { [index: string]: string };
53+
54+
constructor(...args: any[]) {}
55+
56+
public static deserialize(jsonData: Map<string, any>): RequestData {
57+
if (!jsonData) {
58+
jsonData = new Map<string, any>();
59+
}
60+
const reqData: RequestData = new RequestData(jsonData);
61+
jsonData.forEach((value: any, key: string) => {
62+
if (key.endsWith('Credentials')) {
63+
type credentialsType = 'callerCredentials' | 'platformCredentials' | 'providerCredentials';
64+
const prop: credentialsType = key as credentialsType;
65+
const creds = value;
66+
if (creds) {
67+
reqData[prop] = creds as Credentials;
68+
}
69+
}
70+
});
71+
return reqData;
72+
}
73+
74+
serialize(): Map<string, any> {
75+
return null;
76+
}
77+
}
78+
79+
@allArgsConstructor
80+
export class HandlerRequest<ResourceT = Map<string, any>, CallbackT = Map<string, any>> {
81+
action: Action;
82+
awsAccountId: string;
83+
bearerToken: string;
84+
nextToken?: NextToken;
85+
region: string;
86+
responseEndpoint: string;
87+
resourceType: string;
88+
resourceTypeVersion: string;
89+
requestData: RequestData<ResourceT>;
90+
stackId: string;
91+
requestContext: RequestContext<CallbackT>;
92+
93+
constructor(...args: any[]) {}
94+
95+
public static deserialize(jsonData: Map<string, any>): HandlerRequest {
96+
if (!jsonData) {
97+
jsonData = new Map<string, any>();
98+
}
99+
const event: HandlerRequest = new HandlerRequest(jsonData);
100+
const requestData = new Map<string, any>(Object.entries(jsonData.get('requestData') || {}));
101+
event.requestData = RequestData.deserialize(requestData);
102+
return event;
103+
};
104+
105+
public fromJSON(jsonData: Map<string, any>): HandlerRequest {
106+
return null;
107+
};
108+
109+
public toJSON(): any {
110+
return null;
111+
};
112+
}
113+
114+
@allArgsConstructor
115+
export class UnmodeledRequest extends BaseResourceHandlerRequest<BaseResourceModel> {
116+
117+
constructor(...args: any[]) {super()}
118+
119+
public static fromUnmodeled(obj: Object): UnmodeledRequest {
120+
const mapped = new Map(Object.entries(obj));
121+
const request: UnmodeledRequest = new UnmodeledRequest(mapped);
122+
return request;
123+
}
124+
125+
public toModeled<T extends BaseResourceModel = BaseResourceModel>(modelCls: Constructor<T> & { deserialize?: Function }): BaseResourceHandlerRequest<T> {
126+
return new BaseResourceHandlerRequest<T>(new Map(Object.entries({
127+
clientRequestToken: this.clientRequestToken,
128+
desiredResourceState: modelCls.deserialize(this.desiredResourceState || {}),
129+
previousResourceState: modelCls.deserialize(this.previousResourceState || {}),
130+
logicalResourceIdentifier: this.logicalResourceIdentifier,
131+
nextToken: this.nextToken,
132+
})));
133+
}
134+
}
135+
136+
export interface LambdaContext {
137+
invokedFunctionArn: string;
138+
getRemainingTimeInMillis(): number;
139+
}

tests/lib/utils.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import {
2+
minToCron,
3+
} from '../../src/utils';
4+
5+
6+
describe('when getting utils', () => {
7+
8+
test('minutes to cron', () => {
9+
const spy: jest.SpyInstance = jest.spyOn(global.Date, 'now').mockImplementationOnce(() => {
10+
return new Date(2020, 1, 1, 1, 1).valueOf();
11+
});
12+
const cron = minToCron(1);
13+
expect(spy).toHaveBeenCalledTimes(1);
14+
expect(cron).toBe('cron(3 1 1 1 ? 2020)');
15+
});
16+
});

0 commit comments

Comments
 (0)