Skip to content
Merged
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion codegen/layouts/partials/route-class-endpoint-export.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export type {{parametersTypeName}} = {{> request-object parameters=parameters}}
export type {{parametersTypeName}} = {{#if requiresAtLeastOneParameter}}RequireAtLeastOne<{{/if}}{{> request-object parameters=parameters}}{{#if requiresAtLeastOneParameter}}>{{/if}}

/**
* @deprecated Use {{requestTypeName}} instead.
Expand Down
2 changes: 2 additions & 0 deletions codegen/layouts/partials/route-class-endpoint.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
{{methodName}}
{{> endpont-method-signature }}
{
assertValidRequestParameters(parameters, '{{path}}', {{hasRequiredParameters}})

return new SeamHttpRequest(this, {
pathname: '{{path}}',
method: '{{method}}',
Expand Down
7 changes: 7 additions & 0 deletions codegen/layouts/route.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@

{{> route-imports }}

{{#if endpoints}}
import { assertValidRequestParameters } from 'lib/request-parameters.js'
{{/if}}
{{#if needsRequireAtLeastOneImport}}
import type { RequireAtLeastOne } from 'lib/request-parameters.js'
{{/if}}

export class {{className}} {
{{> route-class-methods }}

Expand Down
17 changes: 14 additions & 3 deletions codegen/lib/layouts/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface RouteLayoutContext {
subroutes: SubrouteLayoutContext[]
skipClientSessionImport: boolean
needsActionAttemptsImport: boolean
needsRequireAtLeastOneImport: boolean
resourceTypeImports: ResourceTypeImport[]
}

Expand All @@ -35,6 +36,8 @@ export interface EndpointLayoutContext {
returnsActionAttempt: boolean
returnsVoid: boolean
isOptionalParamsOk: boolean
hasRequiredParameters: boolean
requiresAtLeastOneParameter: boolean
parameters: Parameter[]
responseIsList: boolean
responseResourceTypeName: string
Expand Down Expand Up @@ -64,6 +67,10 @@ export const setRouteLayoutContext = (
node.path !== '/action_attempts' &&
'endpoints' in node &&
node.endpoints.some(isActionAttemptEndpoint)
file.needsRequireAtLeastOneImport =
node != null &&
'endpoints' in node &&
node.endpoints.some(requiresAtLeastOneParameter)
file.resourceTypeImports =
node != null && 'endpoints' in node
? [
Expand Down Expand Up @@ -140,9 +147,9 @@ export const getEndpointLayoutContext = (
responseTypeName: `${prefix}Response`,
optionsTypeName: `${prefix}Options`,
requestTypeName: `${prefix}Request`,
isOptionalParamsOk: endpoint.request.parameters.every(
(parameter) => !parameter.isRequired,
),
isOptionalParamsOk: !endpoint.request.hasRequiredParameters,
hasRequiredParameters: endpoint.request.hasRequiredParameters,
requiresAtLeastOneParameter: requiresAtLeastOneParameter(endpoint),
parameters: endpoint.request.parameters,
responseIsList: endpoint.response.responseType === 'resource_list',
responseResourceTypeName:
Expand All @@ -155,6 +162,10 @@ export const getEndpointLayoutContext = (
}
}

const requiresAtLeastOneParameter = (endpoint: Endpoint): boolean =>
endpoint.request.hasRequiredParameters &&
endpoint.request.parameters.every(({ isRequired }) => !isRequired)

const isActionAttemptEndpoint = (endpoint: Endpoint): boolean =>
endpoint.response.responseType === 'resource' &&
endpoint.response.resourceType === 'action_attempt'
Expand Down
33 changes: 33 additions & 0 deletions src/lib/request-parameters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export type RequireAtLeastOne<
T,
Keys extends keyof T = keyof T,
> = Keys extends keyof T
? Required<Pick<T, Keys>> & Partial<Omit<T, Keys>>
: never

export const assertValidRequestParameters = (
parameters: unknown,
path: string,
hasRequiredParameters: boolean,
): void => {
if (parameters === undefined) {
if (hasRequiredParameters) {
throw new TypeError(`Parameters are required for ${path}`)
}
return
}

if (
parameters === null ||
typeof parameters !== 'object' ||
Array.isArray(parameters)
) {
throw new TypeError(`Parameters for ${path} must be an object`)
}

if (hasRequiredParameters && Object.keys(parameters).length === 0) {
throw new TypeError(
`Parameters for ${path} must contain at least one property`,
)
}
}
56 changes: 50 additions & 6 deletions src/lib/routes/access-codes/access-codes.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions src/lib/routes/access-codes/simulate/simulate.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 37 additions & 3 deletions src/lib/routes/access-codes/unmanaged/unmanaged.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading