Skip to content

Commit

Permalink
fix: optional oneOf / allOf / anyOf / $ref's (#110)
Browse files Browse the repository at this point in the history
previously, these would never be marked as optional, even if the key
they belonged to wasn't `required`

this was made evident whilst testing
#109
which relies on `oneOf` to handle arrays of `type`

this moves that logic up into the `AbstractSchemaBuilder`, and applies
it more predictably,
as well as swapping the order such that `nullable` always comes before
`optional`

this means that schemas like:
```
schema:
  type: object
  properties:
    enabled:
      "$ref": "#/components/schemas/actions-enabled"
    allowed_actions:
      "$ref": "#/components/schemas/allowed-actions"
  required:
    - enabled
```
will correctly mark `allowed_actions` as optional, and schemas like:
```
setup_intent_payment_method_options:
  description: ''
  properties:
    us_bank_account:
      anyOf:
        - $ref: >-
            #/components/schemas/setup_intent_payment_method_options_us_bank_account
        - $ref: >-
            #/components/schemas/setup_intent_type_specific_payment_method_options_client
  title: SetupIntentPaymentMethodOptions
  type: object
```
correctly mark `us_bank_account` as optional.

note: the typescript types were already correct here. the problem wasn't
picked up by typescript because were being stricter on the validation
and then passing that to a looser type, eg: passing `T` to a `T |
undefined` parameter.
  • Loading branch information
mnahkies authored Nov 12, 2023
1 parent 7564c10 commit 2ff114a
Show file tree
Hide file tree
Showing 12 changed files with 9,796 additions and 8,176 deletions.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,8 @@ export const s_AppAuthenticatorEnrollmentRequest = z.object({
pushToken: z.string(),
keys: z.object({
proofOfPossession: s_KeyObject,
userVerification: s_KeyObject,
capabilities: s_AppAuthenticatorMethodCapabilities,
userVerification: s_KeyObject.optional(),
capabilities: s_AppAuthenticatorMethodCapabilities.optional(),
}),
}),
}),
Expand All @@ -199,8 +199,10 @@ export const s_UpdateAppAuthenticatorEnrollmentRequest = z.object({
push: z
.object({
pushToken: z.string().optional(),
keys: z.object({ userVerification: s_KeyObject }).optional(),
capabilities: s_AppAuthenticatorMethodCapabilities,
keys: z
.object({ userVerification: s_KeyObject.optional() })
.optional(),
capabilities: s_AppAuthenticatorMethodCapabilities.optional(),
})
.optional(),
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -479,21 +479,21 @@ export function createRouter(implementation: Implementation): KoaRouter {
)

const authorizeQuerySchema = z.object({
acr_values: s_AcrValue,
acr_values: s_AcrValue.optional(),
client_id: z.string().optional(),
code_challenge: z.string().optional(),
code_challenge_method: s_CodeChallengeMethod,
code_challenge_method: s_CodeChallengeMethod.optional(),
display: z.string().optional(),
enroll_amr_values: s_AmrValue,
enroll_amr_values: s_AmrValue.optional(),
idp_scope: z.string().optional(),
idp: z.string().optional(),
login_hint: z.string().optional(),
max_age: z.coerce.number().optional(),
nonce: z.string().optional(),
prompt: s_Prompt,
prompt: s_Prompt.optional(),
redirect_uri: z.string().optional(),
response_type: s_ResponseTypesSupported,
response_mode: s_ResponseMode,
response_type: s_ResponseTypesSupported.optional(),
response_mode: s_ResponseMode.optional(),
request_uri: z.string().optional(),
request: z.string().optional(),
scope: z.string().optional(),
Expand Down Expand Up @@ -1031,21 +1031,21 @@ export function createRouter(implementation: Implementation): KoaRouter {
})

const authorizeCustomAsQuerySchema = z.object({
acr_values: s_AcrValue,
acr_values: s_AcrValue.optional(),
client_id: z.string().optional(),
code_challenge: z.string().optional(),
code_challenge_method: s_CodeChallengeMethod,
code_challenge_method: s_CodeChallengeMethod.optional(),
display: z.string().optional(),
enroll_amr_values: s_AmrValue,
enroll_amr_values: s_AmrValue.optional(),
idp_scope: z.string().optional(),
idp: z.string().optional(),
login_hint: z.string().optional(),
max_age: z.coerce.number().optional(),
nonce: z.string().optional(),
prompt: s_Prompt,
prompt: s_Prompt.optional(),
redirect_uri: z.string().optional(),
response_type: s_ResponseTypesSupported,
response_mode: s_ResponseMode,
response_type: s_ResponseTypesSupported.optional(),
response_mode: s_ResponseMode.optional(),
request_uri: z.string().optional(),
request: z.string().optional(),
scope: z.string().optional(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,15 +226,15 @@ export const s_UserInfo = z.object({ sub: z.string().optional() })

export const s_IntrospectionRequest = z.object({
token: z.string().optional(),
token_type_hint: s_TokenTypeHintIntrospect,
token_type_hint: s_TokenTypeHintIntrospect.optional(),
})

export const s_JsonWebKey = z.object({
alg: s_SigningAlgorithm,
alg: s_SigningAlgorithm.optional(),
kid: z.string().optional(),
kty: s_JsonWebKeyType,
status: s_JsonWebKeyStatus,
use: s_JsonWebKeyUse,
kty: s_JsonWebKeyType.optional(),
status: s_JsonWebKeyStatus.optional(),
use: s_JsonWebKeyUse.optional(),
})

export const s_OAuthMetadata = z.object({
Expand Down Expand Up @@ -278,41 +278,41 @@ export const s_OAuthMetadata = z.object({

export const s_RevokeRequest = z.object({
token: z.string().optional(),
token_type_hint: s_TokenTypeHintRevoke,
token_type_hint: s_TokenTypeHintRevoke.optional(),
})

export const s_TokenRequest = z.object({ grant_type: s_GrantType })
export const s_TokenRequest = z.object({ grant_type: s_GrantType.optional() })

export const s_TokenResponse = z.object({
access_token: z.string().optional(),
device_secret: z.string().optional(),
expires_in: z.coerce.number().optional(),
id_token: z.string().optional(),
issued_token_type: s_TokenType,
issued_token_type: s_TokenType.optional(),
refresh_token: z.string().optional(),
scope: z.string().optional(),
token_type: s_TokenResponseTokenType,
token_type: s_TokenResponseTokenType.optional(),
})

export const s_Client = z.object({
application_type: s_ApplicationType,
application_type: s_ApplicationType.optional(),
client_id: z.string().optional(),
client_id_issued_at: z.coerce.number().optional(),
client_name: z.string().optional(),
client_secret: z.string().optional().nullable(),
client_secret_expires_at: z.coerce.number().optional().nullable(),
client_secret: z.string().nullable().optional(),
client_secret_expires_at: z.coerce.number().nullable().optional(),
grant_types: z.array(s_GrantType).optional(),
initiate_login_uri: z.string().optional(),
jwks: z.array(s_JsonWebKey).optional(),
jwks_uri: z.string().optional(),
logo_uri: z.string().optional().nullable(),
policy_uri: z.string().optional().nullable(),
logo_uri: z.string().nullable().optional(),
policy_uri: z.string().nullable().optional(),
post_logout_redirect_uris: z.string().optional(),
redirect_uris: z.array(z.string()).optional(),
request_object_signing_alg: z.array(s_SigningAlgorithm).optional(),
response_types: z.array(s_ResponseType).optional(),
token_endpoint_auth_method: s_EndpointAuthMethod,
tos_uri: z.string().optional().nullable(),
token_endpoint_auth_method: s_EndpointAuthMethod.optional(),
tos_uri: z.string().nullable().optional(),
})

export const s_OAuthKeys = z.object({ keys: z.array(s_JsonWebKey).optional() })
Expand Down
Loading

0 comments on commit 2ff114a

Please sign in to comment.