Skip to content

Add a "normalize" function to the config definition and remove that responsibility from the "apply" function #94

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
19 changes: 17 additions & 2 deletions packages/build-types/src/customization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,27 @@ export interface ConfigurationPropertyDefinitionRuntimeAttributes {
*/
default?: DefaultValue|DefaultProvider;

/**
* A string containing a valid TypeScript expression that evaluates to a
* function that will normalize user input to a subtype of the allowed input
* type union.
*
* This function will be called with the supplied input and the full
* configuration object at its current point in processing. The function
* must return the normalized input.
*
* This function will not be called if the user did not supply a value.
*
* If an imported type is used, it must be referred to as a property of the
* imported package.
*/
normalize?: string;

/**
* A string containing a valid TypeScript expression that evaluates to a
* function that, when called, will react to the value supplied for this
* configuration property. Examples of actions taken during `apply` handlers
* include normalizing a type, altering the configuration object, and
* altering the client middleware stack.
* include altering the configuration object or the client middleware stack.
*
* This function will be called with the full configuration object at its
* current point in processing.
Expand Down
24 changes: 23 additions & 1 deletion packages/config-resolver/src/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,29 @@ describe('resolveConfiguration', () => {
expect(defaultProvider.mock.calls.length).toBe(0);
});

it('should always call a normalizer function if one is provided', () => {
const normalize = jest.fn(() => 'normalized!');
const middlewareStack = {} as any;
const definition: ConfigurationDefinition<
{region: string},
{region: string}
> = {
region: {
required: true,
normalize,
}
};

expect(resolveConfiguration(
{region: 'eu-central-1'},
definition,
middlewareStack
)).toEqual({region: 'normalized!'});

expect(normalize.mock.calls.length).toBe(1);
expect(normalize.mock.calls[0][0]).toBe('eu-central-1');
});

it('should always call an apply function if one is provided', () => {
const apply = jest.fn(() => {});
const middlewareStack = {} as any;
Expand All @@ -112,7 +135,6 @@ describe('resolveConfiguration', () => {

expect(apply.mock.calls.length).toBe(1);
expect(apply.mock.calls[0]).toEqual([
'eu-central-1',
{region: 'eu-central-1'},
middlewareStack
]);
Expand Down
16 changes: 9 additions & 7 deletions packages/config-resolver/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
ConfigApplicator,
ConfigurationDefinition,
MiddlewareStack
MiddlewareStack,
} from '@aws/types';

export type IndexedObject = {[key: string]: any};
Expand All @@ -17,6 +18,7 @@ export function resolveConfiguration<
middlewareStack: MiddlewareStack<Input, Output, Stream>
): R {
const out: Partial<R> = {};
const applicators: Array<ConfigApplicator<R>> = [];

// Iterate over the definitions own keys, using getOwnPropertyNames to
// guarantee insertion order is preserved.
Expand All @@ -26,7 +28,8 @@ export function resolveConfiguration<
required,
defaultValue,
defaultProvider,
apply
normalize,
apply,
} = configurationDefinition[property];
let input = providedConfiguration[property];

Expand All @@ -40,18 +43,17 @@ export function resolveConfiguration<
`No input provided for required configuration parameter: ${property}`
);
}
} else if (normalize) {
input = normalize(input, out);
}

out[property] = input;

if (apply) {
apply(
input,
out as R,
middlewareStack
);
applicators.push(apply);
}
}

applicators.forEach(func => func(out as R, middlewareStack));
return out as R;
}
20 changes: 20 additions & 0 deletions packages/sdk-codecommit-browser/CodeCommitClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ export class CodeCommitClient {
configurationProperties,
this.middlewareStack
);
this.middlewareStack.add(
__aws_middleware_serializer.serializerMiddleware(this.config.serializer),
{
step: 'serialize',
priority: 90,
tags: {SERIALIZER: true}
}
);
this.middlewareStack.add(
__aws_middleware_content_length.contentLengthMiddleware(
this.config.bodyLengthChecker
Expand All @@ -61,6 +69,18 @@ export class CodeCommitClient {
}
);
}
this.middlewareStack.add(
__aws_signing_middleware.signingMiddleware<
InputTypesUnion,
OutputTypesUnion,
ReadableStream
>(this.config.signer),
{
step: 'finalize',
priority: 0,
tags: {SIGNATURE: true}
}
);
}

destroy(): void {
Expand Down
116 changes: 32 additions & 84 deletions packages/sdk-codecommit-browser/CodeCommitConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,39 +195,33 @@ export const configurationProperties: __aws_types.ConfigurationDefinition<
CodeCommitResolvableConfiguration,
CodeCommitResolvedConfiguration
> = {
profile: {
required: false
},
profile: {},
maxRedirects: {
required: false,
defaultValue: 10
},
maxRetries: {
required: false,
defaultValue: 3
},
region: {
required: true,
apply: (
region: string|__aws_types.Provider<string>|undefined,
configuration: {region?: string|__aws_types.Provider<string>}
normalize: (
value: string|__aws_types.Provider<string>|undefined
) => {
if (typeof region === 'string') {
const promisified = Promise.resolve(region);
configuration.region = () => promisified;
if (typeof value === 'string') {
const promisified = Promise.resolve(value);
return () => promisified;
}

return value!;
}
},
sslEnabled: {
required: false,
defaultValue: true
},
urlParser: {
required: false,
defaultValue: __aws_url_parser_browser.parseUrl
},
endpointProvider: {
required: false,
defaultValue: (
sslEnabled: boolean,
region: string,
Expand All @@ -238,7 +232,6 @@ export const configurationProperties: __aws_types.ConfigurationDefinition<
})
},
endpoint: {
required: false,
defaultProvider: (
configuration: {
sslEnabled: boolean,
Expand All @@ -253,46 +246,43 @@ export const configurationProperties: __aws_types.ConfigurationDefinition<
));
return () => promisified;
},
apply: (
normalize: (
value: string|__aws_types.HttpEndpoint|__aws_types.Provider<__aws_types.HttpEndpoint>|undefined,
configuration: {
endpointProvider: any,
endpoint?: string|__aws_types.HttpEndpoint|__aws_types.Provider<__aws_types.HttpEndpoint>,
sslEnabled: boolean,
urlParser: __aws_types.UrlParser,
urlParser?: __aws_types.UrlParser,
}
): void => {
): __aws_types.Provider<__aws_types.HttpEndpoint> => {
if (typeof value === 'string') {
const promisified = Promise.resolve(configuration.urlParser(value));
configuration.endpoint = () => promisified;
const promisified = Promise.resolve(configuration.urlParser!(value));
return () => promisified;
} else if (typeof value === 'object') {
const promisified = Promise.resolve(value);
configuration.endpoint = () => promisified;
return () => promisified;
}

// Users are not required to supply an endpoint, so `value`
// could be undefined. This function, however, will only be
// invoked if `value` is defined, so the return will never
// be undefined.
return value!;
}
},
base64Decoder: {
required: false,
defaultValue: __aws_util_base64_browser.fromBase64
},
base64Encoder: {
required: false,
defaultValue: __aws_util_base64_browser.toBase64
},
utf8Decoder: {
required: false,
defaultValue: __aws_util_utf8_browser.fromUtf8
},
utf8Encoder: {
required: false,
defaultValue: __aws_util_utf8_browser.toUtf8
},
streamCollector: {
required: false,
defaultValue: __aws_stream_collector_browser.streamCollector
},
serializer: {
required: false,
defaultProvider: (
configuration: {
base64Encoder: __aws_types.Encoder,
Expand All @@ -309,24 +299,9 @@ export const configurationProperties: __aws_types.ConfigurationDefinition<
)
));
return () => promisified;
},
apply: (
serializerProvider: __aws_types.Provider<__aws_types.RequestSerializer<ReadableStream>>,
configuration: object,
middlewareStack: __aws_types.MiddlewareStack<any, any, any>
): void => {
middlewareStack.add(
__aws_middleware_serializer.serializerMiddleware(serializerProvider),
{
step: 'serialize',
tags: {SERIALIZER: true},
priority: 90
}
);
}
},
parser: {
required: false,
defaultProvider: (
configuration: {
base64Decoder: __aws_types.Decoder,
Expand All @@ -343,15 +318,12 @@ export const configurationProperties: __aws_types.ConfigurationDefinition<
)
},
_user_injected_http_handler: {
required: false,
defaultProvider: (configuration: {httpHandler?: any}) => !configuration.httpHandler
},
httpHandler: {
required: false,
defaultProvider: () => new __aws_fetch_http_handler.FetchHttpHandler()
},
handler: {
required: false,
defaultProvider: (
configuration: {
httpHandler: __aws_types.HttpHandler<ReadableStream>,
Expand All @@ -364,30 +336,28 @@ export const configurationProperties: __aws_types.ConfigurationDefinition<
},
credentials: {
required: true,
apply: (
credentials: __aws_types.Credentials|__aws_types.Provider<__aws_types.Credentials>|undefined,
configuration: {credentials?: __aws_types.Credentials|__aws_types.Provider<__aws_types.Credentials>}
normalize: (
value: __aws_types.Credentials|__aws_types.Provider<__aws_types.Credentials>
) => {
if (typeof credentials === 'object') {
const promisified = Promise.resolve(credentials);
configuration.credentials = () => promisified;
if (typeof value === 'object') {
const promisified = Promise.resolve(value);
return () => promisified;
}

return value;
}
},
sha256: {
required: false,
defaultValue: __aws_crypto_sha256_browser.Sha256
},
signingName: {
required: false,
defaultValue: 'codecommit'
},
signer: {
required: false,
defaultProvider: (
configuration: {
credentials: __aws_types.Credentials|__aws_types.Provider<__aws_types.Credentials>
region: string|__aws_types.Provider<string>,
credentials: __aws_types.Provider<__aws_types.Credentials>,
region: __aws_types.Provider<string>,
sha256: __aws_types.HashConstructor,
signingName: string,
}
Expand All @@ -398,33 +368,11 @@ export const configurationProperties: __aws_types.ConfigurationDefinition<
sha256: configuration.sha256,
unsignedPayload: false,
uriEscapePath: false,
}),
apply: (
signer: __aws_types.RequestSigner|undefined,
configuration: object,
middlewareStack: __aws_types.MiddlewareStack<any, any, any>
): void => {
if (!signer) {
throw new Error('No signer was defined');
}

middlewareStack.add(
__aws_signing_middleware.signingMiddleware(signer),
{
step: 'finalize',
tags: {SIGNATURE: true}
}
);
}
})
},
bodyLengthChecker: {
required: false,
defaultValue: __aws_util_body_length_browser.calculateBodyLength
},
retryDecider: {
required: false
},
delayDecider: {
required: false
},
retryDecider: {},
delayDecider: {},
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {ResponseMetadata as __ResponseMetadata__, ServiceException as __ServiceException__} from '@aws/types';
import {ServiceException as __ServiceException__} from '@aws/types';

/**
* <p>The specified Amazon Resource Name (ARN) does not exist in the AWS account.</p>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {ResponseMetadata as __ResponseMetadata__, ServiceException as __ServiceException__} from '@aws/types';
import {ServiceException as __ServiceException__} from '@aws/types';

/**
* <p>The specified Amazon Resource Name (ARN) does not exist in the AWS account.</p>
Expand Down
Loading