diff --git a/.changeset/heavy-ads-check.md b/.changeset/heavy-ads-check.md new file mode 100644 index 000000000..6996df266 --- /dev/null +++ b/.changeset/heavy-ads-check.md @@ -0,0 +1,5 @@ +--- +"effect-http": patch +--- + +Add `Api.setOptions`, `Api.setEndpointOptions`, `ApiGroup.setOptions`, `ApiGroup.setEndpointOptions` and `ApiEndpoint.setOptions`. diff --git a/.changeset/selfish-mugs-develop.md b/.changeset/selfish-mugs-develop.md new file mode 100644 index 000000000..072195567 --- /dev/null +++ b/.changeset/selfish-mugs-develop.md @@ -0,0 +1,5 @@ +--- +"effect-http": minor +--- + +Rename `Api.ApiOptions` to `Api.Options`. diff --git a/packages/effect-http/dtslint/Api.ts b/packages/effect-http/dtslint/Api.ts new file mode 100644 index 000000000..08a606498 --- /dev/null +++ b/packages/effect-http/dtslint/Api.ts @@ -0,0 +1,22 @@ +import { Api } from "effect-http" + +// $ExpectType Api +Api.make().pipe( + Api.setOptions({ title: "My API" }) +) + +// $ExpectType Api> +Api.make().pipe( + Api.addEndpoint(Api.get("hello", "/hello")), + Api.setOptions({ title: "My API" }) +) + +// $ExpectType Api> +Api.make().pipe( + Api.addEndpoint( + Api.get("hello", "/hello").pipe( + Api.setEndpointOptions({ description: "My endpoint" }) + ) + ), + Api.setOptions({ title: "My API" }) +) diff --git a/packages/effect-http/dtslint/ApiEndpoint.ts b/packages/effect-http/dtslint/ApiEndpoint.ts new file mode 100644 index 000000000..315ea1caf --- /dev/null +++ b/packages/effect-http/dtslint/ApiEndpoint.ts @@ -0,0 +1,6 @@ +import { ApiEndpoint } from "effect-http" + +// $ExpectType Default<"hello"> +ApiEndpoint.get("hello", "/hello").pipe( + ApiEndpoint.setOptions({ description: "my endpoint" }) +) diff --git a/packages/effect-http/dtslint/ApiGroup.ts b/packages/effect-http/dtslint/ApiGroup.ts new file mode 100644 index 000000000..dce258546 --- /dev/null +++ b/packages/effect-http/dtslint/ApiGroup.ts @@ -0,0 +1,16 @@ +import { ApiGroup } from "effect-http" + +// $ExpectType ApiGroup +ApiGroup.make("myGroup").pipe( + ApiGroup.setOptions({ description: "My group" }) +) + +// $ExpectType ApiGroup> +ApiGroup.make("myGroup").pipe( + ApiGroup.addEndpoint( + ApiGroup.get("hello", "/hello").pipe( + ApiGroup.setEndpointOptions({ description: "My endpoint" }) + ) + ), + ApiGroup.setOptions({ description: "My group" }) +) diff --git a/packages/effect-http/dtslint/tsconfig.json b/packages/effect-http/dtslint/tsconfig.json new file mode 100644 index 000000000..6b2c70900 --- /dev/null +++ b/packages/effect-http/dtslint/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../../tsconfig.base.json", + "include": ["."], + "compilerOptions": { + "incremental": false, + "composite": false, + "noUnusedLocals": false + } +} diff --git a/packages/effect-http/package.json b/packages/effect-http/package.json index d9f91431e..90d3a768c 100644 --- a/packages/effect-http/package.json +++ b/packages/effect-http/package.json @@ -19,13 +19,14 @@ "directory": "dist" }, "scripts": { + "check": "tsc -b tsconfig.json", + "check:watch": "tsc -b tsconfig.json --watch", "codegen": "build-utils prepare-v2", "build": "pnpm codegen && pnpm build-esm && pnpm build-cjs && pnpm build-annotate && build-utils pack-v2", "build-esm": "tsc -b tsconfig.build.json", "build-cjs": "babel build/esm --plugins @babel/transform-export-namespace-from --plugins @babel/transform-modules-commonjs --out-dir build/cjs --source-maps", "build-annotate": "babel build --plugins annotate-pure-calls --out-dir build --source-maps", - "check": "tsc -b tsconfig.json", - "check:watch": "tsc -b tsconfig.json --watch", + "dtslint": "dtslint dtslint", "test": "vitest", "coverage": "vitest --coverage" }, diff --git a/packages/effect-http/src/Api.ts b/packages/effect-http/src/Api.ts index ce5a120cc..aeeeb2f4d 100644 --- a/packages/effect-http/src/Api.ts +++ b/packages/effect-http/src/Api.ts @@ -29,7 +29,7 @@ export type TypeId = typeof TypeId * @category models * @since 1.0.0 */ -export interface ApiOptions { +export interface Options { readonly title: string readonly version: string readonly description?: string @@ -46,7 +46,7 @@ export interface ApiOptions { */ export interface Api extends Pipeable.Pipeable, Api.Variance { readonly groups: ReadonlyArray> - readonly options: ApiOptions + readonly options: Options } /** @@ -114,7 +114,7 @@ export declare namespace Api { * @category constructors * @since 1.0.0 */ -export const make: (options?: Partial) => Api.Empty = internal.make +export const make: (options?: Partial) => Api.Empty = internal.make /** * @category combining @@ -175,6 +175,11 @@ export { * @since 1.0.0 */ put, + /** + * @category modifications + * @since 1.0.0 + */ + setOptions as setEndpointOptions, /** * @category constructors * @since 1.0.0 @@ -230,12 +235,16 @@ export { * @since 1.0.0 */ setSecurity - /** - * @category modifications - * @since 1.0.0 - */ } from "./ApiEndpoint.js" +/** + * @category combining + * @since 1.0.0 + */ +export const setOptions: ( + options: Partial +) => (self: Api) => Api = internal.setOptions + /** * FormData schema * diff --git a/packages/effect-http/src/ApiEndpoint.ts b/packages/effect-http/src/ApiEndpoint.ts index f5128a2a2..a8cb7b184 100644 --- a/packages/effect-http/src/ApiEndpoint.ts +++ b/packages/effect-http/src/ApiEndpoint.ts @@ -337,6 +337,13 @@ export const setSecurity: (security: Sec >(endpoint: ApiEndpoint) => ApiEndpoint = internal.setSecurity +/** + * @category modifications + * @since 1.0.0 + */ +export const setOptions: (options: Partial) => (endpoint: A) => A = + internal.setOptions + /** * @category modifications * @since 1.0.0 diff --git a/packages/effect-http/src/ApiGroup.ts b/packages/effect-http/src/ApiGroup.ts index 49b85e8dc..d1fc5b77a 100644 --- a/packages/effect-http/src/ApiGroup.ts +++ b/packages/effect-http/src/ApiGroup.ts @@ -135,6 +135,11 @@ export { * @since 1.0.0 */ put, + /** + * @category modifications + * @since 1.0.0 + */ + setOptions as setEndpointOptions, /** * @category constructors * @since 1.0.0 @@ -190,12 +195,16 @@ export { * @since 1.0.0 */ setSecurity - /** - * @category modifications - * @since 1.0.0 - */ } from "./ApiEndpoint.js" +/** + * @category modifications + * @since 1.0.0 + */ +export const setOptions: ( + options: Partial +) => (api: ApiGroup) => ApiGroup = internal.setOptions + /** * @category refinements * @since 1.0.0 diff --git a/packages/effect-http/src/internal/api-endpoint.ts b/packages/effect-http/src/internal/api-endpoint.ts index 6c78213a2..f6db3929f 100644 --- a/packages/effect-http/src/internal/api-endpoint.ts +++ b/packages/effect-http/src/internal/api-endpoint.ts @@ -201,6 +201,19 @@ export const setSecurity = ( getOptions(endpoint) ) +/** @internal */ +export const setOptions = + (options: Partial) => (endpoint: A): A => + new ApiEndpointImpl( + getId(endpoint), + getPath(endpoint), + getMethod(endpoint), + getRequest(endpoint), + getResponse(endpoint), + getSecurity(endpoint), + { ...getOptions(endpoint), ...options } + ) as unknown as A + /** @internal */ export const getId = < Id extends ApiEndpoint.ApiEndpoint.AnyId, diff --git a/packages/effect-http/src/internal/api-group.ts b/packages/effect-http/src/internal/api-group.ts index e9a105162..2e4795cfc 100644 --- a/packages/effect-http/src/internal/api-group.ts +++ b/packages/effect-http/src/internal/api-group.ts @@ -22,8 +22,8 @@ export class ApiGroupImpl impleme constructor( readonly name: string, - readonly endpoints: Array, - readonly options: ApiGroup.ApiGroup.Any["options"] + readonly endpoints: ReadonlyArray, + readonly options: ApiGroup.Options ) {} pipe() { @@ -36,7 +36,7 @@ export class ApiGroupImpl impleme export const isApiGroup = (u: unknown): u is ApiGroup.ApiGroup.Any => typeof u === "object" && u !== null && TypeId in u /** @internal */ -export const make = (name: string, options?: Partial): ApiGroup.ApiGroup.Empty => +export const make = (name: string, options?: Partial): ApiGroup.ApiGroup.Empty => new ApiGroupImpl(name, [], { ...options }) /** @internal */ @@ -58,3 +58,9 @@ export const addEndpoint = return new ApiGroupImpl(self.name, [...self.endpoints, endpoint], self.options) } + +/** @internal */ +export const setOptions = + (options: Partial) => + (self: ApiGroup.ApiGroup): ApiGroup.ApiGroup => + new ApiGroupImpl(self.name, self.endpoints, { ...self.options, ...options }) diff --git a/packages/effect-http/src/internal/api.ts b/packages/effect-http/src/internal/api.ts index 1e31c7918..36b1ab6bc 100644 --- a/packages/effect-http/src/internal/api.ts +++ b/packages/effect-http/src/internal/api.ts @@ -42,7 +42,7 @@ const DEFAULT_API_OPTIONS: Api.Api.Any["options"] = { export const isApi = (u: unknown): u is Api.Api.Any => typeof u === "object" && u !== null && TypeId in u /** @internal */ -export const make = (options?: Partial): Api.Api.Empty => +export const make = (options?: Partial): Api.Api.Empty => new ApiImpl([], { ...DEFAULT_API_OPTIONS, ...options }) /** @internal */ @@ -90,3 +90,8 @@ export const getEndpoint = >( return endpoint as Api.Api.EndpointById } + +/** @internal */ +export const setOptions = + (options: Partial) => (self: Api.Api): Api.Api => + new ApiImpl(self.groups, { ...self.options, ...options })