Skip to content

Commit

Permalink
Merge pull request #179 from clebert/partial-config-parsing
Browse files Browse the repository at this point in the history
Do not parse full config for commands that don't need it
  • Loading branch information
clebert committed Oct 16, 2023
2 parents d506d76 + bddbb00 commit c85843b
Show file tree
Hide file tree
Showing 26 changed files with 172 additions and 137 deletions.
2 changes: 1 addition & 1 deletion src/cdk/add-lambda-resource.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {LambdaRoute, StackConfig} from '../read-stack-config.js';
import type {LambdaRoute, StackConfig} from '../parse-stack-config.js';
import type {Stack, aws_lambda} from 'aws-cdk-lib';

import {addCorsPreflight} from './add-cors-preflight.js';
Expand Down
2 changes: 1 addition & 1 deletion src/cdk/add-s3-resource.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {S3Route} from '../read-stack-config.js';
import type {S3Route} from '../parse-stack-config.js';
import type {aws_iam, aws_s3} from 'aws-cdk-lib';

import {addCorsPreflight} from './add-cors-preflight.js';
Expand Down
2 changes: 1 addition & 1 deletion src/cdk/create-lambda-function.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {LambdaRoute, StackConfig} from '../read-stack-config.js';
import type {LambdaRoute, StackConfig} from '../parse-stack-config.js';
import type {Stack} from 'aws-cdk-lib';

import {getDomainName} from '../utils/get-domain-name.js';
Expand Down
2 changes: 1 addition & 1 deletion src/cdk/create-request-authorizer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {StackConfig} from '../read-stack-config.js';
import type {StackConfig} from '../parse-stack-config.js';
import type {Stack} from 'aws-cdk-lib';

import {getDomainName} from '../utils/get-domain-name.js';
Expand Down
2 changes: 1 addition & 1 deletion src/cdk/create-rest-api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {StackConfig} from '../read-stack-config.js';
import type {StackConfig} from '../parse-stack-config.js';
import type {Stack} from 'aws-cdk-lib';

import {getDomainName} from '../utils/get-domain-name.js';
Expand Down
2 changes: 1 addition & 1 deletion src/cdk/create-stack.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {StackConfig} from '../read-stack-config.js';
import type {StackConfig} from '../parse-stack-config.js';

import {getDomainName} from '../utils/get-domain-name.js';
import {getStackName} from '../utils/get-stack-name.js';
Expand Down
6 changes: 5 additions & 1 deletion src/delete-command.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type {CommandModule} from 'yargs';

import {parseDomainNameParts} from './parse-domain-name-parts.js';
import {readStackConfig} from './read-stack-config.js';
import {deleteStack} from './sdk/delete-stack.js';
import {getDomainName} from './utils/get-domain-name.js';
Expand Down Expand Up @@ -34,7 +35,10 @@ export const deleteCommand: CommandModule<

handler: async (args): Promise<void> => {
const stackName =
args.stackName || getStackName(getDomainName(await readStackConfig()));
args.stackName ||
getStackName(
getDomainName(parseDomainNameParts(await readStackConfig())),
);

print.warning(`Stack: ${stackName}`);

Expand Down
2 changes: 1 addition & 1 deletion src/dev/create-lambda-request-handler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {LambdaRoute} from '../read-stack-config.js';
import type {LambdaRoute} from '../parse-stack-config.js';
import type {APIGatewayProxyResult} from 'aws-lambda';
import type express from 'express';

Expand Down
2 changes: 1 addition & 1 deletion src/dev/get-router-matcher.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {LambdaRoute} from '../read-stack-config.js';
import type {LambdaRoute} from '../parse-stack-config.js';
import type {Express, IRouterMatcher} from 'express';

export function getRouterMatcher(
Expand Down
2 changes: 1 addition & 1 deletion src/dev/register-s3-route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {S3Route} from '../read-stack-config.js';
import type {S3Route} from '../parse-stack-config.js';
import type {Express} from 'express';

import express from 'express';
Expand Down
2 changes: 1 addition & 1 deletion src/dev/sort-routes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {Route} from '../read-stack-config.js';
import type {Route} from '../parse-stack-config.js';

export function sortRoutes<TRoute extends Pick<Route, 'publicPath'>>(
routes: readonly TRoute[],
Expand Down
6 changes: 5 additions & 1 deletion src/flush-cache-command.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type {CommandModule} from 'yargs';

import {parseDomainNameParts} from './parse-domain-name-parts.js';
import {readStackConfig} from './read-stack-config.js';
import {findStack} from './sdk/find-stack.js';
import {flushRestApiCache} from './sdk/flush-rest-api-cache.js';
Expand Down Expand Up @@ -36,7 +37,10 @@ export const flushCacheCommand: CommandModule<

handler: async (args): Promise<void> => {
const stackName =
args.stackName || getStackName(getDomainName(await readStackConfig()));
args.stackName ||
getStackName(
getDomainName(parseDomainNameParts(await readStackConfig())),
);

print.warning(`Stack: ${stackName}`);

Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type {
Route,
S3Route,
StackConfig,
} from './read-stack-config.js';
} from './parse-stack-config.js';

import {cleanupCommand} from './cleanup-command.js';
import {deleteCommand} from './delete-command.js';
Expand Down
4 changes: 3 additions & 1 deletion src/list-command.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type {CommandModule} from 'yargs';

import {parseDomainNameParts} from './parse-domain-name-parts.js';
import {readStackConfig} from './read-stack-config.js';
import {findStacks} from './sdk/find-stacks.js';
import {getFormattedAgeInDays} from './utils/get-formatted-age-in-days.js';
Expand Down Expand Up @@ -53,7 +54,8 @@ export const listCommand: CommandModule<

const hostedZoneName = all
? undefined
: args.hostedZoneName || (await readStackConfig()).hostedZoneName;
: args.hostedZoneName ||
parseDomainNameParts(await readStackConfig()).hostedZoneName;

if (!hostedZoneName && !all) {
throw new Error(
Expand Down
12 changes: 12 additions & 0 deletions src/parse-domain-name-parts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {z} from 'zod';

export type DomainNameParts = z.TypeOf<typeof DomainNamePartsSchema>;

export const DomainNamePartsSchema = z.object({
hostedZoneName: z.string().optional(),
aliasRecordName: z.string().optional(),
});

export function parseDomainNameParts(config: unknown): DomainNameParts {
return DomainNamePartsSchema.parse(config);
}
111 changes: 111 additions & 0 deletions src/parse-stack-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import type {Stack, aws_apigateway, aws_lambda} from 'aws-cdk-lib';
import type {Express} from 'express';

import {DomainNamePartsSchema} from './parse-domain-name-parts.js';
import {validateRoutes} from './utils/validate-routes.js';
import {z} from 'zod';

export type StackConfig = Omit<
z.TypeOf<typeof StackConfigSchema>,
'routes' | 'onSynthesize' | 'onStart'
> & {
readonly routes: Route[];

readonly onSynthesize?: (constructs: {
readonly stack: Stack;
readonly restApi: aws_apigateway.RestApiBase;
}) => void;

readonly onStart?: (app: Express) => void;
};

export type Route = LambdaRoute | S3Route;

export type LambdaRoute = Omit<
z.TypeOf<typeof LambdaRouteSchema>,
'onSynthesize'
> & {
readonly onSynthesize?: (constructs: {
readonly stack: Stack;
readonly restApi: aws_apigateway.RestApiBase;
readonly lambdaFunction: aws_lambda.FunctionBase;
}) => void;
};

export type S3Route = z.TypeOf<typeof S3RouteSchema>;

const LambdaRouteSchema = z.object({
type: z.literal(`function`),
httpMethod: z.enum([`DELETE`, `GET`, `HEAD`, `PATCH`, `POST`, `PUT`]),
publicPath: z.string(),
path: z.string(),
functionName: z.string(),
memorySize: z.number().optional(),
timeoutInSeconds: z.number().int().min(0).max(28).optional(),
environment: z.record(z.string()).optional(),
requestParameters: z
.record(
z.object({
cacheKey: z.boolean().optional(),
required: z.boolean().optional(),
}),
)
.optional(),
throttling: z
.object({rateLimit: z.number(), burstLimit: z.number()})
.optional(),
cacheTtlInSeconds: z.number().int().min(0).max(3600).optional(),
authenticationEnabled: z.boolean().optional(),
corsEnabled: z.boolean().optional(),
onSynthesize: z.function().optional(),
});

const S3RouteSchema = z.object({
type: z.enum([`file`, `folder`]),
httpMethod: z.literal(`GET`).optional(),
publicPath: z.string(),
path: z.string(),
responseHeaders: z.record(z.string()).optional(),
throttling: z
.object({rateLimit: z.number(), burstLimit: z.number()})
.optional(),
cacheTtlInSeconds: z.number().int().min(0).max(3600).optional(),
authenticationEnabled: z.boolean().optional(),
corsEnabled: z.boolean().optional(),
});

const StackConfigSchema = DomainNamePartsSchema.extend({
cachingEnabled: z.boolean().optional(),
terminationProtectionEnabled: z.boolean().optional(),
authentication: z
.object({
username: z.string(),
password: z.string(),
realm: z.string().optional(),
cacheTtlInSeconds: z.number().int().min(0).max(3600).optional(),
})
.optional(),
monitoring: z
.union([
z.literal(true),
z.object({
accessLoggingEnabled: z.boolean().optional(),
loggingEnabled: z.boolean().optional(),
metricsEnabled: z.boolean().optional(),
tracingEnabled: z.boolean().optional(),
}),
])
.optional(),
tags: z.record(z.string()).optional(),
routes: z.array(z.union([LambdaRouteSchema, S3RouteSchema])).min(1),
onSynthesize: z.function().optional(),
onStart: z.function().optional(),
});

export function parseStackConfig(config: unknown): StackConfig {
const stackConfig = StackConfigSchema.parse(config);

validateRoutes(stackConfig.routes);

return stackConfig;
}
4 changes: 3 additions & 1 deletion src/purge-command.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {Stack, Tag} from '@aws-sdk/client-cloudformation';
import type {CommandModule} from 'yargs';

import {parseDomainNameParts} from './parse-domain-name-parts.js';
import {readStackConfig} from './read-stack-config.js';
import {deleteStack} from './sdk/delete-stack.js';
import {findStacks} from './sdk/find-stacks.js';
Expand Down Expand Up @@ -53,7 +54,8 @@ export const purgeCommand: CommandModule<

handler: async (args): Promise<void> => {
const hostedZoneName =
args.hostedZoneName || (await readStackConfig()).hostedZoneName;
args.hostedZoneName ||
parseDomainNameParts(await readStackConfig()).hostedZoneName;

if (!hostedZoneName) {
throw new Error(`Please specify a hosted zone name.`);
Expand Down
112 changes: 2 additions & 110 deletions src/read-stack-config.ts
Original file line number Diff line number Diff line change
@@ -1,111 +1,7 @@
import type {Stack, aws_apigateway, aws_lambda} from 'aws-cdk-lib';
import type {Express} from 'express';

import {validateRoutes} from './utils/validate-routes.js';
import {resolve} from 'path';
import {pathToFileURL} from 'url';
import {z} from 'zod';

export type StackConfig = Omit<
z.TypeOf<typeof StackConfigSchema>,
'routes' | 'onSynthesize' | 'onStart'
> & {
readonly routes: Route[];

readonly onSynthesize?: (constructs: {
readonly stack: Stack;
readonly restApi: aws_apigateway.RestApiBase;
}) => void;

readonly onStart?: (app: Express) => void;
};

export type Route = LambdaRoute | S3Route;

export type LambdaRoute = Omit<
z.TypeOf<typeof LambdaRouteSchema>,
'onSynthesize'
> & {
readonly onSynthesize?: (constructs: {
readonly stack: Stack;
readonly restApi: aws_apigateway.RestApiBase;
readonly lambdaFunction: aws_lambda.FunctionBase;
}) => void;
};

export type S3Route = z.TypeOf<typeof S3RouteSchema>;

const LambdaRouteSchema = z.object({
type: z.literal(`function`),
httpMethod: z.enum([`DELETE`, `GET`, `HEAD`, `PATCH`, `POST`, `PUT`]),
publicPath: z.string(),
path: z.string(),
functionName: z.string(),
memorySize: z.number().optional(),
timeoutInSeconds: z.number().int().min(0).max(28).optional(),
environment: z.record(z.string()).optional(),
requestParameters: z
.record(
z.object({
cacheKey: z.boolean().optional(),
required: z.boolean().optional(),
}),
)
.optional(),
throttling: z
.object({rateLimit: z.number(), burstLimit: z.number()})
.optional(),
cacheTtlInSeconds: z.number().int().min(0).max(3600).optional(),
authenticationEnabled: z.boolean().optional(),
corsEnabled: z.boolean().optional(),
onSynthesize: z.function().optional(),
});

const S3RouteSchema = z.object({
type: z.enum([`file`, `folder`]),
httpMethod: z.literal(`GET`).optional(),
publicPath: z.string(),
path: z.string(),
responseHeaders: z.record(z.string()).optional(),
throttling: z
.object({rateLimit: z.number(), burstLimit: z.number()})
.optional(),
cacheTtlInSeconds: z.number().int().min(0).max(3600).optional(),
authenticationEnabled: z.boolean().optional(),
corsEnabled: z.boolean().optional(),
});

const StackConfigSchema = z.object({
hostedZoneName: z.string().optional(),
aliasRecordName: z.string().optional(),
cachingEnabled: z.boolean().optional(),
terminationProtectionEnabled: z.boolean().optional(),
authentication: z
.object({
username: z.string(),
password: z.string(),
realm: z.string().optional(),
cacheTtlInSeconds: z.number().int().min(0).max(3600).optional(),
})
.optional(),
monitoring: z
.union([
z.literal(true),
z.object({
accessLoggingEnabled: z.boolean().optional(),
loggingEnabled: z.boolean().optional(),
metricsEnabled: z.boolean().optional(),
tracingEnabled: z.boolean().optional(),
}),
])
.optional(),
tags: z.record(z.string()).optional(),
routes: z.array(z.union([LambdaRouteSchema, S3RouteSchema])).min(1),
onSynthesize: z.function().optional(),
onStart: z.function().optional(),
});

export async function readStackConfig(port?: number): Promise<StackConfig> {
export async function readStackConfig(port?: number): Promise<unknown> {
let module;

const path = resolve(`aws-simple.config.mjs`);
Expand All @@ -123,9 +19,5 @@ export async function readStackConfig(port?: number): Promise<StackConfig> {
);
}

const stackConfig = StackConfigSchema.parse(module.default(port));

validateRoutes(stackConfig.routes);

return stackConfig;
return module.default(port);
}

0 comments on commit c85843b

Please sign in to comment.