From 664132bad2e77985313d0e747579edcec40cb1fd Mon Sep 17 00:00:00 2001 From: jonaslagoni Date: Thu, 30 Jul 2026 10:50:54 +0200 Subject: [PATCH 1/2] fix: make generated code compile, unblank the blackbox tier, correct the docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses the three ideas in .claude/thoughts/shared/improvements/2026-07-29-2227-improvements.md. Generated code did not compile (idea 1) - `ajv-formats` is imported by every validating payload/header model but was documented nowhere and declared in no package.json. Document it alongside `ajv` on the payloads/headers/channels pages, and declare it in the five examples, the runtime suite, and the blackbox project template that import it. - `{default as addFormats}` resolves to the module namespace under `moduleResolution: node16`/`nodenext`, so `addFormats(ajv)` was not callable (TS2349). Import the module and unwrap `.default` at the call site — verified against ajv-formats v2 and v3, under node/node16/nodenext/bundler. - `importExtension` never reached the imports Modelina renders between models, so those stayed extensionless and failed TS2835 in exactly the projects the option exists for. Apply it at the single Modelina emission seam. - The companion interface was re-exported as a value, which breaks under `isolatedModules: true` (TS1205, Next.js/SWC/esbuild). Split it into `export type`. - Header unions (a channel whose messages each declare headers) referenced the expanded `A | B | C` type without importing its members, and emitted `A | B | C.unmarshal(...)` — a bitwise-or expression, not a call. Import union header models as a namespace, like payload unions, and give them module-level `unmarshal`/`marshal`. - The client generator's subscribe wrappers omitted the `headers` callback slot the channel functions declare, and never imported the header models. - NATS reply passed a string as `ErrorOptions` to `new Error(...)`. The blackbox tier compiled nothing (idea 2) Since the in-memory generator seam, `runGenerators` returns files rather than writing them; the harness never got the write call, so all 216 outputs were an empty `index.ts` and every pair passed regardless. Write the files, assert they reach disk, and wire up the missing OpenAPI loader arm. All 214 pairs pass on real generated output. Also wires `codegen-node16.mjs` — an orphan config with no npm script — into the runtime `generate` chain. Docs described an API the generator does not have (idea 3) `import { Protocols }` was removed but still taught on seven pages (and used by an example whose documented `npm run demo` threw), while the migration guide told readers to stop using it. Fixed that, the positional call sites across the protocol pages, `postPingPostRequest` -> `postPostPing`, the AMQP/EventSource/ WebSocket/client signatures, the invalid `custom.md` snippet, the `amqp_publish`/`amqp_consume` values that generate nothing, `mapType`'s default, and the OpenAPI channels/client support claims. Documents the payloads and headers options, which had no table at all. Co-Authored-By: Claude Opus 5 (1M context) --- README.md | 2 +- docs/generators/channels.md | 5 +- docs/generators/client.md | 24 +- docs/generators/custom.md | 4 +- docs/generators/headers.md | 12 + docs/generators/models.md | 3 +- docs/generators/payloads.md | 18 + docs/getting-started/generators.md | 35 +- docs/getting-started/protocols.md | 27 +- docs/inputs/asyncapi.md | 4 +- docs/migrations/v0.md | 3 +- docs/protocols/amqp.md | 20 +- docs/protocols/eventsource.md | 37 +- docs/protocols/http_client.md | 33 +- docs/protocols/kafka.md | 36 +- docs/protocols/mqtt.md | 3 +- docs/protocols/websocket.md | 5 +- .../package-lock.json | 72 ++++ .../ecommerce-asyncapi-channels/package.json | 4 +- .../headers/OrderCancelledHeaders.ts | 5 +- .../generated/headers/OrderCreatedHeaders.ts | 5 +- .../headers/OrderLifecycleHeaders.ts | 45 ++ .../generated/headers/OrderUpdatedHeaders.ts | 5 +- .../src/generated/kafka.ts | 14 +- .../src/generated/nats.ts | 32 +- .../parameter/OrderLifecycleParameters.ts | 3 +- .../src/generated/payload/Address.ts | 8 +- .../src/generated/payload/Money.ts | 8 +- .../src/generated/payload/OrderCancelled.ts | 8 +- .../src/generated/payload/OrderCreated.ts | 8 +- .../src/generated/payload/OrderItem.ts | 8 +- .../payload/OrderLifecyclePayload.ts | 5 +- .../src/generated/payload/OrderUpdated.ts | 8 +- .../payload/SubscribeToOrderEventsPayload.ts | 5 +- .../ecommerce-asyncapi-channels/src/index.ts | 12 +- .../package-lock.json | 72 ++++ .../ecommerce-asyncapi-client/package.json | 8 +- .../src/generated/NatsClient.ts | 7 +- .../channels/headers/OrderCancelledHeaders.ts | 5 +- .../channels/headers/OrderCreatedHeaders.ts | 5 +- .../channels/headers/OrderLifecycleHeaders.ts | 45 ++ .../channels/headers/OrderUpdatedHeaders.ts | 5 +- .../src/generated/channels/nats.ts | 32 +- .../parameter/OrderLifecycleParameters.ts | 3 +- .../src/generated/channels/payload/Address.ts | 8 +- .../src/generated/channels/payload/Money.ts | 8 +- .../channels/payload/OrderCancelled.ts | 8 +- .../channels/payload/OrderCreated.ts | 8 +- .../channels/payload/OrderEventsPayload.ts | 5 +- .../generated/channels/payload/OrderItem.ts | 8 +- .../channels/payload/OrderLifecyclePayload.ts | 5 +- .../channels/payload/OrderUpdated.ts | 8 +- .../ecommerce-asyncapi-client/src/index.ts | 8 +- .../package-lock.json | 74 ++++ .../ecommerce-asyncapi-headers/package.json | 7 +- .../headers/AdminActionPerformedHeaders.ts | 5 +- .../headers/InventoryUpdatedHeaders.ts | 5 +- .../headers/NotificationSentHeaders.ts | 5 +- .../generated/headers/OrderCreatedHeaders.ts | 5 +- .../generated/headers/OrderEventsHeaders.ts | 51 +++ .../headers/OrderStatusChangedHeaders.ts | 5 +- .../headers/PaymentProcessedHeaders.ts | 5 +- .../headers/UserBehaviorTrackedHeaders.ts | 5 +- .../parameters/InventoryUpdatesParameters.ts | 3 +- .../parameters/OrderEventsParameters.ts | 3 +- .../parameters/ProductUpdatesParameters.ts | 3 +- .../parameters/SupportTicketsParameters.ts | 3 +- .../parameters/TenantAnalyticsParameters.ts | 3 +- .../parameters/UserActivityParameters.ts | 3 +- .../parameters/UserNotificationsParameters.ts | 3 +- .../src/generated/models/Address.ts | 8 +- .../src/generated/models/Attachment.ts | 8 +- .../src/generated/models/EmailNotification.ts | 8 +- .../src/generated/models/NotificationSent.ts | 5 +- .../src/generated/models/OrderCreated.ts | 8 +- .../generated/models/OrderEventsPayload.ts | 5 +- .../src/generated/models/OrderItem.ts | 8 +- .../generated/models/OrderStatusChanged.ts | 8 +- .../src/generated/models/PaymentProcessed.ts | 8 +- .../src/generated/models/PushNotification.ts | 8 +- .../src/generated/models/SmsNotification.ts | 8 +- .../GetV2ConnectReferenceIdParameters.ts | 3 +- ...sSafepayAccountIdBankAccountsParameters.ts | 3 +- .../src/generated/payload/BankAccount.ts | 8 +- .../src/generated/payload/GetConnectModel.ts | 8 +- .../GetV2ConnectReferenceIdResponse_200.ts | 8 +- ...afepayAccountIdBankAccountsResponse_200.ts | 8 +- .../src/generated/payload/InitializeModel.ts | 8 +- .../generated/payload/InitializeRequest.ts | 8 +- .../generated/payload/PostV2ConnectRequest.ts | 8 +- .../payload/PostV2ConnectResponse_200.ts | 8 +- examples/typescript-library/package-lock.json | 127 +++++- examples/typescript-library/package.json | 6 +- .../src/__gen__/payloads/UserSignedUp.ts | 8 +- examples/typescript-nextjs/package-lock.json | 387 +++++++++--------- examples/typescript-nextjs/package.json | 4 +- .../src/__gen__/payloads/UserSignedUp.ts | 8 +- .../generators/typescript/channels/index.ts | 7 +- .../protocols/amqp/publishExchange.ts | 4 +- .../channels/protocols/amqp/publishQueue.ts | 4 +- .../channels/protocols/amqp/subscribeQueue.ts | 8 +- .../channels/protocols/eventsource/fetch.ts | 4 +- .../channels/protocols/http/client.ts | 5 +- .../channels/protocols/kafka/publish.ts | 4 +- .../channels/protocols/kafka/subscribe.ts | 4 +- .../channels/protocols/kafka/utils.ts | 6 +- .../channels/protocols/mqtt/publish.ts | 4 +- .../channels/protocols/mqtt/subscribe.ts | 8 +- .../channels/protocols/nats/coreReply.ts | 4 +- .../channels/protocols/nats/coreSubscribe.ts | 2 + .../protocols/nats/jetstreamPullSubscribe.ts | 5 +- .../nats/jetstreamPushSubscription.ts | 5 +- .../channels/protocols/nats/utils.ts | 12 +- .../generators/typescript/channels/types.ts | 13 + .../generators/typescript/channels/utils.ts | 35 ++ .../typescript/client/protocols/nats.ts | 12 + .../client/protocols/nats/coreSubscribe.ts | 206 +++++----- .../nats/jetStreamPullSubscription.ts | 194 ++++----- .../nats/jetstreamPushSubscription.ts | 192 +++++---- src/codegen/generators/typescript/headers.ts | 18 +- src/codegen/generators/typescript/models.ts | 5 +- .../generators/typescript/parameters.ts | 18 +- src/codegen/generators/typescript/payloads.ts | 46 ++- src/codegen/generators/typescript/utils.ts | 5 +- src/codegen/index.ts | 1 + src/codegen/modelina/presets/validation.ts | 11 +- src/codegen/output/index.ts | 2 +- src/codegen/output/modelina.ts | 53 ++- src/codegen/types.ts | 7 + src/index.ts | 2 + .../blackbox/projects/typescript/package.json | 2 + test/blackbox/typescript.spec.ts | 20 +- .../__snapshots__/headers.spec.ts.snap | 5 +- .../__snapshots__/parameters.spec.ts.snap | 126 ++++-- .../__snapshots__/payload.spec.ts.snap | 24 +- .../typescript/channels/header-union.spec.ts | 135 ++++++ .../generators/typescript/client.spec.ts | 22 + .../generators/typescript/payload.spec.ts | 5 +- .../modelina/presets/validation.spec.ts | 17 +- .../output/modelina-import-extension.spec.ts | 70 ++++ test/runtime/typescript/package-lock.json | 18 + test/runtime/typescript/package.json | 4 +- .../channels/headers/UserSignedUpHeaders.ts | 5 +- .../parameter/UserSignedupParameters.ts | 3 +- .../channels/payload/ArrayMessage.ts | 5 +- .../channels/payload/LegacyNotification.ts | 8 +- .../channels/payload/StringMessage.ts | 5 +- .../channels/payload/UnionMessage.ts | 5 +- .../payload/UnionPayloadOneOfOption2.ts | 8 +- .../channels/payload/UserSignedUp.ts | 8 +- .../parameter/UserSignedupParameters.ts | 3 +- .../channels/payload/AdminAlert.ts | 8 +- .../channels/payload/SystemPing.ts | 8 +- .../channels/payload/UserSignedUp.ts | 8 +- .../typescript/src/client/NatsClient.ts | 13 +- .../src/headers/UserSignedUpHeaders.ts | 5 +- .../typescript/src/node16/channels/nats.ts | 30 +- .../src/node16/headers/UserSignedUpHeaders.ts | 34 +- .../parameters/UserSignedupParameters.ts | 5 +- .../src/node16/payloads/ArrayMessage.ts | 5 +- .../src/node16/payloads/LegacyNotification.ts | 60 +-- .../src/node16/payloads/StringMessage.ts | 5 +- .../src/node16/payloads/UnionMessage.ts | 7 +- .../payloads/UnionPayloadOneOfOption2.ts | 52 ++- .../src/node16/payloads/UserSignedUp.ts | 58 +-- .../FindPetsByStatusAndCategoryParameters.ts | 3 +- .../channels/payload/APet.ts | 8 +- .../channels/payload/AUser.ts | 8 +- .../channels/payload/AnUploadedResponse.ts | 8 +- ...FindPetsByStatusAndCategoryResponse_200.ts | 5 +- .../channels/payload/PetCategory.ts | 8 +- .../channels/payload/PetOrder.ts | 8 +- .../channels/payload/PetTag.ts | 8 +- .../payloads/GetCountResponse_200.ts | 5 +- .../payloads/GetEchoResponse_200.ts | 5 +- .../FindPetsByStatusAndCategoryParameters.ts | 3 +- .../channels/payload/APet.ts | 8 +- .../channels/payload/AUser.ts | 8 +- .../channels/payload/AnUploadedResponse.ts | 8 +- ...FindPetsByStatusAndCategoryResponse_200.ts | 5 +- .../channels/payload/PetCategory.ts | 8 +- .../channels/payload/PetOrder.ts | 8 +- .../channels/payload/PetTag.ts | 8 +- .../FindPetsByStatusAndCategoryParameters.ts | 3 +- .../typescript/src/openapi/payloads/APet.ts | 8 +- .../typescript/src/openapi/payloads/AUser.ts | 8 +- .../openapi/payloads/AnUploadedResponse.ts | 8 +- ...FindPetsByStatusAndCategoryResponse_200.ts | 5 +- .../src/openapi/payloads/PetCategory.ts | 8 +- .../src/openapi/payloads/PetOrder.ts | 8 +- .../typescript/src/openapi/payloads/PetTag.ts | 8 +- .../src/parameters/UserSignedupParameters.ts | 3 +- .../payload-types/payloads/AllOfThreeTypes.ts | 8 +- .../payload-types/payloads/AllOfTwoTypes.ts | 8 +- .../payload-types/payloads/AnyOfTwoTypes.ts | 5 +- .../payloads/AnyOfTwoTypesAnyOfOption0.ts | 8 +- .../payloads/AnyOfTwoTypesAnyOfOption1.ts | 8 +- .../payloads/ArrayWithMaxItems.ts | 5 +- .../payloads/ArrayWithMinItems.ts | 5 +- .../payloads/ArrayWithUniqueItems.ts | 5 +- .../payload-types/payloads/BooleanPlain.ts | 5 +- .../src/payload-types/payloads/CatPayload.ts | 8 +- .../payloads/DeeplyNestedObject.ts | 8 +- .../payloads/DeeplyNestedObjectLevel1.ts | 8 +- .../DeeplyNestedObjectLevel1Level2.ts | 8 +- .../DeeplyNestedObjectLevel1Level2Level3.ts | 8 +- .../src/payload-types/payloads/DogPayload.ts | 8 +- .../src/payload-types/payloads/FormatDate.ts | 5 +- .../payload-types/payloads/FormatDateTime.ts | 5 +- .../src/payload-types/payloads/FormatEmail.ts | 5 +- .../payload-types/payloads/FormatHostname.ts | 5 +- .../src/payload-types/payloads/FormatIpv4.ts | 5 +- .../src/payload-types/payloads/FormatIpv6.ts | 5 +- .../src/payload-types/payloads/FormatTime.ts | 5 +- .../src/payload-types/payloads/FormatUri.ts | 5 +- .../src/payload-types/payloads/FormatUuid.ts | 5 +- .../payload-types/payloads/IntegerPlain.ts | 5 +- .../payloads/IntegerWithRange.ts | 5 +- .../src/payload-types/payloads/NestedArray.ts | 5 +- .../payload-types/payloads/NestedObject.ts | 8 +- .../payloads/NestedObjectOuter.ts | 8 +- .../src/payload-types/payloads/NullPlain.ts | 5 +- .../src/payload-types/payloads/NumberPlain.ts | 5 +- .../payloads/NumberWithMaximum.ts | 5 +- .../payloads/NumberWithMinimum.ts | 5 +- .../payload-types/payloads/NumberWithRange.ts | 5 +- .../payloads/ObjectAdditionalPropsFalse.ts | 8 +- .../payloads/ObjectAdditionalPropsSchema.ts | 8 +- .../payloads/ObjectAdditionalPropsTrue.ts | 8 +- .../src/payload-types/payloads/ObjectArray.ts | 5 +- .../payload-types/payloads/ObjectArrayItem.ts | 8 +- .../payloads/ObjectWithDefaults.ts | 8 +- .../payloads/ObjectWithFormats.ts | 8 +- .../payloads/ObjectWithOptional.ts | 8 +- .../payloads/ObjectWithRequired.ts | 8 +- .../payload-types/payloads/OneOfThreeTypes.ts | 5 +- .../payloads/OneOfThreeTypesOneOfOption2.ts | 8 +- .../payload-types/payloads/OneOfTwoTypes.ts | 5 +- .../payloads/OneOfWithDiscriminator.ts | 5 +- .../payload-types/payloads/SimpleObject.ts | 8 +- .../src/payload-types/payloads/StringArray.ts | 5 +- .../src/payload-types/payloads/StringPlain.ts | 5 +- .../payloads/StringWithMaxLength.ts | 5 +- .../payloads/StringWithMinLength.ts | 5 +- .../payloads/StringWithPattern.ts | 5 +- .../src/payload-types/payloads/TupleArray.ts | 5 +- .../typescript/src/payloads/ArrayMessage.ts | 5 +- .../src/payloads/LegacyNotification.ts | 8 +- .../typescript/src/payloads/StringMessage.ts | 5 +- .../typescript/src/payloads/UnionMessage.ts | 5 +- .../src/payloads/UnionPayloadOneOfOption2.ts | 8 +- .../typescript/src/payloads/UserSignedUp.ts | 8 +- .../src/request-reply/channels/nats.ts | 2 +- .../src/request-reply/client/NatsClient.ts | 1 + .../headers/ItemRequestHeaders.ts | 5 +- .../parameters/UserItemsParameters.ts | 3 +- .../payloads/GetUserItemReplyPayload.ts | 5 +- .../src/request-reply/payloads/ItemRequest.ts | 8 +- .../request-reply/payloads/ItemResponse.ts | 8 +- .../MultiStatusResponseReplyPayload.ts | 5 +- .../src/request-reply/payloads/NotFound.ts | 8 +- .../src/request-reply/payloads/Ping.ts | 8 +- .../src/request-reply/payloads/PingPayload.ts | 5 +- .../src/request-reply/payloads/Pong.ts | 8 +- .../payloads/UpdateUserItemReplyPayload.ts | 5 +- .../payloads/UserItemsPayload.ts | 5 +- 266 files changed, 2843 insertions(+), 1145 deletions(-) create mode 100644 test/codegen/generators/typescript/channels/header-union.spec.ts create mode 100644 test/codegen/output/modelina-import-extension.spec.ts diff --git a/README.md b/README.md index 2c6173a3..7aeb84ed 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ # Core Features - 📃 From your [AsyncAPI v2 and v3](https://the-codegen-project.org/docs/inputs/asyncapi) documents, generate [payloads](https://the-codegen-project.org/docs/generators/payloads), [headers](https://the-codegen-project.org/docs/generators/headers), [parameters](https://the-codegen-project.org/docs/generators/parameters), [protocol helpers](https://the-codegen-project.org/docs/generators/channels), [full clients](https://the-codegen-project.org/docs/generators/client), [models](https://the-codegen-project.org/docs/generators/models), [simple types](https://the-codegen-project.org/docs/generators/types), or all of the above. -- 📃 From your [Swagger 2.0, or OpenAPI 3.0, and 3.1](https://the-codegen-project.org/docs/inputs/openapi) documents, generate [payloads](https://the-codegen-project.org/docs/generators/payloads), [headers](https://the-codegen-project.org/docs/generators/headers), [parameters](https://the-codegen-project.org/docs/generators/parameters), [models](https://the-codegen-project.org/docs/generators/models), [simple types](https://the-codegen-project.org/docs/generators/types), or all of the above. +- 📃 From your [Swagger 2.0, or OpenAPI 3.0, and 3.1](https://the-codegen-project.org/docs/inputs/openapi) documents, generate [payloads](https://the-codegen-project.org/docs/generators/payloads), [headers](https://the-codegen-project.org/docs/generators/headers), [parameters](https://the-codegen-project.org/docs/generators/parameters), [protocol helpers](https://the-codegen-project.org/docs/generators/channels), [full clients](https://the-codegen-project.org/docs/generators/client), [models](https://the-codegen-project.org/docs/generators/models), [simple types](https://the-codegen-project.org/docs/generators/types), or all of the above. - 📃 From your [JSON Schema Draft-4, Draft-6 and Draft-7](https://the-codegen-project.org/docs/inputs/jsonschema) schemas, generate [models](https://the-codegen-project.org/docs/generators/models) or [completely customize it](https://the-codegen-project.org/docs/generators/custom). - 📊 Every generator fully customizable to fit your hearts desire - 👀 Integrate it into any project (Demos in [Next.JS](./examples/typescript-nextjs), [TypeScript Libraries](./examples/typescript-library)) diff --git a/docs/generators/channels.md b/docs/generators/channels.md index e276f671..a1608eaf 100644 --- a/docs/generators/channels.md +++ b/docs/generators/channels.md @@ -18,11 +18,11 @@ export default { }; ``` -`channels` preset with `asyncapi` input generates support functions for each operation based on the selected protocol. +`channels` preset generates support functions for each operation based on the selected protocol. This generator uses [`payloads`](./payloads.md), [`headers`](./headers.md) and [`parameters`](./parameters.md) generators, in case you dont have any defined, it will automatically include them with default values. -This is supported through the following inputs: [`asyncapi`](../inputs/asyncapi.md) +This is supported through the following inputs: [`asyncapi`](../inputs/asyncapi.md), [`openapi`](../inputs/openapi.md) It supports the following languages; [`typescript`](#typescript) @@ -43,6 +43,7 @@ These are the available options for the `channels` generator; ## TypeScript Regardless of protocol, these are the dependencies: - If validation enabled, [ajv](https://ajv.js.org/guide/getting-started.html): ^8.17.1 +- If validation enabled, [ajv-formats](https://github.com/ajv-validator/ajv-formats): ^3.0.1 Depending on which protocol, these are the dependencies: - `NATS`: https://github.com/nats-io/nats.js v2 diff --git a/docs/generators/client.md b/docs/generators/client.md index 48bb78c0..65ad8406 100644 --- a/docs/generators/client.md +++ b/docs/generators/client.md @@ -53,8 +53,7 @@ export {Payload}; import {Parameters} from './parameters/Parameters'; //Import channel functions -import { Protocols } from './channels/index'; -const { nats } = Protocols; +import { nats } from './channels/index'; import * as Nats from 'nats'; @@ -96,15 +95,22 @@ export class NatsClient { /** * Try to connect to the NATS server with the different payloads. */ - connect(options: Nats.ConnectionOptions, codec?: Nats.Codec): Promise { + connect( + options: Nats.ConnectionOptions, + codec?: Nats.Codec + ): Promise<{nc: Nats.NatsConnection, js: Nats.JetStreamClient}> { ... } - - public async jetStreamPublishToChannel( - message: Payload, - parameters: Parameters, - options: Partial = {} - ): Promise { + + public async jetStreamPublishToChannel({ + message, + parameters, + options = {} + }: { + message: PayloadInterface | Payload, + parameters: Parameters, + options?: Partial + }): Promise { ... } jetStreamPullSubscribeToChannel diff --git a/docs/generators/custom.md b/docs/generators/custom.md index 30fc77d1..dd9985a1 100644 --- a/docs/generators/custom.md +++ b/docs/generators/custom.md @@ -18,8 +18,7 @@ export default { { preset: 'custom', ... - renderFunction: ({generator, inputType, asyncapiDocument, openapiDocument, dependencyOutputs}) - { + renderFunction: ({generator, inputType, asyncapiDocument, openapiDocument, jsonSchemaDocument, dependencyOutputs}) => { const modelinaGenerator = new JavaFileGenerator({}); modelinaGenerator.generateCompleteModels(...) } @@ -71,4 +70,5 @@ In the `renderFunction` you have access to a bunch of arguments to help you crea - `inputType` - is the root `inputType` for the input document - `asyncapiDocument` - is the parsed AsyncAPI document input (according to the [AsyncAPI parser](https://github.com/asyncapi/parser-js/)), undefined if the `inputType` is not `asyncapi` - `openapiDocument` - is the parsed OpenAPI document input (according to the [readme/openapi-parser](https://github.com/readmeio/oas)), undefined if the `inputType` is not `openapi` +- `jsonSchemaDocument` - is the parsed JSON Schema document input, undefined if the `inputType` is not `jsonschema` - `dependencyOutputs` - if you have defined any `dependencies`, this is where you can access the output. Checkout the [dependency documentation](#dependencies) for more information. \ No newline at end of file diff --git a/docs/generators/headers.md b/docs/generators/headers.md index 0a9a9aa1..1a78a179 100644 --- a/docs/generators/headers.md +++ b/docs/generators/headers.md @@ -37,9 +37,21 @@ The `headers` preset with `openapi` input generates all the headers for each pat The return type is a map of paths and the model that represent the headers. +## Options +These are the available options for the `headers` generator; + +| **Option** | Default | Type | Description | +|---|---|---|---| +| id | `'headers-typescript'` | String | Unique identifier for this generator instance. The `channels`/`client` generators reference it as their `headerGeneratorId`. | +| dependencies | `[]` | String[] | IDs of other generators that must run before this one. | +| outputPath | `'src/__gen__/headers'` | String | Directory the generated header models are written to. | +| serializationType | `'json'` | `'json'` | Serialization format used by the generated models. Only `json` is supported. | +| includeValidation | `true` | Boolean | Include the built-in JSON Schema `validate`/`createValidator` methods. Requires `ajv` and `ajv-formats` (see [Dependencies](#typescript)). | + ## Typescript Dependencies: - If validation enabled, [ajv](https://ajv.js.org/guide/getting-started.html): ^8.17.1 +- If validation enabled, [ajv-formats](https://github.com/ajv-validator/ajv-formats): ^3.0.1 ### Validation Each generated class includes built-in JSON Schema validation capabilities through two static methods: diff --git a/docs/generators/models.md b/docs/generators/models.md index 8092ba33..223f7bdd 100644 --- a/docs/generators/models.md +++ b/docs/generators/models.md @@ -213,10 +213,11 @@ The TypeScript implementation provides full access to Modelina's TypeScript gene |--------|------|---------|-------------| | `modelType` | `'class' \| 'interface'` | `'class'` | Type of models to generate | | `enumType` | `'enum' \| 'union'` | `'enum'` | How to render enum types | -| `mapType` | `'indexedObject' \| 'record'` | `'record'` | How to render map/dictionary types | +| `mapType` | `'indexedObject' \| 'map' \| 'record'` | `'map'` | How to render map/dictionary types | | `moduleSystem` | `'CJS' \| 'ESM'` | `'ESM'` | Module system to use | | `rawPropertyNames` | `boolean` | `false` | Use raw property names without transformation | | `useJavascriptReservedKeywords` | `boolean` | `true` | Allow JavaScript reserved keywords | +| `isolatedModules` | `boolean` | `false` | Emit `export type` / `import type` for type-only models. Required for projects using TypeScript's `isolatedModules` (Next.js, SWC, esbuild) | **Common Presets**: diff --git a/docs/generators/payloads.md b/docs/generators/payloads.md index 9ab2375b..39d41a5c 100644 --- a/docs/generators/payloads.md +++ b/docs/generators/payloads.md @@ -56,6 +56,23 @@ free-function marshalling — they have no companion interface and are exported a single symbol. See the [protocols documentation](../protocols) for how each channel accepts payloads. +## Options +These are the available options for the `payloads` generator; + +| **Option** | Default | Type | Description | +|---|---|---|---| +| id | `'payloads-typescript'` | String | Unique identifier for this generator instance. Other generators reference it as a dependency, and the `channels`/`client` generators use it as their `payloadGeneratorId`. | +| dependencies | `[]` | String[] | IDs of other generators that must run before this one. | +| outputPath | `'src/__gen__/payloads'` | String | Directory the generated payload models are written to. | +| serializationType | `'json'` | `'json'` | Serialization format used by the generated models. Only `json` is supported. | +| enum | `'enum'` | `'enum' \| 'union'` | Render enums as TypeScript `enum`s, or as string/number union types. | +| map | `'record'` | `'indexedObject' \| 'map' \| 'record'` | Render dictionary/map types as `Record`, the `Map` class, or an index signature. | +| useForJavaScript | `true` | Boolean | Apply JavaScript restrictions so the models stay valid when transpiled to JavaScript (for example avoiding reserved keywords as identifiers). | +| includeValidation | `true` | Boolean | Include the built-in JSON Schema `validate`/`createValidator` methods. Requires `ajv` and `ajv-formats` (see [Dependencies](#typescript)). | +| rawPropertyNames | `false` | Boolean | Keep the raw property names from the input schema. Consumers then access them with `obj["propertyName"]` instead of `obj.propertyName`. | + +The global [`importExtension`](../configurations.md#import-extensions-node16nodenextverbatimmodulesyntax) option also applies to the imports between generated payload models. + ## Languages Each language has a set of constraints which means that some typed model types are either supported or not, or it might just be the code generation library that does not yet support it. @@ -67,6 +84,7 @@ Each language has a set of constraints which means that some typed model types a Dependencies: - If validation enabled, [ajv](https://ajv.js.org/guide/getting-started.html): ^8.17.1 +- If validation enabled, [ajv-formats](https://github.com/ajv-validator/ajv-formats): ^3.0.1 #### Validation Each generated class includes built-in JSON Schema validation capabilities through two static methods: diff --git a/docs/getting-started/generators.md b/docs/getting-started/generators.md index cff7dec1..48e1b7df 100644 --- a/docs/getting-started/generators.md +++ b/docs/getting-started/generators.md @@ -36,7 +36,10 @@ Generators take your specifications (AsyncAPI, OpenAPI, or JSON Schema) and extr ```js export default { inputType: 'asyncapi', - inputPath: './my-api.yaml' + inputPath: './my-api.yaml', + generators: [ + { preset: 'payloads', outputPath: './src/__gen__/payloads' } + ] }; ``` @@ -65,27 +68,29 @@ Each generator produces different code, so have a look at each generator to get **Payload Generator** produces: ```typescript +// A companion interface is exported alongside the class, so you can construct +// a payload from a plain object. +export interface UserSignupInterface { /* ... */ } export class UserSignup { - constructor(data: UserSignupData) { /* ... */ } + constructor(input: UserSignupInterface) { /* ... */ } marshal(): string { /* ... */ } - static unmarshal(json: string): UserSignup { /* ... */ } + static unmarshal(json: string | object): UserSignup { /* ... */ } } ``` **Channels Generator** produces: ```typescript -export const Protocols = { - nats: { - publishToUserSignup: ..., - subscribeToUserSignup: ..., - jetStreamPublishToUserSignup: ... - }, - kafka: { - publishToUserSignup: ..., - subscribeToUserSignup: ... - }, - // ... other protocols -}; +// One module per protocol, re-exported from the generated barrel file +import * as nats from './nats'; +import * as kafka from './kafka'; + +export { nats, kafka }; + +// nats.publishToUserSignup({ message, nc }) +// nats.subscribeToUserSignup({ onDataCallback, nc }) +// nats.jetStreamPublishToUserSignup({ message, js }) +// kafka.produceToUserSignup({ message, kafka }) +// kafka.consumeFromUserSignup({ onDataCallback, kafka, options }) ``` ## Input Type Support diff --git a/docs/getting-started/protocols.md b/docs/getting-started/protocols.md index 544ea7a3..a879e6e2 100644 --- a/docs/getting-started/protocols.md +++ b/docs/getting-started/protocols.md @@ -50,20 +50,29 @@ export default { The `channels` generator creates protocol-specific functions for each channel in your AsyncAPI specification: -```typescript -import { Protocols } from './src/__gen__/index'; +Each protocol is exported as its own namespace from the generated barrel file, +and every generated function takes a single object argument: -const { nats, kafka } = Protocols; +```typescript +import { nats, kafka } from './src/__gen__/channels'; // NATS functions -await nats.publishToUserSignup(connection, message); -await nats.subscribeToUserSignup(connection, callback); - -// Kafka functions -await kafka.publishToUserSignup(producer, message); -await kafka.subscribeToUserSignup(consumer, callback); +await nats.publishToUserSignup({ message, nc: connection }); +await nats.subscribeToUserSignup({ onDataCallback: callback, nc: connection }); + +// Kafka functions — note Kafka uses produceTo/consumeFrom +await kafka.produceToUserSignup({ message, kafka: kafkaClient }); +await kafka.consumeFromUserSignup({ + onDataCallback: callback, + kafka: kafkaClient, + options: { fromBeginning: true, groupId: 'my-group' } +}); ``` +The exact parameters depend on the channel — channels with parameters also take +`parameters`, and channels with headers accept `headers`. See each protocol's +page for the full generated signatures. + Each protocol has unique features that are reflected in the generated code: **NATS** supports: diff --git a/docs/inputs/asyncapi.md b/docs/inputs/asyncapi.md index f8daf402..0008b37a 100644 --- a/docs/inputs/asyncapi.md +++ b/docs/inputs/asyncapi.md @@ -737,7 +737,7 @@ Generate AMQP producers and consumers for message queuing. } }, "x-the-codegen-project": { - "functionTypeMapping": ["amqp_publish"] + "functionTypeMapping": ["amqp_queue_publish"] } }, "consumeOrders": { @@ -756,7 +756,7 @@ Generate AMQP producers and consumers for message queuing. } }, "x-the-codegen-project": { - "functionTypeMapping": ["amqp_consume"] + "functionTypeMapping": ["amqp_queue_subscribe"] } } }, diff --git a/docs/migrations/v0.md b/docs/migrations/v0.md index 5e3a9895..17de6031 100644 --- a/docs/migrations/v0.md +++ b/docs/migrations/v0.md @@ -56,7 +56,7 @@ await jetStreamPublishToSendUserSignedup({ await publishToSendUserSignedup({ message, parameters, - connection + nc }); // Subscribing @@ -248,5 +248,6 @@ import * as NodeFetch from 'node-fetch'; + diff --git a/docs/protocols/amqp.md b/docs/protocols/amqp.md index ff6d6afa..b6ba1509 100644 --- a/docs/protocols/amqp.md +++ b/docs/protocols/amqp.md @@ -70,8 +70,7 @@ import * as Amqp from 'amqplib'; // Location depends on the payload generator configurations import { UserSignedup } from './__gen__/payloads/UserSignedup'; // Location depends on the channel generator configurations -import { Protocols } from './__gen__/channels'; -const { amqp } = Protocols; +import { amqp } from './__gen__/channels'; const { publishToPublishUserSignupsExchange, publishToPublishUserSignupsQueue, subscribeToConsumeUserSignupsQueue } = amqp; /** @@ -81,13 +80,20 @@ const client = await Amqp.connect('amqp://localhost'); const myPayload = new UserSignedup({displayName: 'test', email: 'test@test.dk'}); // Use exchange -await publishToPublishUserSignupsExchange(myPayload, client); +await publishToPublishUserSignupsExchange({ message: myPayload, amqp: client }); // Use queue -await publishToPublishUserSignupsQueue(myPayload, client); -await subscribeToConsumeUserSignupsQueue((message) => { - console.log(`Received message: ${message.displayName}, ${message.email}`); -}, client); +await publishToPublishUserSignupsQueue({ message: myPayload, amqp: client }); +await subscribeToConsumeUserSignupsQueue({ + onDataCallback: ({ err, msg, headers, amqpMsg }) => { + if (err) { + console.error('Error receiving message:', err); + return; + } + console.log(`Received message: ${msg?.displayName}, ${msg?.email}`); + }, + amqp: client +}); ``` diff --git a/docs/protocols/eventsource.md b/docs/protocols/eventsource.md index f86e7fcb..e0bc41e1 100644 --- a/docs/protocols/eventsource.md +++ b/docs/protocols/eventsource.md @@ -75,28 +75,31 @@ import express, { Router } from 'express' // Location depends on the payload generator configurations import { UserSignedup } from './__gen__/payloads/UserSignedup'; // Location depends on the channel generator configurations -import { Protocols } from './__gen__/channels'; -const { event_source_client } = Protocols; -const { listenForUserSignedup } = event_source_client; -const listenCallback = async ( - messageEvent: UserSignedUp | null, - parameters: UserSignedUpParameters | null, - error?: string -) => { - // Do stuff once you receive the event from the server -}; -listenForUserSignedup(listenCallback, {baseUrl: 'http://localhost:3000'}) +import { event_source } from './__gen__/channels'; +const { listenForUserSignedup, registerSendUserSignedup } = event_source; -// Use express to listen for clients registering for events +// The client-side listener takes an object callback +listenForUserSignedup({ + callback: ({ error, messageEvent }) => { + // Do stuff once you receive the event from the server + }, + options: { baseUrl: 'http://localhost:3000' } +}) + +// Use express to listen for clients registering for events. The Express +// handler keeps Express' own positional (req, res, next) convention. const router = Router() const app = express() app.use(express.json({ limit: '3000kb' })) app.use(express.urlencoded({ extended: true })) -registerSendUserSignedup(router, (req, res, next, parameters, sendEvent) => { - //Do stuff when client starts listening to the event. - //For example send a message to the client - const testMessage = new UserSignedup({displayName: 'test', email: 'test@test.dk'}); - sendEvent(testMessage); +registerSendUserSignedup({ + router, + callback: (req, res, next, parameters, sendEvent) => { + //Do stuff when client starts listening to the event. + //For example send a message to the client + const testMessage = new UserSignedup({displayName: 'test', email: 'test@test.dk'}); + sendEvent(testMessage); + } }) app.use(router) app.listen(3000) diff --git a/docs/protocols/http_client.md b/docs/protocols/http_client.md index 28e718cb..d5541281 100644 --- a/docs/protocols/http_client.md +++ b/docs/protocols/http_client.md @@ -101,18 +101,17 @@ components: ```ts // Location depends on the payload generator configurations -import { Ping } from './__gen__/payloads/Ping'; -import { Pong } from './__gen__/payloads/Pong'; +import { PingRequest } from './__gen__/payloads/PingRequest'; +import { PongResponse } from './__gen__/payloads/PongResponse'; // Location depends on the channel generator configurations -import { Protocols } from './__gen__/channels'; -const { http_client } = Protocols; -const { postPingPostRequest } = http_client; +import { http_client } from './__gen__/channels'; +const { postPostPing } = http_client; // Create a request payload -const pingMessage = new Ping({ message: 'Hello!' }); +const pingMessage = new PingRequest({ message: 'Hello!' }); // Make a simple request -const response = await postPingPostRequest({ +const response = await postPostPing({ payload: pingMessage, baseUrl: 'https://api.example.com' }); @@ -175,7 +174,7 @@ The HTTP client uses a discriminated union for authentication, providing excelle ### Bearer Token ```typescript -const response = await postPingPostRequest({ +const response = await postPostPing({ payload: message, baseUrl: 'https://api.example.com', auth: { @@ -188,7 +187,7 @@ const response = await postPingPostRequest({ ### Basic Authentication ```typescript -const response = await postPingPostRequest({ +const response = await postPostPing({ payload: message, baseUrl: 'https://api.example.com', auth: { @@ -203,7 +202,7 @@ const response = await postPingPostRequest({ ```typescript // API Key in header (default) -const response = await postPingPostRequest({ +const response = await postPostPing({ payload: message, baseUrl: 'https://api.example.com', auth: { @@ -215,7 +214,7 @@ const response = await postPingPostRequest({ }); // API Key in query parameter -const response = await postPingPostRequest({ +const response = await postPostPing({ payload: message, baseUrl: 'https://api.example.com', auth: { @@ -232,7 +231,7 @@ const response = await postPingPostRequest({ For server-to-server authentication: ```typescript -const response = await postPingPostRequest({ +const response = await postPostPing({ payload: message, baseUrl: 'https://api.example.com', auth: { @@ -255,7 +254,7 @@ const response = await postPingPostRequest({ For legacy applications requiring username/password: ```typescript -const response = await postPingPostRequest({ +const response = await postPostPing({ payload: message, baseUrl: 'https://api.example.com', auth: { @@ -281,7 +280,7 @@ For tokens obtained via browser-based flows (implicit, authorization code): // Token obtained from browser OAuth flow const accessToken = getTokenFromBrowserFlow(); -const response = await postPingPostRequest({ +const response = await postPostPing({ payload: message, baseUrl: 'https://api.example.com', auth: { @@ -303,7 +302,7 @@ const response = await postPingPostRequest({ Configure automatic retry for failed requests: ```typescript -const response = await postPingPostRequest({ +const response = await postPostPing({ payload: message, baseUrl: 'https://api.example.com', retry: { @@ -354,7 +353,7 @@ try { Customize request behavior with hooks: ```typescript -const response = await postPingPostRequest({ +const response = await postPostPing({ payload: message, baseUrl: 'https://api.example.com', hooks: { @@ -449,7 +448,7 @@ const response = await putUpdateUserItem({ Add custom headers or query parameters to any request: ```typescript -const response = await postPingPostRequest({ +const response = await postPostPing({ payload: message, baseUrl: 'https://api.example.com', additionalHeaders: { diff --git a/docs/protocols/kafka.md b/docs/protocols/kafka.md index de1bf35f..ccee224e 100644 --- a/docs/protocols/kafka.md +++ b/docs/protocols/kafka.md @@ -70,8 +70,7 @@ import { Kafka } from 'kafkajs'; // Location depends on the payload generator configurations import { UserSignedup } from './__gen__/payloads/UserSignedup'; // Location depends on the channel generator configurations -import { Protocols } from './__gen__/channels'; -const { kafka } = Protocols; +import { kafka } from './__gen__/channels'; const { consumeFromConsumeUserSignups, produceToPublishUserSignups } = kafka; /** @@ -85,26 +84,31 @@ const kafkaClient = new Kafka({ const myPayload = new UserSignedup({displayName: 'test', email: 'test@test.dk'}); // Consume the messages with the generated channel function -const consumerCallback = async ( - err, - msg: UserSignedUp | undefined, - parameters: UserSignedUpParameters | undefined, - kafkaMsg: EachMessagePayload | undefined +const consumerCallback = ( + err?: Error, + msg?: UserSignedup, + parameters?: UserSignedupParameters, + headers?: UserSignedupHeaders, + kafkaMsg?: EachMessagePayload ) => { - // Do stuff once you consumer from the topic + // Do stuff once you consume from the topic }; -const consumer = await consumeFromConsumeUserSignups( - consumerCallback, - myParameters, - kafkaClient, - { - fromBeginning: true, +const consumer = await consumeFromConsumeUserSignups({ + onDataCallback: consumerCallback, + parameters: myParameters, + kafka: kafkaClient, + options: { + fromBeginning: true, groupId: 'testId1' } -); +}); // Produce the messages with the generated channel function -const producer = await produceToPublishUserSignups(myPayload, kafkaClient); +const producer = await produceToPublishUserSignups({ + message: myPayload, + parameters: myParameters, + kafka: kafkaClient +}); ``` diff --git a/docs/protocols/mqtt.md b/docs/protocols/mqtt.md index db89e699..042cdd5c 100644 --- a/docs/protocols/mqtt.md +++ b/docs/protocols/mqtt.md @@ -92,8 +92,7 @@ import { UserSignedup } from './__gen__/payloads/UserSignedup'; // Location depends on the header generator configurations (if using headers) import { UserSignedUpHeaders } from './__gen__/headers/UserSignedUpHeaders'; // Location depends on the channel generator configurations -import { Protocols } from './__gen__/channels'; -const { mqtt } = Protocols; +import { mqtt } from './__gen__/channels'; const { publishToUserSignedup, subscribeToConsumeUserSignups } = mqtt; /** diff --git a/docs/protocols/websocket.md b/docs/protocols/websocket.md index ee22c2f5..a99aed35 100644 --- a/docs/protocols/websocket.md +++ b/docs/protocols/websocket.md @@ -103,14 +103,13 @@ const ws = new WebSocket('ws://localhost:8080/user/events/user123'); await ws.on('open', async () => { // Use generated publish function + // Channel parameters are part of the connection URL, so the publish + // function only takes the message and the socket. await publishToSendUserEvent({ message: new UserSignedUp({ userId: 'user123', email: 'user@example.com' }), - parameters: new UserEventsParameters({ - userId: 'user123' - }), ws }); }); diff --git a/examples/ecommerce-asyncapi-channels/package-lock.json b/examples/ecommerce-asyncapi-channels/package-lock.json index 1ddb67a8..1b2c675a 100644 --- a/examples/ecommerce-asyncapi-channels/package-lock.json +++ b/examples/ecommerce-asyncapi-channels/package-lock.json @@ -8,6 +8,8 @@ "name": "ecommerce-asyncapi-channels", "version": "1.0.0", "dependencies": { + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", "kafkajs": "^2.2.4", "nats": "^2.26.0" }, @@ -429,6 +431,39 @@ "undici-types": "~6.19.2" } }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/esbuild": { "version": "0.25.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", @@ -469,6 +504,28 @@ "@esbuild/win32-x64": "0.25.5" } }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", + "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -495,6 +552,12 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, "node_modules/kafkajs": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/kafkajs/-/kafkajs-2.2.4.tgz", @@ -525,6 +588,15 @@ "node": ">=10.0.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", diff --git a/examples/ecommerce-asyncapi-channels/package.json b/examples/ecommerce-asyncapi-channels/package.json index 1a437edb..795b9dce 100644 --- a/examples/ecommerce-asyncapi-channels/package.json +++ b/examples/ecommerce-asyncapi-channels/package.json @@ -21,7 +21,9 @@ ], "dependencies": { "kafkajs": "^2.2.4", - "nats": "^2.26.0" + "nats": "^2.26.0", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1" }, "devDependencies": { "@types/node": "^20.0.0", diff --git a/examples/ecommerce-asyncapi-channels/src/generated/headers/OrderCancelledHeaders.ts b/examples/ecommerce-asyncapi-channels/src/generated/headers/OrderCancelledHeaders.ts index a31e61e3..83ea276b 100644 --- a/examples/ecommerce-asyncapi-channels/src/generated/headers/OrderCancelledHeaders.ts +++ b/examples/ecommerce-asyncapi-channels/src/generated/headers/OrderCancelledHeaders.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; class OrderCancelledHeaders { private _xCorrelationId: string; private _xOrderId: string; @@ -107,6 +107,9 @@ class OrderCancelledHeaders { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); diff --git a/examples/ecommerce-asyncapi-channels/src/generated/headers/OrderCreatedHeaders.ts b/examples/ecommerce-asyncapi-channels/src/generated/headers/OrderCreatedHeaders.ts index ccac000b..cd63efe8 100644 --- a/examples/ecommerce-asyncapi-channels/src/generated/headers/OrderCreatedHeaders.ts +++ b/examples/ecommerce-asyncapi-channels/src/generated/headers/OrderCreatedHeaders.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; class OrderCreatedHeaders { private _xCorrelationId: string; private _xOrderId: string; @@ -107,6 +107,9 @@ class OrderCreatedHeaders { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); diff --git a/examples/ecommerce-asyncapi-channels/src/generated/headers/OrderLifecycleHeaders.ts b/examples/ecommerce-asyncapi-channels/src/generated/headers/OrderLifecycleHeaders.ts index e2b9df98..6347916b 100644 --- a/examples/ecommerce-asyncapi-channels/src/generated/headers/OrderLifecycleHeaders.ts +++ b/examples/ecommerce-asyncapi-channels/src/generated/headers/OrderLifecycleHeaders.ts @@ -1,5 +1,50 @@ import {OrderCreatedHeaders} from './OrderCreatedHeaders'; import {OrderUpdatedHeaders} from './OrderUpdatedHeaders'; import {OrderCancelledHeaders} from './OrderCancelledHeaders'; +import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; +import addFormatsModule from 'ajv-formats'; type OrderLifecycleHeaders = OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders; + +export function unmarshal(json: any): OrderLifecycleHeaders { + + return JSON.parse(json); +} +export function marshal(payload: OrderLifecycleHeaders) { + if(payload instanceof OrderCreatedHeaders) { +return payload.marshal(); +} +if(payload instanceof OrderUpdatedHeaders) { +return payload.marshal(); +} +if(payload instanceof OrderCancelledHeaders) { +return payload.marshal(); +} + return JSON.stringify(payload); +} + +export const theCodeGenSchema = {"$id":"OrderLifecycleHeaders","$schema":"http://json-schema.org/draft-07/schema","oneOf":[{"type":"object","required":["x-correlation-id","x-order-id","x-customer-id"],"properties":{"x-correlation-id":{"type":"string","format":"uuid"},"x-order-id":{"type":"string","format":"uuid"},"x-customer-id":{"type":"string","format":"uuid"},"x-source-service":{"type":"string"}},"$id":"OrderCreatedHeaders","$schema":"http://json-schema.org/draft-07/schema"},{"type":"object","required":["x-correlation-id","x-order-id","x-customer-id"],"properties":{"x-correlation-id":{"type":"string","format":"uuid"},"x-order-id":{"type":"string","format":"uuid"},"x-customer-id":{"type":"string","format":"uuid"},"x-source-service":{"type":"string"}},"$id":"OrderUpdatedHeaders","$schema":"http://json-schema.org/draft-07/schema"},{"type":"object","required":["x-correlation-id","x-order-id","x-customer-id"],"properties":{"x-correlation-id":{"type":"string","format":"uuid"},"x-order-id":{"type":"string","format":"uuid"},"x-customer-id":{"type":"string","format":"uuid"},"x-source-service":{"type":"string"}},"$id":"OrderCancelledHeaders","$schema":"http://json-schema.org/draft-07/schema"}]}; +export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFunction, ajvInstance?: Ajv, ajvOptions?: AjvOptions}): { valid: boolean; errors?: ErrorObject[]; } { + const {data, ajvValidatorFunction} = context ?? {}; + // Intentionally parse JSON strings to support validation of marshalled output. + // Example: validate({data: marshal(obj)}) works because marshal returns JSON string. + // Note: String 'true' will be coerced to boolean true due to JSON.parse. + const parsedData = typeof data === 'string' ? JSON.parse(data) : data; + const validate = ajvValidatorFunction ?? createValidator(context) + return { + valid: validate(parsedData), + errors: validate.errors ?? undefined, + }; +} +export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { + const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; + addFormats(ajvInstance); + + const validate = ajvInstance.compile(theCodeGenSchema); + return validate; +} + + export { OrderLifecycleHeaders }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-channels/src/generated/headers/OrderUpdatedHeaders.ts b/examples/ecommerce-asyncapi-channels/src/generated/headers/OrderUpdatedHeaders.ts index 000c6cfb..51245693 100644 --- a/examples/ecommerce-asyncapi-channels/src/generated/headers/OrderUpdatedHeaders.ts +++ b/examples/ecommerce-asyncapi-channels/src/generated/headers/OrderUpdatedHeaders.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; class OrderUpdatedHeaders { private _xCorrelationId: string; private _xOrderId: string; @@ -107,6 +107,9 @@ class OrderUpdatedHeaders { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); diff --git a/examples/ecommerce-asyncapi-channels/src/generated/kafka.ts b/examples/ecommerce-asyncapi-channels/src/generated/kafka.ts index 86afeed5..cfaace3b 100644 --- a/examples/ecommerce-asyncapi-channels/src/generated/kafka.ts +++ b/examples/ecommerce-asyncapi-channels/src/generated/kafka.ts @@ -9,7 +9,7 @@ import {Currency} from './payload/Currency'; import {Address, AddressInterface} from './payload/Address'; import {OrderStatus} from './payload/OrderStatus'; import {OrderLifecycleParameters, OrderLifecycleParametersInterface} from './parameter/OrderLifecycleParameters'; -import {OrderLifecycleHeaders} from './headers/OrderLifecycleHeaders'; +import * as OrderLifecycleHeadersModule from './headers/OrderLifecycleHeaders'; import * as Kafka from 'kafkajs'; /** @@ -28,7 +28,7 @@ function produceToPublishOrderCreated({ }: { message: OrderCreatedInterface | OrderCreated, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, - headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, + headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, kafka: Kafka.Kafka }): Promise { return new Promise(async (resolve, reject) => { @@ -81,7 +81,7 @@ function produceToPublishOrderUpdated({ }: { message: OrderUpdatedInterface | OrderUpdated, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, - headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, + headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, kafka: Kafka.Kafka }): Promise { return new Promise(async (resolve, reject) => { @@ -134,7 +134,7 @@ function produceToPublishOrderCancelled({ }: { message: OrderCancelledInterface | OrderCancelled, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, - headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, + headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, kafka: Kafka.Kafka }): Promise { return new Promise(async (resolve, reject) => { @@ -198,7 +198,7 @@ function consumeFromSubscribeToOrderEvents({ options = {fromBeginning: true, groupId: ''}, skipMessageValidation = false }: { - onDataCallback: (err?: Error, msg?: SubscribeToOrderEventsPayloadModule.SubscribeToOrderEventsPayload, parameters?: OrderLifecycleParameters, headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, kafkaMsg?: Kafka.EachMessagePayload) => void, + onDataCallback: (err?: Error, msg?: SubscribeToOrderEventsPayloadModule.SubscribeToOrderEventsPayload, parameters?: OrderLifecycleParameters, headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, kafkaMsg?: Kafka.EachMessagePayload) => void, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, kafka: Kafka.Kafka, options: {fromBeginning: boolean, groupId: string}, @@ -221,7 +221,7 @@ function consumeFromSubscribeToOrderEvents({ const parameters = OrderLifecycleParameters.createFromChannel(topic, 'orders.{action}', /^orders.([^.]*)$/); // Extract headers if present - let extractedHeaders: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders | undefined = undefined; + let extractedHeaders: OrderLifecycleHeadersModule.OrderLifecycleHeaders | undefined = undefined; if (message.headers) { const headerObj: Record = {}; for (const [key, value] of Object.entries(message.headers)) { @@ -229,7 +229,7 @@ function consumeFromSubscribeToOrderEvents({ headerObj[key] = value.toString(); } } - extractedHeaders = OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders.unmarshal(headerObj); + extractedHeaders = OrderLifecycleHeadersModule.unmarshal(headerObj); } if(!skipMessageValidation) { const {valid, errors} = SubscribeToOrderEventsPayloadModule.validate({data: receivedData, ajvValidatorFunction: validator}); diff --git a/examples/ecommerce-asyncapi-channels/src/generated/nats.ts b/examples/ecommerce-asyncapi-channels/src/generated/nats.ts index e101d374..050e25df 100644 --- a/examples/ecommerce-asyncapi-channels/src/generated/nats.ts +++ b/examples/ecommerce-asyncapi-channels/src/generated/nats.ts @@ -9,7 +9,7 @@ import {Currency} from './payload/Currency'; import {Address, AddressInterface} from './payload/Address'; import {OrderStatus} from './payload/OrderStatus'; import {OrderLifecycleParameters, OrderLifecycleParametersInterface} from './parameter/OrderLifecycleParameters'; -import {OrderLifecycleHeaders} from './headers/OrderLifecycleHeaders'; +import * as OrderLifecycleHeadersModule from './headers/OrderLifecycleHeaders'; import * as Nats from 'nats'; /** @@ -32,7 +32,7 @@ function publishToPublishOrderCreated({ }: { message: OrderCreatedInterface | OrderCreated, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, - headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, + headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, nc: Nats.NatsConnection, codec?: Nats.Codec, options?: Nats.PublishOptions @@ -81,7 +81,7 @@ function jetStreamPublishToPublishOrderCreated({ }: { message: OrderCreatedInterface | OrderCreated, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, - headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, + headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, js: Nats.JetStreamClient, codec?: Nats.Codec, options?: Partial @@ -130,7 +130,7 @@ function publishToPublishOrderUpdated({ }: { message: OrderUpdatedInterface | OrderUpdated, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, - headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, + headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, nc: Nats.NatsConnection, codec?: Nats.Codec, options?: Nats.PublishOptions @@ -179,7 +179,7 @@ function jetStreamPublishToPublishOrderUpdated({ }: { message: OrderUpdatedInterface | OrderUpdated, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, - headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, + headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, js: Nats.JetStreamClient, codec?: Nats.Codec, options?: Partial @@ -228,7 +228,7 @@ function publishToPublishOrderCancelled({ }: { message: OrderCancelledInterface | OrderCancelled, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, - headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, + headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, nc: Nats.NatsConnection, codec?: Nats.Codec, options?: Nats.PublishOptions @@ -277,7 +277,7 @@ function jetStreamPublishToPublishOrderCancelled({ }: { message: OrderCancelledInterface | OrderCancelled, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, - headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, + headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, js: Nats.JetStreamClient, codec?: Nats.Codec, options?: Partial @@ -335,7 +335,7 @@ function subscribeToSubscribeToOrderEvents({ options, skipMessageValidation = false }: { - onDataCallback: (err?: Error, msg?: SubscribeToOrderEventsPayloadModule.SubscribeToOrderEventsPayload, parameters?: OrderLifecycleParameters, headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, natsMsg?: Nats.Msg) => void, + onDataCallback: (err?: Error, msg?: SubscribeToOrderEventsPayloadModule.SubscribeToOrderEventsPayload, parameters?: OrderLifecycleParameters, headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, natsMsg?: Nats.Msg) => void, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, nc: Nats.NatsConnection, codec?: Nats.Codec, @@ -351,7 +351,7 @@ function subscribeToSubscribeToOrderEvents({ const parameters = OrderLifecycleParameters.createFromChannel(msg.subject, 'orders.{action}', /^orders.([^.]*)$/) let receivedData: any = codec.decode(msg.data); // Extract headers if present - let extractedHeaders: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders | undefined = undefined; + let extractedHeaders: OrderLifecycleHeadersModule.OrderLifecycleHeaders | undefined = undefined; if (msg.headers) { const headerObj: Record = {}; // NATS headers support both iteration and get() method @@ -366,7 +366,7 @@ function subscribeToSubscribeToOrderEvents({ headerObj[key] = value; } } - extractedHeaders = OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders.unmarshal(headerObj); + extractedHeaders = OrderLifecycleHeadersModule.unmarshal(headerObj); } if(!skipMessageValidation) { const {valid, errors} = SubscribeToOrderEventsPayloadModule.validate({data: receivedData, ajvValidatorFunction: validator}); @@ -413,7 +413,7 @@ function jetStreamPullSubscribeToSubscribeToOrderEvents({ codec = Nats.JSONCodec(), skipMessageValidation = false }: { - onDataCallback: (err?: Error, msg?: SubscribeToOrderEventsPayloadModule.SubscribeToOrderEventsPayload, parameters?: OrderLifecycleParameters, headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, jetstreamMsg?: Nats.JsMsg) => void, + onDataCallback: (err?: Error, msg?: SubscribeToOrderEventsPayloadModule.SubscribeToOrderEventsPayload, parameters?: OrderLifecycleParameters, headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, jetstreamMsg?: Nats.JsMsg) => void, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, js: Nats.JetStreamClient, options: Nats.ConsumerOptsBuilder | Partial, @@ -429,7 +429,7 @@ function jetStreamPullSubscribeToSubscribeToOrderEvents({ const parameters = OrderLifecycleParameters.createFromChannel(msg.subject, 'orders.{action}', /^orders.([^.]*)$/) let receivedData: any = codec.decode(msg.data); // Extract headers if present - let extractedHeaders: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders | undefined = undefined; + let extractedHeaders: OrderLifecycleHeadersModule.OrderLifecycleHeaders | undefined = undefined; if (msg.headers) { const headerObj: Record = {}; // NATS headers support both iteration and get() method @@ -444,7 +444,7 @@ function jetStreamPullSubscribeToSubscribeToOrderEvents({ headerObj[key] = value; } } - extractedHeaders = OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders.unmarshal(headerObj); + extractedHeaders = OrderLifecycleHeadersModule.unmarshal(headerObj); } if(!skipMessageValidation) { const {valid, errors} = SubscribeToOrderEventsPayloadModule.validate({data: receivedData, ajvValidatorFunction: validator}); @@ -491,7 +491,7 @@ function jetStreamPushSubscriptionFromSubscribeToOrderEvents({ codec = Nats.JSONCodec(), skipMessageValidation = false }: { - onDataCallback: (err?: Error, msg?: SubscribeToOrderEventsPayloadModule.SubscribeToOrderEventsPayload, parameters?: OrderLifecycleParameters, headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, jetstreamMsg?: Nats.JsMsg) => void, + onDataCallback: (err?: Error, msg?: SubscribeToOrderEventsPayloadModule.SubscribeToOrderEventsPayload, parameters?: OrderLifecycleParameters, headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, jetstreamMsg?: Nats.JsMsg) => void, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, js: Nats.JetStreamClient, options: Nats.ConsumerOptsBuilder | Partial, @@ -507,7 +507,7 @@ function jetStreamPushSubscriptionFromSubscribeToOrderEvents({ const parameters = OrderLifecycleParameters.createFromChannel(msg.subject, 'orders.{action}', /^orders.([^.]*)$/) let receivedData: any = codec.decode(msg.data); // Extract headers if present - let extractedHeaders: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders | undefined = undefined; + let extractedHeaders: OrderLifecycleHeadersModule.OrderLifecycleHeaders | undefined = undefined; if (msg.headers) { const headerObj: Record = {}; // NATS headers support both iteration and get() method @@ -522,7 +522,7 @@ function jetStreamPushSubscriptionFromSubscribeToOrderEvents({ headerObj[key] = value; } } - extractedHeaders = OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders.unmarshal(headerObj); + extractedHeaders = OrderLifecycleHeadersModule.unmarshal(headerObj); } if(!skipMessageValidation) { const {valid, errors} = SubscribeToOrderEventsPayloadModule.validate({data: receivedData, ajvValidatorFunction: validator}); diff --git a/examples/ecommerce-asyncapi-channels/src/generated/parameter/OrderLifecycleParameters.ts b/examples/ecommerce-asyncapi-channels/src/generated/parameter/OrderLifecycleParameters.ts index f73eafe2..8b251091 100644 --- a/examples/ecommerce-asyncapi-channels/src/generated/parameter/OrderLifecycleParameters.ts +++ b/examples/ecommerce-asyncapi-channels/src/generated/parameter/OrderLifecycleParameters.ts @@ -42,4 +42,5 @@ class OrderLifecycleParameters { return parameters; } } -export { OrderLifecycleParameters, OrderLifecycleParametersInterface }; \ No newline at end of file +export { OrderLifecycleParameters }; +export type { OrderLifecycleParametersInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-channels/src/generated/payload/Address.ts b/examples/ecommerce-asyncapi-channels/src/generated/payload/Address.ts index d4b5a267..3bdbb653 100644 --- a/examples/ecommerce-asyncapi-channels/src/generated/payload/Address.ts +++ b/examples/ecommerce-asyncapi-channels/src/generated/payload/Address.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface AddressInterface { street: string city: string @@ -120,6 +120,9 @@ class Address { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -127,4 +130,5 @@ class Address { } } -export { Address, AddressInterface }; \ No newline at end of file +export { Address }; +export type { AddressInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-channels/src/generated/payload/Money.ts b/examples/ecommerce-asyncapi-channels/src/generated/payload/Money.ts index 72c26296..ccdaef6f 100644 --- a/examples/ecommerce-asyncapi-channels/src/generated/payload/Money.ts +++ b/examples/ecommerce-asyncapi-channels/src/generated/payload/Money.ts @@ -1,6 +1,6 @@ import {Currency} from './Currency'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface MoneyInterface { amount: number currency: Currency @@ -88,6 +88,9 @@ class Money { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -95,4 +98,5 @@ class Money { } } -export { Money, MoneyInterface }; \ No newline at end of file +export { Money }; +export type { MoneyInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderCancelled.ts b/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderCancelled.ts index 9dcfacc6..de3c4372 100644 --- a/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderCancelled.ts +++ b/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderCancelled.ts @@ -1,6 +1,6 @@ import {Money} from './Money'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface OrderCancelledInterface { orderId: string reason: string @@ -109,6 +109,9 @@ class OrderCancelled { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -116,4 +119,5 @@ class OrderCancelled { } } -export { OrderCancelled, OrderCancelledInterface }; \ No newline at end of file +export { OrderCancelled }; +export type { OrderCancelledInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderCreated.ts b/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderCreated.ts index ccc37a23..b78947b7 100644 --- a/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderCreated.ts +++ b/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderCreated.ts @@ -2,7 +2,7 @@ import {OrderItem} from './OrderItem'; import {Money} from './Money'; import {Address} from './Address'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface OrderCreatedInterface { orderId: string customerId: string @@ -139,6 +139,9 @@ class OrderCreated { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -146,4 +149,5 @@ class OrderCreated { } } -export { OrderCreated, OrderCreatedInterface }; \ No newline at end of file +export { OrderCreated }; +export type { OrderCreatedInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderItem.ts b/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderItem.ts index b4972a02..b6384a37 100644 --- a/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderItem.ts +++ b/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderItem.ts @@ -1,6 +1,6 @@ import {Money} from './Money'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface OrderItemInterface { productId: string quantity: number @@ -121,6 +121,9 @@ class OrderItem { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -128,4 +131,5 @@ class OrderItem { } } -export { OrderItem, OrderItemInterface }; \ No newline at end of file +export { OrderItem }; +export type { OrderItemInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderLifecyclePayload.ts b/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderLifecyclePayload.ts index dfd62abb..1edce78e 100644 --- a/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderLifecyclePayload.ts +++ b/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderLifecyclePayload.ts @@ -3,7 +3,7 @@ import {OrderUpdated} from './OrderUpdated'; import {OrderCancelled} from './OrderCancelled'; import {OrderStatus} from './OrderStatus'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; type OrderLifecyclePayload = OrderCreated | OrderUpdated | OrderCancelled; export function unmarshal(json: any): OrderLifecyclePayload { @@ -42,6 +42,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderUpdated.ts b/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderUpdated.ts index c7dca941..47f5651b 100644 --- a/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderUpdated.ts +++ b/examples/ecommerce-asyncapi-channels/src/generated/payload/OrderUpdated.ts @@ -1,6 +1,6 @@ import {OrderStatus} from './OrderStatus'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface OrderUpdatedInterface { orderId: string status: OrderStatus @@ -121,6 +121,9 @@ class OrderUpdated { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -128,4 +131,5 @@ class OrderUpdated { } } -export { OrderUpdated, OrderUpdatedInterface }; \ No newline at end of file +export { OrderUpdated }; +export type { OrderUpdatedInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-channels/src/generated/payload/SubscribeToOrderEventsPayload.ts b/examples/ecommerce-asyncapi-channels/src/generated/payload/SubscribeToOrderEventsPayload.ts index 7281d4fa..a0ed3be1 100644 --- a/examples/ecommerce-asyncapi-channels/src/generated/payload/SubscribeToOrderEventsPayload.ts +++ b/examples/ecommerce-asyncapi-channels/src/generated/payload/SubscribeToOrderEventsPayload.ts @@ -3,7 +3,7 @@ import {OrderUpdated} from './OrderUpdated'; import {OrderCancelled} from './OrderCancelled'; import {OrderStatus} from './OrderStatus'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; type SubscribeToOrderEventsPayload = OrderCreated | OrderUpdated | OrderCancelled; export function unmarshal(json: any): SubscribeToOrderEventsPayload { @@ -42,6 +42,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/examples/ecommerce-asyncapi-channels/src/index.ts b/examples/ecommerce-asyncapi-channels/src/index.ts index b319e683..f2759de9 100644 --- a/examples/ecommerce-asyncapi-channels/src/index.ts +++ b/examples/ecommerce-asyncapi-channels/src/index.ts @@ -3,7 +3,7 @@ */ // Import the generated protocols and types -import { Protocols } from './generated/index'; +import { nats, kafka } from './generated/index'; import { OrderCreated } from './generated/payload/OrderCreated'; import { OrderUpdated } from './generated/payload/OrderUpdated'; import { OrderCancelled } from './generated/payload/OrderCancelled'; @@ -99,7 +99,7 @@ async function demonstrateProtocolFunctions() { const orderCreatedParams = new OrderLifecycleParameters({ action: 'created' }); // Publish order created with NATS - await Protocols.nats.publishToPublishOrderCreated({ + await nats.publishToPublishOrderCreated({ message: orderCreatedMessage, parameters: orderCreatedParams, nc: natsConnection @@ -119,7 +119,7 @@ async function demonstrateProtocolFunctions() { const orderUpdatedParams = new OrderLifecycleParameters({ action: 'updated' }); // Publish order updated with Kafka - await Protocols.kafka.produceToPublishOrderUpdated({ + await kafka.produceToPublishOrderUpdated({ message: orderUpdatedMessage, parameters: orderUpdatedParams, kafka: kafkaClient @@ -141,7 +141,7 @@ async function demonstrateProtocolFunctions() { const orderCancelledParams = new OrderLifecycleParameters({ action: 'cancelled' }); // Publish order cancelled with NATS - await Protocols.nats.publishToPublishOrderCancelled({ + await nats.publishToPublishOrderCancelled({ message: orderCancelledMessage, parameters: orderCancelledParams, nc: natsConnection @@ -151,7 +151,7 @@ async function demonstrateProtocolFunctions() { // Subscribe to order events with NATS (for real-time processing) const orderSubscriptionParams = new OrderLifecycleParameters({ action: 'created' }); - await Protocols.nats.subscribeToSubscribeToOrderEvents({ + await nats.subscribeToSubscribeToOrderEvents({ onDataCallback: (err, message, parameters, natsMsg) => { if (err) { console.error('[NATS Handler] Error processing order event:', err.message); @@ -180,7 +180,7 @@ async function demonstrateProtocolFunctions() { // Subscribe to order events with Kafka (for analytics and reporting) const kafkaSubscriptionParams = new OrderLifecycleParameters({ action: 'created' }); - await Protocols.kafka.consumeFromSubscribeToOrderEvents({ + await kafka.consumeFromSubscribeToOrderEvents({ onDataCallback: (err, message, parameters, kafkaMsg) => { if (err) { console.error('[Kafka Handler] Error processing order event:', err.message); diff --git a/examples/ecommerce-asyncapi-client/package-lock.json b/examples/ecommerce-asyncapi-client/package-lock.json index d5082f90..320364d2 100644 --- a/examples/ecommerce-asyncapi-client/package-lock.json +++ b/examples/ecommerce-asyncapi-client/package-lock.json @@ -8,6 +8,8 @@ "name": "ecommerce-asyncapi-client", "version": "1.0.0", "dependencies": { + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", "nats": "^2.26.0" }, "devDependencies": { @@ -428,6 +430,39 @@ "undici-types": "~6.19.2" } }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/esbuild": { "version": "0.25.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", @@ -468,6 +503,28 @@ "@esbuild/win32-x64": "0.25.5" } }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", + "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -494,6 +551,12 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, "node_modules/nats": { "version": "2.29.3", "resolved": "https://registry.npmjs.org/nats/-/nats-2.29.3.tgz", @@ -516,6 +579,15 @@ "node": ">=10.0.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", diff --git a/examples/ecommerce-asyncapi-client/package.json b/examples/ecommerce-asyncapi-client/package.json index 93e78614..bede4c9b 100644 --- a/examples/ecommerce-asyncapi-client/package.json +++ b/examples/ecommerce-asyncapi-client/package.json @@ -12,7 +12,7 @@ }, "keywords": [ "asyncapi", - "codegen", + "codegen", "client", "sdk", "messaging", @@ -21,7 +21,9 @@ "lifecycle-events" ], "dependencies": { - "nats": "^2.26.0" + "nats": "^2.26.0", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1" }, "devDependencies": { "@types/node": "^20.0.0", @@ -31,4 +33,4 @@ "engines": { "node": ">=18.0.0" } -} \ No newline at end of file +} diff --git a/examples/ecommerce-asyncapi-client/src/generated/NatsClient.ts b/examples/ecommerce-asyncapi-client/src/generated/NatsClient.ts index ff9ecc9a..df39c007 100644 --- a/examples/ecommerce-asyncapi-client/src/generated/NatsClient.ts +++ b/examples/ecommerce-asyncapi-client/src/generated/NatsClient.ts @@ -20,6 +20,7 @@ export {Address}; export {OrderStatus}; import {OrderLifecycleParameters, OrderLifecycleParametersInterface} from './channels/parameter/OrderLifecycleParameters'; export {OrderLifecycleParameters}; +import * as OrderLifecycleHeadersModule from './channels/headers/OrderLifecycleHeaders'; //Import channel functions import * as nats from './channels/nats'; @@ -309,7 +310,7 @@ export class NatsClient { options, flush }: { - onDataCallback: (err?: Error, msg?: OrderEventsPayloadModule.OrderEventsPayload, parameters?: OrderLifecycleParameters, natsMsg?: Nats.Msg) => void, + onDataCallback: (err?: Error, msg?: OrderEventsPayloadModule.OrderEventsPayload, parameters?: OrderLifecycleParameters, headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, natsMsg?: Nats.Msg) => void, parameters: OrderLifecycleParameters, options?: Nats.SubscriptionOptions, flush?: boolean @@ -349,7 +350,7 @@ export class NatsClient { parameters, options = {} }: { - onDataCallback: (err?: Error, msg?: OrderEventsPayloadModule.OrderEventsPayload, parameters?: OrderLifecycleParameters, jetstreamMsg?: Nats.JsMsg) => void, + onDataCallback: (err?: Error, msg?: OrderEventsPayloadModule.OrderEventsPayload, parameters?: OrderLifecycleParameters, headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, jetstreamMsg?: Nats.JsMsg) => void, parameters: OrderLifecycleParameters, options: Nats.ConsumerOptsBuilder | Partial }): Promise { @@ -386,7 +387,7 @@ export class NatsClient { parameters, options = {} }: { - onDataCallback: (err?: Error, msg?: OrderEventsPayloadModule.OrderEventsPayload, parameters?: OrderLifecycleParameters, jetstreamMsg?: Nats.JsMsg) => void, + onDataCallback: (err?: Error, msg?: OrderEventsPayloadModule.OrderEventsPayload, parameters?: OrderLifecycleParameters, headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, jetstreamMsg?: Nats.JsMsg) => void, parameters: OrderLifecycleParameters, options: Nats.ConsumerOptsBuilder | Partial }): Promise { diff --git a/examples/ecommerce-asyncapi-client/src/generated/channels/headers/OrderCancelledHeaders.ts b/examples/ecommerce-asyncapi-client/src/generated/channels/headers/OrderCancelledHeaders.ts index a31e61e3..83ea276b 100644 --- a/examples/ecommerce-asyncapi-client/src/generated/channels/headers/OrderCancelledHeaders.ts +++ b/examples/ecommerce-asyncapi-client/src/generated/channels/headers/OrderCancelledHeaders.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; class OrderCancelledHeaders { private _xCorrelationId: string; private _xOrderId: string; @@ -107,6 +107,9 @@ class OrderCancelledHeaders { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); diff --git a/examples/ecommerce-asyncapi-client/src/generated/channels/headers/OrderCreatedHeaders.ts b/examples/ecommerce-asyncapi-client/src/generated/channels/headers/OrderCreatedHeaders.ts index ccac000b..cd63efe8 100644 --- a/examples/ecommerce-asyncapi-client/src/generated/channels/headers/OrderCreatedHeaders.ts +++ b/examples/ecommerce-asyncapi-client/src/generated/channels/headers/OrderCreatedHeaders.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; class OrderCreatedHeaders { private _xCorrelationId: string; private _xOrderId: string; @@ -107,6 +107,9 @@ class OrderCreatedHeaders { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); diff --git a/examples/ecommerce-asyncapi-client/src/generated/channels/headers/OrderLifecycleHeaders.ts b/examples/ecommerce-asyncapi-client/src/generated/channels/headers/OrderLifecycleHeaders.ts index e2b9df98..6347916b 100644 --- a/examples/ecommerce-asyncapi-client/src/generated/channels/headers/OrderLifecycleHeaders.ts +++ b/examples/ecommerce-asyncapi-client/src/generated/channels/headers/OrderLifecycleHeaders.ts @@ -1,5 +1,50 @@ import {OrderCreatedHeaders} from './OrderCreatedHeaders'; import {OrderUpdatedHeaders} from './OrderUpdatedHeaders'; import {OrderCancelledHeaders} from './OrderCancelledHeaders'; +import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; +import addFormatsModule from 'ajv-formats'; type OrderLifecycleHeaders = OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders; + +export function unmarshal(json: any): OrderLifecycleHeaders { + + return JSON.parse(json); +} +export function marshal(payload: OrderLifecycleHeaders) { + if(payload instanceof OrderCreatedHeaders) { +return payload.marshal(); +} +if(payload instanceof OrderUpdatedHeaders) { +return payload.marshal(); +} +if(payload instanceof OrderCancelledHeaders) { +return payload.marshal(); +} + return JSON.stringify(payload); +} + +export const theCodeGenSchema = {"$id":"OrderLifecycleHeaders","$schema":"http://json-schema.org/draft-07/schema","oneOf":[{"type":"object","required":["x-correlation-id","x-order-id","x-customer-id"],"properties":{"x-correlation-id":{"type":"string","format":"uuid"},"x-order-id":{"type":"string","format":"uuid"},"x-customer-id":{"type":"string","format":"uuid"},"x-source-service":{"type":"string"}},"$id":"OrderCreatedHeaders","$schema":"http://json-schema.org/draft-07/schema"},{"type":"object","required":["x-correlation-id","x-order-id","x-customer-id"],"properties":{"x-correlation-id":{"type":"string","format":"uuid"},"x-order-id":{"type":"string","format":"uuid"},"x-customer-id":{"type":"string","format":"uuid"},"x-source-service":{"type":"string"}},"$id":"OrderUpdatedHeaders","$schema":"http://json-schema.org/draft-07/schema"},{"type":"object","required":["x-correlation-id","x-order-id","x-customer-id"],"properties":{"x-correlation-id":{"type":"string","format":"uuid"},"x-order-id":{"type":"string","format":"uuid"},"x-customer-id":{"type":"string","format":"uuid"},"x-source-service":{"type":"string"}},"$id":"OrderCancelledHeaders","$schema":"http://json-schema.org/draft-07/schema"}]}; +export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFunction, ajvInstance?: Ajv, ajvOptions?: AjvOptions}): { valid: boolean; errors?: ErrorObject[]; } { + const {data, ajvValidatorFunction} = context ?? {}; + // Intentionally parse JSON strings to support validation of marshalled output. + // Example: validate({data: marshal(obj)}) works because marshal returns JSON string. + // Note: String 'true' will be coerced to boolean true due to JSON.parse. + const parsedData = typeof data === 'string' ? JSON.parse(data) : data; + const validate = ajvValidatorFunction ?? createValidator(context) + return { + valid: validate(parsedData), + errors: validate.errors ?? undefined, + }; +} +export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { + const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; + addFormats(ajvInstance); + + const validate = ajvInstance.compile(theCodeGenSchema); + return validate; +} + + export { OrderLifecycleHeaders }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-client/src/generated/channels/headers/OrderUpdatedHeaders.ts b/examples/ecommerce-asyncapi-client/src/generated/channels/headers/OrderUpdatedHeaders.ts index 000c6cfb..51245693 100644 --- a/examples/ecommerce-asyncapi-client/src/generated/channels/headers/OrderUpdatedHeaders.ts +++ b/examples/ecommerce-asyncapi-client/src/generated/channels/headers/OrderUpdatedHeaders.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; class OrderUpdatedHeaders { private _xCorrelationId: string; private _xOrderId: string; @@ -107,6 +107,9 @@ class OrderUpdatedHeaders { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); diff --git a/examples/ecommerce-asyncapi-client/src/generated/channels/nats.ts b/examples/ecommerce-asyncapi-client/src/generated/channels/nats.ts index 4613e172..6a926374 100644 --- a/examples/ecommerce-asyncapi-client/src/generated/channels/nats.ts +++ b/examples/ecommerce-asyncapi-client/src/generated/channels/nats.ts @@ -9,7 +9,7 @@ import {Currency} from './payload/Currency'; import {Address, AddressInterface} from './payload/Address'; import {OrderStatus} from './payload/OrderStatus'; import {OrderLifecycleParameters, OrderLifecycleParametersInterface} from './parameter/OrderLifecycleParameters'; -import {OrderLifecycleHeaders} from './headers/OrderLifecycleHeaders'; +import * as OrderLifecycleHeadersModule from './headers/OrderLifecycleHeaders'; import * as Nats from 'nats'; /** @@ -32,7 +32,7 @@ function publishToOrderCreated({ }: { message: OrderCreatedInterface | OrderCreated, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, - headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, + headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, nc: Nats.NatsConnection, codec?: Nats.Codec, options?: Nats.PublishOptions @@ -81,7 +81,7 @@ function jetStreamPublishToOrderCreated({ }: { message: OrderCreatedInterface | OrderCreated, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, - headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, + headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, js: Nats.JetStreamClient, codec?: Nats.Codec, options?: Partial @@ -130,7 +130,7 @@ function publishToOrderUpdated({ }: { message: OrderUpdatedInterface | OrderUpdated, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, - headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, + headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, nc: Nats.NatsConnection, codec?: Nats.Codec, options?: Nats.PublishOptions @@ -179,7 +179,7 @@ function jetStreamPublishToOrderUpdated({ }: { message: OrderUpdatedInterface | OrderUpdated, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, - headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, + headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, js: Nats.JetStreamClient, codec?: Nats.Codec, options?: Partial @@ -228,7 +228,7 @@ function publishToOrderCancelled({ }: { message: OrderCancelledInterface | OrderCancelled, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, - headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, + headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, nc: Nats.NatsConnection, codec?: Nats.Codec, options?: Nats.PublishOptions @@ -277,7 +277,7 @@ function jetStreamPublishToOrderCancelled({ }: { message: OrderCancelledInterface | OrderCancelled, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, - headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, + headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, js: Nats.JetStreamClient, codec?: Nats.Codec, options?: Partial @@ -335,7 +335,7 @@ function subscribeToOrderEvents({ options, skipMessageValidation = false }: { - onDataCallback: (err?: Error, msg?: OrderEventsPayloadModule.OrderEventsPayload, parameters?: OrderLifecycleParameters, headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, natsMsg?: Nats.Msg) => void, + onDataCallback: (err?: Error, msg?: OrderEventsPayloadModule.OrderEventsPayload, parameters?: OrderLifecycleParameters, headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, natsMsg?: Nats.Msg) => void, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, nc: Nats.NatsConnection, codec?: Nats.Codec, @@ -351,7 +351,7 @@ function subscribeToOrderEvents({ const parameters = OrderLifecycleParameters.createFromChannel(msg.subject, 'orders.{action}', /^orders.([^.]*)$/) let receivedData: any = codec.decode(msg.data); // Extract headers if present - let extractedHeaders: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders | undefined = undefined; + let extractedHeaders: OrderLifecycleHeadersModule.OrderLifecycleHeaders | undefined = undefined; if (msg.headers) { const headerObj: Record = {}; // NATS headers support both iteration and get() method @@ -366,7 +366,7 @@ function subscribeToOrderEvents({ headerObj[key] = value; } } - extractedHeaders = OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders.unmarshal(headerObj); + extractedHeaders = OrderLifecycleHeadersModule.unmarshal(headerObj); } if(!skipMessageValidation) { const {valid, errors} = OrderEventsPayloadModule.validate({data: receivedData, ajvValidatorFunction: validator}); @@ -413,7 +413,7 @@ function jetStreamPullSubscribeToOrderEvents({ codec = Nats.JSONCodec(), skipMessageValidation = false }: { - onDataCallback: (err?: Error, msg?: OrderEventsPayloadModule.OrderEventsPayload, parameters?: OrderLifecycleParameters, headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, jetstreamMsg?: Nats.JsMsg) => void, + onDataCallback: (err?: Error, msg?: OrderEventsPayloadModule.OrderEventsPayload, parameters?: OrderLifecycleParameters, headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, jetstreamMsg?: Nats.JsMsg) => void, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, js: Nats.JetStreamClient, options: Nats.ConsumerOptsBuilder | Partial, @@ -429,7 +429,7 @@ function jetStreamPullSubscribeToOrderEvents({ const parameters = OrderLifecycleParameters.createFromChannel(msg.subject, 'orders.{action}', /^orders.([^.]*)$/) let receivedData: any = codec.decode(msg.data); // Extract headers if present - let extractedHeaders: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders | undefined = undefined; + let extractedHeaders: OrderLifecycleHeadersModule.OrderLifecycleHeaders | undefined = undefined; if (msg.headers) { const headerObj: Record = {}; // NATS headers support both iteration and get() method @@ -444,7 +444,7 @@ function jetStreamPullSubscribeToOrderEvents({ headerObj[key] = value; } } - extractedHeaders = OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders.unmarshal(headerObj); + extractedHeaders = OrderLifecycleHeadersModule.unmarshal(headerObj); } if(!skipMessageValidation) { const {valid, errors} = OrderEventsPayloadModule.validate({data: receivedData, ajvValidatorFunction: validator}); @@ -491,7 +491,7 @@ function jetStreamPushSubscriptionFromOrderEvents({ codec = Nats.JSONCodec(), skipMessageValidation = false }: { - onDataCallback: (err?: Error, msg?: OrderEventsPayloadModule.OrderEventsPayload, parameters?: OrderLifecycleParameters, headers?: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders, jetstreamMsg?: Nats.JsMsg) => void, + onDataCallback: (err?: Error, msg?: OrderEventsPayloadModule.OrderEventsPayload, parameters?: OrderLifecycleParameters, headers?: OrderLifecycleHeadersModule.OrderLifecycleHeaders, jetstreamMsg?: Nats.JsMsg) => void, parameters: OrderLifecycleParametersInterface | OrderLifecycleParameters, js: Nats.JetStreamClient, options: Nats.ConsumerOptsBuilder | Partial, @@ -507,7 +507,7 @@ function jetStreamPushSubscriptionFromOrderEvents({ const parameters = OrderLifecycleParameters.createFromChannel(msg.subject, 'orders.{action}', /^orders.([^.]*)$/) let receivedData: any = codec.decode(msg.data); // Extract headers if present - let extractedHeaders: OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders | undefined = undefined; + let extractedHeaders: OrderLifecycleHeadersModule.OrderLifecycleHeaders | undefined = undefined; if (msg.headers) { const headerObj: Record = {}; // NATS headers support both iteration and get() method @@ -522,7 +522,7 @@ function jetStreamPushSubscriptionFromOrderEvents({ headerObj[key] = value; } } - extractedHeaders = OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders.unmarshal(headerObj); + extractedHeaders = OrderLifecycleHeadersModule.unmarshal(headerObj); } if(!skipMessageValidation) { const {valid, errors} = OrderEventsPayloadModule.validate({data: receivedData, ajvValidatorFunction: validator}); diff --git a/examples/ecommerce-asyncapi-client/src/generated/channels/parameter/OrderLifecycleParameters.ts b/examples/ecommerce-asyncapi-client/src/generated/channels/parameter/OrderLifecycleParameters.ts index f73eafe2..8b251091 100644 --- a/examples/ecommerce-asyncapi-client/src/generated/channels/parameter/OrderLifecycleParameters.ts +++ b/examples/ecommerce-asyncapi-client/src/generated/channels/parameter/OrderLifecycleParameters.ts @@ -42,4 +42,5 @@ class OrderLifecycleParameters { return parameters; } } -export { OrderLifecycleParameters, OrderLifecycleParametersInterface }; \ No newline at end of file +export { OrderLifecycleParameters }; +export type { OrderLifecycleParametersInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-client/src/generated/channels/payload/Address.ts b/examples/ecommerce-asyncapi-client/src/generated/channels/payload/Address.ts index d4b5a267..3bdbb653 100644 --- a/examples/ecommerce-asyncapi-client/src/generated/channels/payload/Address.ts +++ b/examples/ecommerce-asyncapi-client/src/generated/channels/payload/Address.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface AddressInterface { street: string city: string @@ -120,6 +120,9 @@ class Address { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -127,4 +130,5 @@ class Address { } } -export { Address, AddressInterface }; \ No newline at end of file +export { Address }; +export type { AddressInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-client/src/generated/channels/payload/Money.ts b/examples/ecommerce-asyncapi-client/src/generated/channels/payload/Money.ts index 72c26296..ccdaef6f 100644 --- a/examples/ecommerce-asyncapi-client/src/generated/channels/payload/Money.ts +++ b/examples/ecommerce-asyncapi-client/src/generated/channels/payload/Money.ts @@ -1,6 +1,6 @@ import {Currency} from './Currency'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface MoneyInterface { amount: number currency: Currency @@ -88,6 +88,9 @@ class Money { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -95,4 +98,5 @@ class Money { } } -export { Money, MoneyInterface }; \ No newline at end of file +export { Money }; +export type { MoneyInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderCancelled.ts b/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderCancelled.ts index 9dcfacc6..de3c4372 100644 --- a/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderCancelled.ts +++ b/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderCancelled.ts @@ -1,6 +1,6 @@ import {Money} from './Money'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface OrderCancelledInterface { orderId: string reason: string @@ -109,6 +109,9 @@ class OrderCancelled { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -116,4 +119,5 @@ class OrderCancelled { } } -export { OrderCancelled, OrderCancelledInterface }; \ No newline at end of file +export { OrderCancelled }; +export type { OrderCancelledInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderCreated.ts b/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderCreated.ts index ccc37a23..b78947b7 100644 --- a/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderCreated.ts +++ b/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderCreated.ts @@ -2,7 +2,7 @@ import {OrderItem} from './OrderItem'; import {Money} from './Money'; import {Address} from './Address'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface OrderCreatedInterface { orderId: string customerId: string @@ -139,6 +139,9 @@ class OrderCreated { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -146,4 +149,5 @@ class OrderCreated { } } -export { OrderCreated, OrderCreatedInterface }; \ No newline at end of file +export { OrderCreated }; +export type { OrderCreatedInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderEventsPayload.ts b/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderEventsPayload.ts index 3a3806ab..8ca03228 100644 --- a/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderEventsPayload.ts +++ b/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderEventsPayload.ts @@ -3,7 +3,7 @@ import {OrderUpdated} from './OrderUpdated'; import {OrderCancelled} from './OrderCancelled'; import {OrderStatus} from './OrderStatus'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; type OrderEventsPayload = OrderCreated | OrderUpdated | OrderCancelled; export function unmarshal(json: any): OrderEventsPayload { @@ -42,6 +42,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderItem.ts b/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderItem.ts index b4972a02..b6384a37 100644 --- a/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderItem.ts +++ b/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderItem.ts @@ -1,6 +1,6 @@ import {Money} from './Money'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface OrderItemInterface { productId: string quantity: number @@ -121,6 +121,9 @@ class OrderItem { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -128,4 +131,5 @@ class OrderItem { } } -export { OrderItem, OrderItemInterface }; \ No newline at end of file +export { OrderItem }; +export type { OrderItemInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderLifecyclePayload.ts b/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderLifecyclePayload.ts index dfd62abb..1edce78e 100644 --- a/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderLifecyclePayload.ts +++ b/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderLifecyclePayload.ts @@ -3,7 +3,7 @@ import {OrderUpdated} from './OrderUpdated'; import {OrderCancelled} from './OrderCancelled'; import {OrderStatus} from './OrderStatus'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; type OrderLifecyclePayload = OrderCreated | OrderUpdated | OrderCancelled; export function unmarshal(json: any): OrderLifecyclePayload { @@ -42,6 +42,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderUpdated.ts b/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderUpdated.ts index c7dca941..47f5651b 100644 --- a/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderUpdated.ts +++ b/examples/ecommerce-asyncapi-client/src/generated/channels/payload/OrderUpdated.ts @@ -1,6 +1,6 @@ import {OrderStatus} from './OrderStatus'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface OrderUpdatedInterface { orderId: string status: OrderStatus @@ -121,6 +121,9 @@ class OrderUpdated { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -128,4 +131,5 @@ class OrderUpdated { } } -export { OrderUpdated, OrderUpdatedInterface }; \ No newline at end of file +export { OrderUpdated }; +export type { OrderUpdatedInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-client/src/index.ts b/examples/ecommerce-asyncapi-client/src/index.ts index e22cb77f..17dbd0bb 100644 --- a/examples/ecommerce-asyncapi-client/src/index.ts +++ b/examples/ecommerce-asyncapi-client/src/index.ts @@ -42,7 +42,7 @@ function createSampleOrder() { country: 'US', postalCode: '94102' }), - createdAt: new Date().toISOString() + createdAt: new Date() }); } @@ -94,7 +94,7 @@ class OrderService { const orderUpdate = new OrderUpdated({ orderId, status, - updatedAt: new Date().toISOString(), + updatedAt: new Date(), reason: `Order status changed to ${status}`, updatedFields: ['status'] }); @@ -115,7 +115,7 @@ class OrderService { const orderCancellation = new OrderCancelled({ orderId, reason, - cancelledAt: new Date().toISOString(), + cancelledAt: new Date(), refundAmount: new Money({ amount: 309895, // $3098.95 in cents currency: Currency.USD @@ -254,7 +254,7 @@ class DurableOrderProcessor { const updateMessage = new OrderUpdated({ orderId: order?.orderId || 'unknown', status: OrderStatus.PROCESSING, - updatedAt: new Date().toISOString(), + updatedAt: new Date(), reason: 'Order processing started by fulfillment system', updatedFields: ['status'] }); diff --git a/examples/ecommerce-asyncapi-headers/package-lock.json b/examples/ecommerce-asyncapi-headers/package-lock.json index ab2614bb..feb37ae4 100644 --- a/examples/ecommerce-asyncapi-headers/package-lock.json +++ b/examples/ecommerce-asyncapi-headers/package-lock.json @@ -8,6 +8,10 @@ "name": "ecommerce-asyncapi-headers", "version": "1.0.0", "license": "Apache-2.0", + "dependencies": { + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1" + }, "devDependencies": { "rimraf": "^5.0.5", "tsx": "^4.19.4" @@ -440,6 +444,39 @@ "node": ">=14" } }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/ansi-regex": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", @@ -563,6 +600,28 @@ "@esbuild/win32-x64": "0.25.5" } }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", + "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/foreground-child": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", @@ -655,6 +714,12 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, "node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", @@ -716,6 +781,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", diff --git a/examples/ecommerce-asyncapi-headers/package.json b/examples/ecommerce-asyncapi-headers/package.json index 78ccb60d..7a34c88e 100644 --- a/examples/ecommerce-asyncapi-headers/package.json +++ b/examples/ecommerce-asyncapi-headers/package.json @@ -8,7 +8,10 @@ "demo": "tsx src/index.ts", "clean": "rimraf src/generated" }, - "dependencies": {}, + "dependencies": { + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1" + }, "devDependencies": { "rimraf": "^5.0.5", "tsx": "^4.19.4" @@ -25,4 +28,4 @@ ], "author": "The Codegen Project", "license": "Apache-2.0" -} \ No newline at end of file +} diff --git a/examples/ecommerce-asyncapi-headers/src/generated/headers/AdminActionPerformedHeaders.ts b/examples/ecommerce-asyncapi-headers/src/generated/headers/AdminActionPerformedHeaders.ts index 51df54d1..a421e534 100644 --- a/examples/ecommerce-asyncapi-headers/src/generated/headers/AdminActionPerformedHeaders.ts +++ b/examples/ecommerce-asyncapi-headers/src/generated/headers/AdminActionPerformedHeaders.ts @@ -2,7 +2,7 @@ import {AdminActionType} from './AdminActionType'; import {PermissionLevel} from './PermissionLevel'; import {AuditLevel} from './AuditLevel'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; class AdminActionPerformedHeaders { private _xCorrelationId: string; private _xTenantId: string; @@ -242,6 +242,9 @@ class AdminActionPerformedHeaders { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); diff --git a/examples/ecommerce-asyncapi-headers/src/generated/headers/InventoryUpdatedHeaders.ts b/examples/ecommerce-asyncapi-headers/src/generated/headers/InventoryUpdatedHeaders.ts index 2266e5b7..8a8f3f25 100644 --- a/examples/ecommerce-asyncapi-headers/src/generated/headers/InventoryUpdatedHeaders.ts +++ b/examples/ecommerce-asyncapi-headers/src/generated/headers/InventoryUpdatedHeaders.ts @@ -1,6 +1,6 @@ import {InventoryUpdateType} from './InventoryUpdateType'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; class InventoryUpdatedHeaders { private _xCorrelationId: string; private _xTenantId: string; @@ -195,6 +195,9 @@ class InventoryUpdatedHeaders { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); diff --git a/examples/ecommerce-asyncapi-headers/src/generated/headers/NotificationSentHeaders.ts b/examples/ecommerce-asyncapi-headers/src/generated/headers/NotificationSentHeaders.ts index bc20b3e4..fa2f003c 100644 --- a/examples/ecommerce-asyncapi-headers/src/generated/headers/NotificationSentHeaders.ts +++ b/examples/ecommerce-asyncapi-headers/src/generated/headers/NotificationSentHeaders.ts @@ -2,7 +2,7 @@ import {NotificationType} from './NotificationType'; import {NotificationChannel} from './NotificationChannel'; import {NotificationProvider} from './NotificationProvider'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; class NotificationSentHeaders { private _xCorrelationId: string; private _xTenantId: string; @@ -212,6 +212,9 @@ class NotificationSentHeaders { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); diff --git a/examples/ecommerce-asyncapi-headers/src/generated/headers/OrderCreatedHeaders.ts b/examples/ecommerce-asyncapi-headers/src/generated/headers/OrderCreatedHeaders.ts index e7af1f98..1256bc8a 100644 --- a/examples/ecommerce-asyncapi-headers/src/generated/headers/OrderCreatedHeaders.ts +++ b/examples/ecommerce-asyncapi-headers/src/generated/headers/OrderCreatedHeaders.ts @@ -1,6 +1,6 @@ import {SourceService} from './SourceService'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; class OrderCreatedHeaders { private _xCorrelationId: string; private _xTenantId: string; @@ -180,6 +180,9 @@ class OrderCreatedHeaders { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); diff --git a/examples/ecommerce-asyncapi-headers/src/generated/headers/OrderEventsHeaders.ts b/examples/ecommerce-asyncapi-headers/src/generated/headers/OrderEventsHeaders.ts index adac64e3..298ccb20 100644 --- a/examples/ecommerce-asyncapi-headers/src/generated/headers/OrderEventsHeaders.ts +++ b/examples/ecommerce-asyncapi-headers/src/generated/headers/OrderEventsHeaders.ts @@ -1,4 +1,55 @@ import {OrderCreatedHeaders} from './OrderCreatedHeaders'; import {OrderStatusChangedHeaders} from './OrderStatusChangedHeaders'; +import {SourceService} from './SourceService'; +import {ActorType} from './ActorType'; +import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; +import addFormatsModule from 'ajv-formats'; type OrderEventsHeaders = OrderCreatedHeaders | OrderStatusChangedHeaders; + +export function unmarshal(json: any): OrderEventsHeaders { + if(typeof json === 'object') { + if(json.x-source-service === SourceService.WEB_MINUS_APP) { + return OrderCreatedHeaders.unmarshal(json); + } + if(json.x-actor-type === ActorType.USER) { + return OrderStatusChangedHeaders.unmarshal(json); + } + } + return JSON.parse(json); +} +export function marshal(payload: OrderEventsHeaders) { + if(payload instanceof OrderCreatedHeaders) { +return payload.marshal(); +} +if(payload instanceof OrderStatusChangedHeaders) { +return payload.marshal(); +} + return JSON.stringify(payload); +} + +export const theCodeGenSchema = {"$id":"OrderEventsHeaders","$schema":"http://json-schema.org/draft-07/schema","oneOf":[{"type":"object","allOf":[{"type":"object","required":["x-correlation-id","x-tenant-id"],"properties":{"x-correlation-id":{"type":"string","format":"uuid","description":"Unique correlation ID for request tracing"},"x-tenant-id":{"type":"string","description":"Multi-tenant identifier"},"x-timestamp":{"type":"string","format":"date-time","description":"Event creation timestamp"}}},{"type":"object","properties":{"authorization":{"type":"string","pattern":"^Bearer [A-Za-z0-9\\-\\._~\\+\\/]+=*$","description":"JWT token for authentication"}}},{"type":"object","properties":{"x-source-service":{"type":"string","enum":["web-app","mobile-app","admin-panel"],"description":"Service that originated the event"},"x-api-version":{"type":"string","pattern":"^v[0-9]+$","description":"API version used","default":"v1"},"x-request-id":{"type":"string","format":"uuid","description":"Original request ID from the client"}}},{"type":"object","required":["x-user-id"],"properties":{"x-user-id":{"type":"string","format":"uuid","description":"ID of the user who created the order"}}}],"$id":"OrderCreatedHeaders","$schema":"http://json-schema.org/draft-07/schema"},{"type":"object","allOf":[{"type":"object","required":["x-correlation-id","x-tenant-id"],"properties":{"x-correlation-id":{"type":"string","format":"uuid","description":"Unique correlation ID for request tracing"},"x-tenant-id":{"type":"string","description":"Multi-tenant identifier"},"x-timestamp":{"type":"string","format":"date-time","description":"Event creation timestamp"}}},{"type":"object","properties":{"x-actor-id":{"type":"string","format":"uuid","description":"ID of user/system that triggered the change"},"x-actor-type":{"type":"string","enum":["user","system","admin"],"description":"Type of actor that triggered the change"}}},{"type":"object","required":["x-event-type"],"properties":{"x-event-type":{"type":"string","enum":["status-change","cancellation","refund"],"description":"Type of status change event"},"x-previous-status":{"type":"string","enum":["pending","confirmed","processing","shipped","delivered","cancelled"],"description":"Order status values"},"x-reason-code":{"type":"string","enum":["customer-request","payment-failed","inventory-unavailable","fraud-detected"],"description":"Reason code for status change"},"x-priority":{"type":"string","enum":["low","normal","high","urgent"],"default":"normal","description":"Processing priority"}}}],"$id":"OrderStatusChangedHeaders","$schema":"http://json-schema.org/draft-07/schema"}]}; +export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFunction, ajvInstance?: Ajv, ajvOptions?: AjvOptions}): { valid: boolean; errors?: ErrorObject[]; } { + const {data, ajvValidatorFunction} = context ?? {}; + // Intentionally parse JSON strings to support validation of marshalled output. + // Example: validate({data: marshal(obj)}) works because marshal returns JSON string. + // Note: String 'true' will be coerced to boolean true due to JSON.parse. + const parsedData = typeof data === 'string' ? JSON.parse(data) : data; + const validate = ajvValidatorFunction ?? createValidator(context) + return { + valid: validate(parsedData), + errors: validate.errors ?? undefined, + }; +} +export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { + const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; + addFormats(ajvInstance); + + const validate = ajvInstance.compile(theCodeGenSchema); + return validate; +} + + export { OrderEventsHeaders }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-headers/src/generated/headers/OrderStatusChangedHeaders.ts b/examples/ecommerce-asyncapi-headers/src/generated/headers/OrderStatusChangedHeaders.ts index fef8a7dc..76465d57 100644 --- a/examples/ecommerce-asyncapi-headers/src/generated/headers/OrderStatusChangedHeaders.ts +++ b/examples/ecommerce-asyncapi-headers/src/generated/headers/OrderStatusChangedHeaders.ts @@ -4,7 +4,7 @@ import {OrderStatus} from './OrderStatus'; import {OrderReasonCode} from './OrderReasonCode'; import {Priority} from './Priority'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; class OrderStatusChangedHeaders { private _xCorrelationId: string; private _xTenantId: string; @@ -199,6 +199,9 @@ class OrderStatusChangedHeaders { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); diff --git a/examples/ecommerce-asyncapi-headers/src/generated/headers/PaymentProcessedHeaders.ts b/examples/ecommerce-asyncapi-headers/src/generated/headers/PaymentProcessedHeaders.ts index d77d4d96..5cbd7acd 100644 --- a/examples/ecommerce-asyncapi-headers/src/generated/headers/PaymentProcessedHeaders.ts +++ b/examples/ecommerce-asyncapi-headers/src/generated/headers/PaymentProcessedHeaders.ts @@ -1,7 +1,7 @@ import {PaymentProvider} from './PaymentProvider'; import {PaymentMethod} from './PaymentMethod'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; class PaymentProcessedHeaders { private _xCorrelationId: string; private _xTenantId: string; @@ -226,6 +226,9 @@ class PaymentProcessedHeaders { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); diff --git a/examples/ecommerce-asyncapi-headers/src/generated/headers/UserBehaviorTrackedHeaders.ts b/examples/ecommerce-asyncapi-headers/src/generated/headers/UserBehaviorTrackedHeaders.ts index 632d9bce..6404e533 100644 --- a/examples/ecommerce-asyncapi-headers/src/generated/headers/UserBehaviorTrackedHeaders.ts +++ b/examples/ecommerce-asyncapi-headers/src/generated/headers/UserBehaviorTrackedHeaders.ts @@ -1,7 +1,7 @@ import {DeviceType} from './DeviceType'; import {Platform} from './Platform'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; class UserBehaviorTrackedHeaders { private _xCorrelationId: string; private _xTenantId: string; @@ -226,6 +226,9 @@ class UserBehaviorTrackedHeaders { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); diff --git a/examples/ecommerce-asyncapi-parameters/src/generated/parameters/InventoryUpdatesParameters.ts b/examples/ecommerce-asyncapi-parameters/src/generated/parameters/InventoryUpdatesParameters.ts index bf46ff76..134ada0b 100644 --- a/examples/ecommerce-asyncapi-parameters/src/generated/parameters/InventoryUpdatesParameters.ts +++ b/examples/ecommerce-asyncapi-parameters/src/generated/parameters/InventoryUpdatesParameters.ts @@ -77,4 +77,5 @@ class InventoryUpdatesParameters { return parameters; } } -export { InventoryUpdatesParameters, InventoryUpdatesParametersInterface }; \ No newline at end of file +export { InventoryUpdatesParameters }; +export type { InventoryUpdatesParametersInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-parameters/src/generated/parameters/OrderEventsParameters.ts b/examples/ecommerce-asyncapi-parameters/src/generated/parameters/OrderEventsParameters.ts index 586a432d..8d17514b 100644 --- a/examples/ecommerce-asyncapi-parameters/src/generated/parameters/OrderEventsParameters.ts +++ b/examples/ecommerce-asyncapi-parameters/src/generated/parameters/OrderEventsParameters.ts @@ -59,4 +59,5 @@ class OrderEventsParameters { return parameters; } } -export { OrderEventsParameters, OrderEventsParametersInterface }; \ No newline at end of file +export { OrderEventsParameters }; +export type { OrderEventsParametersInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-parameters/src/generated/parameters/ProductUpdatesParameters.ts b/examples/ecommerce-asyncapi-parameters/src/generated/parameters/ProductUpdatesParameters.ts index 0880f726..9d0527d8 100644 --- a/examples/ecommerce-asyncapi-parameters/src/generated/parameters/ProductUpdatesParameters.ts +++ b/examples/ecommerce-asyncapi-parameters/src/generated/parameters/ProductUpdatesParameters.ts @@ -59,4 +59,5 @@ class ProductUpdatesParameters { return parameters; } } -export { ProductUpdatesParameters, ProductUpdatesParametersInterface }; \ No newline at end of file +export { ProductUpdatesParameters }; +export type { ProductUpdatesParametersInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-parameters/src/generated/parameters/SupportTicketsParameters.ts b/examples/ecommerce-asyncapi-parameters/src/generated/parameters/SupportTicketsParameters.ts index 4bbeb8da..31cbf381 100644 --- a/examples/ecommerce-asyncapi-parameters/src/generated/parameters/SupportTicketsParameters.ts +++ b/examples/ecommerce-asyncapi-parameters/src/generated/parameters/SupportTicketsParameters.ts @@ -76,4 +76,5 @@ class SupportTicketsParameters { return parameters; } } -export { SupportTicketsParameters, SupportTicketsParametersInterface }; \ No newline at end of file +export { SupportTicketsParameters }; +export type { SupportTicketsParametersInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-parameters/src/generated/parameters/TenantAnalyticsParameters.ts b/examples/ecommerce-asyncapi-parameters/src/generated/parameters/TenantAnalyticsParameters.ts index fa046f88..861742b3 100644 --- a/examples/ecommerce-asyncapi-parameters/src/generated/parameters/TenantAnalyticsParameters.ts +++ b/examples/ecommerce-asyncapi-parameters/src/generated/parameters/TenantAnalyticsParameters.ts @@ -93,4 +93,5 @@ class TenantAnalyticsParameters { return parameters; } } -export { TenantAnalyticsParameters, TenantAnalyticsParametersInterface }; \ No newline at end of file +export { TenantAnalyticsParameters }; +export type { TenantAnalyticsParametersInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-parameters/src/generated/parameters/UserActivityParameters.ts b/examples/ecommerce-asyncapi-parameters/src/generated/parameters/UserActivityParameters.ts index 05dbf459..24d8084e 100644 --- a/examples/ecommerce-asyncapi-parameters/src/generated/parameters/UserActivityParameters.ts +++ b/examples/ecommerce-asyncapi-parameters/src/generated/parameters/UserActivityParameters.ts @@ -43,4 +43,5 @@ class UserActivityParameters { return parameters; } } -export { UserActivityParameters, UserActivityParametersInterface }; \ No newline at end of file +export { UserActivityParameters }; +export type { UserActivityParametersInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-parameters/src/generated/parameters/UserNotificationsParameters.ts b/examples/ecommerce-asyncapi-parameters/src/generated/parameters/UserNotificationsParameters.ts index 66eaef18..b7d31b13 100644 --- a/examples/ecommerce-asyncapi-parameters/src/generated/parameters/UserNotificationsParameters.ts +++ b/examples/ecommerce-asyncapi-parameters/src/generated/parameters/UserNotificationsParameters.ts @@ -76,4 +76,5 @@ class UserNotificationsParameters { return parameters; } } -export { UserNotificationsParameters, UserNotificationsParametersInterface }; \ No newline at end of file +export { UserNotificationsParameters }; +export type { UserNotificationsParametersInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-payload/src/generated/models/Address.ts b/examples/ecommerce-asyncapi-payload/src/generated/models/Address.ts index 2d3d7393..8f89bc0d 100644 --- a/examples/ecommerce-asyncapi-payload/src/generated/models/Address.ts +++ b/examples/ecommerce-asyncapi-payload/src/generated/models/Address.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface AddressInterface { street: string city: string @@ -123,6 +123,9 @@ class Address { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -130,4 +133,5 @@ class Address { } } -export { Address, AddressInterface }; \ No newline at end of file +export { Address }; +export type { AddressInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-payload/src/generated/models/Attachment.ts b/examples/ecommerce-asyncapi-payload/src/generated/models/Attachment.ts index b2665eca..2ea711de 100644 --- a/examples/ecommerce-asyncapi-payload/src/generated/models/Attachment.ts +++ b/examples/ecommerce-asyncapi-payload/src/generated/models/Attachment.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface AttachmentInterface { filename?: string contentType?: string @@ -96,6 +96,9 @@ class Attachment { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -103,4 +106,5 @@ class Attachment { } } -export { Attachment, AttachmentInterface }; \ No newline at end of file +export { Attachment }; +export type { AttachmentInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-payload/src/generated/models/EmailNotification.ts b/examples/ecommerce-asyncapi-payload/src/generated/models/EmailNotification.ts index 59ba2f39..3c7b4626 100644 --- a/examples/ecommerce-asyncapi-payload/src/generated/models/EmailNotification.ts +++ b/examples/ecommerce-asyncapi-payload/src/generated/models/EmailNotification.ts @@ -1,6 +1,6 @@ import {Attachment} from './Attachment'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface EmailNotificationInterface { recipientId: string subject: string @@ -121,6 +121,9 @@ class EmailNotification { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -128,4 +131,5 @@ class EmailNotification { } } -export { EmailNotification, EmailNotificationInterface }; \ No newline at end of file +export { EmailNotification }; +export type { EmailNotificationInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-payload/src/generated/models/NotificationSent.ts b/examples/ecommerce-asyncapi-payload/src/generated/models/NotificationSent.ts index fc6dd656..7b6ece2e 100644 --- a/examples/ecommerce-asyncapi-payload/src/generated/models/NotificationSent.ts +++ b/examples/ecommerce-asyncapi-payload/src/generated/models/NotificationSent.ts @@ -2,7 +2,7 @@ import {EmailNotification} from './EmailNotification'; import {SmsNotification} from './SmsNotification'; import {PushNotification} from './PushNotification'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; type NotificationSent = EmailNotification | SmsNotification | PushNotification; export function unmarshal(json: any): NotificationSent { @@ -47,6 +47,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/examples/ecommerce-asyncapi-payload/src/generated/models/OrderCreated.ts b/examples/ecommerce-asyncapi-payload/src/generated/models/OrderCreated.ts index 04731593..c24f9532 100644 --- a/examples/ecommerce-asyncapi-payload/src/generated/models/OrderCreated.ts +++ b/examples/ecommerce-asyncapi-payload/src/generated/models/OrderCreated.ts @@ -2,7 +2,7 @@ import {OrderItem} from './OrderItem'; import {Currency} from './Currency'; import {Address} from './Address'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface OrderCreatedInterface { orderId: string customerId: string @@ -172,6 +172,9 @@ class OrderCreated { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -179,4 +182,5 @@ class OrderCreated { } } -export { OrderCreated, OrderCreatedInterface }; \ No newline at end of file +export { OrderCreated }; +export type { OrderCreatedInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-payload/src/generated/models/OrderEventsPayload.ts b/examples/ecommerce-asyncapi-payload/src/generated/models/OrderEventsPayload.ts index 8eef81a2..f2c05843 100644 --- a/examples/ecommerce-asyncapi-payload/src/generated/models/OrderEventsPayload.ts +++ b/examples/ecommerce-asyncapi-payload/src/generated/models/OrderEventsPayload.ts @@ -3,7 +3,7 @@ import {OrderStatusChanged} from './OrderStatusChanged'; import {Currency} from './Currency'; import {OrderStatus} from './OrderStatus'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; type OrderEventsPayload = OrderCreated | OrderStatusChanged; export function unmarshal(json: any): OrderEventsPayload { @@ -42,6 +42,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/examples/ecommerce-asyncapi-payload/src/generated/models/OrderItem.ts b/examples/ecommerce-asyncapi-payload/src/generated/models/OrderItem.ts index 43ec4a96..c3d10889 100644 --- a/examples/ecommerce-asyncapi-payload/src/generated/models/OrderItem.ts +++ b/examples/ecommerce-asyncapi-payload/src/generated/models/OrderItem.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface OrderItemInterface { productId: string quantity: number @@ -126,6 +126,9 @@ class OrderItem { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -133,4 +136,5 @@ class OrderItem { } } -export { OrderItem, OrderItemInterface }; \ No newline at end of file +export { OrderItem }; +export type { OrderItemInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-payload/src/generated/models/OrderStatusChanged.ts b/examples/ecommerce-asyncapi-payload/src/generated/models/OrderStatusChanged.ts index e5c9cbe3..e7673e9a 100644 --- a/examples/ecommerce-asyncapi-payload/src/generated/models/OrderStatusChanged.ts +++ b/examples/ecommerce-asyncapi-payload/src/generated/models/OrderStatusChanged.ts @@ -1,6 +1,6 @@ import {OrderStatus} from './OrderStatus'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface OrderStatusChangedInterface { orderId: string previousStatus: OrderStatus @@ -124,6 +124,9 @@ class OrderStatusChanged { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -131,4 +134,5 @@ class OrderStatusChanged { } } -export { OrderStatusChanged, OrderStatusChangedInterface }; \ No newline at end of file +export { OrderStatusChanged }; +export type { OrderStatusChangedInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-payload/src/generated/models/PaymentProcessed.ts b/examples/ecommerce-asyncapi-payload/src/generated/models/PaymentProcessed.ts index d1b45ae6..beb6219d 100644 --- a/examples/ecommerce-asyncapi-payload/src/generated/models/PaymentProcessed.ts +++ b/examples/ecommerce-asyncapi-payload/src/generated/models/PaymentProcessed.ts @@ -1,7 +1,7 @@ import {Currency} from './Currency'; import {PaymentStatus} from './PaymentStatus'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface PaymentProcessedInterface { paymentId: string orderId: string @@ -149,6 +149,9 @@ class PaymentProcessed { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -156,4 +159,5 @@ class PaymentProcessed { } } -export { PaymentProcessed, PaymentProcessedInterface }; \ No newline at end of file +export { PaymentProcessed }; +export type { PaymentProcessedInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-payload/src/generated/models/PushNotification.ts b/examples/ecommerce-asyncapi-payload/src/generated/models/PushNotification.ts index 096ccb15..842a2d47 100644 --- a/examples/ecommerce-asyncapi-payload/src/generated/models/PushNotification.ts +++ b/examples/ecommerce-asyncapi-payload/src/generated/models/PushNotification.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface PushNotificationInterface { recipientId: string title: string @@ -114,6 +114,9 @@ class PushNotification { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -121,4 +124,5 @@ class PushNotification { } } -export { PushNotification, PushNotificationInterface }; \ No newline at end of file +export { PushNotification }; +export type { PushNotificationInterface }; \ No newline at end of file diff --git a/examples/ecommerce-asyncapi-payload/src/generated/models/SmsNotification.ts b/examples/ecommerce-asyncapi-payload/src/generated/models/SmsNotification.ts index 82a471aa..7f7dd321 100644 --- a/examples/ecommerce-asyncapi-payload/src/generated/models/SmsNotification.ts +++ b/examples/ecommerce-asyncapi-payload/src/generated/models/SmsNotification.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface SmsNotificationInterface { recipientId: string message: string @@ -90,6 +90,9 @@ class SmsNotification { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -97,4 +100,5 @@ class SmsNotification { } } -export { SmsNotification, SmsNotificationInterface }; \ No newline at end of file +export { SmsNotification }; +export type { SmsNotificationInterface }; \ No newline at end of file diff --git a/examples/openapi-http-client/src/generated/parameter/GetV2ConnectReferenceIdParameters.ts b/examples/openapi-http-client/src/generated/parameter/GetV2ConnectReferenceIdParameters.ts index 7a73074a..43fd94be 100644 --- a/examples/openapi-http-client/src/generated/parameter/GetV2ConnectReferenceIdParameters.ts +++ b/examples/openapi-http-client/src/generated/parameter/GetV2ConnectReferenceIdParameters.ts @@ -118,4 +118,5 @@ class GetV2ConnectReferenceIdParameters { return result; } } -export { GetV2ConnectReferenceIdParameters, GetV2ConnectReferenceIdParametersInterface }; \ No newline at end of file +export { GetV2ConnectReferenceIdParameters }; +export type { GetV2ConnectReferenceIdParametersInterface }; \ No newline at end of file diff --git a/examples/openapi-http-client/src/generated/parameter/GetV2UsersSafepayAccountIdBankAccountsParameters.ts b/examples/openapi-http-client/src/generated/parameter/GetV2UsersSafepayAccountIdBankAccountsParameters.ts index 971de2cb..b6bcf988 100644 --- a/examples/openapi-http-client/src/generated/parameter/GetV2UsersSafepayAccountIdBankAccountsParameters.ts +++ b/examples/openapi-http-client/src/generated/parameter/GetV2UsersSafepayAccountIdBankAccountsParameters.ts @@ -118,4 +118,5 @@ class GetV2UsersSafepayAccountIdBankAccountsParameters { return result; } } -export { GetV2UsersSafepayAccountIdBankAccountsParameters, GetV2UsersSafepayAccountIdBankAccountsParametersInterface }; \ No newline at end of file +export { GetV2UsersSafepayAccountIdBankAccountsParameters }; +export type { GetV2UsersSafepayAccountIdBankAccountsParametersInterface }; \ No newline at end of file diff --git a/examples/openapi-http-client/src/generated/payload/BankAccount.ts b/examples/openapi-http-client/src/generated/payload/BankAccount.ts index 7a5a699f..0e604d38 100644 --- a/examples/openapi-http-client/src/generated/payload/BankAccount.ts +++ b/examples/openapi-http-client/src/generated/payload/BankAccount.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface BankAccountInterface { id?: string iban?: string @@ -96,6 +96,9 @@ class BankAccount { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -103,4 +106,5 @@ class BankAccount { } } -export { BankAccount, BankAccountInterface }; \ No newline at end of file +export { BankAccount }; +export type { BankAccountInterface }; \ No newline at end of file diff --git a/examples/openapi-http-client/src/generated/payload/GetConnectModel.ts b/examples/openapi-http-client/src/generated/payload/GetConnectModel.ts index 4b973dd0..518b5a9b 100644 --- a/examples/openapi-http-client/src/generated/payload/GetConnectModel.ts +++ b/examples/openapi-http-client/src/generated/payload/GetConnectModel.ts @@ -1,6 +1,6 @@ import {Status} from './Status'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface GetConnectModelInterface { referenceId?: string safepayAccountId?: string @@ -97,6 +97,9 @@ class GetConnectModel { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -104,4 +107,5 @@ class GetConnectModel { } } -export { GetConnectModel, GetConnectModelInterface }; \ No newline at end of file +export { GetConnectModel }; +export type { GetConnectModelInterface }; \ No newline at end of file diff --git a/examples/openapi-http-client/src/generated/payload/GetV2ConnectReferenceIdResponse_200.ts b/examples/openapi-http-client/src/generated/payload/GetV2ConnectReferenceIdResponse_200.ts index f1b9bf12..5c1035df 100644 --- a/examples/openapi-http-client/src/generated/payload/GetV2ConnectReferenceIdResponse_200.ts +++ b/examples/openapi-http-client/src/generated/payload/GetV2ConnectReferenceIdResponse_200.ts @@ -1,6 +1,6 @@ import {Status} from './Status'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface GetV2ConnectReferenceIdResponse_200Interface { referenceId?: string safepayAccountId?: string @@ -97,6 +97,9 @@ class GetV2ConnectReferenceIdResponse_200 { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -104,4 +107,5 @@ class GetV2ConnectReferenceIdResponse_200 { } } -export { GetV2ConnectReferenceIdResponse_200, GetV2ConnectReferenceIdResponse_200Interface }; \ No newline at end of file +export { GetV2ConnectReferenceIdResponse_200 }; +export type { GetV2ConnectReferenceIdResponse_200Interface }; \ No newline at end of file diff --git a/examples/openapi-http-client/src/generated/payload/GetV2UsersSafepayAccountIdBankAccountsResponse_200.ts b/examples/openapi-http-client/src/generated/payload/GetV2UsersSafepayAccountIdBankAccountsResponse_200.ts index 80cb4534..bd065a4d 100644 --- a/examples/openapi-http-client/src/generated/payload/GetV2UsersSafepayAccountIdBankAccountsResponse_200.ts +++ b/examples/openapi-http-client/src/generated/payload/GetV2UsersSafepayAccountIdBankAccountsResponse_200.ts @@ -1,6 +1,6 @@ import {BankAccount} from './BankAccount'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface GetV2UsersSafepayAccountIdBankAccountsResponse_200Interface { bankAccounts?: BankAccount[] additionalProperties?: Record @@ -79,6 +79,9 @@ class GetV2UsersSafepayAccountIdBankAccountsResponse_200 { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -86,4 +89,5 @@ class GetV2UsersSafepayAccountIdBankAccountsResponse_200 { } } -export { GetV2UsersSafepayAccountIdBankAccountsResponse_200, GetV2UsersSafepayAccountIdBankAccountsResponse_200Interface }; \ No newline at end of file +export { GetV2UsersSafepayAccountIdBankAccountsResponse_200 }; +export type { GetV2UsersSafepayAccountIdBankAccountsResponse_200Interface }; \ No newline at end of file diff --git a/examples/openapi-http-client/src/generated/payload/InitializeModel.ts b/examples/openapi-http-client/src/generated/payload/InitializeModel.ts index dce7b9c9..e2bea5cf 100644 --- a/examples/openapi-http-client/src/generated/payload/InitializeModel.ts +++ b/examples/openapi-http-client/src/generated/payload/InitializeModel.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface InitializeModelInterface { referenceId?: string connectUrl?: string @@ -84,6 +84,9 @@ class InitializeModel { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -91,4 +94,5 @@ class InitializeModel { } } -export { InitializeModel, InitializeModelInterface }; \ No newline at end of file +export { InitializeModel }; +export type { InitializeModelInterface }; \ No newline at end of file diff --git a/examples/openapi-http-client/src/generated/payload/InitializeRequest.ts b/examples/openapi-http-client/src/generated/payload/InitializeRequest.ts index af34d425..09cc1282 100644 --- a/examples/openapi-http-client/src/generated/payload/InitializeRequest.ts +++ b/examples/openapi-http-client/src/generated/payload/InitializeRequest.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface InitializeRequestInterface { returnUrl: string skipKyc?: boolean @@ -84,6 +84,9 @@ class InitializeRequest { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -91,4 +94,5 @@ class InitializeRequest { } } -export { InitializeRequest, InitializeRequestInterface }; \ No newline at end of file +export { InitializeRequest }; +export type { InitializeRequestInterface }; \ No newline at end of file diff --git a/examples/openapi-http-client/src/generated/payload/PostV2ConnectRequest.ts b/examples/openapi-http-client/src/generated/payload/PostV2ConnectRequest.ts index e2caea1b..61c66c1d 100644 --- a/examples/openapi-http-client/src/generated/payload/PostV2ConnectRequest.ts +++ b/examples/openapi-http-client/src/generated/payload/PostV2ConnectRequest.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface PostV2ConnectRequestInterface { returnUrl: string skipKyc?: boolean @@ -84,6 +84,9 @@ class PostV2ConnectRequest { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -91,4 +94,5 @@ class PostV2ConnectRequest { } } -export { PostV2ConnectRequest, PostV2ConnectRequestInterface }; \ No newline at end of file +export { PostV2ConnectRequest }; +export type { PostV2ConnectRequestInterface }; \ No newline at end of file diff --git a/examples/openapi-http-client/src/generated/payload/PostV2ConnectResponse_200.ts b/examples/openapi-http-client/src/generated/payload/PostV2ConnectResponse_200.ts index a2e05fbc..93fb84eb 100644 --- a/examples/openapi-http-client/src/generated/payload/PostV2ConnectResponse_200.ts +++ b/examples/openapi-http-client/src/generated/payload/PostV2ConnectResponse_200.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface PostV2ConnectResponse_200Interface { referenceId?: string connectUrl?: string @@ -84,6 +84,9 @@ class PostV2ConnectResponse_200 { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -91,4 +94,5 @@ class PostV2ConnectResponse_200 { } } -export { PostV2ConnectResponse_200, PostV2ConnectResponse_200Interface }; \ No newline at end of file +export { PostV2ConnectResponse_200 }; +export type { PostV2ConnectResponse_200Interface }; \ No newline at end of file diff --git a/examples/typescript-library/package-lock.json b/examples/typescript-library/package-lock.json index 8d2296c4..80af52ba 100644 --- a/examples/typescript-library/package-lock.json +++ b/examples/typescript-library/package-lock.json @@ -8,6 +8,10 @@ "name": "typescript-library", "version": "1.0.0", "license": "Apache-2.0", + "dependencies": { + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1" + }, "devDependencies": { "@the-codegen-project/cli": "^0", "rimraf": "5.0.5", @@ -17,26 +21,34 @@ }, "../..": { "name": "@the-codegen-project/cli", - "version": "0.7.0", + "version": "0.80.0", "dev": true, "license": "Apache-2.0", "dependencies": { - "@asyncapi/avro-schema-parser": "^3.0.22", - "@asyncapi/modelina": "^4.0.0-next.35", - "@asyncapi/openapi-schema-parser": "^3.0.22", - "@asyncapi/parser": "^3.0.14", - "@asyncapi/protobuf-schema-parser": "^3.2.12", - "@asyncapi/raml-dt-schema-parser": "^4.0.22", + "@apidevtools/json-schema-ref-parser": "^14.2.0", + "@asyncapi/avro-schema-parser": "^3.0.24", + "@asyncapi/modelina": "^6.0.0-next.14", + "@asyncapi/openapi-schema-parser": "^3.0.24", + "@asyncapi/parser": "^3.6.0", + "@asyncapi/protobuf-schema-parser": "^3.5.1", + "@asyncapi/raml-dt-schema-parser": "^4.0.24", "@oclif/core": "^3.26.3", "@oclif/errors": "^1.3.6", - "@oclif/plugin-autocomplete": "^3.0.16", + "@oclif/plugin-autocomplete": "^3.2.45", "@oclif/plugin-help": "^6.0.21", "@oclif/plugin-version": "^2.0.17", - "graphology": "^0.25.4", + "@readme/openapi-parser": "^5.0.1", + "chokidar": "^4.0.3", + "comment-json": "^4.6.2", + "cosmiconfig": "^9.0.0", + "graphology": "^0.26.0", "inquirer": "^8.2.6", - "supports-esm": "1.0.0", - "yaml": "^2.4.5", - "zod": "^3.23.8" + "openapi-types": "^12.1.3", + "picocolors": "^1.1.1", + "uuid": "^11.1.0", + "yaml": "^2.8.0", + "zod": "^3.25.76", + "zod-validation-error": "^3.3.0" }, "bin": { "codegen": "bin/run.mjs" @@ -48,19 +60,24 @@ "@swc/jest": "^0.2.23", "@types/inquirer": "^9.0.7", "@types/jest": "^29.5.12", - "@types/node": "^18", + "@types/node": "^22", "@types/rimraf": "^4.0.5", - "@typescript-eslint/eslint-plugin": "^6.7.5", - "@typescript-eslint/parser": "^6.7.5", + "@types/uuid": "^10.0.0", + "@typescript-eslint/eslint-plugin": "^8.58.0", + "@typescript-eslint/parser": "^8.58.0", + "concurrently": "^9.0.1", + "esbuild": "^0.20.2", + "esbuild-plugin-polyfill-node": "^0.3.0", "eslint": "^8.51.0", "eslint-config-prettier": "9.0.0", "eslint-plugin-github": "^4.10.1", - "eslint-plugin-jest": "^27.2.1", + "eslint-plugin-jest": "^29.15.1", "eslint-plugin-prettier": "^5.0.1", - "eslint-plugin-security": "^1.7.1", + "eslint-plugin-security": "^4.0.0", "eslint-plugin-sonarjs": "^0.19.0", - "eslint-plugin-unused-imports": "^3.0.0", + "eslint-plugin-unused-imports": "^4.4.1", "graphology-types": "^0.24.7", + "lodash-es": "^4.18.1", "markdown-toc": "1.2.0", "oclif": "^4.8.5", "rimraf": "^5.0.5", @@ -68,10 +85,10 @@ "ts-jest": "^29.1.3", "ts-node": "^10.9.2", "typescript": "^5.4.5", - "zod-to-json-schema": "^3.23.0" + "zod-to-json-schema": "^3.25.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=22.0.0" } }, "node_modules/@cspotcode/source-map-support": { @@ -200,6 +217,39 @@ "node": ">=0.4.0" } }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -304,6 +354,28 @@ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", + "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/foreground-child": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", @@ -375,6 +447,12 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, "node_modules/lru-cache": { "version": "10.2.2", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", @@ -439,6 +517,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/rimraf": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", diff --git a/examples/typescript-library/package.json b/examples/typescript-library/package.json index e713b6d0..0a8726c5 100644 --- a/examples/typescript-library/package.json +++ b/examples/typescript-library/package.json @@ -9,10 +9,14 @@ "dev": "codegen generate --watch" }, "license": "Apache-2.0", + "dependencies": { + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1" + }, "devDependencies": { "typescript": "5.4.5", "rimraf": "5.0.5", "@the-codegen-project/cli": "^0", "ts-node": "10.9.2" } -} \ No newline at end of file +} diff --git a/examples/typescript-library/src/__gen__/payloads/UserSignedUp.ts b/examples/typescript-library/src/__gen__/payloads/UserSignedUp.ts index ce77fc5e..2d521c70 100644 --- a/examples/typescript-library/src/__gen__/payloads/UserSignedUp.ts +++ b/examples/typescript-library/src/__gen__/payloads/UserSignedUp.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface UserSignedUpInterface { displayName?: string email?: string @@ -90,6 +90,9 @@ class UserSignedUp { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -97,4 +100,5 @@ class UserSignedUp { } } -export { UserSignedUp, UserSignedUpInterface }; \ No newline at end of file +export { UserSignedUp }; +export type { UserSignedUpInterface }; \ No newline at end of file diff --git a/examples/typescript-nextjs/package-lock.json b/examples/typescript-nextjs/package-lock.json index 19389220..68954a1f 100644 --- a/examples/typescript-nextjs/package-lock.json +++ b/examples/typescript-nextjs/package-lock.json @@ -9,6 +9,8 @@ "version": "0.1.0", "dependencies": { "@t3-oss/env-nextjs": "^0.10.1", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", "geist": "^1.3.0", "next": "^14.2.1", "react": "^18.3.0", @@ -89,22 +91,6 @@ "js-yaml": "^3.13.1" } }, - "node_modules/@apidevtools/swagger-parser/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/@apidevtools/swagger-parser/node_modules/ajv-draft-04": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", @@ -141,12 +127,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@apidevtools/swagger-parser/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/@asyncapi/avro-schema-parser": { "version": "3.0.24", "resolved": "https://registry.npmjs.org/@asyncapi/avro-schema-parser/-/avro-schema-parser-3.0.24.tgz", @@ -195,22 +175,6 @@ "ajv-formats": "^2.1.1" } }, - "node_modules/@asyncapi/openapi-schema-parser/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/@asyncapi/openapi-schema-parser/node_modules/ajv-errors": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", @@ -220,11 +184,23 @@ "ajv": "^8.0.1" } }, - "node_modules/@asyncapi/openapi-schema-parser/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "node_modules/@asyncapi/openapi-schema-parser/node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } }, "node_modules/@asyncapi/parser": { "version": "3.1.0", @@ -253,22 +229,6 @@ "node-fetch": "2.6.7" } }, - "node_modules/@asyncapi/parser/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/@asyncapi/parser/node_modules/ajv-errors": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", @@ -278,11 +238,23 @@ "ajv": "^8.0.1" } }, - "node_modules/@asyncapi/parser/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "node_modules/@asyncapi/parser/node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } }, "node_modules/@asyncapi/protobuf-schema-parser": { "version": "3.2.14", @@ -391,6 +363,23 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1749,22 +1738,6 @@ "node": "^12.20 || >=14.13" } }, - "node_modules/@stoplight/spectral-core/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/@stoplight/spectral-core/node_modules/ajv-errors": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", @@ -1774,6 +1747,24 @@ "ajv": "^8.0.1" } }, + "node_modules/@stoplight/spectral-core/node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/@stoplight/spectral-core/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1784,12 +1775,6 @@ "concat-map": "0.0.1" } }, - "node_modules/@stoplight/spectral-core/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/@stoplight/spectral-core/node_modules/jsonpath-plus": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-7.1.0.tgz", @@ -1864,22 +1849,6 @@ "ajv": ">=8" } }, - "node_modules/@stoplight/spectral-functions/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/@stoplight/spectral-functions/node_modules/ajv-draft-04": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", @@ -1903,11 +1872,23 @@ "ajv": "^8.0.1" } }, - "node_modules/@stoplight/spectral-functions/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "node_modules/@stoplight/spectral-functions/node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } }, "node_modules/@stoplight/spectral-parsers": { "version": "1.0.4", @@ -2749,16 +2730,15 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -2766,10 +2746,10 @@ } }, "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", "dependencies": { "ajv": "^8.0.0" }, @@ -2782,27 +2762,11 @@ } } }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "node_modules/ajv/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "license": "MIT" }, "node_modules/alterschema": { "version": "1.1.3", @@ -4593,6 +4557,23 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4716,7 +4697,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, "license": "MIT" }, "node_modules/fast-glob": { @@ -4769,6 +4749,22 @@ "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==", "dev": true }, + "node_modules/fast-uri": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", + "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fastest-stable-stringify": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/fastest-stable-stringify/-/fastest-stable-stringify-2.0.2.tgz", @@ -9342,22 +9338,6 @@ "@types/json-schema": "^7.0.11" } }, - "node_modules/parserapiv1/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/parserapiv1/node_modules/ajv-errors": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", @@ -9367,11 +9347,23 @@ "ajv": "^8.0.1" } }, - "node_modules/parserapiv1/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "node_modules/parserapiv1/node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } }, "node_modules/parserapiv2": { "name": "@asyncapi/parser", @@ -9399,22 +9391,6 @@ "webapi-parser": "^0.5.0" } }, - "node_modules/parserapiv2/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/parserapiv2/node_modules/ajv-errors": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", @@ -9424,11 +9400,23 @@ "ajv": "^8.0.1" } }, - "node_modules/parserapiv2/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "node_modules/parserapiv2/node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } }, "node_modules/parserapiv3": { "name": "@asyncapi/parser", @@ -9458,22 +9446,6 @@ "node-fetch": "2.6.7" } }, - "node_modules/parserapiv3/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/parserapiv3/node_modules/ajv-errors": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", @@ -9483,11 +9455,23 @@ "ajv": "^8.0.1" } }, - "node_modules/parserapiv3/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "node_modules/parserapiv3/node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } }, "node_modules/pascal-case": { "version": "3.1.2", @@ -9887,7 +9871,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, "engines": { "node": ">=0.10.0" } diff --git a/examples/typescript-nextjs/package.json b/examples/typescript-nextjs/package.json index 52163825..3d21ef9b 100644 --- a/examples/typescript-nextjs/package.json +++ b/examples/typescript-nextjs/package.json @@ -17,7 +17,9 @@ "next": "^14.2.1", "react": "^18.3.0", "react-dom": "^18.3.0", - "zod": "^3.23.3" + "zod": "^3.23.3", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1" }, "devDependencies": { "@types/eslint": "^8.56.2", diff --git a/examples/typescript-nextjs/src/__gen__/payloads/UserSignedUp.ts b/examples/typescript-nextjs/src/__gen__/payloads/UserSignedUp.ts index ce77fc5e..2d521c70 100644 --- a/examples/typescript-nextjs/src/__gen__/payloads/UserSignedUp.ts +++ b/examples/typescript-nextjs/src/__gen__/payloads/UserSignedUp.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface UserSignedUpInterface { displayName?: string email?: string @@ -90,6 +90,9 @@ class UserSignedUp { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -97,4 +100,5 @@ class UserSignedUp { } } -export { UserSignedUp, UserSignedUpInterface }; \ No newline at end of file +export { UserSignedUp }; +export type { UserSignedUpInterface }; \ No newline at end of file diff --git a/src/codegen/generators/typescript/channels/index.ts b/src/codegen/generators/typescript/channels/index.ts index 53ea3eac..8cad104a 100644 --- a/src/codegen/generators/typescript/channels/index.ts +++ b/src/codegen/generators/typescript/channels/index.ts @@ -93,7 +93,8 @@ export async function generateTypeScriptChannels( protocolCodeFunctions, externalProtocolFunctionInformation, parameters, - payloads + payloads, + headers ); } @@ -106,7 +107,8 @@ async function finalizeGeneration( TypeScriptChannelRenderedFunctionType[] >, parameters: TypeScriptParameterRenderType, - payloads: TypeScriptPayloadRenderType + payloads: TypeScriptPayloadRenderType, + headers: TypeScriptHeadersRenderType ): Promise { const files: GeneratedFile[] = []; const generatedProtocols: string[] = []; @@ -169,6 +171,7 @@ async function finalizeGeneration( return { parameterRender: parameters, payloadRender: payloads, + headerRender: headers, generator: context.generator, renderedFunctions: externalProtocolFunctionInformation, result: indexContent, diff --git a/src/codegen/generators/typescript/channels/protocols/amqp/publishExchange.ts b/src/codegen/generators/typescript/channels/protocols/amqp/publishExchange.ts index f357d4b8..d72c2a1f 100644 --- a/src/codegen/generators/typescript/channels/protocols/amqp/publishExchange.ts +++ b/src/codegen/generators/typescript/channels/protocols/amqp/publishExchange.ts @@ -4,6 +4,7 @@ import {SingleFunctionRenderType} from '../../../../../types'; import {pascalCase} from '../../../utils'; import {RenderRegularParameters} from '../../types'; import { + getHeaderTypeAndModule, parameterInstanceExpression, parameterUnionType, payloadInstanceExpression, @@ -63,6 +64,7 @@ const routingKey = ${addressToUse}; ${headersHandling} channel.publish(exchange, routingKey, Buffer.from(dataToSend), publishOptions);`; + const {headerType} = getHeaderTypeAndModule(channelHeaders); const functionParameters = [ { parameter: `message`, @@ -82,7 +84,7 @@ channel.publish(exchange, routingKey, Buffer.from(dataToSend), publishOptions);` ? [ { parameter: `headers`, - parameterType: `headers?: ${channelHeaders.type}`, + parameterType: `headers?: ${headerType}`, jsDoc: ' * @param headers optional headers to include with the message' } diff --git a/src/codegen/generators/typescript/channels/protocols/amqp/publishQueue.ts b/src/codegen/generators/typescript/channels/protocols/amqp/publishQueue.ts index ca3dc70f..2778e76c 100644 --- a/src/codegen/generators/typescript/channels/protocols/amqp/publishQueue.ts +++ b/src/codegen/generators/typescript/channels/protocols/amqp/publishQueue.ts @@ -4,6 +4,7 @@ import {SingleFunctionRenderType} from '../../../../../types'; import {pascalCase} from '../../../utils'; import {RenderRegularParameters} from '../../types'; import { + getHeaderTypeAndModule, parameterInstanceExpression, parameterUnionType, payloadInstanceExpression, @@ -60,6 +61,7 @@ const queue = ${addressToUse}; ${headersHandling} channel.sendToQueue(queue, Buffer.from(dataToSend), publishOptions);`; + const {headerType} = getHeaderTypeAndModule(channelHeaders); const functionParameters = [ { parameter: `message`, @@ -79,7 +81,7 @@ channel.sendToQueue(queue, Buffer.from(dataToSend), publishOptions);`; ? [ { parameter: `headers`, - parameterType: `headers?: ${channelHeaders.type}`, + parameterType: `headers?: ${headerType}`, jsDoc: ' * @param headers optional headers to include with the message' } diff --git a/src/codegen/generators/typescript/channels/protocols/amqp/subscribeQueue.ts b/src/codegen/generators/typescript/channels/protocols/amqp/subscribeQueue.ts index 6ed2e6ed..64735750 100644 --- a/src/codegen/generators/typescript/channels/protocols/amqp/subscribeQueue.ts +++ b/src/codegen/generators/typescript/channels/protocols/amqp/subscribeQueue.ts @@ -3,6 +3,7 @@ import {SingleFunctionRenderType} from '../../../../../types'; import {pascalCase} from '../../../utils'; import {RenderRegularParameters} from '../../types'; import { + getHeaderTypeAndModule, getValidationFunctions, parameterInstanceExpression, parameterUnionType, @@ -21,6 +22,7 @@ export function renderSubscribeQueue({ description, deprecated }: RenderRegularParameters): SingleFunctionRenderType { + const {headerType, headerModule} = getHeaderTypeAndModule(channelHeaders); const includeValidation = payloadGenerator.generator.includeValidation; const addressToUse = channelParameters ? `${parameterInstanceExpression({modelName: channelParameters.type, source: 'parameters'})}.getChannelWithParameters('${topic}')` @@ -45,7 +47,7 @@ channel.consume(queue, (msg) => { ${ channelHeaders ? `// Extract headers if present - let extractedHeaders: ${channelHeaders.type} | undefined = undefined; + let extractedHeaders: ${headerType} | undefined = undefined; if (msg.properties && msg.properties.headers) { const headerObj: Record = {}; for (const [key, value] of Object.entries(msg.properties.headers)) { @@ -53,7 +55,7 @@ channel.consume(queue, (msg) => { headerObj[key] = value; } } - extractedHeaders = ${channelHeaders.type}.unmarshal(headerObj); + extractedHeaders = ${headerModule ?? headerType}.unmarshal(headerObj); }` : '' } @@ -75,7 +77,7 @@ channel.consume(queue, (msg) => { ...(channelHeaders ? [ { - parameter: `headers?: ${channelHeaders.type}`, + parameter: `headers?: ${headerType}`, jsDoc: ' * @param headers that was received with the message' } ] diff --git a/src/codegen/generators/typescript/channels/protocols/eventsource/fetch.ts b/src/codegen/generators/typescript/channels/protocols/eventsource/fetch.ts index 8c5b4e8b..6a995dfa 100644 --- a/src/codegen/generators/typescript/channels/protocols/eventsource/fetch.ts +++ b/src/codegen/generators/typescript/channels/protocols/eventsource/fetch.ts @@ -7,6 +7,7 @@ import { RenderRegularParameters } from '../../types'; import { + getHeaderTypeAndModule, getValidationFunctions, parameterInstanceExpression, parameterUnionType, @@ -44,6 +45,7 @@ export function renderFetch({ messageType, onValidationFail: `return callback({error: new Error(\`Invalid message payload received; $\{JSON.stringify({cause: errors})}\`), messageEvent: undefined});` }); + const {headerType} = getHeaderTypeAndModule(channelHeaders); const functionParameters = [ { parameter: `callback`, @@ -63,7 +65,7 @@ export function renderFetch({ ? [ { parameter: `headers`, - parameterType: `headers?: ${channelHeaders.type}`, + parameterType: `headers?: ${headerType}`, jsDoc: ' * @param headers optional headers to include with the EventSource connection' } diff --git a/src/codegen/generators/typescript/channels/protocols/http/client.ts b/src/codegen/generators/typescript/channels/protocols/http/client.ts index 457c4767..f2515785 100644 --- a/src/codegen/generators/typescript/channels/protocols/http/client.ts +++ b/src/codegen/generators/typescript/channels/protocols/http/client.ts @@ -6,6 +6,7 @@ import {HttpRenderType} from '../../../../../types'; import {pascalCase} from '../../../utils'; import {ChannelFunctionTypes, RenderHttpParameters} from '../../types'; import { + getHeaderTypeAndModule, parameterUnionType, payloadUnionType, renderParameterNormalization, @@ -64,7 +65,7 @@ export function renderHttpFetchClient({ contextInterfaceName, payloadInputType, channelParameters?.type, - channelHeaders?.type, + getHeaderTypeAndModule(channelHeaders).headerType, method ); @@ -89,7 +90,7 @@ export function renderHttpFetchClient({ hasParameters, parameterModelName: channelParameters?.name, hasHeaders, - headersType: channelHeaders?.type, + headersType: getHeaderTypeAndModule(channelHeaders).headerType, hasSerializeHeaders, method, servers, diff --git a/src/codegen/generators/typescript/channels/protocols/kafka/publish.ts b/src/codegen/generators/typescript/channels/protocols/kafka/publish.ts index e925b7aa..bd323d79 100644 --- a/src/codegen/generators/typescript/channels/protocols/kafka/publish.ts +++ b/src/codegen/generators/typescript/channels/protocols/kafka/publish.ts @@ -4,6 +4,7 @@ import {SingleFunctionRenderType} from '../../../../../types'; import {pascalCase} from '../../../utils'; import {RenderRegularParameters} from '../../types'; import { + getHeaderTypeAndModule, parameterInstanceExpression, parameterUnionType, payloadInstanceExpression, @@ -43,6 +44,7 @@ export function renderPublish({ ? `let dataToSend: any = null;` : `let dataToSend: any = ${messageMarshalling};`; + const {headerType} = getHeaderTypeAndModule(channelHeaders); const functionParameters = [ { parameter: `message`, @@ -62,7 +64,7 @@ export function renderPublish({ ? [ { parameter: `headers`, - parameterType: `headers?: ${channelHeaders.type}`, + parameterType: `headers?: ${headerType}`, jsDoc: ' * @param headers optional headers to include with the message' } diff --git a/src/codegen/generators/typescript/channels/protocols/kafka/subscribe.ts b/src/codegen/generators/typescript/channels/protocols/kafka/subscribe.ts index 2e75b2a3..c3cd9497 100644 --- a/src/codegen/generators/typescript/channels/protocols/kafka/subscribe.ts +++ b/src/codegen/generators/typescript/channels/protocols/kafka/subscribe.ts @@ -11,6 +11,7 @@ import { renderChannelJSDoc } from '../../utils'; import {generateKafkaMessageReceivingCode} from './utils'; +import {getHeaderTypeAndModule} from '../../utils'; export function renderSubscribe({ topic, @@ -46,6 +47,7 @@ export function renderSubscribe({ : `return onDataCallback(new Error(\`Invalid message payload received; $\{JSON.stringify({cause: errors})}\`), undefined, kafkaMessage);` }); + const {headerType} = getHeaderTypeAndModule(channelHeaders); const callbackFunctionParameters = [ { parameter: 'err?: Error', @@ -66,7 +68,7 @@ export function renderSubscribe({ ...(channelHeaders ? [ { - parameter: `headers?: ${channelHeaders.type}`, + parameter: `headers?: ${headerType}`, jsDoc: ' * @param headers that was received with the message' } ] diff --git a/src/codegen/generators/typescript/channels/protocols/kafka/utils.ts b/src/codegen/generators/typescript/channels/protocols/kafka/utils.ts index 561f7c00..6214501a 100644 --- a/src/codegen/generators/typescript/channels/protocols/kafka/utils.ts +++ b/src/codegen/generators/typescript/channels/protocols/kafka/utils.ts @@ -1,4 +1,5 @@ import {ConstrainedObjectModel} from '@asyncapi/modelina'; +import {getHeaderTypeAndModule} from '../../utils'; /** * Generates the message receiving code for Kafka subscribe functions @@ -16,11 +17,12 @@ export function generateKafkaMessageReceivingCode({ messageUnmarshalling: string; potentialValidationFunction: string; }): string { + const {headerType, headerModule} = getHeaderTypeAndModule(channelHeaders); // Generate header extraction code const headerExtraction = channelHeaders ? ` // Extract headers if present - let extractedHeaders: ${channelHeaders.type} | undefined = undefined; + let extractedHeaders: ${headerType} | undefined = undefined; if (message.headers) { const headerObj: Record = {}; for (const [key, value] of Object.entries(message.headers)) { @@ -28,7 +30,7 @@ export function generateKafkaMessageReceivingCode({ headerObj[key] = value.toString(); } } - extractedHeaders = ${channelHeaders.type}.unmarshal(headerObj); + extractedHeaders = ${headerModule ?? headerType}.unmarshal(headerObj); }` : ''; diff --git a/src/codegen/generators/typescript/channels/protocols/mqtt/publish.ts b/src/codegen/generators/typescript/channels/protocols/mqtt/publish.ts index d1109b6d..87cf1c48 100644 --- a/src/codegen/generators/typescript/channels/protocols/mqtt/publish.ts +++ b/src/codegen/generators/typescript/channels/protocols/mqtt/publish.ts @@ -4,6 +4,7 @@ import {SingleFunctionRenderType} from '../../../../../types'; import {pascalCase} from '../../../utils'; import {RenderRegularParameters} from '../../types'; import { + getHeaderTypeAndModule, parameterInstanceExpression, parameterUnionType, payloadInstanceExpression, @@ -63,6 +64,7 @@ export function renderPublish({ ${headersHandling} mqtt.publish(${addressToUse}, dataToSend, publishOptions);`; + const {headerType} = getHeaderTypeAndModule(channelHeaders); const functionParameters = [ { parameter: `message`, @@ -82,7 +84,7 @@ export function renderPublish({ ? [ { parameter: `headers`, - parameterType: `headers?: ${channelHeaders.type}`, + parameterType: `headers?: ${headerType}`, jsDoc: ' * @param headers optional headers to include with the message as MQTT user properties' } diff --git a/src/codegen/generators/typescript/channels/protocols/mqtt/subscribe.ts b/src/codegen/generators/typescript/channels/protocols/mqtt/subscribe.ts index 6923230d..e38d54ec 100644 --- a/src/codegen/generators/typescript/channels/protocols/mqtt/subscribe.ts +++ b/src/codegen/generators/typescript/channels/protocols/mqtt/subscribe.ts @@ -5,6 +5,7 @@ import {SingleFunctionRenderType} from '../../../../../types'; import {findRegexFromChannel, pascalCase} from '../../../utils'; import {RenderRegularParameters} from '../../types'; import { + getHeaderTypeAndModule, getValidationFunctions, parameterInstanceExpression, parameterUnionType, @@ -24,6 +25,7 @@ export function renderSubscribe({ description, deprecated }: RenderRegularParameters): SingleFunctionRenderType { + const {headerType, headerModule} = getHeaderTypeAndModule(channelHeaders); const includeValidation = payloadGenerator.generator.includeValidation; const addressToUse = channelParameters ? `${parameterInstanceExpression({modelName: channelParameters.type, source: 'parameters'})}.getChannelWithParameters('${topic}')` @@ -86,7 +88,7 @@ export function renderSubscribe({ ...(channelHeaders ? [ { - parameter: `headers?: ${channelHeaders.type}`, + parameter: `headers?: ${headerType}`, jsDoc: ' * @param headers that was received with the message as MQTT user properties' } @@ -141,10 +143,10 @@ export function renderSubscribe({ channelHeaders ? ` // Extract headers from MQTT v5 user properties - let extractedHeaders: ${channelHeaders.type} | undefined; + let extractedHeaders: ${headerType} | undefined; if (packet.properties && packet.properties.userProperties) { try { - extractedHeaders = ${channelHeaders.type}.unmarshal(packet.properties.userProperties); + extractedHeaders = ${headerModule ?? headerType}.unmarshal(packet.properties.userProperties); } catch (headerError) { onDataCallback({err: new Error(\`${PARSE_HEADERS_ERROR}\`), msg: undefined${channelParameters ? PARAMETERS_PARAM : ''}${channelHeaders ? HEADERS_UNDEFINED_PARAM : ''}, mqttMsg: packet}); return; diff --git a/src/codegen/generators/typescript/channels/protocols/nats/coreReply.ts b/src/codegen/generators/typescript/channels/protocols/nats/coreReply.ts index 8c5c0ef3..bf8c19ed 100644 --- a/src/codegen/generators/typescript/channels/protocols/nats/coreReply.ts +++ b/src/codegen/generators/typescript/channels/protocols/nats/coreReply.ts @@ -39,8 +39,8 @@ export function renderCoreReply({ messageModule: requestMessageModule, messageType: requestMessageType, onValidationFail: channelParameters - ? `onDataCallback(new Error('Invalid request payload received', JSON.stringify({cause: errors})), undefined, parameters); continue;` - : `onDataCallback(new Error('Invalid request payload received', JSON.stringify({cause: errors})), undefined); continue;` + ? `onDataCallback(new Error(\`Invalid request payload received; $\{JSON.stringify({cause: errors})}\`), undefined, parameters); continue;` + : `onDataCallback(new Error(\`Invalid request payload received; $\{JSON.stringify({cause: errors})}\`), undefined); continue;` }); const callbackFunctionParameters = [ diff --git a/src/codegen/generators/typescript/channels/protocols/nats/coreSubscribe.ts b/src/codegen/generators/typescript/channels/protocols/nats/coreSubscribe.ts index 948bcaea..0b829358 100644 --- a/src/codegen/generators/typescript/channels/protocols/nats/coreSubscribe.ts +++ b/src/codegen/generators/typescript/channels/protocols/nats/coreSubscribe.ts @@ -5,6 +5,7 @@ import {SingleFunctionRenderType} from '../../../../../types'; import {findRegexFromChannel, pascalCase} from '../../../utils'; import {RenderRegularParameters} from '../../types'; import { + getHeaderTypeAndModule, getValidationFunctions, parameterInstanceExpression, parameterUnionType, @@ -170,6 +171,7 @@ function ${functionName}({ code, functionName, dependencies: [`import * as Nats from 'nats';`], + headerType: getHeaderTypeAndModule(channelHeaders).headerType, functionType: ChannelFunctionTypes.NATS_SUBSCRIBE }; } diff --git a/src/codegen/generators/typescript/channels/protocols/nats/jetstreamPullSubscribe.ts b/src/codegen/generators/typescript/channels/protocols/nats/jetstreamPullSubscribe.ts index 3e2944e7..828a2c82 100644 --- a/src/codegen/generators/typescript/channels/protocols/nats/jetstreamPullSubscribe.ts +++ b/src/codegen/generators/typescript/channels/protocols/nats/jetstreamPullSubscribe.ts @@ -5,6 +5,7 @@ import {SingleFunctionRenderType} from '../../../../../types'; import {findRegexFromChannel, pascalCase} from '../../../utils'; import {RenderRegularParameters} from '../../types'; import { + getHeaderTypeAndModule, getValidationFunctions, parameterInstanceExpression, parameterUnionType, @@ -45,6 +46,7 @@ export function renderJetstreamPullSubscribe({ onValidationFail: `onDataCallback(new Error(\`Invalid message payload received; $\{JSON.stringify({cause: errors})}\`), undefined,${channelParameters ? 'parameters, ' : ''}${channelHeaders ? 'extractedHeaders, ' : ''} msg); continue;` }); + const {headerType} = getHeaderTypeAndModule(channelHeaders); const callbackFunctionParameters = [ { parameter: 'err?: Error', @@ -65,7 +67,7 @@ export function renderJetstreamPullSubscribe({ ...(channelHeaders ? [ { - parameter: `headers?: ${channelHeaders.type}`, + parameter: `headers?: ${headerType}`, jsDoc: ' * @param headers that was received with the message' } ] @@ -171,6 +173,7 @@ function ${functionName}({ code, functionName, dependencies: [`import * as Nats from 'nats';`], + headerType: getHeaderTypeAndModule(channelHeaders).headerType, functionType: ChannelFunctionTypes.NATS_JETSTREAM_PULL_SUBSCRIBE }; } diff --git a/src/codegen/generators/typescript/channels/protocols/nats/jetstreamPushSubscription.ts b/src/codegen/generators/typescript/channels/protocols/nats/jetstreamPushSubscription.ts index 7f8e5472..2a282edb 100644 --- a/src/codegen/generators/typescript/channels/protocols/nats/jetstreamPushSubscription.ts +++ b/src/codegen/generators/typescript/channels/protocols/nats/jetstreamPushSubscription.ts @@ -5,6 +5,7 @@ import {SingleFunctionRenderType} from '../../../../../types'; import {findRegexFromChannel, pascalCase} from '../../../utils'; import {RenderRegularParameters} from '../../types'; import { + getHeaderTypeAndModule, getValidationFunctions, parameterInstanceExpression, parameterUnionType, @@ -45,6 +46,7 @@ export function renderJetstreamPushSubscription({ onValidationFail: `onDataCallback(new Error(\`Invalid message payload received; $\{JSON.stringify({cause: errors})}\`), undefined,${channelParameters ? 'parameters, ' : ''}${channelHeaders ? 'extractedHeaders, ' : ''} msg); continue;` }); + const {headerType} = getHeaderTypeAndModule(channelHeaders); const callbackFunctionParameters = [ { parameter: 'err?: Error', @@ -65,7 +67,7 @@ export function renderJetstreamPushSubscription({ ...(channelHeaders ? [ { - parameter: `headers?: ${channelHeaders.type}`, + parameter: `headers?: ${headerType}`, jsDoc: ' * @param headers that was received with the message' } ] @@ -174,6 +176,7 @@ function ${functionName}({ code, functionName, dependencies: [`import * as Nats from 'nats';`], + headerType: getHeaderTypeAndModule(channelHeaders).headerType, functionType: ChannelFunctionTypes.NATS_JETSTREAM_PUSH_SUBSCRIBE }; } diff --git a/src/codegen/generators/typescript/channels/protocols/nats/utils.ts b/src/codegen/generators/typescript/channels/protocols/nats/utils.ts index ac9086c0..ad928c21 100644 --- a/src/codegen/generators/typescript/channels/protocols/nats/utils.ts +++ b/src/codegen/generators/typescript/channels/protocols/nats/utils.ts @@ -1,4 +1,5 @@ import {ConstrainedObjectModel} from '@asyncapi/modelina'; +import {getHeaderTypeAndModule} from '../../utils'; /** * Generates the header setup code for NATS publish operations @@ -34,8 +35,9 @@ export function generateHeaderExtractionCode( return ''; } + const {headerType, headerModule} = getHeaderTypeAndModule(channelHeaders); return `// Extract headers if present - let extractedHeaders: ${channelHeaders.type} | undefined = undefined; + let extractedHeaders: ${headerType} | undefined = undefined; if (msg.headers) { const headerObj: Record = {}; // NATS headers support both iteration and get() method @@ -50,7 +52,7 @@ export function generateHeaderExtractionCode( headerObj[key] = value; } } - extractedHeaders = ${channelHeaders.type}.unmarshal(headerObj); + extractedHeaders = ${headerModule ?? headerType}.unmarshal(headerObj); }`; } @@ -68,9 +70,10 @@ export function generateHeaderParameter( return null; } + const {headerType} = getHeaderTypeAndModule(channelHeaders); return { parameter: 'headers', - parameterType: `headers?: ${channelHeaders.type}`, + parameterType: `headers?: ${headerType}`, jsDoc: ' * @param headers optional headers to include with the message' }; } @@ -88,8 +91,9 @@ export function generateHeaderCallbackParameter( return null; } + const {headerType} = getHeaderTypeAndModule(channelHeaders); return { - parameter: `headers?: ${channelHeaders.type}`, + parameter: `headers?: ${headerType}`, jsDoc: ' * @param headers that were received with the message' }; } diff --git a/src/codegen/generators/typescript/channels/types.ts b/src/codegen/generators/typescript/channels/types.ts index 67342b26..e5369055 100644 --- a/src/codegen/generators/typescript/channels/types.ts +++ b/src/codegen/generators/typescript/channels/types.ts @@ -4,6 +4,7 @@ import {zodImportExtension} from '../../../utils'; import {AsyncAPIDocumentInterface} from '@asyncapi/parser'; import {TypeScriptPayloadRenderType} from '../payloads'; import {TypeScriptParameterRenderType} from '../parameters'; +import {TypeScriptHeadersRenderType} from '../headers'; import {ConstrainedObjectModel} from '@asyncapi/modelina'; import {OpenAPIV2, OpenAPIV3, OpenAPIV3_1} from 'openapi-types'; import {SecuritySchemeOptions} from '../../../inputs/openapi/security'; @@ -214,6 +215,12 @@ export type TypeScriptChannelRenderedFunctionType = { * ergonomic plain object the channel functions accept. */ messageUnionType?: string; + /** + * The header type used in the channel function's callback, when the channel + * has headers. Read by the client generator so its wrapper subscribe methods + * declare the same callback signature as the channel function they delegate to. + */ + headerType?: string; replyType?: string; parameterType?: string; /** @@ -229,6 +236,12 @@ export type TypeScriptChannelRenderedFunctionType = { export interface TypeScriptChannelRenderType { payloadRender: TypeScriptPayloadRenderType; parameterRender: TypeScriptParameterRenderType; + /** + * The headers render this channels render was built from. Exposed so the + * client generator can import the same header models its wrapper subscribe + * methods reference in their callback signatures. + */ + headerRender: TypeScriptHeadersRenderType; generator: TypeScriptChannelsGeneratorInternal; /** * All the rendered functions based on type. diff --git a/src/codegen/generators/typescript/channels/utils.ts b/src/codegen/generators/typescript/channels/utils.ts index ccd2b541..133dcae4 100644 --- a/src/codegen/generators/typescript/channels/utils.ts +++ b/src/codegen/generators/typescript/channels/utils.ts @@ -1,6 +1,7 @@ import { ConstrainedEnumModel, ConstrainedObjectModel, + ConstrainedMetaModel, OutputModel } from '@asyncapi/modelina'; import {ChannelPayload, SingleFunctionRenderType} from '../../../types'; @@ -246,6 +247,14 @@ export function addHeadersToDependencies( importExtension ); + if (!(header.model instanceof ConstrainedObjectModel)) { + // Union header model — namespace import, matching payload unions. + dependencies.push( + `import * as ${header.modelName}Module from '${importPath}';` + ); + return; + } + const fns = headerFunctions?.[header.modelName] ?? []; const importNames = fns.length > 0 @@ -254,6 +263,30 @@ export function addHeadersToDependencies( dependencies.push(`import {${importNames}} from '${importPath}';`); }); } +/** + * Resolve how a channel's header model is referenced in generated code. + * + * A channel whose messages each declare their own headers produces a `oneOf` + * union model. Its `type` is the expanded union (`A | B | C`), which neither + * resolves (the members are not imported) nor carries the static `unmarshal` + * the receive paths call. Union models are therefore imported as a namespace — + * exactly like payload unions — so the type is `Module.` and the + * runtime helpers live on `Module`. + */ +export function getHeaderTypeAndModule(headers?: ConstrainedMetaModel): { + headerType?: string; + headerModule?: string; +} { + if (!headers) { + return {headerType: undefined, headerModule: undefined}; + } + if (headers instanceof ConstrainedObjectModel) { + return {headerType: headers.type, headerModule: undefined}; + } + const headerModule = `${headers.name}Module`; + return {headerType: `${headerModule}.${headers.name}`, headerModule}; +} + export function getMessageTypeAndModule(payload: ChannelPayload) { if (payload === undefined) { return { @@ -550,6 +583,7 @@ type RenderForExternal = Pick< > & { messageType?: string; messageUnionType?: string; + headerType?: string; replyType?: string; parameterType?: string; }; @@ -591,6 +625,7 @@ export function addRendersToExternal({ functionName: value.functionName, messageType: value.messageType ?? '', messageUnionType: value.messageUnionType ?? value.messageType ?? '', + headerType: value.headerType, replyType: value.replyType, parameterType: value.parameterType ?? parameter?.type, tags: value.tags, diff --git a/src/codegen/generators/typescript/client/protocols/nats.ts b/src/codegen/generators/typescript/client/protocols/nats.ts index e3ef3545..9198f348 100644 --- a/src/codegen/generators/typescript/client/protocols/nats.ts +++ b/src/codegen/generators/typescript/client/protocols/nats.ts @@ -19,6 +19,7 @@ import {renderJetStreamPullSubscription} from './nats/jetStreamPullSubscription' import {renderJetStreamPushSubscription} from './nats/jetstreamPushSubscription'; import { addParametersToDependencies, + addHeadersToDependencies, addParametersToExports, addPayloadsToDependencies, addPayloadsToExports @@ -59,6 +60,7 @@ export async function generateNatsClient( const payloads = channels.payloadRender; const parameters = channels.parameterRender; + const headers = channels.headerRender; const dependencies: string[] = []; const importExtension = resolveImportExtension( @@ -86,12 +88,22 @@ export async function generateNatsClient( importExtension ); addParametersToExports(parameters.channelModels, dependencies); + // The wrapper subscribe methods reference the channel header types in their + // callback signatures, so those models have to be imported here too. + addHeadersToDependencies( + headers.channelModels, + headers.generator, + context.generator, + dependencies, + importExtension + ); const natsFunctions: string[] = []; for (const func of renderedNatsFunctions) { const context = { channelName: func.functionName, channelParameterType: func.parameterType, + channelHeaderType: func.headerType, description: '', messageType: func.messageType, // Publish wrappers accept the widened `Interface | Class` union so callers diff --git a/src/codegen/generators/typescript/client/protocols/nats/coreSubscribe.ts b/src/codegen/generators/typescript/client/protocols/nats/coreSubscribe.ts index 25a3e855..81050d54 100644 --- a/src/codegen/generators/typescript/client/protocols/nats/coreSubscribe.ts +++ b/src/codegen/generators/typescript/client/protocols/nats/coreSubscribe.ts @@ -1,98 +1,108 @@ -export function renderCoreSubscribe({ - description, - messageType, - channelParameterType, - channelName -}: { - description: string; - messageType: string; - channelParameterType?: string; - channelName: string; -}) { - const callbackFunctionParameters = [ - { - parameter: 'err?: Error', - jsDoc: ' * @param err if any error occurred this will be sat' - }, - { - parameter: `msg?: ${messageType}`, - jsDoc: ' * @param msg that was received' - }, - ...(channelParameterType - ? [ - { - parameter: `parameters?: ${channelParameterType}`, - jsDoc: ' * @param parameters that was received in the topic' - } - ] - : []), - { - parameter: `natsMsg?: Nats.Msg`, - jsDoc: ' * @param natsMsg' - } - ]; - - const functionParameters = [ - { - parameter: `onDataCallback`, - parameterType: `onDataCallback: (${callbackFunctionParameters.map((param) => param.parameter).join(', ')}) => void`, - jsDoc: ` * @param {${channelName}Callback} onDataCallback to call when messages are received` - }, - ...(channelParameterType - ? [ - { - parameter: `parameters`, - parameterType: `parameters: ${channelParameterType}`, - jsDoc: ' * @param parameters for topic substitution' - } - ] - : []), - { - parameter: 'options', - parameterType: 'options?: Nats.SubscriptionOptions', - jsDoc: ' * @param options when setting up the subscription' - }, - { - parameter: 'flush', - parameterType: 'flush?: boolean', - jsDoc: ' * @param options when setting up the subscription' - } - ]; - - const functionCallParameters = [ - 'onDataCallback', - ...(channelParameterType ? ['parameters'] : []), - 'nc: this.nc', - 'codec: this.codec', - 'options' - ]; - return ` - /** - * ${description} - * - ${functionParameters.map((param) => param.jsDoc).join('\n ')} - */ - public ${channelName}({ - ${functionParameters.map((param) => param.parameter).join(', \n ')} - }: { - ${functionParameters.map((param) => param.parameterType).join(', \n ')} - }): Promise { - return new Promise(async (resolve, reject) => { - if(!this.isClosed() && this.nc !== undefined && this.codec !== undefined){ - try { - const sub = await nats.${channelName}({ - ${functionCallParameters.join(', \n ')} - }); - if(flush){ - await this.nc.flush(); - } - resolve(sub); - }catch(e: any){ - reject(e); - } - } else { - Promise.reject('Nats client not available yet, please connect or set the client'); - } - }); -}`; -} +export function renderCoreSubscribe({ + description, + messageType, + channelParameterType, + channelHeaderType, + channelName +}: { + description: string; + messageType: string; + channelParameterType?: string; + channelHeaderType?: string; + channelName: string; +}) { + const callbackFunctionParameters = [ + { + parameter: 'err?: Error', + jsDoc: ' * @param err if any error occurred this will be sat' + }, + { + parameter: `msg?: ${messageType}`, + jsDoc: ' * @param msg that was received' + }, + ...(channelParameterType + ? [ + { + parameter: `parameters?: ${channelParameterType}`, + jsDoc: ' * @param parameters that was received in the topic' + } + ] + : []), + ...(channelHeaderType + ? [ + { + parameter: `headers?: ${channelHeaderType}`, + jsDoc: ' * @param headers that was received with the message' + } + ] + : []), + { + parameter: `natsMsg?: Nats.Msg`, + jsDoc: ' * @param natsMsg' + } + ]; + + const functionParameters = [ + { + parameter: `onDataCallback`, + parameterType: `onDataCallback: (${callbackFunctionParameters.map((param) => param.parameter).join(', ')}) => void`, + jsDoc: ` * @param {${channelName}Callback} onDataCallback to call when messages are received` + }, + ...(channelParameterType + ? [ + { + parameter: `parameters`, + parameterType: `parameters: ${channelParameterType}`, + jsDoc: ' * @param parameters for topic substitution' + } + ] + : []), + { + parameter: 'options', + parameterType: 'options?: Nats.SubscriptionOptions', + jsDoc: ' * @param options when setting up the subscription' + }, + { + parameter: 'flush', + parameterType: 'flush?: boolean', + jsDoc: ' * @param options when setting up the subscription' + } + ]; + + const functionCallParameters = [ + 'onDataCallback', + ...(channelParameterType ? ['parameters'] : []), + 'nc: this.nc', + 'codec: this.codec', + 'options' + ]; + return ` + /** + * ${description} + * + ${functionParameters.map((param) => param.jsDoc).join('\n ')} + */ + public ${channelName}({ + ${functionParameters.map((param) => param.parameter).join(', \n ')} + }: { + ${functionParameters.map((param) => param.parameterType).join(', \n ')} + }): Promise { + return new Promise(async (resolve, reject) => { + if(!this.isClosed() && this.nc !== undefined && this.codec !== undefined){ + try { + const sub = await nats.${channelName}({ + ${functionCallParameters.join(', \n ')} + }); + if(flush){ + await this.nc.flush(); + } + resolve(sub); + }catch(e: any){ + reject(e); + } + } else { + Promise.reject('Nats client not available yet, please connect or set the client'); + } + }); +}`; +} diff --git a/src/codegen/generators/typescript/client/protocols/nats/jetStreamPullSubscription.ts b/src/codegen/generators/typescript/client/protocols/nats/jetStreamPullSubscription.ts index 0e25b486..e6f3ae34 100644 --- a/src/codegen/generators/typescript/client/protocols/nats/jetStreamPullSubscription.ts +++ b/src/codegen/generators/typescript/client/protocols/nats/jetStreamPullSubscription.ts @@ -1,92 +1,102 @@ -export function renderJetStreamPullSubscription({ - description, - messageType, - channelParameterType, - channelName -}: { - description: string; - messageType: string; - channelParameterType?: string; - channelName: string; -}) { - const callbackFunctionParameters = [ - { - parameter: 'err?: Error', - jsDoc: ' * @param err if any error occurred this will be sat' - }, - { - parameter: `msg?: ${messageType}`, - jsDoc: ' * @param msg that was received' - }, - ...(channelParameterType - ? [ - { - parameter: `parameters?: ${channelParameterType}`, - jsDoc: ' * @param parameters that was received in the topic' - } - ] - : []), - { - parameter: `jetstreamMsg?: Nats.JsMsg`, - jsDoc: ' * @param jetstreamMsg' - } - ]; - - const functionParameters = [ - { - parameter: `onDataCallback`, - parameterType: `onDataCallback: (${callbackFunctionParameters.map((param) => param.parameter).join(', ')}) => void`, - jsDoc: ` * @param {${channelName}Callback} onDataCallback to call when messages are received` - }, - ...(channelParameterType - ? [ - { - parameter: `parameters`, - parameterType: `parameters: ${channelParameterType}`, - jsDoc: ' * @param parameters for topic substitution' - } - ] - : []), - { - parameter: 'options = {}', - parameterType: - 'options: Nats.ConsumerOptsBuilder | Partial', - jsDoc: ' * @param options when setting up the subscription' - } - ]; - - const functionCallParameters = [ - 'onDataCallback', - ...(channelParameterType ? ['parameters'] : []), - 'js: this.js', - 'codec: this.codec', - 'options' - ]; - return ` - /** - * ${description} - * - ${functionParameters.map((param) => param.jsDoc).join('\n ')} - */ - public ${channelName}({ - ${functionParameters.map((param) => param.parameter).join(', \n ')} - }: { - ${functionParameters.map((param) => param.parameterType).join(', \n ')} - }): Promise { - return new Promise(async (resolve, reject) => { - if (!this.isClosed() && this.nc !== undefined && this.codec !== undefined && this.js !== undefined) { - try { - const sub = await nats.${channelName}({ - ${functionCallParameters.join(', \n ')} - }); - resolve(sub); - } catch (e: any) { - reject(e); - } - } else { - Promise.reject('Nats client not available yet, please connect or set the client'); - } - }); - } - `; -} +export function renderJetStreamPullSubscription({ + description, + messageType, + channelParameterType, + channelHeaderType, + channelName +}: { + description: string; + messageType: string; + channelParameterType?: string; + channelHeaderType?: string; + channelName: string; +}) { + const callbackFunctionParameters = [ + { + parameter: 'err?: Error', + jsDoc: ' * @param err if any error occurred this will be sat' + }, + { + parameter: `msg?: ${messageType}`, + jsDoc: ' * @param msg that was received' + }, + ...(channelParameterType + ? [ + { + parameter: `parameters?: ${channelParameterType}`, + jsDoc: ' * @param parameters that was received in the topic' + } + ] + : []), + ...(channelHeaderType + ? [ + { + parameter: `headers?: ${channelHeaderType}`, + jsDoc: ' * @param headers that was received with the message' + } + ] + : []), + { + parameter: `jetstreamMsg?: Nats.JsMsg`, + jsDoc: ' * @param jetstreamMsg' + } + ]; + + const functionParameters = [ + { + parameter: `onDataCallback`, + parameterType: `onDataCallback: (${callbackFunctionParameters.map((param) => param.parameter).join(', ')}) => void`, + jsDoc: ` * @param {${channelName}Callback} onDataCallback to call when messages are received` + }, + ...(channelParameterType + ? [ + { + parameter: `parameters`, + parameterType: `parameters: ${channelParameterType}`, + jsDoc: ' * @param parameters for topic substitution' + } + ] + : []), + { + parameter: 'options = {}', + parameterType: + 'options: Nats.ConsumerOptsBuilder | Partial', + jsDoc: ' * @param options when setting up the subscription' + } + ]; + + const functionCallParameters = [ + 'onDataCallback', + ...(channelParameterType ? ['parameters'] : []), + 'js: this.js', + 'codec: this.codec', + 'options' + ]; + return ` + /** + * ${description} + * + ${functionParameters.map((param) => param.jsDoc).join('\n ')} + */ + public ${channelName}({ + ${functionParameters.map((param) => param.parameter).join(', \n ')} + }: { + ${functionParameters.map((param) => param.parameterType).join(', \n ')} + }): Promise { + return new Promise(async (resolve, reject) => { + if (!this.isClosed() && this.nc !== undefined && this.codec !== undefined && this.js !== undefined) { + try { + const sub = await nats.${channelName}({ + ${functionCallParameters.join(', \n ')} + }); + resolve(sub); + } catch (e: any) { + reject(e); + } + } else { + Promise.reject('Nats client not available yet, please connect or set the client'); + } + }); + } + `; +} diff --git a/src/codegen/generators/typescript/client/protocols/nats/jetstreamPushSubscription.ts b/src/codegen/generators/typescript/client/protocols/nats/jetstreamPushSubscription.ts index efbbed77..f680a3ba 100644 --- a/src/codegen/generators/typescript/client/protocols/nats/jetstreamPushSubscription.ts +++ b/src/codegen/generators/typescript/client/protocols/nats/jetstreamPushSubscription.ts @@ -1,91 +1,101 @@ -export function renderJetStreamPushSubscription({ - description, - messageType, - channelParameterType, - channelName -}: { - description: string; - messageType: string; - channelParameterType?: string; - channelName: string; -}) { - const callbackFunctionParameters = [ - { - parameter: 'err?: Error', - jsDoc: ' * @param err if any error occurred this will be sat' - }, - { - parameter: `msg?: ${messageType}`, - jsDoc: ' * @param msg that was received' - }, - ...(channelParameterType - ? [ - { - parameter: `parameters?: ${channelParameterType}`, - jsDoc: ' * @param parameters that was received in the topic' - } - ] - : []), - { - parameter: `jetstreamMsg?: Nats.JsMsg`, - jsDoc: ' * @param jetstreamMsg' - } - ]; - - const functionParameters = [ - { - parameter: `onDataCallback`, - parameterType: `onDataCallback: (${callbackFunctionParameters.map((param) => param.parameter).join(', ')}) => void`, - jsDoc: ` * @param {${channelName}Callback} onDataCallback to call when messages are received` - }, - ...(channelParameterType - ? [ - { - parameter: `parameters`, - parameterType: `parameters: ${channelParameterType}`, - jsDoc: ' * @param parameters for topic substitution' - } - ] - : []), - { - parameter: 'options = {}', - parameterType: - 'options: Nats.ConsumerOptsBuilder | Partial', - jsDoc: ' * @param options when setting up the subscription' - } - ]; - const functionCallParameters = [ - 'onDataCallback', - ...(channelParameterType ? ['parameters'] : []), - 'js: this.js', - 'codec: this.codec', - 'options' - ]; - - return ` - /** - * ${description} - * - ${functionParameters.map((param) => param.jsDoc).join('\n ')} - */ - public ${channelName}({ - ${functionParameters.map((param) => param.parameter).join(', \n ')} - }: { - ${functionParameters.map((param) => param.parameterType).join(', \n ')} - }): Promise { - return new Promise(async (resolve, reject) => { - if (!this.isClosed() && this.nc !== undefined && this.codec !== undefined && this.js !== undefined) { - try { - const sub = await nats.${channelName}({ - ${functionCallParameters.join(', \n ')} - }); - resolve(sub); - } catch (e: any) { - reject(e); - } - } else { - Promise.reject('Nats client not available yet, please connect or set the client'); - } - }); - }`; -} +export function renderJetStreamPushSubscription({ + description, + messageType, + channelParameterType, + channelHeaderType, + channelName +}: { + description: string; + messageType: string; + channelParameterType?: string; + channelHeaderType?: string; + channelName: string; +}) { + const callbackFunctionParameters = [ + { + parameter: 'err?: Error', + jsDoc: ' * @param err if any error occurred this will be sat' + }, + { + parameter: `msg?: ${messageType}`, + jsDoc: ' * @param msg that was received' + }, + ...(channelParameterType + ? [ + { + parameter: `parameters?: ${channelParameterType}`, + jsDoc: ' * @param parameters that was received in the topic' + } + ] + : []), + ...(channelHeaderType + ? [ + { + parameter: `headers?: ${channelHeaderType}`, + jsDoc: ' * @param headers that was received with the message' + } + ] + : []), + { + parameter: `jetstreamMsg?: Nats.JsMsg`, + jsDoc: ' * @param jetstreamMsg' + } + ]; + + const functionParameters = [ + { + parameter: `onDataCallback`, + parameterType: `onDataCallback: (${callbackFunctionParameters.map((param) => param.parameter).join(', ')}) => void`, + jsDoc: ` * @param {${channelName}Callback} onDataCallback to call when messages are received` + }, + ...(channelParameterType + ? [ + { + parameter: `parameters`, + parameterType: `parameters: ${channelParameterType}`, + jsDoc: ' * @param parameters for topic substitution' + } + ] + : []), + { + parameter: 'options = {}', + parameterType: + 'options: Nats.ConsumerOptsBuilder | Partial', + jsDoc: ' * @param options when setting up the subscription' + } + ]; + const functionCallParameters = [ + 'onDataCallback', + ...(channelParameterType ? ['parameters'] : []), + 'js: this.js', + 'codec: this.codec', + 'options' + ]; + + return ` + /** + * ${description} + * + ${functionParameters.map((param) => param.jsDoc).join('\n ')} + */ + public ${channelName}({ + ${functionParameters.map((param) => param.parameter).join(', \n ')} + }: { + ${functionParameters.map((param) => param.parameterType).join(', \n ')} + }): Promise { + return new Promise(async (resolve, reject) => { + if (!this.isClosed() && this.nc !== undefined && this.codec !== undefined && this.js !== undefined) { + try { + const sub = await nats.${channelName}({ + ${functionCallParameters.join(', \n ')} + }); + resolve(sub); + } catch (e: any) { + reject(e); + } + } else { + Promise.reject('Nats client not available yet, please connect or set the client'); + } + }); + }`; +} diff --git a/src/codegen/generators/typescript/headers.ts b/src/codegen/generators/typescript/headers.ts index a4dd4d88..461f6898 100644 --- a/src/codegen/generators/typescript/headers.ts +++ b/src/codegen/generators/typescript/headers.ts @@ -21,9 +21,13 @@ import { TS_COMMON_PRESET, typeScriptDefaultPropertyKeyConstraints } from '@asyncapi/modelina'; -import {createValidationPreset} from '../../modelina/presets'; +import { + createValidationPreset, + createUnionPreset +} from '../../modelina/presets'; import {createMissingInputDocumentError} from '../../errors'; import {generateModels} from '../../output'; +import {resolveImportExtension} from '../../utils'; export const zodTypescriptHeadersGenerator = z.object({ id: z @@ -123,6 +127,13 @@ function createAsyncAPIHeadersGenerator( createValidationPreset( {includeValidation: generator.includeValidation}, context + ), + // A channel whose messages each declare their own headers produces a + // `oneOf` union model; the union preset gives it module-level + // `unmarshal`/`marshal`, the same way payload unions get them. + createUnionPreset( + {includeValidation: generator.includeValidation}, + context ) ] }); @@ -189,6 +200,8 @@ export async function generateTypescriptHeadersCore({ const channelModels: Record = {}; const allFiles: GeneratedFile[] = []; const headerFunctions: Record = {}; + // Headers have no per-generator override, so the global setting applies. + const importExtension = resolveImportExtension({}, context.config); for (const [channelId, headerData] of Object.entries( processedData.channelHeaders @@ -200,7 +213,8 @@ export async function generateTypescriptHeadersCore({ const result = await generateModels({ generator: modelinaGenerator, input: headerData.schema, - outputPath: generator.outputPath + outputPath: generator.outputPath, + importExtension }); if (isOpenAPI) { appendOpenAPISerializerFunctions(result, headerFunctions); diff --git a/src/codegen/generators/typescript/models.ts b/src/codegen/generators/typescript/models.ts index 86dda4f5..9b3cb565 100644 --- a/src/codegen/generators/typescript/models.ts +++ b/src/codegen/generators/typescript/models.ts @@ -12,6 +12,7 @@ import {zodTypeScriptOptions, zodTypeScriptPresets} from '../../modelina'; import {JsonSchemaDocument} from '../../inputs/jsonschema'; import {CodegenError, ErrorType} from '../../errors'; import {generateModels} from '../../output'; +import {resolveImportExtension} from '../../utils'; export const zodTypescriptModelsGenerator = z.object({ id: z @@ -102,7 +103,9 @@ export async function generateTypescriptModels( const result = await generateModels({ generator: modelGenerator, input: inputDocument, - outputPath: generator.outputPath + outputPath: generator.outputPath, + // Models have no per-generator override, so the global setting applies. + importExtension: resolveImportExtension({}, context.config) }); return { diff --git a/src/codegen/generators/typescript/parameters.ts b/src/codegen/generators/typescript/parameters.ts index 59b4f004..da37ffac 100644 --- a/src/codegen/generators/typescript/parameters.ts +++ b/src/codegen/generators/typescript/parameters.ts @@ -18,7 +18,8 @@ import { processOpenAPIParameters } from '../../inputs/openapi/generators/parameters'; import {createMissingInputDocumentError} from '../../errors'; -import {generateModels} from '../../output'; +import {applyImportExtension, generateModels} from '../../output'; +import {resolveImportExtension} from '../../utils'; import {withCompanionInterfaceExport} from './utils'; export const zodTypescriptParametersGenerator = z.object({ @@ -89,6 +90,8 @@ export async function generateTypescriptParameters( const channelModels: Record = {}; const files: GeneratedFile[] = []; + // Parameters have no per-generator override, so the global setting applies. + const importExtension = resolveImportExtension({}, context.config); let processedSchemaData: ProcessedParameterSchemaData; let parameterGenerator: TypeScriptFileGenerator; @@ -130,7 +133,8 @@ export async function generateTypescriptParameters( const result = await generateModels({ generator: parameterGenerator, input: schemaData.schema, - outputPath: generator.outputPath + outputPath: generator.outputPath, + importExtension }); const mainModel = result.models.length > 0 @@ -141,7 +145,15 @@ export async function generateTypescriptParameters( if (mainModel && file.path.endsWith(`/${mainModel.modelName}.ts`)) { // The parameter model's own file carries the companion interface, // so re-export both symbols from its (rewritten) content. - files.push({path: file.path, content: mainModel.result}); + // Rebuilding from the rewritten model discards what `generateModels` + // already applied, so re-apply the import extension here. + files.push({ + path: file.path, + content: applyImportExtension({ + content: mainModel.result, + extension: importExtension + }) + }); } else { files.push(file); } diff --git a/src/codegen/generators/typescript/payloads.ts b/src/codegen/generators/typescript/payloads.ts index 43bafbe0..7926257a 100644 --- a/src/codegen/generators/typescript/payloads.ts +++ b/src/codegen/generators/typescript/payloads.ts @@ -29,7 +29,8 @@ import { createPrimitivesPreset } from '../../modelina/presets'; import {createMissingInputDocumentError} from '../../errors'; -import {generateModels} from '../../output'; +import {applyImportExtension, generateModels} from '../../output'; +import {ImportExtension, resolveImportExtension} from '../../utils'; export const zodTypeScriptPayloadGenerator = z.object({ id: z @@ -163,16 +164,29 @@ export async function generateTypescriptPayloadsCore( * onto each model's own file. Non-object payloads have no companion interface, * so {@link withCompanionInterfaceExport} returns them unchanged. */ -function applyCompanionInterfaceExports(result: { - models: OutputModel[]; - files: GeneratedFile[]; -}): {models: OutputModel[]; files: GeneratedFile[]} { +function applyCompanionInterfaceExports( + result: { + models: OutputModel[]; + files: GeneratedFile[]; + }, + importExtension: ImportExtension +): {models: OutputModel[]; files: GeneratedFile[]} { const models = result.models.map(withCompanionInterfaceExport); const files = result.files.map((file) => { const model = models.find((candidate) => file.path.endsWith(`/${candidate.modelName}.ts`) ); - return model ? {path: file.path, content: model.result} : file; + // Rebuilding the content from the rewritten model discards what + // `generateModels` already applied, so re-apply the import extension here. + return model + ? { + path: file.path, + content: applyImportExtension({ + content: model.result, + extension: importExtension + }) + } + : file; }); return {models, files}; } @@ -187,6 +201,8 @@ export async function generateTypescriptPayloadsCoreFromSchemas({ context: TypeScriptPayloadContext; }): Promise { const generator = context.generator; + // Payloads have no per-generator override, so the global setting applies. + const importExtension = resolveImportExtension({}, context.config); const modelinaGenerator = new TypeScriptFileGenerator({ ...defaultCodegenTypescriptModelinaOptions, @@ -248,8 +264,10 @@ export async function generateTypescriptPayloadsCoreFromSchemas({ await generateModels({ generator: modelinaGenerator, input: schemaData.schema, - outputPath: generator.outputPath - }) + outputPath: generator.outputPath, + importExtension + }), + importExtension ); const models = result.models; files.push(...result.files); @@ -287,8 +305,10 @@ export async function generateTypescriptPayloadsCoreFromSchemas({ await generateModels({ generator: modelinaGenerator, input: schemaData.schema, - outputPath: generator.outputPath - }) + outputPath: generator.outputPath, + importExtension + }), + importExtension ); const models = result.models; files.push(...result.files); @@ -323,8 +343,10 @@ export async function generateTypescriptPayloadsCoreFromSchemas({ await generateModels({ generator: modelinaGenerator, input: schemaData.schema, - outputPath: generator.outputPath - }) + outputPath: generator.outputPath, + importExtension + }), + importExtension ); files.push(...result.files); diff --git a/src/codegen/generators/typescript/utils.ts b/src/codegen/generators/typescript/utils.ts index c2596cba..6ad7b3bd 100644 --- a/src/codegen/generators/typescript/utils.ts +++ b/src/codegen/generators/typescript/utils.ts @@ -147,9 +147,12 @@ export function withCompanionInterfaceExport(model: OutputModel): OutputModel { ) { return model; } + // The companion is a type, so it must be re-exported with `export type` — + // bundling it into the value export breaks under `isolatedModules: true` + // (TS1205), which Next.js, SWC and esbuild projects enable. const rewritten = model.result.replace( originalExport, - `export { ${model.modelName}, ${interfaceName} };` + `export { ${model.modelName} };\nexport type { ${interfaceName} };` ); return OutputModel.toOutputModel({ result: rewritten, diff --git a/src/codegen/index.ts b/src/codegen/index.ts index 32244476..04198fe8 100644 --- a/src/codegen/index.ts +++ b/src/codegen/index.ts @@ -1,6 +1,7 @@ export {loadAsyncapi, loadAsyncapiFromMemory} from './inputs/asyncapi'; export {loadOpenapi, loadOpenapiFromMemory} from './inputs/openapi'; export {loadJsonSchema, loadJsonSchemaFromMemory} from './inputs/jsonschema'; +export {writeGeneratedFiles, generateModels} from './output'; export { defaultTypeScriptChannelsGenerator, diff --git a/src/codegen/modelina/presets/validation.ts b/src/codegen/modelina/presets/validation.ts index d18378b9..d73e9749 100644 --- a/src/codegen/modelina/presets/validation.ts +++ b/src/codegen/modelina/presets/validation.ts @@ -115,10 +115,12 @@ export function generateTypescriptValidationCode({ '{Ajv, Options as AjvOptions, ErrorObject, ValidateFunction}', 'ajv' ); - // Use named import with default alias for compatibility without esModuleInterop - // This works with both esModuleInterop: true and verbatimModuleSyntax: true + // Import the module rather than its `default` binding directly. `ajv-formats` + // ships as CommonJS, and under `moduleResolution: node16`/`nodenext` a + // `{default as addFormats}` (or plain default) import resolves to the module + // namespace, which is not callable. The call site unwraps `.default` instead. renderer.dependencyManager.addTypeScriptDependency( - '{default as addFormats}', + 'addFormatsModule', 'ajv-formats' ); @@ -156,6 +158,9 @@ ${methodPrefix}validate(context?: {data: any, ajvValidatorFunction?: ValidateFun } ${methodPrefix}createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // \`ajv-formats\` is CommonJS; its default import is the module namespace under + // \`moduleResolution: node16\`/\`nodenext\`, so unwrap \`.default\` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ${vocabularies} const validate = ajvInstance.compile(${compileCall}); diff --git a/src/codegen/output/index.ts b/src/codegen/output/index.ts index 667ec262..157f7cf9 100644 --- a/src/codegen/output/index.ts +++ b/src/codegen/output/index.ts @@ -10,7 +10,7 @@ import {FileSystemAdapter} from './filesystem'; export * from './types'; export {FileSystemAdapter} from './filesystem'; export {MemoryAdapter} from './memory'; -export {generateModels} from './modelina'; +export {generateModels, applyImportExtension} from './modelina'; export type {GenerateModelsArgs, GenerateModelsResult} from './modelina'; // Re-export GeneratedFile type for convenience diff --git a/src/codegen/output/modelina.ts b/src/codegen/output/modelina.ts index e02f41b2..d4e0d0a3 100644 --- a/src/codegen/output/modelina.ts +++ b/src/codegen/output/modelina.ts @@ -10,6 +10,7 @@ import { OutputModel } from '@asyncapi/modelina'; import {GeneratedFile} from '../types'; +import {ImportExtension} from '../utils'; export interface GenerateModelsArgs { /** The Modelina generator instance */ @@ -20,6 +21,47 @@ export interface GenerateModelsArgs { outputPath: string; /** Optional render options */ options?: Partial; + /** + * Extension to append to the relative imports Modelina renders between models + * (for example the enum a model was split into). Modelina has no option for + * this, so it is applied to the rendered output here. + */ + importExtension?: ImportExtension; +} + +/** + * Matches the module specifier of a relative import/export/require that Modelina + * renders between models, e.g. `from './Address'` or `require('./Address')`. + * Specifiers that already carry an extension are left alone. + */ +const RELATIVE_MODULE_SPECIFIER = + /(from\s+|require\(\s*)(['"])(\.{1,2}\/[^'"]*)\2/g; + +/** + * Appends `extension` to every extensionless relative module specifier in a + * rendered model file. Modelina always renders cross-model dependencies as + * `./` with no extension, which does not compile under + * `moduleResolution: node16`/`nodenext`. + */ +export function applyImportExtension({ + content, + extension +}: { + content: string; + extension: ImportExtension; +}): string { + if (extension === 'none') { + return content; + } + return content.replace( + RELATIVE_MODULE_SPECIFIER, + (match, keyword, quote, specifier) => { + if (/\.[a-zA-Z0-9]+$/.test(specifier)) { + return match; + } + return `${keyword}${quote}${specifier}${extension}${quote}`; + } + ); } export interface GenerateModelsResult { @@ -39,7 +81,8 @@ export async function generateModels({ generator, input, outputPath, - options = {} + options = {}, + importExtension = 'none' }: GenerateModelsArgs): Promise { const files: GeneratedFile[] = []; @@ -57,7 +100,13 @@ export async function generateModels({ const fileName = `${model.modelName}.ts`; const filePath = `${outputPath}/${fileName}`; - files.push({path: filePath, content: model.result}); + files.push({ + path: filePath, + content: applyImportExtension({ + content: model.result, + extension: importExtension + }) + }); } return { diff --git a/src/codegen/types.ts b/src/codegen/types.ts index e2b75791..fe0593ec 100644 --- a/src/codegen/types.ts +++ b/src/codegen/types.ts @@ -206,6 +206,13 @@ export interface SingleFunctionRenderType { * methods accept the same ergonomic plain object the channel functions do. */ messageUnionType?: string; + /** + * The header type used in the channel function's callback, when the channel + * has headers. Consumed by the client generator so its wrapper subscribe + * methods declare the same callback signature as the channel function they + * delegate to. + */ + headerType?: string; replyType?: string; /** * Grouping metadata used by the channels generator's `organization` option. diff --git a/src/index.ts b/src/index.ts index 3bae4c92..a214f843 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,6 +30,7 @@ export { SingleFunctionRenderType, runGenerators, loadAsyncapi, + loadOpenapi, loadJsonSchema, getDefaultConfiguration, renderGenerator, @@ -41,6 +42,7 @@ export { loadOpenapiFromMemory, loadAsyncapiFromMemory, loadJsonSchemaFromMemory, + writeGeneratedFiles, ChannelFunctionTypes } from './codegen'; diff --git a/test/blackbox/projects/typescript/package.json b/test/blackbox/projects/typescript/package.json index 63661750..126712d2 100644 --- a/test/blackbox/projects/typescript/package.json +++ b/test/blackbox/projects/typescript/package.json @@ -2,6 +2,8 @@ "name": "temp", "version": "0.0.0", "dependencies": { + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", "nats": "2.28.2", "kafkajs": "^2.2.4", "mqtt": "^5.10.3", diff --git a/test/blackbox/typescript.spec.ts b/test/blackbox/typescript.spec.ts index de00550d..4a05430e 100644 --- a/test/blackbox/typescript.spec.ts +++ b/test/blackbox/typescript.spec.ts @@ -1,7 +1,7 @@ import * as path from 'path'; import * as fs from 'fs'; import {filesToTest, typescriptConfig, isKnownFailing } from './test_files'; -import {loadAsyncapi, loadJsonSchema, loadConfigFile, realizeConfiguration, RunGeneratorContext, runGenerators } from '../../src'; +import {loadAsyncapi, loadOpenapi, loadJsonSchema, loadConfigFile, realizeConfiguration, RunGeneratorContext, runGenerators, writeGeneratedFiles } from '../../src'; import { execCommand } from './utils'; jest.setTimeout(100000); @@ -43,7 +43,7 @@ describe.each(typescriptConfig)( const newConfig = {...config} const newGens = [...newConfig.generators] newConfig.generators = [] - newConfig.inputPath = path.resolve('./', schemaFile.file); + newConfig.inputPath = path.resolve('./test/blackbox/', schemaFile.file); const outputDirectoryPath = outputPath; for (let [index, generator] of Object.entries(newGens)) { @@ -59,13 +59,27 @@ describe.each(typescriptConfig)( if (newConfig.inputType === 'asyncapi') { const document = await loadAsyncapi(context); context.asyncapiDocument = document; + } else if (newConfig.inputType === 'openapi') { + const document = await loadOpenapi(context); + context.openapiDocument = document; } else if (newConfig.inputType === 'jsonschema') { const document = await loadJsonSchema(context); context.jsonSchemaDocument = document; } - await runGenerators(context); + const result = await runGenerators(context); + // `runGenerators` is pure and returns the files in memory; writing them + // is the caller's job (see the `generate` command). Without this step the + // suite compiles an empty project and passes no matter what was generated. + await writeGeneratedFiles(result.files, path.dirname(filePath)); + // Everything that was generated must reach the compiler below. + for (const file of result.files) { + expect(fs.existsSync(file.path)).toEqual(true); + } fs.cpSync(path.resolve(__dirname, './projects/typescript'), path.resolve(outputDirectoryPath), {recursive: true}); const srcDirectory = path.resolve(outputDirectoryPath, './src'); + // Some config/document pairs legitimately generate nothing (a parameters + // config against a document with no channel parameters, for example), so + // give `tsc` an entry point rather than failing the pair. if(!fs.existsSync(srcDirectory)) { fs.mkdirSync(srcDirectory) fs.writeFileSync(path.resolve(srcDirectory, './index.ts'), '') diff --git a/test/codegen/generators/typescript/__snapshots__/headers.spec.ts.snap b/test/codegen/generators/typescript/__snapshots__/headers.spec.ts.snap index 78dfcaa8..c1c50c6a 100644 --- a/test/codegen/generators/typescript/__snapshots__/headers.spec.ts.snap +++ b/test/codegen/generators/typescript/__snapshots__/headers.spec.ts.snap @@ -26,7 +26,7 @@ export { DeletePetHeaders };" exports[`headers typescript should work with basic AsyncAPI inputs 1`] = ` "import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; class SimpleObjectHeaders { private _displayName?: string; private _email?: string; @@ -116,6 +116,9 @@ class SimpleObjectHeaders { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // \`ajv-formats\` is CommonJS; its default import is the module namespace under + // \`moduleResolution: node16\`/\`nodenext\`, so unwrap \`.default\` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); diff --git a/test/codegen/generators/typescript/__snapshots__/parameters.spec.ts.snap b/test/codegen/generators/typescript/__snapshots__/parameters.spec.ts.snap index d638d4c2..f9603ed9 100644 --- a/test/codegen/generators/typescript/__snapshots__/parameters.spec.ts.snap +++ b/test/codegen/generators/typescript/__snapshots__/parameters.spec.ts.snap @@ -42,7 +42,8 @@ class SingleParameterParameters { return parameters; } } -export { SingleParameterParameters, SingleParameterParametersInterface };" +export { SingleParameterParameters }; +export type { SingleParameterParametersInterface };" `; exports[`parameters typescript asyncapi should work with AsyncAPI that contains parameters 2`] = ` @@ -100,7 +101,8 @@ class MultipleParameterParameters { return parameters; } } -export { MultipleParameterParameters, MultipleParameterParametersInterface };" +export { MultipleParameterParameters }; +export type { MultipleParameterParametersInterface };" `; exports[`parameters typescript asyncapi should work with AsyncAPI v2 that contains parameters and const parameters 1`] = ` @@ -145,7 +147,8 @@ class SingleParameterParameters { return parameters; } } -export { SingleParameterParameters, SingleParameterParametersInterface };" +export { SingleParameterParameters }; +export type { SingleParameterParametersInterface };" `; exports[`parameters typescript asyncapi should work with AsyncAPI v2 that contains parameters and const parameters 2`] = ` @@ -200,7 +203,8 @@ class MultipleParameterParameters { return parameters; } } -export { MultipleParameterParameters, MultipleParameterParametersInterface };" +export { MultipleParameterParameters }; +export type { MultipleParameterParametersInterface };" `; exports[`parameters typescript openapi should use constrained property names and skip deserializeUrl without query parameters 1`] = ` @@ -324,7 +328,8 @@ class GetDocumentParameters { return result; } } -export { GetDocumentParameters, GetDocumentParametersInterface };" +export { GetDocumentParameters }; +export type { GetDocumentParametersInterface };" `; exports[`parameters typescript openapi should use constrained property names and skip deserializeUrl without query parameters 2`] = ` @@ -467,7 +472,8 @@ class GetTransactionsParameters { return instance; } } -export { GetTransactionsParameters, GetTransactionsParametersInterface };" +export { GetTransactionsParameters }; +export type { GetTransactionsParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 2.0 that contains parameters 1`] = ` @@ -594,7 +600,8 @@ class DeleteOrderParameters { return result; } } -export { DeleteOrderParameters, DeleteOrderParametersInterface };" +export { DeleteOrderParameters }; +export type { DeleteOrderParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 2.0 that contains parameters 2`] = ` @@ -721,7 +728,8 @@ class DeletePetParameters { return result; } } -export { DeletePetParameters, DeletePetParametersInterface };" +export { DeletePetParameters }; +export type { DeletePetParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 2.0 that contains parameters 3`] = ` @@ -848,7 +856,8 @@ class DeleteUserParameters { return result; } } -export { DeleteUserParameters, DeleteUserParametersInterface };" +export { DeleteUserParameters }; +export type { DeleteUserParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 2.0 that contains parameters 4`] = ` @@ -967,7 +976,8 @@ class FindPetsByStatusParameters { return instance; } } -export { FindPetsByStatusParameters, FindPetsByStatusParametersInterface };" +export { FindPetsByStatusParameters }; +export type { FindPetsByStatusParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 2.0 that contains parameters 5`] = ` @@ -1086,7 +1096,8 @@ class FindPetsByTagsParameters { return instance; } } -export { FindPetsByTagsParameters, FindPetsByTagsParametersInterface };" +export { FindPetsByTagsParameters }; +export type { FindPetsByTagsParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 2.0 that contains parameters 6`] = ` @@ -1213,7 +1224,8 @@ class GetOrderByIdParameters { return result; } } -export { GetOrderByIdParameters, GetOrderByIdParametersInterface };" +export { GetOrderByIdParameters }; +export type { GetOrderByIdParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 2.0 that contains parameters 7`] = ` @@ -1340,7 +1352,8 @@ class GetPetByIdParameters { return result; } } -export { GetPetByIdParameters, GetPetByIdParametersInterface };" +export { GetPetByIdParameters }; +export type { GetPetByIdParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 2.0 that contains parameters 8`] = ` @@ -1467,7 +1480,8 @@ class GetUserByNameParameters { return result; } } -export { GetUserByNameParameters, GetUserByNameParametersInterface };" +export { GetUserByNameParameters }; +export type { GetUserByNameParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 2.0 that contains parameters 9`] = ` @@ -1614,7 +1628,8 @@ class LoginUserParameters { return instance; } } -export { LoginUserParameters, LoginUserParametersInterface };" +export { LoginUserParameters }; +export type { LoginUserParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 2.0 that contains parameters 10`] = ` @@ -1741,7 +1756,8 @@ class UpdatePetWithFormParameters { return result; } } -export { UpdatePetWithFormParameters, UpdatePetWithFormParametersInterface };" +export { UpdatePetWithFormParameters }; +export type { UpdatePetWithFormParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 2.0 that contains parameters 11`] = ` @@ -1868,7 +1884,8 @@ class UpdateUserParameters { return result; } } -export { UpdateUserParameters, UpdateUserParametersInterface };" +export { UpdateUserParameters }; +export type { UpdateUserParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 2.0 that contains parameters 12`] = ` @@ -1995,7 +2012,8 @@ class UploadFileParameters { return result; } } -export { UploadFileParameters, UploadFileParametersInterface };" +export { UploadFileParameters }; +export type { UploadFileParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.0 that contains parameters 1`] = ` @@ -2122,7 +2140,8 @@ class DeleteOrderParameters { return result; } } -export { DeleteOrderParameters, DeleteOrderParametersInterface };" +export { DeleteOrderParameters }; +export type { DeleteOrderParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.0 that contains parameters 2`] = ` @@ -2249,7 +2268,8 @@ class DeletePetParameters { return result; } } -export { DeletePetParameters, DeletePetParametersInterface };" +export { DeletePetParameters }; +export type { DeletePetParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.0 that contains parameters 3`] = ` @@ -2376,7 +2396,8 @@ class DeleteUserParameters { return result; } } -export { DeleteUserParameters, DeleteUserParametersInterface };" +export { DeleteUserParameters }; +export type { DeleteUserParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.0 that contains parameters 4`] = ` @@ -2497,7 +2518,8 @@ class FindPetsByStatusParameters { return instance; } } -export { FindPetsByStatusParameters, FindPetsByStatusParametersInterface };" +export { FindPetsByStatusParameters }; +export type { FindPetsByStatusParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.0 that contains parameters 5`] = ` @@ -2618,7 +2640,8 @@ class FindPetsByTagsParameters { return instance; } } -export { FindPetsByTagsParameters, FindPetsByTagsParametersInterface };" +export { FindPetsByTagsParameters }; +export type { FindPetsByTagsParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.0 that contains parameters 6`] = ` @@ -2745,7 +2768,8 @@ class GetOrderByIdParameters { return result; } } -export { GetOrderByIdParameters, GetOrderByIdParametersInterface };" +export { GetOrderByIdParameters }; +export type { GetOrderByIdParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.0 that contains parameters 7`] = ` @@ -2872,7 +2896,8 @@ class GetPetByIdParameters { return result; } } -export { GetPetByIdParameters, GetPetByIdParametersInterface };" +export { GetPetByIdParameters }; +export type { GetPetByIdParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.0 that contains parameters 8`] = ` @@ -2999,7 +3024,8 @@ class GetUserByNameParameters { return result; } } -export { GetUserByNameParameters, GetUserByNameParametersInterface };" +export { GetUserByNameParameters }; +export type { GetUserByNameParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.0 that contains parameters 9`] = ` @@ -3146,7 +3172,8 @@ class LoginUserParameters { return instance; } } -export { LoginUserParameters, LoginUserParametersInterface };" +export { LoginUserParameters }; +export type { LoginUserParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.0 that contains parameters 10`] = ` @@ -3273,7 +3300,8 @@ class UpdatePetWithFormParameters { return result; } } -export { UpdatePetWithFormParameters, UpdatePetWithFormParametersInterface };" +export { UpdatePetWithFormParameters }; +export type { UpdatePetWithFormParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.0 that contains parameters 11`] = ` @@ -3400,7 +3428,8 @@ class UpdateUserParameters { return result; } } -export { UpdateUserParameters, UpdateUserParametersInterface };" +export { UpdateUserParameters }; +export type { UpdateUserParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.0 that contains parameters 12`] = ` @@ -3527,7 +3556,8 @@ class UploadFileParameters { return result; } } -export { UploadFileParameters, UploadFileParametersInterface };" +export { UploadFileParameters }; +export type { UploadFileParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.1 that contains parameters 1`] = ` @@ -3654,7 +3684,8 @@ class DeleteOrderParameters { return result; } } -export { DeleteOrderParameters, DeleteOrderParametersInterface };" +export { DeleteOrderParameters }; +export type { DeleteOrderParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.1 that contains parameters 2`] = ` @@ -3781,7 +3812,8 @@ class DeletePetParameters { return result; } } -export { DeletePetParameters, DeletePetParametersInterface };" +export { DeletePetParameters }; +export type { DeletePetParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.1 that contains parameters 3`] = ` @@ -3908,7 +3940,8 @@ class DeleteUserParameters { return result; } } -export { DeleteUserParameters, DeleteUserParametersInterface };" +export { DeleteUserParameters }; +export type { DeleteUserParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.1 that contains parameters 4`] = ` @@ -4029,7 +4062,8 @@ class FindPetsByStatusParameters { return instance; } } -export { FindPetsByStatusParameters, FindPetsByStatusParametersInterface };" +export { FindPetsByStatusParameters }; +export type { FindPetsByStatusParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.1 that contains parameters 5`] = ` @@ -4150,7 +4184,8 @@ class FindPetsByTagsParameters { return instance; } } -export { FindPetsByTagsParameters, FindPetsByTagsParametersInterface };" +export { FindPetsByTagsParameters }; +export type { FindPetsByTagsParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.1 that contains parameters 6`] = ` @@ -4277,7 +4312,8 @@ class GetOrderByIdParameters { return result; } } -export { GetOrderByIdParameters, GetOrderByIdParametersInterface };" +export { GetOrderByIdParameters }; +export type { GetOrderByIdParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.1 that contains parameters 7`] = ` @@ -4404,7 +4440,8 @@ class GetPetByIdParameters { return result; } } -export { GetPetByIdParameters, GetPetByIdParametersInterface };" +export { GetPetByIdParameters }; +export type { GetPetByIdParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.1 that contains parameters 8`] = ` @@ -4531,7 +4568,8 @@ class GetUserByNameParameters { return result; } } -export { GetUserByNameParameters, GetUserByNameParametersInterface };" +export { GetUserByNameParameters }; +export type { GetUserByNameParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.1 that contains parameters 9`] = ` @@ -4678,7 +4716,8 @@ class LoginUserParameters { return instance; } } -export { LoginUserParameters, LoginUserParametersInterface };" +export { LoginUserParameters }; +export type { LoginUserParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.1 that contains parameters 10`] = ` @@ -4805,7 +4844,8 @@ class UpdatePetWithFormParameters { return result; } } -export { UpdatePetWithFormParameters, UpdatePetWithFormParametersInterface };" +export { UpdatePetWithFormParameters }; +export type { UpdatePetWithFormParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.1 that contains parameters 11`] = ` @@ -4932,7 +4972,8 @@ class UpdateUserParameters { return result; } } -export { UpdateUserParameters, UpdateUserParametersInterface };" +export { UpdateUserParameters }; +export type { UpdateUserParametersInterface };" `; exports[`parameters typescript openapi should work with OpenAPI 3.1 that contains parameters 12`] = ` @@ -5059,5 +5100,6 @@ class UploadFileParameters { return result; } } -export { UploadFileParameters, UploadFileParametersInterface };" +export { UploadFileParameters }; +export type { UploadFileParametersInterface };" `; diff --git a/test/codegen/generators/typescript/__snapshots__/payload.spec.ts.snap b/test/codegen/generators/typescript/__snapshots__/payload.spec.ts.snap index b59c01f8..f2fa490f 100644 --- a/test/codegen/generators/typescript/__snapshots__/payload.spec.ts.snap +++ b/test/codegen/generators/typescript/__snapshots__/payload.spec.ts.snap @@ -104,13 +104,14 @@ class SimpleObject2 { return SimpleObject2.fromJson(obj as Record); } } -export { SimpleObject2, SimpleObject2Interface };" +export { SimpleObject2 }; +export type { SimpleObject2Interface };" `; exports[`payloads typescript should work with basic AsyncAPI inputs 1`] = ` "import {SimpleObject} from './SimpleObject'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; type UnionPayload = SimpleObject | boolean | string; export function unmarshal(json: any): UnionPayload { @@ -145,6 +146,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // \`ajv-formats\` is CommonJS; its default import is the module namespace under + // \`moduleResolution: node16\`/\`nodenext\`, so unwrap \`.default\` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); @@ -157,7 +161,7 @@ export { UnionPayload };" exports[`payloads typescript should work with basic AsyncAPI inputs 2`] = ` "import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface SimpleObject2Interface { displayName?: string email?: string @@ -248,6 +252,9 @@ class SimpleObject2 { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // \`ajv-formats\` is CommonJS; its default import is the module namespace under + // \`moduleResolution: node16\`/\`nodenext\`, so unwrap \`.default\` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -255,12 +262,13 @@ class SimpleObject2 { } } -export { SimpleObject2, SimpleObject2Interface };" +export { SimpleObject2 }; +export type { SimpleObject2Interface };" `; exports[`payloads typescript should work with no channels 1`] = ` "import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface SimpleObjectInterface { displayName?: string email?: string @@ -357,6 +365,9 @@ class SimpleObject { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // \`ajv-formats\` is CommonJS; its default import is the module namespace under + // \`moduleResolution: node16\`/\`nodenext\`, so unwrap \`.default\` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -364,5 +375,6 @@ class SimpleObject { } } -export { SimpleObject, SimpleObjectInterface };" +export { SimpleObject }; +export type { SimpleObjectInterface };" `; diff --git a/test/codegen/generators/typescript/channels/header-union.spec.ts b/test/codegen/generators/typescript/channels/header-union.spec.ts new file mode 100644 index 00000000..e4f39b02 --- /dev/null +++ b/test/codegen/generators/typescript/channels/header-union.spec.ts @@ -0,0 +1,135 @@ +/** + * Tests for how channel header models are referenced in generated code. + * + * A channel whose messages each declare their own headers produces a `oneOf` + * union model. Its `type` is the expanded union (`A | B | C`) — referencing it + * directly emits identifiers the generated file never imports, and there is no + * static `unmarshal` on a type alias for the receive paths to call. Union + * header models are therefore imported as a namespace, the same way payload + * unions are. + */ +import { + addHeadersToDependencies, + getHeaderTypeAndModule +} from '../../../../../src/codegen/generators/typescript/channels/utils'; +import { + ConstrainedObjectModel, + ConstrainedUnionModel, + OutputModel +} from '@asyncapi/modelina'; + +const objectHeaders = new ConstrainedObjectModel( + 'UserSignedUpHeaders', + undefined, + {}, + 'UserSignedUpHeaders', + {} +); + +const unionHeaders = new ConstrainedUnionModel( + 'OrderLifecycleHeaders', + undefined, + {}, + 'OrderCreatedHeaders | OrderUpdatedHeaders | OrderCancelledHeaders', + [ + new ConstrainedObjectModel( + 'OrderCreatedHeaders', + undefined, + {}, + 'OrderCreatedHeaders', + {} + ), + new ConstrainedObjectModel( + 'OrderUpdatedHeaders', + undefined, + {}, + 'OrderUpdatedHeaders', + {} + ) + ] +); + +const asOutputModel = (model: ConstrainedObjectModel | ConstrainedUnionModel) => + new OutputModel( + '', + model, + model.name, + {models: {}, originalInput: undefined}, + [] + ); + +describe('getHeaderTypeAndModule', () => { + it('returns undefined for a channel without headers', () => { + expect(getHeaderTypeAndModule(undefined)).toEqual({ + headerType: undefined, + headerModule: undefined + }); + }); + + it('uses the model type directly for a single-message header model', () => { + expect(getHeaderTypeAndModule(objectHeaders)).toEqual({ + headerType: 'UserSignedUpHeaders', + headerModule: undefined + }); + }); + + it('routes a union header model through its namespace module', () => { + // Not the expanded `A | B | C` — those members are never imported, and the + // runtime helpers live on the module. + expect(getHeaderTypeAndModule(unionHeaders)).toEqual({ + headerType: 'OrderLifecycleHeadersModule.OrderLifecycleHeaders', + headerModule: 'OrderLifecycleHeadersModule' + }); + }); +}); + +describe('addHeadersToDependencies', () => { + const headerGenerator = {outputPath: './src/__gen__/channels/headers'}; + const currentGenerator = {outputPath: './src/__gen__/channels'}; + + it('emits a named import for a single-message header model', () => { + const dependencies: string[] = []; + + addHeadersToDependencies( + {channel: asOutputModel(objectHeaders)}, + headerGenerator, + currentGenerator, + dependencies + ); + + expect(dependencies).toEqual([ + `import {UserSignedUpHeaders} from './headers/UserSignedUpHeaders';` + ]); + }); + + it('emits a namespace import for a union header model', () => { + const dependencies: string[] = []; + + addHeadersToDependencies( + {channel: asOutputModel(unionHeaders)}, + headerGenerator, + currentGenerator, + dependencies + ); + + expect(dependencies).toEqual([ + `import * as OrderLifecycleHeadersModule from './headers/OrderLifecycleHeaders';` + ]); + }); + + it('applies the import extension to the namespace import', () => { + const dependencies: string[] = []; + + addHeadersToDependencies( + {channel: asOutputModel(unionHeaders)}, + headerGenerator, + currentGenerator, + dependencies, + '.js' + ); + + expect(dependencies).toEqual([ + `import * as OrderLifecycleHeadersModule from './headers/OrderLifecycleHeaders.js';` + ]); + }); +}); diff --git a/test/codegen/generators/typescript/client.spec.ts b/test/codegen/generators/typescript/client.spec.ts index 63c3b7a1..1479dcd7 100644 --- a/test/codegen/generators/typescript/client.spec.ts +++ b/test/codegen/generators/typescript/client.spec.ts @@ -1,5 +1,6 @@ import path from "node:path"; import { defaultTypeScriptClientGenerator, generateTypeScriptClient, TypeScriptParameterRenderType } from "../../../../src/codegen/generators"; +import { TypeScriptHeadersRenderType } from "../../../../src/codegen/generators/typescript/headers"; import { loadAsyncapiDocument } from "../../../../src/codegen/inputs/asyncapi"; import { ConstrainedAnyModel, ConstrainedObjectModel, OutputModel } from "@asyncapi/modelina"; import { ChannelFunctionTypes, defaultTypeScriptChannelsGenerator, TypeScriptChannelRenderType } from "../../../../src/codegen/generators/typescript/channels"; @@ -31,10 +32,17 @@ describe('client', () => { generator: {outputPath: './test'} as any, files: [] }; + const headersDependency: TypeScriptHeadersRenderType = { + channelModels: {}, + generator: {outputPath: './test'} as any, + headerFunctions: {}, + files: [] + }; const channelsDependency: TypeScriptChannelRenderType = { payloadRender: payloadsDependency, result: '', parameterRender: parametersDependency, + headerRender: headersDependency, renderedFunctions: { nats: [ { @@ -105,10 +113,17 @@ describe('client', () => { generator: {outputPath: './test'} as any, files: [] }; + const headersDependency: TypeScriptHeadersRenderType = { + channelModels: {}, + generator: {outputPath: './test'} as any, + headerFunctions: {}, + files: [] + }; const channelsDependency: TypeScriptChannelRenderType = { payloadRender: payloadsDependency, result: '', parameterRender: parametersDependency, + headerRender: headersDependency, renderedFunctions: { http_client: [ { @@ -153,10 +168,17 @@ describe('client', () => { generator: {outputPath: './test'} as any, files: [] }; + const headersDependency: TypeScriptHeadersRenderType = { + channelModels: {}, + generator: {outputPath: './test'} as any, + headerFunctions: {}, + files: [] + }; const channelsDependency: TypeScriptChannelRenderType = { payloadRender: payloadsDependency, result: '', parameterRender: parametersDependency, + headerRender: headersDependency, renderedFunctions: {http_client: []}, generator: defaultTypeScriptChannelsGenerator, protocolFiles: {}, diff --git a/test/codegen/generators/typescript/payload.spec.ts b/test/codegen/generators/typescript/payload.spec.ts index 53bdeb01..c23404a8 100644 --- a/test/codegen/generators/typescript/payload.spec.ts +++ b/test/codegen/generators/typescript/payload.spec.ts @@ -380,7 +380,10 @@ describe('payloads', () => { expect(result).toContain('interface SimpleObject2Interface {'); expect(result).toContain('constructor(input: SimpleObject2Interface)'); - expect(result).toContain('export { SimpleObject2, SimpleObject2Interface };'); + // The companion is a type, so it is re-exported with `export type` — + // a combined value export breaks under `isolatedModules: true` (TS1205). + expect(result).toContain('export { SimpleObject2 };'); + expect(result).toContain('export type { SimpleObject2Interface };'); }); it('includes every accepted ctor property (including additionalProperties) in the companion interface', async () => { diff --git a/test/codegen/modelina/presets/validation.spec.ts b/test/codegen/modelina/presets/validation.spec.ts index 71c2ced5..bb0892da 100644 --- a/test/codegen/modelina/presets/validation.spec.ts +++ b/test/codegen/modelina/presets/validation.spec.ts @@ -33,7 +33,7 @@ const createMockModel = () => ({ describe('Validation Preset', () => { describe('ajv-formats import', () => { - it('should use named import with default alias for ajv-formats', () => { + it('should import the ajv-formats module, not its default binding', () => { const mockRenderer = createMockRenderer(); const mockModel = createMockModel(); const context = { @@ -54,14 +54,14 @@ describe('Validation Preset', () => { (d) => d.from === 'ajv-formats' ); expect(ajvFormatsDep).toBeDefined(); - // Should use named import pattern that works without esModuleInterop - // Either: `{default as addFormats}` or `* as addFormatsModule` - expect(ajvFormatsDep?.what).toMatch( - /(\{default as addFormats\})|(\* as \w+)/ - ); + // `ajv-formats` is CommonJS. Under `moduleResolution: node16`/`nodenext` + // both `addFormats` and `{default as addFormats}` resolve to the module + // namespace, which is not callable (TS2349), so the module itself is + // imported and the call site unwraps `.default`. + expect(ajvFormatsDep?.what).toBe('addFormatsModule'); }); - it('should not use bare default import for ajv-formats', () => { + it('should not import the default binding directly for ajv-formats', () => { const mockRenderer = createMockRenderer(); const mockModel = createMockModel(); const context = { @@ -81,8 +81,9 @@ describe('Validation Preset', () => { const ajvFormatsDep = mockRenderer.dependencies.find( (d) => d.from === 'ajv-formats' ); - // Should NOT be a bare default import + // Neither of these is callable under node16/nodenext resolution. expect(ajvFormatsDep?.what).not.toBe('addFormats'); + expect(ajvFormatsDep?.what).not.toBe('{default as addFormats}'); }); }); diff --git a/test/codegen/output/modelina-import-extension.spec.ts b/test/codegen/output/modelina-import-extension.spec.ts new file mode 100644 index 00000000..9ffa1018 --- /dev/null +++ b/test/codegen/output/modelina-import-extension.spec.ts @@ -0,0 +1,70 @@ +/** + * Tests for the import-extension pass applied to Modelina's rendered models. + * + * Modelina renders the imports between models (an object model and the enum it + * was split into, for example) as `./` with no extension, and it has + * no option to change that. Those imports do not compile under + * `moduleResolution: node16`/`nodenext`, so the extension is applied to the + * rendered output instead. + */ +import {applyImportExtension} from '../../../src/codegen/output/modelina'; + +describe('applyImportExtension', () => { + it('leaves content untouched when the extension is "none"', () => { + const content = `import {Command} from './Command';\nexport {Thing};`; + + expect(applyImportExtension({content, extension: 'none'})).toEqual(content); + }); + + it('appends the extension to relative cross-model imports', () => { + const content = `import {Command} from './Command';\nimport {Money} from './nested/Money';`; + + expect(applyImportExtension({content, extension: '.js'})).toEqual( + `import {Command} from './Command.js';\nimport {Money} from './nested/Money.js';` + ); + }); + + it('supports the .ts extension', () => { + const content = `import {Command} from './Command';`; + + expect(applyImportExtension({content, extension: '.ts'})).toEqual( + `import {Command} from './Command.ts';` + ); + }); + + it('leaves bare module specifiers untouched', () => { + const content = `import {Ajv} from 'ajv';\nimport addFormatsModule from 'ajv-formats';`; + + expect(applyImportExtension({content, extension: '.js'})).toEqual(content); + }); + + it('does not double-append when a specifier already has an extension', () => { + const content = `import {Command} from './Command.js';`; + + expect(applyImportExtension({content, extension: '.js'})).toEqual(content); + }); + + it('handles parent-relative specifiers and double quotes', () => { + const content = `import {Money} from "../payloads/Money";`; + + expect(applyImportExtension({content, extension: '.js'})).toEqual( + `import {Money} from "../payloads/Money.js";` + ); + }); + + it('handles type-only imports and exports', () => { + const content = `import type {Command} from './Command';\nexport type {Command} from './Command';`; + + expect(applyImportExtension({content, extension: '.js'})).toEqual( + `import type {Command} from './Command.js';\nexport type {Command} from './Command.js';` + ); + }); + + it('handles CommonJS require specifiers', () => { + const content = `const {Command} = require('./Command');`; + + expect(applyImportExtension({content, extension: '.js'})).toEqual( + `const {Command} = require('./Command.js');` + ); + }); +}); diff --git a/test/runtime/typescript/package-lock.json b/test/runtime/typescript/package-lock.json index 2b2c4bb7..b29192e6 100644 --- a/test/runtime/typescript/package-lock.json +++ b/test/runtime/typescript/package-lock.json @@ -9,6 +9,7 @@ "@swc/core": "^1.3.5", "@swc/jest": "^0.2.23", "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", "amqplib": "^0.10.5", "body-parser": "^1.20.2", "express": "^4.21.0", @@ -1522,6 +1523,23 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/amqplib": { "version": "0.10.5", "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.10.5.tgz", diff --git a/test/runtime/typescript/package.json b/test/runtime/typescript/package.json index 554e67f1..f14131e1 100644 --- a/test/runtime/typescript/package.json +++ b/test/runtime/typescript/package.json @@ -13,7 +13,7 @@ "test:websocket": "jest -- ./test/channels/regular/websocket.spec.ts", "test:http": "jest -- ./test/channels/request_reply/http_client/", "test:payload-types": "jest -- ./test/payload-types/", - "generate": "npm run generate:regular && npm run generate:request:reply && npm run generate:openapi && npm run generate:openapi-primitive && npm run generate:payload-types && npm run generate:organization", + "generate": "npm run generate:regular && npm run generate:request:reply && npm run generate:openapi && npm run generate:openapi-primitive && npm run generate:payload-types && npm run generate:organization && npm run generate:node16", "generate:organization": "npm run generate:organization:openapi-tag && npm run generate:organization:openapi-path && npm run generate:organization:asyncapi-tag && npm run generate:organization:asyncapi-path", "generate:organization:openapi-tag": "cross-env CODEGEN_TELEMETRY_DISABLED=1 node ../../../bin/run.mjs generate ./codegen-openapi-tag.mjs", "generate:organization:openapi-path": "cross-env CODEGEN_TELEMETRY_DISABLED=1 node ../../../bin/run.mjs generate ./codegen-openapi-path.mjs", @@ -24,6 +24,7 @@ "generate:openapi": "cross-env CODEGEN_TELEMETRY_DISABLED=1 node ../../../bin/run.mjs generate ./codegen-openapi.mjs", "generate:openapi-primitive": "cross-env CODEGEN_TELEMETRY_DISABLED=1 node ../../../bin/run.mjs generate ./codegen-openapi-primitive.mjs", "generate:payload-types": "cross-env CODEGEN_TELEMETRY_DISABLED=1 node ../../../bin/run.mjs generate ./codegen-payload-types.mjs", + "generate:node16": "cross-env CODEGEN_TELEMETRY_DISABLED=1 node ../../../bin/run.mjs generate ./codegen-node16.mjs", "debug:generate": "node --inspect-brk ../../../bin/run.mjs generate" }, "dependencies": { @@ -31,6 +32,7 @@ "@swc/core": "^1.3.5", "@swc/jest": "^0.2.23", "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", "amqplib": "^0.10.5", "body-parser": "^1.20.2", "express": "^4.21.0", diff --git a/test/runtime/typescript/src/asyncapi-path-organization/channels/headers/UserSignedUpHeaders.ts b/test/runtime/typescript/src/asyncapi-path-organization/channels/headers/UserSignedUpHeaders.ts index d20d9d5a..c7ca7593 100644 --- a/test/runtime/typescript/src/asyncapi-path-organization/channels/headers/UserSignedUpHeaders.ts +++ b/test/runtime/typescript/src/asyncapi-path-organization/channels/headers/UserSignedUpHeaders.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; class UserSignedUpHeaders { private _xTestHeader?: string; private _additionalProperties?: Map; @@ -74,6 +74,9 @@ class UserSignedUpHeaders { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); diff --git a/test/runtime/typescript/src/asyncapi-path-organization/channels/parameter/UserSignedupParameters.ts b/test/runtime/typescript/src/asyncapi-path-organization/channels/parameter/UserSignedupParameters.ts index 4195c425..db0c02ca 100644 --- a/test/runtime/typescript/src/asyncapi-path-organization/channels/parameter/UserSignedupParameters.ts +++ b/test/runtime/typescript/src/asyncapi-path-organization/channels/parameter/UserSignedupParameters.ts @@ -58,4 +58,5 @@ class UserSignedupParameters { return parameters; } } -export { UserSignedupParameters, UserSignedupParametersInterface }; \ No newline at end of file +export { UserSignedupParameters }; +export type { UserSignedupParametersInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/ArrayMessage.ts b/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/ArrayMessage.ts index e3d8a41c..14959285 100644 --- a/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/ArrayMessage.ts +++ b/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/ArrayMessage.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * An array of strings payload */ @@ -29,6 +29,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/LegacyNotification.ts b/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/LegacyNotification.ts index 8295e7c0..0dc0a368 100644 --- a/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/LegacyNotification.ts +++ b/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/LegacyNotification.ts @@ -1,6 +1,6 @@ import {LegacyNotificationPayloadLevelEnum} from './LegacyNotificationPayloadLevelEnum'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface LegacyNotificationInterface { message?: string level?: LegacyNotificationPayloadLevelEnum @@ -94,6 +94,9 @@ class LegacyNotification { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -101,4 +104,5 @@ class LegacyNotification { } } -export { LegacyNotification, LegacyNotificationInterface }; \ No newline at end of file +export { LegacyNotification }; +export type { LegacyNotificationInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/StringMessage.ts b/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/StringMessage.ts index b4efe734..443c9709 100644 --- a/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/StringMessage.ts +++ b/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/StringMessage.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * A simple string payload */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/UnionMessage.ts b/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/UnionMessage.ts index f2545d83..e8955759 100644 --- a/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/UnionMessage.ts +++ b/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/UnionMessage.ts @@ -1,6 +1,6 @@ import {UnionPayloadOneOfOption2} from './UnionPayloadOneOfOption2'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * A union type payload */ @@ -34,6 +34,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/UnionPayloadOneOfOption2.ts b/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/UnionPayloadOneOfOption2.ts index 7ed8cb00..1c3bb054 100644 --- a/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/UnionPayloadOneOfOption2.ts +++ b/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/UnionPayloadOneOfOption2.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface UnionPayloadOneOfOption2Interface { name?: string additionalProperties?: Record @@ -72,6 +72,9 @@ class UnionPayloadOneOfOption2 { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -79,4 +82,5 @@ class UnionPayloadOneOfOption2 { } } -export { UnionPayloadOneOfOption2, UnionPayloadOneOfOption2Interface }; \ No newline at end of file +export { UnionPayloadOneOfOption2 }; +export type { UnionPayloadOneOfOption2Interface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/UserSignedUp.ts b/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/UserSignedUp.ts index fa5f3407..1dabff95 100644 --- a/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/UserSignedUp.ts +++ b/test/runtime/typescript/src/asyncapi-path-organization/channels/payload/UserSignedUp.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface UserSignedUpInterface { displayName?: string email?: string @@ -93,6 +93,9 @@ class UserSignedUp { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -100,4 +103,5 @@ class UserSignedUp { } } -export { UserSignedUp, UserSignedUpInterface }; \ No newline at end of file +export { UserSignedUp }; +export type { UserSignedUpInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/asyncapi-tag-organization/channels/parameter/UserSignedupParameters.ts b/test/runtime/typescript/src/asyncapi-tag-organization/channels/parameter/UserSignedupParameters.ts index 1cd5731e..eaefe59b 100644 --- a/test/runtime/typescript/src/asyncapi-tag-organization/channels/parameter/UserSignedupParameters.ts +++ b/test/runtime/typescript/src/asyncapi-tag-organization/channels/parameter/UserSignedupParameters.ts @@ -42,4 +42,5 @@ class UserSignedupParameters { return parameters; } } -export { UserSignedupParameters, UserSignedupParametersInterface }; \ No newline at end of file +export { UserSignedupParameters }; +export type { UserSignedupParametersInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/asyncapi-tag-organization/channels/payload/AdminAlert.ts b/test/runtime/typescript/src/asyncapi-tag-organization/channels/payload/AdminAlert.ts index f1cbf645..dc933bd8 100644 --- a/test/runtime/typescript/src/asyncapi-tag-organization/channels/payload/AdminAlert.ts +++ b/test/runtime/typescript/src/asyncapi-tag-organization/channels/payload/AdminAlert.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface AdminAlertInterface { message?: string } @@ -56,6 +56,9 @@ class AdminAlert { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -63,4 +66,5 @@ class AdminAlert { } } -export { AdminAlert, AdminAlertInterface }; \ No newline at end of file +export { AdminAlert }; +export type { AdminAlertInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/asyncapi-tag-organization/channels/payload/SystemPing.ts b/test/runtime/typescript/src/asyncapi-tag-organization/channels/payload/SystemPing.ts index 270a8f08..0fc0e6d4 100644 --- a/test/runtime/typescript/src/asyncapi-tag-organization/channels/payload/SystemPing.ts +++ b/test/runtime/typescript/src/asyncapi-tag-organization/channels/payload/SystemPing.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface SystemPingInterface { timestamp?: Date } @@ -56,6 +56,9 @@ class SystemPing { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -63,4 +66,5 @@ class SystemPing { } } -export { SystemPing, SystemPingInterface }; \ No newline at end of file +export { SystemPing }; +export type { SystemPingInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/asyncapi-tag-organization/channels/payload/UserSignedUp.ts b/test/runtime/typescript/src/asyncapi-tag-organization/channels/payload/UserSignedUp.ts index f4cd3d94..a96e1ca5 100644 --- a/test/runtime/typescript/src/asyncapi-tag-organization/channels/payload/UserSignedUp.ts +++ b/test/runtime/typescript/src/asyncapi-tag-organization/channels/payload/UserSignedUp.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface UserSignedUpInterface { displayName?: string email?: string @@ -68,6 +68,9 @@ class UserSignedUp { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -75,4 +78,5 @@ class UserSignedUp { } } -export { UserSignedUp, UserSignedUpInterface }; \ No newline at end of file +export { UserSignedUp }; +export type { UserSignedUpInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/client/NatsClient.ts b/test/runtime/typescript/src/client/NatsClient.ts index 149eb794..116ebdef 100644 --- a/test/runtime/typescript/src/client/NatsClient.ts +++ b/test/runtime/typescript/src/client/NatsClient.ts @@ -14,6 +14,7 @@ export {UnionPayloadOneOfOption2}; export {LegacyNotificationPayloadLevelEnum}; import {UserSignedupParameters, UserSignedupParametersInterface} from './../parameters/UserSignedupParameters'; export {UserSignedupParameters}; +import {UserSignedUpHeaders} from './../headers/UserSignedUpHeaders'; //Import channel functions import * as nats from './../channels/nats'; @@ -185,7 +186,7 @@ export class NatsClient { options, flush }: { - onDataCallback: (err?: Error, msg?: UserSignedUp, parameters?: UserSignedupParameters, natsMsg?: Nats.Msg) => void, + onDataCallback: (err?: Error, msg?: UserSignedUp, parameters?: UserSignedupParameters, headers?: UserSignedUpHeaders, natsMsg?: Nats.Msg) => void, parameters: UserSignedupParameters, options?: Nats.SubscriptionOptions, flush?: boolean @@ -225,7 +226,7 @@ export class NatsClient { parameters, options = {} }: { - onDataCallback: (err?: Error, msg?: UserSignedUp, parameters?: UserSignedupParameters, jetstreamMsg?: Nats.JsMsg) => void, + onDataCallback: (err?: Error, msg?: UserSignedUp, parameters?: UserSignedupParameters, headers?: UserSignedUpHeaders, jetstreamMsg?: Nats.JsMsg) => void, parameters: UserSignedupParameters, options: Nats.ConsumerOptsBuilder | Partial }): Promise { @@ -262,7 +263,7 @@ export class NatsClient { parameters, options = {} }: { - onDataCallback: (err?: Error, msg?: UserSignedUp, parameters?: UserSignedupParameters, jetstreamMsg?: Nats.JsMsg) => void, + onDataCallback: (err?: Error, msg?: UserSignedUp, parameters?: UserSignedupParameters, headers?: UserSignedUpHeaders, jetstreamMsg?: Nats.JsMsg) => void, parameters: UserSignedupParameters, options: Nats.ConsumerOptsBuilder | Partial }): Promise { @@ -323,7 +324,7 @@ export class NatsClient { options, flush }: { - onDataCallback: (err?: Error, msg?: UserSignedUp, natsMsg?: Nats.Msg) => void, + onDataCallback: (err?: Error, msg?: UserSignedUp, headers?: UserSignedUpHeaders, natsMsg?: Nats.Msg) => void, options?: Nats.SubscriptionOptions, flush?: boolean }): Promise { @@ -359,7 +360,7 @@ export class NatsClient { onDataCallback, options = {} }: { - onDataCallback: (err?: Error, msg?: UserSignedUp, jetstreamMsg?: Nats.JsMsg) => void, + onDataCallback: (err?: Error, msg?: UserSignedUp, headers?: UserSignedUpHeaders, jetstreamMsg?: Nats.JsMsg) => void, options: Nats.ConsumerOptsBuilder | Partial }): Promise { return new Promise(async (resolve, reject) => { @@ -392,7 +393,7 @@ export class NatsClient { onDataCallback, options = {} }: { - onDataCallback: (err?: Error, msg?: UserSignedUp, jetstreamMsg?: Nats.JsMsg) => void, + onDataCallback: (err?: Error, msg?: UserSignedUp, headers?: UserSignedUpHeaders, jetstreamMsg?: Nats.JsMsg) => void, options: Nats.ConsumerOptsBuilder | Partial }): Promise { return new Promise(async (resolve, reject) => { diff --git a/test/runtime/typescript/src/headers/UserSignedUpHeaders.ts b/test/runtime/typescript/src/headers/UserSignedUpHeaders.ts index d20d9d5a..c7ca7593 100644 --- a/test/runtime/typescript/src/headers/UserSignedUpHeaders.ts +++ b/test/runtime/typescript/src/headers/UserSignedUpHeaders.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; class UserSignedUpHeaders { private _xTestHeader?: string; private _additionalProperties?: Map; @@ -74,6 +74,9 @@ class UserSignedUpHeaders { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); diff --git a/test/runtime/typescript/src/node16/channels/nats.ts b/test/runtime/typescript/src/node16/channels/nats.ts index 81fe632b..fe73fc12 100644 --- a/test/runtime/typescript/src/node16/channels/nats.ts +++ b/test/runtime/typescript/src/node16/channels/nats.ts @@ -1,9 +1,9 @@ -import {UserSignedUp} from './../payloads/UserSignedUp.ts'; +import {UserSignedUp, UserSignedUpInterface} from './../payloads/UserSignedUp.ts'; import * as StringMessageModule from './../payloads/StringMessage.ts'; import * as ArrayMessageModule from './../payloads/ArrayMessage.ts'; import * as UnionMessageModule from './../payloads/UnionMessage.ts'; -import {LegacyNotification} from './../payloads/LegacyNotification.ts'; -import {UnionPayloadOneOfOption2} from './../payloads/UnionPayloadOneOfOption2.ts'; +import {LegacyNotification, LegacyNotificationInterface} from './../payloads/LegacyNotification.ts'; +import {UnionPayloadOneOfOption2, UnionPayloadOneOfOption2Interface} from './../payloads/UnionPayloadOneOfOption2.ts'; import {LegacyNotificationPayloadLevelEnum} from './../payloads/LegacyNotificationPayloadLevelEnum.ts'; import {UserSignedupParameters, UserSignedupParametersInterface} from './../parameters/UserSignedupParameters.ts'; import {UserSignedUpHeaders} from './../headers/UserSignedUpHeaders.ts'; @@ -27,7 +27,7 @@ function publishToSendUserSignedup({ codec = Nats.JSONCodec(), options }: { - message: UserSignedUp, + message: UserSignedUpInterface | UserSignedUp, parameters: UserSignedupParametersInterface | UserSignedupParameters, headers?: UserSignedUpHeaders, nc: Nats.NatsConnection, @@ -36,7 +36,7 @@ function publishToSendUserSignedup({ }): Promise { return new Promise(async (resolve, reject) => { try { - let dataToSend: any = message.marshal(); + let dataToSend: any = (message instanceof UserSignedUp ? message : new UserSignedUp(message)).marshal(); // Set up headers if provided if (headers) { const natsHeaders = Nats.headers(); @@ -76,7 +76,7 @@ function jetStreamPublishToSendUserSignedup({ codec = Nats.JSONCodec(), options = {} }: { - message: UserSignedUp, + message: UserSignedUpInterface | UserSignedUp, parameters: UserSignedupParametersInterface | UserSignedupParameters, headers?: UserSignedUpHeaders, js: Nats.JetStreamClient, @@ -85,7 +85,7 @@ function jetStreamPublishToSendUserSignedup({ }): Promise { return new Promise(async (resolve, reject) => { try { - let dataToSend: any = message.marshal(); + let dataToSend: any = (message instanceof UserSignedUp ? message : new UserSignedUp(message)).marshal(); // Set up headers if provided if (headers) { const natsHeaders = Nats.headers(); @@ -357,7 +357,7 @@ function publishToNoParameter({ codec = Nats.JSONCodec(), options }: { - message: UserSignedUp, + message: UserSignedUpInterface | UserSignedUp, headers?: UserSignedUpHeaders, nc: Nats.NatsConnection, codec?: Nats.Codec, @@ -365,7 +365,7 @@ function publishToNoParameter({ }): Promise { return new Promise(async (resolve, reject) => { try { - let dataToSend: any = message.marshal(); + let dataToSend: any = (message instanceof UserSignedUp ? message : new UserSignedUp(message)).marshal(); // Set up headers if provided if (headers) { const natsHeaders = Nats.headers(); @@ -625,7 +625,7 @@ function jetStreamPublishToNoParameter({ codec = Nats.JSONCodec(), options = {} }: { - message: UserSignedUp, + message: UserSignedUpInterface | UserSignedUp, headers?: UserSignedUpHeaders, js: Nats.JetStreamClient, codec?: Nats.Codec, @@ -633,7 +633,7 @@ function jetStreamPublishToNoParameter({ }): Promise { return new Promise(async (resolve, reject) => { try { - let dataToSend: any = message.marshal(); + let dataToSend: any = (message instanceof UserSignedUp ? message : new UserSignedUp(message)).marshal(); // Set up headers if provided if (headers) { const natsHeaders = Nats.headers(); @@ -1358,14 +1358,14 @@ function publishToSendLegacyNotification({ codec = Nats.JSONCodec(), options }: { - message: LegacyNotification, + message: LegacyNotificationInterface | LegacyNotification, nc: Nats.NatsConnection, codec?: Nats.Codec, options?: Nats.PublishOptions }): Promise { return new Promise(async (resolve, reject) => { try { - let dataToSend: any = message.marshal(); + let dataToSend: any = (message instanceof LegacyNotification ? message : new LegacyNotification(message)).marshal(); dataToSend = codec.encode(dataToSend); nc.publish('legacy.notification', dataToSend, options); @@ -1392,14 +1392,14 @@ function jetStreamPublishToSendLegacyNotification({ codec = Nats.JSONCodec(), options = {} }: { - message: LegacyNotification, + message: LegacyNotificationInterface | LegacyNotification, js: Nats.JetStreamClient, codec?: Nats.Codec, options?: Partial }): Promise { return new Promise(async (resolve, reject) => { try { - let dataToSend: any = message.marshal(); + let dataToSend: any = (message instanceof LegacyNotification ? message : new LegacyNotification(message)).marshal(); dataToSend = codec.encode(dataToSend); await js.publish('legacy.notification', dataToSend, options); diff --git a/test/runtime/typescript/src/node16/headers/UserSignedUpHeaders.ts b/test/runtime/typescript/src/node16/headers/UserSignedUpHeaders.ts index e15ff250..c7ca7593 100644 --- a/test/runtime/typescript/src/node16/headers/UserSignedUpHeaders.ts +++ b/test/runtime/typescript/src/node16/headers/UserSignedUpHeaders.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; class UserSignedUpHeaders { private _xTestHeader?: string; private _additionalProperties?: Map; @@ -21,30 +21,32 @@ class UserSignedUpHeaders { get additionalProperties(): Map | undefined { return this._additionalProperties; } set additionalProperties(additionalProperties: Map | undefined) { this._additionalProperties = additionalProperties; } - public marshal() : string { - let json = '{' + public toJson(): Record { + const json: Record = {}; if(this.xTestHeader !== undefined) { - json += `"x-test-header": ${typeof this.xTestHeader === 'number' || typeof this.xTestHeader === 'boolean' ? this.xTestHeader : JSON.stringify(this.xTestHeader)},`; + json["x-test-header"] = this.xTestHeader; } - if(this.additionalProperties !== undefined) { + if(this.additionalProperties !== undefined) { for (const [key, value] of this.additionalProperties.entries()) { //Only unwrap those that are not already a property in the JSON object if(["x-test-header","additionalProperties"].includes(String(key))) continue; - json += `"${key}": ${typeof value === 'number' || typeof value === 'boolean' ? value : JSON.stringify(value)},`; + json[key] = value; } } - //Remove potential last comma - return `${json.charAt(json.length-1) === ',' ? json.slice(0, json.length-1) : json}}`; + return json; } - public static unmarshal(json: string | object): UserSignedUpHeaders { - const obj = typeof json === "object" ? json : JSON.parse(json); + public marshal(): string { + return JSON.stringify(this.toJson()); + } + + public static fromJson(obj: Record): UserSignedUpHeaders { const instance = new UserSignedUpHeaders({} as any); if (obj["x-test-header"] !== undefined) { - instance.xTestHeader = obj["x-test-header"]; + instance.xTestHeader = obj["x-test-header"] as string; } - + instance.additionalProperties = new Map(); const propsToCheck = Object.entries(obj).filter((([key,]) => {return !["x-test-header","additionalProperties"].includes(key);})); for (const [key, value] of propsToCheck) { @@ -52,6 +54,11 @@ class UserSignedUpHeaders { } return instance; } + + public static unmarshal(json: string | object): UserSignedUpHeaders { + const obj = typeof json === "object" ? json : JSON.parse(json); + return UserSignedUpHeaders.fromJson(obj as Record); + } public static theCodeGenSchema = {"type":"object","properties":{"x-test-header":{"type":"string","description":"Test header"}},"$id":"UserSignedUpHeaders","$schema":"http://json-schema.org/draft-07/schema"}; public static validate(context?: {data: any, ajvValidatorFunction?: ValidateFunction, ajvInstance?: Ajv, ajvOptions?: AjvOptions}): { valid: boolean; errors?: ErrorObject[]; } { const {data, ajvValidatorFunction} = context ?? {}; @@ -67,6 +74,9 @@ class UserSignedUpHeaders { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); diff --git a/test/runtime/typescript/src/node16/parameters/UserSignedupParameters.ts b/test/runtime/typescript/src/node16/parameters/UserSignedupParameters.ts index 4195c425..8052340b 100644 --- a/test/runtime/typescript/src/node16/parameters/UserSignedupParameters.ts +++ b/test/runtime/typescript/src/node16/parameters/UserSignedupParameters.ts @@ -1,4 +1,4 @@ -import {EnumParameter} from './EnumParameter'; +import {EnumParameter} from './EnumParameter.ts'; interface UserSignedupParametersInterface { myParameter: string enumParameter: EnumParameter @@ -58,4 +58,5 @@ class UserSignedupParameters { return parameters; } } -export { UserSignedupParameters, UserSignedupParametersInterface }; \ No newline at end of file +export { UserSignedupParameters }; +export type { UserSignedupParametersInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/node16/payloads/ArrayMessage.ts b/test/runtime/typescript/src/node16/payloads/ArrayMessage.ts index e3d8a41c..14959285 100644 --- a/test/runtime/typescript/src/node16/payloads/ArrayMessage.ts +++ b/test/runtime/typescript/src/node16/payloads/ArrayMessage.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * An array of strings payload */ @@ -29,6 +29,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/node16/payloads/LegacyNotification.ts b/test/runtime/typescript/src/node16/payloads/LegacyNotification.ts index 7a50dcf7..0d64c3d9 100644 --- a/test/runtime/typescript/src/node16/payloads/LegacyNotification.ts +++ b/test/runtime/typescript/src/node16/payloads/LegacyNotification.ts @@ -1,6 +1,11 @@ -import {LegacyNotificationPayloadLevelEnum} from './LegacyNotificationPayloadLevelEnum'; +import {LegacyNotificationPayloadLevelEnum} from './LegacyNotificationPayloadLevelEnum.ts'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; +interface LegacyNotificationInterface { + message?: string + level?: LegacyNotificationPayloadLevelEnum + additionalProperties?: Record +} /** * Legacy notification payload - use NewNotificationPayload instead */ @@ -9,11 +14,7 @@ class LegacyNotification { private _level?: LegacyNotificationPayloadLevelEnum; private _additionalProperties?: Record; - constructor(input: { - message?: string, - level?: LegacyNotificationPayloadLevelEnum, - additionalProperties?: Record, - }) { + constructor(input: LegacyNotificationInterface) { this._message = input.message; this._level = input.level; this._additionalProperties = input.additionalProperties; @@ -34,43 +35,50 @@ class LegacyNotification { get additionalProperties(): Record | undefined { return this._additionalProperties; } set additionalProperties(additionalProperties: Record | undefined) { this._additionalProperties = additionalProperties; } - public marshal() : string { - let json = '{' + public toJson(): Record { + const json: Record = {}; if(this.message !== undefined) { - json += `"message": ${typeof this.message === 'number' || typeof this.message === 'boolean' ? this.message : JSON.stringify(this.message)},`; + json["message"] = this.message; } if(this.level !== undefined) { - json += `"level": ${typeof this.level === 'number' || typeof this.level === 'boolean' ? this.level : JSON.stringify(this.level)},`; + json["level"] = this.level; } - if(this.additionalProperties !== undefined) { - for (const [key, value] of this.additionalProperties.entries()) { + if(this.additionalProperties !== undefined) { + for (const [key, value] of Object.entries(this.additionalProperties)) { //Only unwrap those that are not already a property in the JSON object if(["message","level","additionalProperties"].includes(String(key))) continue; - json += `"${key}": ${typeof value === 'number' || typeof value === 'boolean' ? value : JSON.stringify(value)},`; + json[key] = value; } } - //Remove potential last comma - return `${json.charAt(json.length-1) === ',' ? json.slice(0, json.length-1) : json}}`; + return json; } - public static unmarshal(json: string | object): LegacyNotification { - const obj = typeof json === "object" ? json : JSON.parse(json); + public marshal(): string { + return JSON.stringify(this.toJson()); + } + + public static fromJson(obj: Record): LegacyNotification { const instance = new LegacyNotification({} as any); if (obj["message"] !== undefined) { - instance.message = obj["message"]; + instance.message = obj["message"] as string; } if (obj["level"] !== undefined) { - instance.level = obj["level"]; + instance.level = obj["level"] as LegacyNotificationPayloadLevelEnum; } - - instance.additionalProperties = new Map(); + + instance.additionalProperties = {}; const propsToCheck = Object.entries(obj).filter((([key,]) => {return !["message","level","additionalProperties"].includes(key);})); for (const [key, value] of propsToCheck) { - instance.additionalProperties.set(key, value as any); + instance.additionalProperties[key] = value as any; } return instance; } + + public static unmarshal(json: string | object): LegacyNotification { + const obj = typeof json === "object" ? json : JSON.parse(json); + return LegacyNotification.fromJson(obj as Record); + } public static theCodeGenSchema = {"type":"object","$schema":"http://json-schema.org/draft-07/schema","description":"Legacy notification payload - use NewNotificationPayload instead","deprecated":true,"properties":{"message":{"type":"string","description":"The notification message"},"level":{"type":"string","enum":["info","warning","error"],"description":"Notification severity level"}},"$id":"LegacyNotification"}; public static validate(context?: {data: any, ajvValidatorFunction?: ValidateFunction, ajvInstance?: Ajv, ajvOptions?: AjvOptions}): { valid: boolean; errors?: ErrorObject[]; } { const {data, ajvValidatorFunction} = context ?? {}; @@ -86,6 +94,9 @@ class LegacyNotification { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -93,4 +104,5 @@ class LegacyNotification { } } -export { LegacyNotification }; \ No newline at end of file +export { LegacyNotification }; +export type { LegacyNotificationInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/node16/payloads/StringMessage.ts b/test/runtime/typescript/src/node16/payloads/StringMessage.ts index b4efe734..443c9709 100644 --- a/test/runtime/typescript/src/node16/payloads/StringMessage.ts +++ b/test/runtime/typescript/src/node16/payloads/StringMessage.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * A simple string payload */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/node16/payloads/UnionMessage.ts b/test/runtime/typescript/src/node16/payloads/UnionMessage.ts index f2545d83..93957fc2 100644 --- a/test/runtime/typescript/src/node16/payloads/UnionMessage.ts +++ b/test/runtime/typescript/src/node16/payloads/UnionMessage.ts @@ -1,6 +1,6 @@ -import {UnionPayloadOneOfOption2} from './UnionPayloadOneOfOption2'; +import {UnionPayloadOneOfOption2} from './UnionPayloadOneOfOption2.ts'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * A union type payload */ @@ -34,6 +34,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/node16/payloads/UnionPayloadOneOfOption2.ts b/test/runtime/typescript/src/node16/payloads/UnionPayloadOneOfOption2.ts index d166bc77..1c3bb054 100644 --- a/test/runtime/typescript/src/node16/payloads/UnionPayloadOneOfOption2.ts +++ b/test/runtime/typescript/src/node16/payloads/UnionPayloadOneOfOption2.ts @@ -1,13 +1,14 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; +interface UnionPayloadOneOfOption2Interface { + name?: string + additionalProperties?: Record +} class UnionPayloadOneOfOption2 { private _name?: string; private _additionalProperties?: Record; - constructor(input: { - name?: string, - additionalProperties?: Record, - }) { + constructor(input: UnionPayloadOneOfOption2Interface) { this._name = input.name; this._additionalProperties = input.additionalProperties; } @@ -18,37 +19,44 @@ class UnionPayloadOneOfOption2 { get additionalProperties(): Record | undefined { return this._additionalProperties; } set additionalProperties(additionalProperties: Record | undefined) { this._additionalProperties = additionalProperties; } - public marshal() : string { - let json = '{' + public toJson(): Record { + const json: Record = {}; if(this.name !== undefined) { - json += `"name": ${typeof this.name === 'number' || typeof this.name === 'boolean' ? this.name : JSON.stringify(this.name)},`; + json["name"] = this.name; } - if(this.additionalProperties !== undefined) { - for (const [key, value] of this.additionalProperties.entries()) { + if(this.additionalProperties !== undefined) { + for (const [key, value] of Object.entries(this.additionalProperties)) { //Only unwrap those that are not already a property in the JSON object if(["name","additionalProperties"].includes(String(key))) continue; - json += `"${key}": ${typeof value === 'number' || typeof value === 'boolean' ? value : JSON.stringify(value)},`; + json[key] = value; } } - //Remove potential last comma - return `${json.charAt(json.length-1) === ',' ? json.slice(0, json.length-1) : json}}`; + return json; } - public static unmarshal(json: string | object): UnionPayloadOneOfOption2 { - const obj = typeof json === "object" ? json : JSON.parse(json); + public marshal(): string { + return JSON.stringify(this.toJson()); + } + + public static fromJson(obj: Record): UnionPayloadOneOfOption2 { const instance = new UnionPayloadOneOfOption2({} as any); if (obj["name"] !== undefined) { - instance.name = obj["name"]; + instance.name = obj["name"] as string; } - - instance.additionalProperties = new Map(); + + instance.additionalProperties = {}; const propsToCheck = Object.entries(obj).filter((([key,]) => {return !["name","additionalProperties"].includes(key);})); for (const [key, value] of propsToCheck) { - instance.additionalProperties.set(key, value as any); + instance.additionalProperties[key] = value as any; } return instance; } + + public static unmarshal(json: string | object): UnionPayloadOneOfOption2 { + const obj = typeof json === "object" ? json : JSON.parse(json); + return UnionPayloadOneOfOption2.fromJson(obj as Record); + } public static theCodeGenSchema = {"type":"object","properties":{"name":{"type":"string"}}}; public static validate(context?: {data: any, ajvValidatorFunction?: ValidateFunction, ajvInstance?: Ajv, ajvOptions?: AjvOptions}): { valid: boolean; errors?: ErrorObject[]; } { const {data, ajvValidatorFunction} = context ?? {}; @@ -64,6 +72,9 @@ class UnionPayloadOneOfOption2 { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -71,4 +82,5 @@ class UnionPayloadOneOfOption2 { } } -export { UnionPayloadOneOfOption2 }; \ No newline at end of file +export { UnionPayloadOneOfOption2 }; +export type { UnionPayloadOneOfOption2Interface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/node16/payloads/UserSignedUp.ts b/test/runtime/typescript/src/node16/payloads/UserSignedUp.ts index 13f2c67a..1dabff95 100644 --- a/test/runtime/typescript/src/node16/payloads/UserSignedUp.ts +++ b/test/runtime/typescript/src/node16/payloads/UserSignedUp.ts @@ -1,5 +1,10 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; +interface UserSignedUpInterface { + displayName?: string + email?: string + additionalProperties?: Record +} /** * Payload for user signup events containing user registration details */ @@ -8,11 +13,7 @@ class UserSignedUp { private _email?: string; private _additionalProperties?: Record; - constructor(input: { - displayName?: string, - email?: string, - additionalProperties?: Record, - }) { + constructor(input: UserSignedUpInterface) { this._displayName = input.displayName; this._email = input.email; this._additionalProperties = input.additionalProperties; @@ -33,43 +34,50 @@ class UserSignedUp { get additionalProperties(): Record | undefined { return this._additionalProperties; } set additionalProperties(additionalProperties: Record | undefined) { this._additionalProperties = additionalProperties; } - public marshal() : string { - let json = '{' + public toJson(): Record { + const json: Record = {}; if(this.displayName !== undefined) { - json += `"display_name": ${typeof this.displayName === 'number' || typeof this.displayName === 'boolean' ? this.displayName : JSON.stringify(this.displayName)},`; + json["display_name"] = this.displayName; } if(this.email !== undefined) { - json += `"email": ${typeof this.email === 'number' || typeof this.email === 'boolean' ? this.email : JSON.stringify(this.email)},`; + json["email"] = this.email; } - if(this.additionalProperties !== undefined) { - for (const [key, value] of this.additionalProperties.entries()) { + if(this.additionalProperties !== undefined) { + for (const [key, value] of Object.entries(this.additionalProperties)) { //Only unwrap those that are not already a property in the JSON object if(["display_name","email","additionalProperties"].includes(String(key))) continue; - json += `"${key}": ${typeof value === 'number' || typeof value === 'boolean' ? value : JSON.stringify(value)},`; + json[key] = value; } } - //Remove potential last comma - return `${json.charAt(json.length-1) === ',' ? json.slice(0, json.length-1) : json}}`; + return json; } - public static unmarshal(json: string | object): UserSignedUp { - const obj = typeof json === "object" ? json : JSON.parse(json); + public marshal(): string { + return JSON.stringify(this.toJson()); + } + + public static fromJson(obj: Record): UserSignedUp { const instance = new UserSignedUp({} as any); if (obj["display_name"] !== undefined) { - instance.displayName = obj["display_name"]; + instance.displayName = obj["display_name"] as string; } if (obj["email"] !== undefined) { - instance.email = obj["email"]; + instance.email = obj["email"] as string; } - - instance.additionalProperties = new Map(); + + instance.additionalProperties = {}; const propsToCheck = Object.entries(obj).filter((([key,]) => {return !["display_name","email","additionalProperties"].includes(key);})); for (const [key, value] of propsToCheck) { - instance.additionalProperties.set(key, value as any); + instance.additionalProperties[key] = value as any; } return instance; } + + public static unmarshal(json: string | object): UserSignedUp { + const obj = typeof json === "object" ? json : JSON.parse(json); + return UserSignedUp.fromJson(obj as Record); + } public static theCodeGenSchema = {"type":"object","$schema":"http://json-schema.org/draft-07/schema","description":"Payload for user signup events containing user registration details","properties":{"display_name":{"type":"string","description":"Name of the user"},"email":{"type":"string","format":"email","description":"Email of the user"}},"$id":"UserSignedUp"}; public static validate(context?: {data: any, ajvValidatorFunction?: ValidateFunction, ajvInstance?: Ajv, ajvOptions?: AjvOptions}): { valid: boolean; errors?: ErrorObject[]; } { const {data, ajvValidatorFunction} = context ?? {}; @@ -85,6 +93,9 @@ class UserSignedUp { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -92,4 +103,5 @@ class UserSignedUp { } } -export { UserSignedUp }; \ No newline at end of file +export { UserSignedUp }; +export type { UserSignedUpInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi-path-organization/channels/parameter/FindPetsByStatusAndCategoryParameters.ts b/test/runtime/typescript/src/openapi-path-organization/channels/parameter/FindPetsByStatusAndCategoryParameters.ts index d978dc08..60c3951e 100644 --- a/test/runtime/typescript/src/openapi-path-organization/channels/parameter/FindPetsByStatusAndCategoryParameters.ts +++ b/test/runtime/typescript/src/openapi-path-organization/channels/parameter/FindPetsByStatusAndCategoryParameters.ts @@ -389,4 +389,5 @@ class FindPetsByStatusAndCategoryParameters { return result; } } -export { FindPetsByStatusAndCategoryParameters, FindPetsByStatusAndCategoryParametersInterface }; \ No newline at end of file +export { FindPetsByStatusAndCategoryParameters }; +export type { FindPetsByStatusAndCategoryParametersInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi-path-organization/channels/payload/APet.ts b/test/runtime/typescript/src/openapi-path-organization/channels/payload/APet.ts index a1fe03de..cf97761e 100644 --- a/test/runtime/typescript/src/openapi-path-organization/channels/payload/APet.ts +++ b/test/runtime/typescript/src/openapi-path-organization/channels/payload/APet.ts @@ -2,7 +2,7 @@ import {PetCategory} from './PetCategory'; import {PetTag} from './PetTag'; import {Status} from './Status'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface APetInterface { id?: number category?: PetCategory @@ -150,6 +150,9 @@ class APet { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -157,4 +160,5 @@ class APet { } } -export { APet, APetInterface }; \ No newline at end of file +export { APet }; +export type { APetInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi-path-organization/channels/payload/AUser.ts b/test/runtime/typescript/src/openapi-path-organization/channels/payload/AUser.ts index 48ed2ebf..2e2bd007 100644 --- a/test/runtime/typescript/src/openapi-path-organization/channels/payload/AUser.ts +++ b/test/runtime/typescript/src/openapi-path-organization/channels/payload/AUser.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface AUserInterface { id?: number username?: string @@ -162,6 +162,9 @@ class AUser { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -169,4 +172,5 @@ class AUser { } } -export { AUser, AUserInterface }; \ No newline at end of file +export { AUser }; +export type { AUserInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi-path-organization/channels/payload/AnUploadedResponse.ts b/test/runtime/typescript/src/openapi-path-organization/channels/payload/AnUploadedResponse.ts index 1bd74e80..52e26695 100644 --- a/test/runtime/typescript/src/openapi-path-organization/channels/payload/AnUploadedResponse.ts +++ b/test/runtime/typescript/src/openapi-path-organization/channels/payload/AnUploadedResponse.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface AnUploadedResponseInterface { code?: number type?: string @@ -99,6 +99,9 @@ class AnUploadedResponse { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -106,4 +109,5 @@ class AnUploadedResponse { } } -export { AnUploadedResponse, AnUploadedResponseInterface }; \ No newline at end of file +export { AnUploadedResponse }; +export type { AnUploadedResponseInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi-path-organization/channels/payload/FindPetsByStatusAndCategoryResponse_200.ts b/test/runtime/typescript/src/openapi-path-organization/channels/payload/FindPetsByStatusAndCategoryResponse_200.ts index 316729c0..6792b23f 100644 --- a/test/runtime/typescript/src/openapi-path-organization/channels/payload/FindPetsByStatusAndCategoryResponse_200.ts +++ b/test/runtime/typescript/src/openapi-path-organization/channels/payload/FindPetsByStatusAndCategoryResponse_200.ts @@ -1,6 +1,6 @@ import {APet} from './APet'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; type FindPetsByStatusAndCategoryResponse_200 = APet[]; export function unmarshal(json: string | any[]): FindPetsByStatusAndCategoryResponse_200 { @@ -35,6 +35,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/openapi-path-organization/channels/payload/PetCategory.ts b/test/runtime/typescript/src/openapi-path-organization/channels/payload/PetCategory.ts index 4d62020c..4e6363d8 100644 --- a/test/runtime/typescript/src/openapi-path-organization/channels/payload/PetCategory.ts +++ b/test/runtime/typescript/src/openapi-path-organization/channels/payload/PetCategory.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface PetCategoryInterface { id?: number name?: string @@ -87,6 +87,9 @@ class PetCategory { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -94,4 +97,5 @@ class PetCategory { } } -export { PetCategory, PetCategoryInterface }; \ No newline at end of file +export { PetCategory }; +export type { PetCategoryInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi-path-organization/channels/payload/PetOrder.ts b/test/runtime/typescript/src/openapi-path-organization/channels/payload/PetOrder.ts index 89ec5be1..46f10b36 100644 --- a/test/runtime/typescript/src/openapi-path-organization/channels/payload/PetOrder.ts +++ b/test/runtime/typescript/src/openapi-path-organization/channels/payload/PetOrder.ts @@ -1,6 +1,6 @@ import {Status} from './Status'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface PetOrderInterface { id?: number petId?: number @@ -139,6 +139,9 @@ class PetOrder { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -146,4 +149,5 @@ class PetOrder { } } -export { PetOrder, PetOrderInterface }; \ No newline at end of file +export { PetOrder }; +export type { PetOrderInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi-path-organization/channels/payload/PetTag.ts b/test/runtime/typescript/src/openapi-path-organization/channels/payload/PetTag.ts index 50071c6b..2c7e4e42 100644 --- a/test/runtime/typescript/src/openapi-path-organization/channels/payload/PetTag.ts +++ b/test/runtime/typescript/src/openapi-path-organization/channels/payload/PetTag.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface PetTagInterface { id?: number name?: string @@ -87,6 +87,9 @@ class PetTag { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -94,4 +97,5 @@ class PetTag { } } -export { PetTag, PetTagInterface }; \ No newline at end of file +export { PetTag }; +export type { PetTagInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi-primitive/payloads/GetCountResponse_200.ts b/test/runtime/typescript/src/openapi-primitive/payloads/GetCountResponse_200.ts index bd134e4e..87be8184 100644 --- a/test/runtime/typescript/src/openapi-primitive/payloads/GetCountResponse_200.ts +++ b/test/runtime/typescript/src/openapi-primitive/payloads/GetCountResponse_200.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; type GetCountResponse_200 = number; export function unmarshal(json: string): GetCountResponse_200 { @@ -23,6 +23,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/openapi-primitive/payloads/GetEchoResponse_200.ts b/test/runtime/typescript/src/openapi-primitive/payloads/GetEchoResponse_200.ts index d5508632..3c5740c7 100644 --- a/test/runtime/typescript/src/openapi-primitive/payloads/GetEchoResponse_200.ts +++ b/test/runtime/typescript/src/openapi-primitive/payloads/GetEchoResponse_200.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; type GetEchoResponse_200 = string; export function unmarshal(json: string): GetEchoResponse_200 { @@ -23,6 +23,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/openapi-tag-organization/channels/parameter/FindPetsByStatusAndCategoryParameters.ts b/test/runtime/typescript/src/openapi-tag-organization/channels/parameter/FindPetsByStatusAndCategoryParameters.ts index d978dc08..60c3951e 100644 --- a/test/runtime/typescript/src/openapi-tag-organization/channels/parameter/FindPetsByStatusAndCategoryParameters.ts +++ b/test/runtime/typescript/src/openapi-tag-organization/channels/parameter/FindPetsByStatusAndCategoryParameters.ts @@ -389,4 +389,5 @@ class FindPetsByStatusAndCategoryParameters { return result; } } -export { FindPetsByStatusAndCategoryParameters, FindPetsByStatusAndCategoryParametersInterface }; \ No newline at end of file +export { FindPetsByStatusAndCategoryParameters }; +export type { FindPetsByStatusAndCategoryParametersInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi-tag-organization/channels/payload/APet.ts b/test/runtime/typescript/src/openapi-tag-organization/channels/payload/APet.ts index a1fe03de..cf97761e 100644 --- a/test/runtime/typescript/src/openapi-tag-organization/channels/payload/APet.ts +++ b/test/runtime/typescript/src/openapi-tag-organization/channels/payload/APet.ts @@ -2,7 +2,7 @@ import {PetCategory} from './PetCategory'; import {PetTag} from './PetTag'; import {Status} from './Status'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface APetInterface { id?: number category?: PetCategory @@ -150,6 +150,9 @@ class APet { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -157,4 +160,5 @@ class APet { } } -export { APet, APetInterface }; \ No newline at end of file +export { APet }; +export type { APetInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi-tag-organization/channels/payload/AUser.ts b/test/runtime/typescript/src/openapi-tag-organization/channels/payload/AUser.ts index 48ed2ebf..2e2bd007 100644 --- a/test/runtime/typescript/src/openapi-tag-organization/channels/payload/AUser.ts +++ b/test/runtime/typescript/src/openapi-tag-organization/channels/payload/AUser.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface AUserInterface { id?: number username?: string @@ -162,6 +162,9 @@ class AUser { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -169,4 +172,5 @@ class AUser { } } -export { AUser, AUserInterface }; \ No newline at end of file +export { AUser }; +export type { AUserInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi-tag-organization/channels/payload/AnUploadedResponse.ts b/test/runtime/typescript/src/openapi-tag-organization/channels/payload/AnUploadedResponse.ts index 1bd74e80..52e26695 100644 --- a/test/runtime/typescript/src/openapi-tag-organization/channels/payload/AnUploadedResponse.ts +++ b/test/runtime/typescript/src/openapi-tag-organization/channels/payload/AnUploadedResponse.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface AnUploadedResponseInterface { code?: number type?: string @@ -99,6 +99,9 @@ class AnUploadedResponse { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -106,4 +109,5 @@ class AnUploadedResponse { } } -export { AnUploadedResponse, AnUploadedResponseInterface }; \ No newline at end of file +export { AnUploadedResponse }; +export type { AnUploadedResponseInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi-tag-organization/channels/payload/FindPetsByStatusAndCategoryResponse_200.ts b/test/runtime/typescript/src/openapi-tag-organization/channels/payload/FindPetsByStatusAndCategoryResponse_200.ts index 316729c0..6792b23f 100644 --- a/test/runtime/typescript/src/openapi-tag-organization/channels/payload/FindPetsByStatusAndCategoryResponse_200.ts +++ b/test/runtime/typescript/src/openapi-tag-organization/channels/payload/FindPetsByStatusAndCategoryResponse_200.ts @@ -1,6 +1,6 @@ import {APet} from './APet'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; type FindPetsByStatusAndCategoryResponse_200 = APet[]; export function unmarshal(json: string | any[]): FindPetsByStatusAndCategoryResponse_200 { @@ -35,6 +35,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/openapi-tag-organization/channels/payload/PetCategory.ts b/test/runtime/typescript/src/openapi-tag-organization/channels/payload/PetCategory.ts index 4d62020c..4e6363d8 100644 --- a/test/runtime/typescript/src/openapi-tag-organization/channels/payload/PetCategory.ts +++ b/test/runtime/typescript/src/openapi-tag-organization/channels/payload/PetCategory.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface PetCategoryInterface { id?: number name?: string @@ -87,6 +87,9 @@ class PetCategory { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -94,4 +97,5 @@ class PetCategory { } } -export { PetCategory, PetCategoryInterface }; \ No newline at end of file +export { PetCategory }; +export type { PetCategoryInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi-tag-organization/channels/payload/PetOrder.ts b/test/runtime/typescript/src/openapi-tag-organization/channels/payload/PetOrder.ts index 89ec5be1..46f10b36 100644 --- a/test/runtime/typescript/src/openapi-tag-organization/channels/payload/PetOrder.ts +++ b/test/runtime/typescript/src/openapi-tag-organization/channels/payload/PetOrder.ts @@ -1,6 +1,6 @@ import {Status} from './Status'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface PetOrderInterface { id?: number petId?: number @@ -139,6 +139,9 @@ class PetOrder { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -146,4 +149,5 @@ class PetOrder { } } -export { PetOrder, PetOrderInterface }; \ No newline at end of file +export { PetOrder }; +export type { PetOrderInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi-tag-organization/channels/payload/PetTag.ts b/test/runtime/typescript/src/openapi-tag-organization/channels/payload/PetTag.ts index 50071c6b..2c7e4e42 100644 --- a/test/runtime/typescript/src/openapi-tag-organization/channels/payload/PetTag.ts +++ b/test/runtime/typescript/src/openapi-tag-organization/channels/payload/PetTag.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface PetTagInterface { id?: number name?: string @@ -87,6 +87,9 @@ class PetTag { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -94,4 +97,5 @@ class PetTag { } } -export { PetTag, PetTagInterface }; \ No newline at end of file +export { PetTag }; +export type { PetTagInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi/parameters/FindPetsByStatusAndCategoryParameters.ts b/test/runtime/typescript/src/openapi/parameters/FindPetsByStatusAndCategoryParameters.ts index d978dc08..60c3951e 100644 --- a/test/runtime/typescript/src/openapi/parameters/FindPetsByStatusAndCategoryParameters.ts +++ b/test/runtime/typescript/src/openapi/parameters/FindPetsByStatusAndCategoryParameters.ts @@ -389,4 +389,5 @@ class FindPetsByStatusAndCategoryParameters { return result; } } -export { FindPetsByStatusAndCategoryParameters, FindPetsByStatusAndCategoryParametersInterface }; \ No newline at end of file +export { FindPetsByStatusAndCategoryParameters }; +export type { FindPetsByStatusAndCategoryParametersInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi/payloads/APet.ts b/test/runtime/typescript/src/openapi/payloads/APet.ts index a1fe03de..cf97761e 100644 --- a/test/runtime/typescript/src/openapi/payloads/APet.ts +++ b/test/runtime/typescript/src/openapi/payloads/APet.ts @@ -2,7 +2,7 @@ import {PetCategory} from './PetCategory'; import {PetTag} from './PetTag'; import {Status} from './Status'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface APetInterface { id?: number category?: PetCategory @@ -150,6 +150,9 @@ class APet { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -157,4 +160,5 @@ class APet { } } -export { APet, APetInterface }; \ No newline at end of file +export { APet }; +export type { APetInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi/payloads/AUser.ts b/test/runtime/typescript/src/openapi/payloads/AUser.ts index 48ed2ebf..2e2bd007 100644 --- a/test/runtime/typescript/src/openapi/payloads/AUser.ts +++ b/test/runtime/typescript/src/openapi/payloads/AUser.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface AUserInterface { id?: number username?: string @@ -162,6 +162,9 @@ class AUser { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -169,4 +172,5 @@ class AUser { } } -export { AUser, AUserInterface }; \ No newline at end of file +export { AUser }; +export type { AUserInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi/payloads/AnUploadedResponse.ts b/test/runtime/typescript/src/openapi/payloads/AnUploadedResponse.ts index 1bd74e80..52e26695 100644 --- a/test/runtime/typescript/src/openapi/payloads/AnUploadedResponse.ts +++ b/test/runtime/typescript/src/openapi/payloads/AnUploadedResponse.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface AnUploadedResponseInterface { code?: number type?: string @@ -99,6 +99,9 @@ class AnUploadedResponse { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -106,4 +109,5 @@ class AnUploadedResponse { } } -export { AnUploadedResponse, AnUploadedResponseInterface }; \ No newline at end of file +export { AnUploadedResponse }; +export type { AnUploadedResponseInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi/payloads/FindPetsByStatusAndCategoryResponse_200.ts b/test/runtime/typescript/src/openapi/payloads/FindPetsByStatusAndCategoryResponse_200.ts index 316729c0..6792b23f 100644 --- a/test/runtime/typescript/src/openapi/payloads/FindPetsByStatusAndCategoryResponse_200.ts +++ b/test/runtime/typescript/src/openapi/payloads/FindPetsByStatusAndCategoryResponse_200.ts @@ -1,6 +1,6 @@ import {APet} from './APet'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; type FindPetsByStatusAndCategoryResponse_200 = APet[]; export function unmarshal(json: string | any[]): FindPetsByStatusAndCategoryResponse_200 { @@ -35,6 +35,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/openapi/payloads/PetCategory.ts b/test/runtime/typescript/src/openapi/payloads/PetCategory.ts index 4d62020c..4e6363d8 100644 --- a/test/runtime/typescript/src/openapi/payloads/PetCategory.ts +++ b/test/runtime/typescript/src/openapi/payloads/PetCategory.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface PetCategoryInterface { id?: number name?: string @@ -87,6 +87,9 @@ class PetCategory { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -94,4 +97,5 @@ class PetCategory { } } -export { PetCategory, PetCategoryInterface }; \ No newline at end of file +export { PetCategory }; +export type { PetCategoryInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi/payloads/PetOrder.ts b/test/runtime/typescript/src/openapi/payloads/PetOrder.ts index 89ec5be1..46f10b36 100644 --- a/test/runtime/typescript/src/openapi/payloads/PetOrder.ts +++ b/test/runtime/typescript/src/openapi/payloads/PetOrder.ts @@ -1,6 +1,6 @@ import {Status} from './Status'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface PetOrderInterface { id?: number petId?: number @@ -139,6 +139,9 @@ class PetOrder { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -146,4 +149,5 @@ class PetOrder { } } -export { PetOrder, PetOrderInterface }; \ No newline at end of file +export { PetOrder }; +export type { PetOrderInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/openapi/payloads/PetTag.ts b/test/runtime/typescript/src/openapi/payloads/PetTag.ts index 50071c6b..2c7e4e42 100644 --- a/test/runtime/typescript/src/openapi/payloads/PetTag.ts +++ b/test/runtime/typescript/src/openapi/payloads/PetTag.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface PetTagInterface { id?: number name?: string @@ -87,6 +87,9 @@ class PetTag { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); ajvInstance.addVocabulary(["xml", "example"]) const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -94,4 +97,5 @@ class PetTag { } } -export { PetTag, PetTagInterface }; \ No newline at end of file +export { PetTag }; +export type { PetTagInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/parameters/UserSignedupParameters.ts b/test/runtime/typescript/src/parameters/UserSignedupParameters.ts index 4195c425..db0c02ca 100644 --- a/test/runtime/typescript/src/parameters/UserSignedupParameters.ts +++ b/test/runtime/typescript/src/parameters/UserSignedupParameters.ts @@ -58,4 +58,5 @@ class UserSignedupParameters { return parameters; } } -export { UserSignedupParameters, UserSignedupParametersInterface }; \ No newline at end of file +export { UserSignedupParameters }; +export type { UserSignedupParametersInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/AllOfThreeTypes.ts b/test/runtime/typescript/src/payload-types/payloads/AllOfThreeTypes.ts index 1f2bf814..18f2e5c9 100644 --- a/test/runtime/typescript/src/payload-types/payloads/AllOfThreeTypes.ts +++ b/test/runtime/typescript/src/payload-types/payloads/AllOfThreeTypes.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface AllOfThreeTypesInterface { id: string name?: string @@ -135,6 +135,9 @@ class AllOfThreeTypes { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -142,4 +145,5 @@ class AllOfThreeTypes { } } -export { AllOfThreeTypes, AllOfThreeTypesInterface }; \ No newline at end of file +export { AllOfThreeTypes }; +export type { AllOfThreeTypesInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/AllOfTwoTypes.ts b/test/runtime/typescript/src/payload-types/payloads/AllOfTwoTypes.ts index 0e18d1b6..e25b385d 100644 --- a/test/runtime/typescript/src/payload-types/payloads/AllOfTwoTypes.ts +++ b/test/runtime/typescript/src/payload-types/payloads/AllOfTwoTypes.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface AllOfTwoTypesInterface { id: string name?: string @@ -111,6 +111,9 @@ class AllOfTwoTypes { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -118,4 +121,5 @@ class AllOfTwoTypes { } } -export { AllOfTwoTypes, AllOfTwoTypesInterface }; \ No newline at end of file +export { AllOfTwoTypes }; +export type { AllOfTwoTypesInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/AnyOfTwoTypes.ts b/test/runtime/typescript/src/payload-types/payloads/AnyOfTwoTypes.ts index 94ad1a78..c9477c83 100644 --- a/test/runtime/typescript/src/payload-types/payloads/AnyOfTwoTypes.ts +++ b/test/runtime/typescript/src/payload-types/payloads/AnyOfTwoTypes.ts @@ -1,7 +1,7 @@ import {AnyOfTwoTypesAnyOfOption0} from './AnyOfTwoTypesAnyOfOption0'; import {AnyOfTwoTypesAnyOfOption1} from './AnyOfTwoTypesAnyOfOption1'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * AnyOf with two object schemas */ @@ -36,6 +36,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/AnyOfTwoTypesAnyOfOption0.ts b/test/runtime/typescript/src/payload-types/payloads/AnyOfTwoTypesAnyOfOption0.ts index d51a0ff1..46550189 100644 --- a/test/runtime/typescript/src/payload-types/payloads/AnyOfTwoTypesAnyOfOption0.ts +++ b/test/runtime/typescript/src/payload-types/payloads/AnyOfTwoTypesAnyOfOption0.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface AnyOfTwoTypesAnyOfOption0Interface { name?: string additionalProperties?: Record @@ -72,6 +72,9 @@ class AnyOfTwoTypesAnyOfOption0 { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -79,4 +82,5 @@ class AnyOfTwoTypesAnyOfOption0 { } } -export { AnyOfTwoTypesAnyOfOption0, AnyOfTwoTypesAnyOfOption0Interface }; \ No newline at end of file +export { AnyOfTwoTypesAnyOfOption0 }; +export type { AnyOfTwoTypesAnyOfOption0Interface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/AnyOfTwoTypesAnyOfOption1.ts b/test/runtime/typescript/src/payload-types/payloads/AnyOfTwoTypesAnyOfOption1.ts index c1a2e6ad..fde4de59 100644 --- a/test/runtime/typescript/src/payload-types/payloads/AnyOfTwoTypesAnyOfOption1.ts +++ b/test/runtime/typescript/src/payload-types/payloads/AnyOfTwoTypesAnyOfOption1.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface AnyOfTwoTypesAnyOfOption1Interface { id?: number additionalProperties?: Record @@ -72,6 +72,9 @@ class AnyOfTwoTypesAnyOfOption1 { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -79,4 +82,5 @@ class AnyOfTwoTypesAnyOfOption1 { } } -export { AnyOfTwoTypesAnyOfOption1, AnyOfTwoTypesAnyOfOption1Interface }; \ No newline at end of file +export { AnyOfTwoTypesAnyOfOption1 }; +export type { AnyOfTwoTypesAnyOfOption1Interface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/ArrayWithMaxItems.ts b/test/runtime/typescript/src/payload-types/payloads/ArrayWithMaxItems.ts index ed67f615..7aa4ec76 100644 --- a/test/runtime/typescript/src/payload-types/payloads/ArrayWithMaxItems.ts +++ b/test/runtime/typescript/src/payload-types/payloads/ArrayWithMaxItems.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * Array with maximum 5 items */ @@ -29,6 +29,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/ArrayWithMinItems.ts b/test/runtime/typescript/src/payload-types/payloads/ArrayWithMinItems.ts index b7e1656b..2c41008b 100644 --- a/test/runtime/typescript/src/payload-types/payloads/ArrayWithMinItems.ts +++ b/test/runtime/typescript/src/payload-types/payloads/ArrayWithMinItems.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * Array with minimum 1 item */ @@ -29,6 +29,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/ArrayWithUniqueItems.ts b/test/runtime/typescript/src/payload-types/payloads/ArrayWithUniqueItems.ts index f7560351..6e708135 100644 --- a/test/runtime/typescript/src/payload-types/payloads/ArrayWithUniqueItems.ts +++ b/test/runtime/typescript/src/payload-types/payloads/ArrayWithUniqueItems.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * Array requiring unique items */ @@ -29,6 +29,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/BooleanPlain.ts b/test/runtime/typescript/src/payload-types/payloads/BooleanPlain.ts index 5d05b408..a45dc34f 100644 --- a/test/runtime/typescript/src/payload-types/payloads/BooleanPlain.ts +++ b/test/runtime/typescript/src/payload-types/payloads/BooleanPlain.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * A plain boolean type */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/CatPayload.ts b/test/runtime/typescript/src/payload-types/payloads/CatPayload.ts index b9d1c292..563da215 100644 --- a/test/runtime/typescript/src/payload-types/payloads/CatPayload.ts +++ b/test/runtime/typescript/src/payload-types/payloads/CatPayload.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface CatPayloadInterface { breed?: string meowPitch?: string @@ -90,6 +90,9 @@ class CatPayload { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -97,4 +100,5 @@ class CatPayload { } } -export { CatPayload, CatPayloadInterface }; \ No newline at end of file +export { CatPayload }; +export type { CatPayloadInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/DeeplyNestedObject.ts b/test/runtime/typescript/src/payload-types/payloads/DeeplyNestedObject.ts index 63f8a41c..d13496f2 100644 --- a/test/runtime/typescript/src/payload-types/payloads/DeeplyNestedObject.ts +++ b/test/runtime/typescript/src/payload-types/payloads/DeeplyNestedObject.ts @@ -1,6 +1,6 @@ import {DeeplyNestedObjectLevel1} from './DeeplyNestedObjectLevel1'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface DeeplyNestedObjectInterface { level1?: DeeplyNestedObjectLevel1 additionalProperties?: Record @@ -76,6 +76,9 @@ class DeeplyNestedObject { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -83,4 +86,5 @@ class DeeplyNestedObject { } } -export { DeeplyNestedObject, DeeplyNestedObjectInterface }; \ No newline at end of file +export { DeeplyNestedObject }; +export type { DeeplyNestedObjectInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/DeeplyNestedObjectLevel1.ts b/test/runtime/typescript/src/payload-types/payloads/DeeplyNestedObjectLevel1.ts index b0f03245..28f6ec2f 100644 --- a/test/runtime/typescript/src/payload-types/payloads/DeeplyNestedObjectLevel1.ts +++ b/test/runtime/typescript/src/payload-types/payloads/DeeplyNestedObjectLevel1.ts @@ -1,6 +1,6 @@ import {DeeplyNestedObjectLevel1Level2} from './DeeplyNestedObjectLevel1Level2'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface DeeplyNestedObjectLevel1Interface { level2?: DeeplyNestedObjectLevel1Level2 additionalProperties?: Record @@ -73,6 +73,9 @@ class DeeplyNestedObjectLevel1 { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -80,4 +83,5 @@ class DeeplyNestedObjectLevel1 { } } -export { DeeplyNestedObjectLevel1, DeeplyNestedObjectLevel1Interface }; \ No newline at end of file +export { DeeplyNestedObjectLevel1 }; +export type { DeeplyNestedObjectLevel1Interface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/DeeplyNestedObjectLevel1Level2.ts b/test/runtime/typescript/src/payload-types/payloads/DeeplyNestedObjectLevel1Level2.ts index 253780bd..db56130f 100644 --- a/test/runtime/typescript/src/payload-types/payloads/DeeplyNestedObjectLevel1Level2.ts +++ b/test/runtime/typescript/src/payload-types/payloads/DeeplyNestedObjectLevel1Level2.ts @@ -1,6 +1,6 @@ import {DeeplyNestedObjectLevel1Level2Level3} from './DeeplyNestedObjectLevel1Level2Level3'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface DeeplyNestedObjectLevel1Level2Interface { level3?: DeeplyNestedObjectLevel1Level2Level3 additionalProperties?: Record @@ -73,6 +73,9 @@ class DeeplyNestedObjectLevel1Level2 { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -80,4 +83,5 @@ class DeeplyNestedObjectLevel1Level2 { } } -export { DeeplyNestedObjectLevel1Level2, DeeplyNestedObjectLevel1Level2Interface }; \ No newline at end of file +export { DeeplyNestedObjectLevel1Level2 }; +export type { DeeplyNestedObjectLevel1Level2Interface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/DeeplyNestedObjectLevel1Level2Level3.ts b/test/runtime/typescript/src/payload-types/payloads/DeeplyNestedObjectLevel1Level2Level3.ts index be65d2cc..f4ca44a5 100644 --- a/test/runtime/typescript/src/payload-types/payloads/DeeplyNestedObjectLevel1Level2Level3.ts +++ b/test/runtime/typescript/src/payload-types/payloads/DeeplyNestedObjectLevel1Level2Level3.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface DeeplyNestedObjectLevel1Level2Level3Interface { value?: string additionalProperties?: Record @@ -72,6 +72,9 @@ class DeeplyNestedObjectLevel1Level2Level3 { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -79,4 +82,5 @@ class DeeplyNestedObjectLevel1Level2Level3 { } } -export { DeeplyNestedObjectLevel1Level2Level3, DeeplyNestedObjectLevel1Level2Level3Interface }; \ No newline at end of file +export { DeeplyNestedObjectLevel1Level2Level3 }; +export type { DeeplyNestedObjectLevel1Level2Level3Interface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/DogPayload.ts b/test/runtime/typescript/src/payload-types/payloads/DogPayload.ts index 628fef66..b668367c 100644 --- a/test/runtime/typescript/src/payload-types/payloads/DogPayload.ts +++ b/test/runtime/typescript/src/payload-types/payloads/DogPayload.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface DogPayloadInterface { breed?: string barkVolume?: number @@ -90,6 +90,9 @@ class DogPayload { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -97,4 +100,5 @@ class DogPayload { } } -export { DogPayload, DogPayloadInterface }; \ No newline at end of file +export { DogPayload }; +export type { DogPayloadInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/FormatDate.ts b/test/runtime/typescript/src/payload-types/payloads/FormatDate.ts index 5fe2175e..0e8d36e4 100644 --- a/test/runtime/typescript/src/payload-types/payloads/FormatDate.ts +++ b/test/runtime/typescript/src/payload-types/payloads/FormatDate.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * String with date format (YYYY-MM-DD) */ @@ -27,6 +27,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/FormatDateTime.ts b/test/runtime/typescript/src/payload-types/payloads/FormatDateTime.ts index 5163284f..85ef0a2a 100644 --- a/test/runtime/typescript/src/payload-types/payloads/FormatDateTime.ts +++ b/test/runtime/typescript/src/payload-types/payloads/FormatDateTime.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * String with date-time format (ISO 8601) */ @@ -27,6 +27,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/FormatEmail.ts b/test/runtime/typescript/src/payload-types/payloads/FormatEmail.ts index bf0a805f..6e269b97 100644 --- a/test/runtime/typescript/src/payload-types/payloads/FormatEmail.ts +++ b/test/runtime/typescript/src/payload-types/payloads/FormatEmail.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * String with email format */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/FormatHostname.ts b/test/runtime/typescript/src/payload-types/payloads/FormatHostname.ts index 4b5c1151..0813c214 100644 --- a/test/runtime/typescript/src/payload-types/payloads/FormatHostname.ts +++ b/test/runtime/typescript/src/payload-types/payloads/FormatHostname.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * String with hostname format */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/FormatIpv4.ts b/test/runtime/typescript/src/payload-types/payloads/FormatIpv4.ts index 6605a818..1c59921a 100644 --- a/test/runtime/typescript/src/payload-types/payloads/FormatIpv4.ts +++ b/test/runtime/typescript/src/payload-types/payloads/FormatIpv4.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * String with IPv4 format */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/FormatIpv6.ts b/test/runtime/typescript/src/payload-types/payloads/FormatIpv6.ts index 3d3be40e..89e92a37 100644 --- a/test/runtime/typescript/src/payload-types/payloads/FormatIpv6.ts +++ b/test/runtime/typescript/src/payload-types/payloads/FormatIpv6.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * String with IPv6 format */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/FormatTime.ts b/test/runtime/typescript/src/payload-types/payloads/FormatTime.ts index e4ed87b0..892d07f8 100644 --- a/test/runtime/typescript/src/payload-types/payloads/FormatTime.ts +++ b/test/runtime/typescript/src/payload-types/payloads/FormatTime.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * String with time format (HH:MM:SS) */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/FormatUri.ts b/test/runtime/typescript/src/payload-types/payloads/FormatUri.ts index 4d9a0365..5129a637 100644 --- a/test/runtime/typescript/src/payload-types/payloads/FormatUri.ts +++ b/test/runtime/typescript/src/payload-types/payloads/FormatUri.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * String with URI format */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/FormatUuid.ts b/test/runtime/typescript/src/payload-types/payloads/FormatUuid.ts index 7a752b7b..df205195 100644 --- a/test/runtime/typescript/src/payload-types/payloads/FormatUuid.ts +++ b/test/runtime/typescript/src/payload-types/payloads/FormatUuid.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * String with UUID format */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/IntegerPlain.ts b/test/runtime/typescript/src/payload-types/payloads/IntegerPlain.ts index 511b0919..8bd1e86b 100644 --- a/test/runtime/typescript/src/payload-types/payloads/IntegerPlain.ts +++ b/test/runtime/typescript/src/payload-types/payloads/IntegerPlain.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * A plain integer type */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/IntegerWithRange.ts b/test/runtime/typescript/src/payload-types/payloads/IntegerWithRange.ts index cf4d0996..5e869d76 100644 --- a/test/runtime/typescript/src/payload-types/payloads/IntegerWithRange.ts +++ b/test/runtime/typescript/src/payload-types/payloads/IntegerWithRange.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * Integer between 1 and 10 */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/NestedArray.ts b/test/runtime/typescript/src/payload-types/payloads/NestedArray.ts index 8a063257..8f70d1d6 100644 --- a/test/runtime/typescript/src/payload-types/payloads/NestedArray.ts +++ b/test/runtime/typescript/src/payload-types/payloads/NestedArray.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * 2D array (array of string arrays) */ @@ -34,6 +34,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/NestedObject.ts b/test/runtime/typescript/src/payload-types/payloads/NestedObject.ts index c4a5f1af..e12e6895 100644 --- a/test/runtime/typescript/src/payload-types/payloads/NestedObject.ts +++ b/test/runtime/typescript/src/payload-types/payloads/NestedObject.ts @@ -1,6 +1,6 @@ import {NestedObjectOuter} from './NestedObjectOuter'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface NestedObjectInterface { outer?: NestedObjectOuter additionalProperties?: Record @@ -76,6 +76,9 @@ class NestedObject { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -83,4 +86,5 @@ class NestedObject { } } -export { NestedObject, NestedObjectInterface }; \ No newline at end of file +export { NestedObject }; +export type { NestedObjectInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/NestedObjectOuter.ts b/test/runtime/typescript/src/payload-types/payloads/NestedObjectOuter.ts index dcea8e7d..fcb426e7 100644 --- a/test/runtime/typescript/src/payload-types/payloads/NestedObjectOuter.ts +++ b/test/runtime/typescript/src/payload-types/payloads/NestedObjectOuter.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface NestedObjectOuterInterface { inner?: string additionalProperties?: Record @@ -72,6 +72,9 @@ class NestedObjectOuter { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -79,4 +82,5 @@ class NestedObjectOuter { } } -export { NestedObjectOuter, NestedObjectOuterInterface }; \ No newline at end of file +export { NestedObjectOuter }; +export type { NestedObjectOuterInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/NullPlain.ts b/test/runtime/typescript/src/payload-types/payloads/NullPlain.ts index 32cab9bc..b0144809 100644 --- a/test/runtime/typescript/src/payload-types/payloads/NullPlain.ts +++ b/test/runtime/typescript/src/payload-types/payloads/NullPlain.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * A null type */ @@ -30,6 +30,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/NumberPlain.ts b/test/runtime/typescript/src/payload-types/payloads/NumberPlain.ts index db2317d7..05ed0919 100644 --- a/test/runtime/typescript/src/payload-types/payloads/NumberPlain.ts +++ b/test/runtime/typescript/src/payload-types/payloads/NumberPlain.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * A plain number type */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/NumberWithMaximum.ts b/test/runtime/typescript/src/payload-types/payloads/NumberWithMaximum.ts index 95dbb0a6..e09590a7 100644 --- a/test/runtime/typescript/src/payload-types/payloads/NumberWithMaximum.ts +++ b/test/runtime/typescript/src/payload-types/payloads/NumberWithMaximum.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * Number with maximum of 100 */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/NumberWithMinimum.ts b/test/runtime/typescript/src/payload-types/payloads/NumberWithMinimum.ts index 946cdda3..599eb582 100644 --- a/test/runtime/typescript/src/payload-types/payloads/NumberWithMinimum.ts +++ b/test/runtime/typescript/src/payload-types/payloads/NumberWithMinimum.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * Number with minimum of 0 */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/NumberWithRange.ts b/test/runtime/typescript/src/payload-types/payloads/NumberWithRange.ts index f1dff0ad..0ffd47dd 100644 --- a/test/runtime/typescript/src/payload-types/payloads/NumberWithRange.ts +++ b/test/runtime/typescript/src/payload-types/payloads/NumberWithRange.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * Number strictly between 0 and 100 */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/ObjectAdditionalPropsFalse.ts b/test/runtime/typescript/src/payload-types/payloads/ObjectAdditionalPropsFalse.ts index 9496b091..a8985133 100644 --- a/test/runtime/typescript/src/payload-types/payloads/ObjectAdditionalPropsFalse.ts +++ b/test/runtime/typescript/src/payload-types/payloads/ObjectAdditionalPropsFalse.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface ObjectAdditionalPropsFalseInterface { known?: string } @@ -59,6 +59,9 @@ class ObjectAdditionalPropsFalse { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -66,4 +69,5 @@ class ObjectAdditionalPropsFalse { } } -export { ObjectAdditionalPropsFalse, ObjectAdditionalPropsFalseInterface }; \ No newline at end of file +export { ObjectAdditionalPropsFalse }; +export type { ObjectAdditionalPropsFalseInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/ObjectAdditionalPropsSchema.ts b/test/runtime/typescript/src/payload-types/payloads/ObjectAdditionalPropsSchema.ts index a7d3a7f9..a2d0c0d5 100644 --- a/test/runtime/typescript/src/payload-types/payloads/ObjectAdditionalPropsSchema.ts +++ b/test/runtime/typescript/src/payload-types/payloads/ObjectAdditionalPropsSchema.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface ObjectAdditionalPropsSchemaInterface { known?: string additionalProperties?: Record @@ -75,6 +75,9 @@ class ObjectAdditionalPropsSchema { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -82,4 +85,5 @@ class ObjectAdditionalPropsSchema { } } -export { ObjectAdditionalPropsSchema, ObjectAdditionalPropsSchemaInterface }; \ No newline at end of file +export { ObjectAdditionalPropsSchema }; +export type { ObjectAdditionalPropsSchemaInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/ObjectAdditionalPropsTrue.ts b/test/runtime/typescript/src/payload-types/payloads/ObjectAdditionalPropsTrue.ts index ccd27557..7ae56c18 100644 --- a/test/runtime/typescript/src/payload-types/payloads/ObjectAdditionalPropsTrue.ts +++ b/test/runtime/typescript/src/payload-types/payloads/ObjectAdditionalPropsTrue.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface ObjectAdditionalPropsTrueInterface { known?: string additionalProperties?: Record @@ -75,6 +75,9 @@ class ObjectAdditionalPropsTrue { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -82,4 +85,5 @@ class ObjectAdditionalPropsTrue { } } -export { ObjectAdditionalPropsTrue, ObjectAdditionalPropsTrueInterface }; \ No newline at end of file +export { ObjectAdditionalPropsTrue }; +export type { ObjectAdditionalPropsTrueInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/ObjectArray.ts b/test/runtime/typescript/src/payload-types/payloads/ObjectArray.ts index 6936584e..a8376bde 100644 --- a/test/runtime/typescript/src/payload-types/payloads/ObjectArray.ts +++ b/test/runtime/typescript/src/payload-types/payloads/ObjectArray.ts @@ -1,6 +1,6 @@ import {ObjectArrayItem} from './ObjectArrayItem'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * Array of objects */ @@ -38,6 +38,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/ObjectArrayItem.ts b/test/runtime/typescript/src/payload-types/payloads/ObjectArrayItem.ts index 629fafc4..9b70ccd4 100644 --- a/test/runtime/typescript/src/payload-types/payloads/ObjectArrayItem.ts +++ b/test/runtime/typescript/src/payload-types/payloads/ObjectArrayItem.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface ObjectArrayItemInterface { id?: number name?: string @@ -84,6 +84,9 @@ class ObjectArrayItem { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -91,4 +94,5 @@ class ObjectArrayItem { } } -export { ObjectArrayItem, ObjectArrayItemInterface }; \ No newline at end of file +export { ObjectArrayItem }; +export type { ObjectArrayItemInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/ObjectWithDefaults.ts b/test/runtime/typescript/src/payload-types/payloads/ObjectWithDefaults.ts index 93be8ba4..12efa523 100644 --- a/test/runtime/typescript/src/payload-types/payloads/ObjectWithDefaults.ts +++ b/test/runtime/typescript/src/payload-types/payloads/ObjectWithDefaults.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface ObjectWithDefaultsInterface { status?: string count?: number @@ -99,6 +99,9 @@ class ObjectWithDefaults { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -106,4 +109,5 @@ class ObjectWithDefaults { } } -export { ObjectWithDefaults, ObjectWithDefaultsInterface }; \ No newline at end of file +export { ObjectWithDefaults }; +export type { ObjectWithDefaultsInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/ObjectWithFormats.ts b/test/runtime/typescript/src/payload-types/payloads/ObjectWithFormats.ts index 4d6ddfcb..64989e7b 100644 --- a/test/runtime/typescript/src/payload-types/payloads/ObjectWithFormats.ts +++ b/test/runtime/typescript/src/payload-types/payloads/ObjectWithFormats.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface ObjectWithFormatsInterface { email?: string website?: string @@ -135,6 +135,9 @@ class ObjectWithFormats { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -142,4 +145,5 @@ class ObjectWithFormats { } } -export { ObjectWithFormats, ObjectWithFormatsInterface }; \ No newline at end of file +export { ObjectWithFormats }; +export type { ObjectWithFormatsInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/ObjectWithOptional.ts b/test/runtime/typescript/src/payload-types/payloads/ObjectWithOptional.ts index 6e1d04b3..c253eb28 100644 --- a/test/runtime/typescript/src/payload-types/payloads/ObjectWithOptional.ts +++ b/test/runtime/typescript/src/payload-types/payloads/ObjectWithOptional.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface ObjectWithOptionalInterface { field1?: string field2?: string @@ -99,6 +99,9 @@ class ObjectWithOptional { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -106,4 +109,5 @@ class ObjectWithOptional { } } -export { ObjectWithOptional, ObjectWithOptionalInterface }; \ No newline at end of file +export { ObjectWithOptional }; +export type { ObjectWithOptionalInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/ObjectWithRequired.ts b/test/runtime/typescript/src/payload-types/payloads/ObjectWithRequired.ts index 3822faca..f072eb63 100644 --- a/test/runtime/typescript/src/payload-types/payloads/ObjectWithRequired.ts +++ b/test/runtime/typescript/src/payload-types/payloads/ObjectWithRequired.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface ObjectWithRequiredInterface { id: string name: string @@ -99,6 +99,9 @@ class ObjectWithRequired { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -106,4 +109,5 @@ class ObjectWithRequired { } } -export { ObjectWithRequired, ObjectWithRequiredInterface }; \ No newline at end of file +export { ObjectWithRequired }; +export type { ObjectWithRequiredInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/OneOfThreeTypes.ts b/test/runtime/typescript/src/payload-types/payloads/OneOfThreeTypes.ts index bd9ba123..bf05bfab 100644 --- a/test/runtime/typescript/src/payload-types/payloads/OneOfThreeTypes.ts +++ b/test/runtime/typescript/src/payload-types/payloads/OneOfThreeTypes.ts @@ -1,6 +1,6 @@ import {OneOfThreeTypesOneOfOption2} from './OneOfThreeTypesOneOfOption2'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * OneOf with three type options */ @@ -34,6 +34,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/OneOfThreeTypesOneOfOption2.ts b/test/runtime/typescript/src/payload-types/payloads/OneOfThreeTypesOneOfOption2.ts index 892952e7..29f9e916 100644 --- a/test/runtime/typescript/src/payload-types/payloads/OneOfThreeTypesOneOfOption2.ts +++ b/test/runtime/typescript/src/payload-types/payloads/OneOfThreeTypesOneOfOption2.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface OneOfThreeTypesOneOfOption2Interface { value?: string additionalProperties?: Record @@ -72,6 +72,9 @@ class OneOfThreeTypesOneOfOption2 { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -79,4 +82,5 @@ class OneOfThreeTypesOneOfOption2 { } } -export { OneOfThreeTypesOneOfOption2, OneOfThreeTypesOneOfOption2Interface }; \ No newline at end of file +export { OneOfThreeTypesOneOfOption2 }; +export type { OneOfThreeTypesOneOfOption2Interface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/OneOfTwoTypes.ts b/test/runtime/typescript/src/payload-types/payloads/OneOfTwoTypes.ts index 53bb0896..689824fd 100644 --- a/test/runtime/typescript/src/payload-types/payloads/OneOfTwoTypes.ts +++ b/test/runtime/typescript/src/payload-types/payloads/OneOfTwoTypes.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * OneOf with string or integer */ @@ -30,6 +30,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/OneOfWithDiscriminator.ts b/test/runtime/typescript/src/payload-types/payloads/OneOfWithDiscriminator.ts index 434ef527..725ee89a 100644 --- a/test/runtime/typescript/src/payload-types/payloads/OneOfWithDiscriminator.ts +++ b/test/runtime/typescript/src/payload-types/payloads/OneOfWithDiscriminator.ts @@ -1,7 +1,7 @@ import {DogPayload} from './DogPayload'; import {CatPayload} from './CatPayload'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * OneOf with discriminator property */ @@ -43,6 +43,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/SimpleObject.ts b/test/runtime/typescript/src/payload-types/payloads/SimpleObject.ts index ad5f7d49..ba873254 100644 --- a/test/runtime/typescript/src/payload-types/payloads/SimpleObject.ts +++ b/test/runtime/typescript/src/payload-types/payloads/SimpleObject.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface SimpleObjectInterface { name?: string age?: number @@ -87,6 +87,9 @@ class SimpleObject { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -94,4 +97,5 @@ class SimpleObject { } } -export { SimpleObject, SimpleObjectInterface }; \ No newline at end of file +export { SimpleObject }; +export type { SimpleObjectInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payload-types/payloads/StringArray.ts b/test/runtime/typescript/src/payload-types/payloads/StringArray.ts index 1a7e094d..510f9ae5 100644 --- a/test/runtime/typescript/src/payload-types/payloads/StringArray.ts +++ b/test/runtime/typescript/src/payload-types/payloads/StringArray.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * Array of strings */ @@ -29,6 +29,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/StringPlain.ts b/test/runtime/typescript/src/payload-types/payloads/StringPlain.ts index 60608c65..8b8b0675 100644 --- a/test/runtime/typescript/src/payload-types/payloads/StringPlain.ts +++ b/test/runtime/typescript/src/payload-types/payloads/StringPlain.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * A plain string type */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/StringWithMaxLength.ts b/test/runtime/typescript/src/payload-types/payloads/StringWithMaxLength.ts index 915c79b5..b3c404fe 100644 --- a/test/runtime/typescript/src/payload-types/payloads/StringWithMaxLength.ts +++ b/test/runtime/typescript/src/payload-types/payloads/StringWithMaxLength.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * String with maximum length of 50 */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/StringWithMinLength.ts b/test/runtime/typescript/src/payload-types/payloads/StringWithMinLength.ts index 99057f0a..4cd86ec9 100644 --- a/test/runtime/typescript/src/payload-types/payloads/StringWithMinLength.ts +++ b/test/runtime/typescript/src/payload-types/payloads/StringWithMinLength.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * String with minimum length of 3 */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/StringWithPattern.ts b/test/runtime/typescript/src/payload-types/payloads/StringWithPattern.ts index b45ba329..125d180a 100644 --- a/test/runtime/typescript/src/payload-types/payloads/StringWithPattern.ts +++ b/test/runtime/typescript/src/payload-types/payloads/StringWithPattern.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * String matching capitalized word pattern */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payload-types/payloads/TupleArray.ts b/test/runtime/typescript/src/payload-types/payloads/TupleArray.ts index 7c771716..8c271b52 100644 --- a/test/runtime/typescript/src/payload-types/payloads/TupleArray.ts +++ b/test/runtime/typescript/src/payload-types/payloads/TupleArray.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * Tuple with fixed position types */ @@ -34,6 +34,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payloads/ArrayMessage.ts b/test/runtime/typescript/src/payloads/ArrayMessage.ts index e3d8a41c..14959285 100644 --- a/test/runtime/typescript/src/payloads/ArrayMessage.ts +++ b/test/runtime/typescript/src/payloads/ArrayMessage.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * An array of strings payload */ @@ -29,6 +29,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payloads/LegacyNotification.ts b/test/runtime/typescript/src/payloads/LegacyNotification.ts index 8295e7c0..0dc0a368 100644 --- a/test/runtime/typescript/src/payloads/LegacyNotification.ts +++ b/test/runtime/typescript/src/payloads/LegacyNotification.ts @@ -1,6 +1,6 @@ import {LegacyNotificationPayloadLevelEnum} from './LegacyNotificationPayloadLevelEnum'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface LegacyNotificationInterface { message?: string level?: LegacyNotificationPayloadLevelEnum @@ -94,6 +94,9 @@ class LegacyNotification { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -101,4 +104,5 @@ class LegacyNotification { } } -export { LegacyNotification, LegacyNotificationInterface }; \ No newline at end of file +export { LegacyNotification }; +export type { LegacyNotificationInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payloads/StringMessage.ts b/test/runtime/typescript/src/payloads/StringMessage.ts index b4efe734..443c9709 100644 --- a/test/runtime/typescript/src/payloads/StringMessage.ts +++ b/test/runtime/typescript/src/payloads/StringMessage.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * A simple string payload */ @@ -26,6 +26,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payloads/UnionMessage.ts b/test/runtime/typescript/src/payloads/UnionMessage.ts index f2545d83..e8955759 100644 --- a/test/runtime/typescript/src/payloads/UnionMessage.ts +++ b/test/runtime/typescript/src/payloads/UnionMessage.ts @@ -1,6 +1,6 @@ import {UnionPayloadOneOfOption2} from './UnionPayloadOneOfOption2'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; /** * A union type payload */ @@ -34,6 +34,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/payloads/UnionPayloadOneOfOption2.ts b/test/runtime/typescript/src/payloads/UnionPayloadOneOfOption2.ts index 7ed8cb00..1c3bb054 100644 --- a/test/runtime/typescript/src/payloads/UnionPayloadOneOfOption2.ts +++ b/test/runtime/typescript/src/payloads/UnionPayloadOneOfOption2.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface UnionPayloadOneOfOption2Interface { name?: string additionalProperties?: Record @@ -72,6 +72,9 @@ class UnionPayloadOneOfOption2 { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -79,4 +82,5 @@ class UnionPayloadOneOfOption2 { } } -export { UnionPayloadOneOfOption2, UnionPayloadOneOfOption2Interface }; \ No newline at end of file +export { UnionPayloadOneOfOption2 }; +export type { UnionPayloadOneOfOption2Interface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/payloads/UserSignedUp.ts b/test/runtime/typescript/src/payloads/UserSignedUp.ts index fa5f3407..1dabff95 100644 --- a/test/runtime/typescript/src/payloads/UserSignedUp.ts +++ b/test/runtime/typescript/src/payloads/UserSignedUp.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface UserSignedUpInterface { displayName?: string email?: string @@ -93,6 +93,9 @@ class UserSignedUp { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -100,4 +103,5 @@ class UserSignedUp { } } -export { UserSignedUp, UserSignedUpInterface }; \ No newline at end of file +export { UserSignedUp }; +export type { UserSignedUpInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/request-reply/channels/nats.ts b/test/runtime/typescript/src/request-reply/channels/nats.ts index a58f59f3..573399f0 100644 --- a/test/runtime/typescript/src/request-reply/channels/nats.ts +++ b/test/runtime/typescript/src/request-reply/channels/nats.ts @@ -97,7 +97,7 @@ function replyToRegularReply({ if(!skipMessageValidation) { const {valid, errors} = Pong.validate({data: receivedData, ajvValidatorFunction: validator}); if(!valid) { - onDataCallback(new Error('Invalid request payload received', JSON.stringify({cause: errors})), undefined); continue; + onDataCallback(new Error(`Invalid request payload received; ${JSON.stringify({cause: errors})}`), undefined); continue; } } const replyMessage = await onDataCallback(undefined, Pong.unmarshal(receivedData) ); diff --git a/test/runtime/typescript/src/request-reply/client/NatsClient.ts b/test/runtime/typescript/src/request-reply/client/NatsClient.ts index dd11eeaf..0380bba5 100644 --- a/test/runtime/typescript/src/request-reply/client/NatsClient.ts +++ b/test/runtime/typescript/src/request-reply/client/NatsClient.ts @@ -20,6 +20,7 @@ export {NotFound}; export {ItemResponse}; import {UserItemsParameters, UserItemsParametersInterface} from './../parameters/UserItemsParameters'; export {UserItemsParameters}; +import {ItemRequestHeaders} from './../headers/ItemRequestHeaders'; //Import channel functions import * as nats from './../channels/nats'; diff --git a/test/runtime/typescript/src/request-reply/headers/ItemRequestHeaders.ts b/test/runtime/typescript/src/request-reply/headers/ItemRequestHeaders.ts index df55332e..a927f91d 100644 --- a/test/runtime/typescript/src/request-reply/headers/ItemRequestHeaders.ts +++ b/test/runtime/typescript/src/request-reply/headers/ItemRequestHeaders.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; class ItemRequestHeaders { private _xCorrelationId: string; private _xRequestId?: string; @@ -89,6 +89,9 @@ class ItemRequestHeaders { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); diff --git a/test/runtime/typescript/src/request-reply/parameters/UserItemsParameters.ts b/test/runtime/typescript/src/request-reply/parameters/UserItemsParameters.ts index bfd07942..550bda37 100644 --- a/test/runtime/typescript/src/request-reply/parameters/UserItemsParameters.ts +++ b/test/runtime/typescript/src/request-reply/parameters/UserItemsParameters.ts @@ -58,4 +58,5 @@ class UserItemsParameters { return parameters; } } -export { UserItemsParameters, UserItemsParametersInterface }; \ No newline at end of file +export { UserItemsParameters }; +export type { UserItemsParametersInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/request-reply/payloads/GetUserItemReplyPayload.ts b/test/runtime/typescript/src/request-reply/payloads/GetUserItemReplyPayload.ts index 1d93d9fc..ada517e1 100644 --- a/test/runtime/typescript/src/request-reply/payloads/GetUserItemReplyPayload.ts +++ b/test/runtime/typescript/src/request-reply/payloads/GetUserItemReplyPayload.ts @@ -1,7 +1,7 @@ import {ItemResponse} from './ItemResponse'; import {NotFound} from './NotFound'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; type GetUserItemReplyPayload = ItemResponse | NotFound; export function unmarshal(json: any): GetUserItemReplyPayload { @@ -42,6 +42,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/request-reply/payloads/ItemRequest.ts b/test/runtime/typescript/src/request-reply/payloads/ItemRequest.ts index 25961227..48459f81 100644 --- a/test/runtime/typescript/src/request-reply/payloads/ItemRequest.ts +++ b/test/runtime/typescript/src/request-reply/payloads/ItemRequest.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface ItemRequestInterface { name: string description?: string @@ -105,6 +105,9 @@ class ItemRequest { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -112,4 +115,5 @@ class ItemRequest { } } -export { ItemRequest, ItemRequestInterface }; \ No newline at end of file +export { ItemRequest }; +export type { ItemRequestInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/request-reply/payloads/ItemResponse.ts b/test/runtime/typescript/src/request-reply/payloads/ItemResponse.ts index d4266b4a..224bb195 100644 --- a/test/runtime/typescript/src/request-reply/payloads/ItemResponse.ts +++ b/test/runtime/typescript/src/request-reply/payloads/ItemResponse.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface ItemResponseInterface { id?: string userId?: string @@ -135,6 +135,9 @@ class ItemResponse { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -142,4 +145,5 @@ class ItemResponse { } } -export { ItemResponse, ItemResponseInterface }; \ No newline at end of file +export { ItemResponse }; +export type { ItemResponseInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/request-reply/payloads/MultiStatusResponseReplyPayload.ts b/test/runtime/typescript/src/request-reply/payloads/MultiStatusResponseReplyPayload.ts index 14c3a859..ad580b5d 100644 --- a/test/runtime/typescript/src/request-reply/payloads/MultiStatusResponseReplyPayload.ts +++ b/test/runtime/typescript/src/request-reply/payloads/MultiStatusResponseReplyPayload.ts @@ -1,7 +1,7 @@ import {Pong} from './Pong'; import {NotFound} from './NotFound'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; type MultiStatusResponseReplyPayload = Pong | NotFound; export function unmarshal(json: any): MultiStatusResponseReplyPayload { @@ -42,6 +42,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/request-reply/payloads/NotFound.ts b/test/runtime/typescript/src/request-reply/payloads/NotFound.ts index 7322b86b..b06a8ae0 100644 --- a/test/runtime/typescript/src/request-reply/payloads/NotFound.ts +++ b/test/runtime/typescript/src/request-reply/payloads/NotFound.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface NotFoundInterface { error?: string code?: string @@ -90,6 +90,9 @@ class NotFound { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -97,4 +100,5 @@ class NotFound { } } -export { NotFound, NotFoundInterface }; \ No newline at end of file +export { NotFound }; +export type { NotFoundInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/request-reply/payloads/Ping.ts b/test/runtime/typescript/src/request-reply/payloads/Ping.ts index 8c70e899..13607cca 100644 --- a/test/runtime/typescript/src/request-reply/payloads/Ping.ts +++ b/test/runtime/typescript/src/request-reply/payloads/Ping.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface PingInterface { ping?: string additionalProperties?: Record @@ -75,6 +75,9 @@ class Ping { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -82,4 +85,5 @@ class Ping { } } -export { Ping, PingInterface }; \ No newline at end of file +export { Ping }; +export type { PingInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/request-reply/payloads/PingPayload.ts b/test/runtime/typescript/src/request-reply/payloads/PingPayload.ts index 84481591..a819985c 100644 --- a/test/runtime/typescript/src/request-reply/payloads/PingPayload.ts +++ b/test/runtime/typescript/src/request-reply/payloads/PingPayload.ts @@ -2,7 +2,7 @@ import {Ping} from './Ping'; import {Pong} from './Pong'; import {NotFound} from './NotFound'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; type PingPayload = Ping | Pong | NotFound; export function unmarshal(json: any): PingPayload { @@ -46,6 +46,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/request-reply/payloads/Pong.ts b/test/runtime/typescript/src/request-reply/payloads/Pong.ts index 6f6194ce..9d943c8f 100644 --- a/test/runtime/typescript/src/request-reply/payloads/Pong.ts +++ b/test/runtime/typescript/src/request-reply/payloads/Pong.ts @@ -1,5 +1,5 @@ import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; interface PongInterface { pong?: string additionalProperties?: Record @@ -75,6 +75,9 @@ class Pong { } public static createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(this.theCodeGenSchema); @@ -82,4 +85,5 @@ class Pong { } } -export { Pong, PongInterface }; \ No newline at end of file +export { Pong }; +export type { PongInterface }; \ No newline at end of file diff --git a/test/runtime/typescript/src/request-reply/payloads/UpdateUserItemReplyPayload.ts b/test/runtime/typescript/src/request-reply/payloads/UpdateUserItemReplyPayload.ts index 02ba0736..681e274e 100644 --- a/test/runtime/typescript/src/request-reply/payloads/UpdateUserItemReplyPayload.ts +++ b/test/runtime/typescript/src/request-reply/payloads/UpdateUserItemReplyPayload.ts @@ -1,7 +1,7 @@ import {ItemResponse} from './ItemResponse'; import {NotFound} from './NotFound'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; type UpdateUserItemReplyPayload = ItemResponse | NotFound; export function unmarshal(json: any): UpdateUserItemReplyPayload { @@ -42,6 +42,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); diff --git a/test/runtime/typescript/src/request-reply/payloads/UserItemsPayload.ts b/test/runtime/typescript/src/request-reply/payloads/UserItemsPayload.ts index 1bf1e0cb..ca68472d 100644 --- a/test/runtime/typescript/src/request-reply/payloads/UserItemsPayload.ts +++ b/test/runtime/typescript/src/request-reply/payloads/UserItemsPayload.ts @@ -2,7 +2,7 @@ import {ItemRequest} from './ItemRequest'; import {ItemResponse} from './ItemResponse'; import {NotFound} from './NotFound'; import {Ajv, Options as AjvOptions, ErrorObject, ValidateFunction} from 'ajv'; -import {default as addFormats} from 'ajv-formats'; +import addFormatsModule from 'ajv-formats'; type UserItemsPayload = ItemRequest | ItemResponse | NotFound; export function unmarshal(json: any): UserItemsPayload { @@ -46,6 +46,9 @@ export function validate(context?: {data: any, ajvValidatorFunction?: ValidateFu } export function createValidator(context?: {ajvInstance?: Ajv, ajvOptions?: AjvOptions}): ValidateFunction { const {ajvInstance} = {...context ?? {}, ajvInstance: new Ajv(context?.ajvOptions ?? {})}; + // `ajv-formats` is CommonJS; its default import is the module namespace under + // `moduleResolution: node16`/`nodenext`, so unwrap `.default` when present. + const addFormats = ((addFormatsModule as unknown as {default?: unknown}).default ?? addFormatsModule) as (ajv: Ajv) => Ajv; addFormats(ajvInstance); const validate = ajvInstance.compile(theCodeGenSchema); From 6d7c7073f056124f104a414ae5cfd2c904a5dede Mon Sep 17 00:00:00 2001 From: jonaslagoni Date: Thu, 30 Jul 2026 11:14:39 +0200 Subject: [PATCH 2/2] fix(deps): align ajv-formats expectations with the declared v3 range Declaring `ajv-formats` moved the runtime suite off a transitively hoisted 2.1.1 and onto the ^3.0.1 the examples already pin, which surfaced a real behaviour difference: v3 follows RFC 3339 `full-time` and requires a time offset, so `format: time` rejects a bare `"10:30:00"` that v2 accepted. The three FormatTime cases asserting bare local times were encoding the behaviour of an undeclared, accidentally resolved version. Point them at offset-bearing values, add explicit coverage for a numeric offset and for the now-invalid no-offset case, and document the change where users read about validation dependencies. Co-Authored-By: Claude Opus 5 (1M context) --- docs/generators/payloads.md | 5 +++++ .../test/payload-types/formats.spec.ts | 17 ++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/docs/generators/payloads.md b/docs/generators/payloads.md index 39d41a5c..7685cbee 100644 --- a/docs/generators/payloads.md +++ b/docs/generators/payloads.md @@ -86,6 +86,11 @@ Dependencies: - If validation enabled, [ajv](https://ajv.js.org/guide/getting-started.html): ^8.17.1 - If validation enabled, [ajv-formats](https://github.com/ajv-validator/ajv-formats): ^3.0.1 +> `ajv-formats` v3 follows RFC 3339 more strictly than v2 did. Most notably, +> `format: time` now requires a time offset, so `"10:30:00"` is rejected while +> `"10:30:00Z"` and `"10:30:00+02:00"` are accepted. Pin `ajv-formats@^2` if you +> need the previous, more lenient behaviour. + #### Validation Each generated class includes built-in JSON Schema validation capabilities through two static methods: diff --git a/test/runtime/typescript/test/payload-types/formats.spec.ts b/test/runtime/typescript/test/payload-types/formats.spec.ts index f0553edc..3edf640a 100644 --- a/test/runtime/typescript/test/payload-types/formats.spec.ts +++ b/test/runtime/typescript/test/payload-types/formats.spec.ts @@ -226,26 +226,33 @@ describe('Format Validation', () => { expect(result).toBe('10:30:00'); }); + // ajv-formats v3 follows RFC 3339 `full-time`, which requires a time + // offset. A bare local time is rejected — v2 accepted it. test('should validate correct time', () => { - const result = FormatTime.validate({ data: '"10:30:00"' }); + const result = FormatTime.validate({ data: '"10:30:00Z"' }); expect(result.valid).toBe(true); }); test('should validate midnight', () => { - const result = FormatTime.validate({ data: '"00:00:00"' }); + const result = FormatTime.validate({ data: '"00:00:00Z"' }); expect(result.valid).toBe(true); }); test('should validate end of day', () => { - const result = FormatTime.validate({ data: '"23:59:59"' }); + const result = FormatTime.validate({ data: '"23:59:59Z"' }); expect(result.valid).toBe(true); }); - test('should validate time with timezone', () => { - const result = FormatTime.validate({ data: '"10:30:00Z"' }); + test('should validate time with a numeric offset', () => { + const result = FormatTime.validate({ data: '"10:30:00+02:00"' }); expect(result.valid).toBe(true); }); + test('should invalidate a time without an offset', () => { + const result = FormatTime.validate({ data: '"10:30:00"' }); + expect(result.valid).toBe(false); + }); + test('should invalidate 24:00:00', () => { const result = FormatTime.validate({ data: '"24:00:00"' }); expect(result.valid).toBe(false);