Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pnpm add @prover-coder-ai/openapi-effect

## Usage (Promise API)

This package re-exports `openapi-fetch`, so most code can be migrated by changing only the import.
This package implements an `openapi-fetch` compatible API, so most code can be migrated by changing only the import.

```ts
import createClient from "@prover-coder-ai/openapi-effect"
Expand Down
82 changes: 81 additions & 1 deletion packages/app/eslint.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,26 @@ export default defineConfig(
message:
"Запрещены Promise.* — используй комбинаторы Effect (all, forEach, etc.).",
},
{
selector: "CallExpression[callee.object.object.name='globalThis'][callee.object.property.name='Promise']",
message:
"Запрещены globalThis.Promise.* — используй комбинаторы Effect.",
},
{
selector: "NewExpression[callee.object.name='globalThis'][callee.property.name='Promise']",
message:
"Запрещён globalThis.Promise — используй Effect.async / Effect.tryPromise.",
},
{
selector: "TSTypeReference[typeName.name='Promise'], TSTypeReference[typeName.name='PromiseLike']",
message:
"Запрещены Promise/PromiseLike в типах — используй Effect.Effect<A, E, R>.",
},
{
selector: "TSTypeReference[typeName.type='TSQualifiedName'][typeName.left.name='globalThis'][typeName.right.name='Promise']",
message:
"Запрещён globalThis.Promise в типах — используй Effect.Effect<A, E, R>.",
},
{
selector: "CallExpression[callee.property.name='push'] > SpreadElement.arguments",
message: "Do not use spread arguments in Array.push",
Expand All @@ -232,6 +252,18 @@ export default defineConfig(
"Запрещён Promise<T> — используй Effect.Effect<T, E, R>.",
suggest: ["Effect.Effect<T, E, R>"],
},
PromiseLike: {
message:
"Запрещён PromiseLike<T> — используй Effect.Effect<T, E, R>.",
},
"PromiseLike<*>": {
message:
"Запрещён PromiseLike<T> — используй Effect.Effect<T, E, R>.",
},
"globalThis.Promise": {
message:
"Запрещён globalThis.Promise<T> — используй Effect.Effect<T, E, R>.",
},
},
},
],
Expand Down Expand Up @@ -312,6 +344,30 @@ export default defineConfig(
selector: 'CallExpression[callee.name="require"]',
message: "Avoid using require(). Use ES6 imports instead.",
},
{
selector: "NewExpression[callee.name='Promise']",
message: "Запрещён new Promise — используй Effect.async / Effect.tryPromise.",
},
{
selector: "CallExpression[callee.object.name='Promise']",
message: "Запрещены Promise.* — используй комбинаторы Effect.",
},
{
selector: "CallExpression[callee.object.object.name='globalThis'][callee.object.property.name='Promise']",
message: "Запрещены globalThis.Promise.* — используй комбинаторы Effect.",
},
{
selector: "NewExpression[callee.object.name='globalThis'][callee.property.name='Promise']",
message: "Запрещён globalThis.Promise — используй Effect.async / Effect.tryPromise.",
},
{
selector: "TSTypeReference[typeName.name='Promise'], TSTypeReference[typeName.name='PromiseLike']",
message: "Запрещены Promise/PromiseLike в типах — используй Effect.Effect<A, E, R>.",
},
{
selector: "TSTypeReference[typeName.type='TSQualifiedName'][typeName.left.name='globalThis'][typeName.right.name='Promise']",
message: "Запрещён globalThis.Promise в типах — используй Effect.Effect<A, E, R>.",
},
],
'@typescript-eslint/no-restricted-types': 'off',
// Axiom type casting functions intentionally use single-use type parameters
Expand All @@ -336,6 +392,30 @@ export default defineConfig(
selector: 'CallExpression[callee.name="require"]',
message: "Avoid using require(). Use ES6 imports instead.",
},
{
selector: "NewExpression[callee.name='Promise']",
message: "Запрещён new Promise — используй Effect.async / Effect.tryPromise.",
},
{
selector: "CallExpression[callee.object.name='Promise']",
message: "Запрещены Promise.* — используй комбинаторы Effect.",
},
{
selector: "CallExpression[callee.object.object.name='globalThis'][callee.object.property.name='Promise']",
message: "Запрещены globalThis.Promise.* — используй комбинаторы Effect.",
},
{
selector: "NewExpression[callee.object.name='globalThis'][callee.property.name='Promise']",
message: "Запрещён globalThis.Promise — используй Effect.async / Effect.tryPromise.",
},
{
selector: "TSTypeReference[typeName.name='Promise'], TSTypeReference[typeName.name='PromiseLike']",
message: "Запрещены Promise/PromiseLike в типах — используй Effect.Effect<A, E, R>.",
},
{
selector: "TSTypeReference[typeName.type='TSQualifiedName'][typeName.left.name='globalThis'][typeName.right.name='Promise']",
message: "Запрещён globalThis.Promise в типах — используй Effect.Effect<A, E, R>.",
},
],
'@typescript-eslint/no-restricted-types': 'off',
},
Expand All @@ -358,6 +438,6 @@ export default defineConfig(
extends: [tseslint.configs.disableTypeChecked],
},

// 6) Глобальные игноры
// 7) Глобальные игноры
{ ignores: ['dist/**', 'build/**', 'coverage/**', '**/dist/**'] },
);
25 changes: 25 additions & 0 deletions packages/app/eslint.effect-ts-check.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,22 @@ const restrictedSyntaxBase = [
selector: "CallExpression[callee.object.name='Promise']",
message: "Avoid Promise.*. Use Effect combinators."
},
{
selector: "CallExpression[callee.object.object.name='globalThis'][callee.object.property.name='Promise']",
message: "Avoid globalThis.Promise.*. Use Effect combinators."
},
{
selector: "NewExpression[callee.object.name='globalThis'][callee.property.name='Promise']",
message: "Avoid globalThis.Promise. Use Effect.async / Effect.tryPromise."
},
{
selector: "TSTypeReference[typeName.name='Promise'], TSTypeReference[typeName.name='PromiseLike']",
message: "Avoid Promise/PromiseLike types. Use Effect.Effect<A, E, R>."
},
{
selector: "TSTypeReference[typeName.type='TSQualifiedName'][typeName.left.name='globalThis'][typeName.right.name='Promise']",
message: "Avoid globalThis.Promise type. Use Effect.Effect<A, E, R>."
},
{
selector: "CallExpression[callee.name='require']",
message: "Avoid require(). Use ES module imports."
Expand Down Expand Up @@ -178,6 +194,15 @@ export default tseslint.config(
},
"Promise<*>": {
message: "Avoid Promise<T>. Use Effect.Effect<T, E, R>."
},
PromiseLike: {
message: "Avoid PromiseLike<T>. Use Effect.Effect<T, E, R>."
},
"PromiseLike<*>": {
message: "Avoid PromiseLike<T>. Use Effect.Effect<T, E, R>."
},
"globalThis.Promise": {
message: "Avoid globalThis.Promise<T>. Use Effect.Effect<T, E, R>."
}
}
}],
Expand Down
1 change: 0 additions & 1 deletion packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@
"@effect/typeclass": "^0.38.0",
"@effect/workflow": "^0.16.0",
"effect": "^3.19.16",
"openapi-fetch": "^0.15.2",
"openapi-typescript-helpers": "^0.1.0",
"ts-morph": "^27.0.2"
},
Expand Down
27 changes: 16 additions & 11 deletions packages/app/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
// CHANGE: Make openapi-effect a drop-in replacement for openapi-fetch (Promise API), with an opt-in Effect API.
// WHY: Consumer projects must be able to swap openapi-fetch -> openapi-effect with near-zero code changes.
// QUOTE(ТЗ): "openapi-effect должен почти 1 в 1 заменяться с openapi-fetch" / "Просто добавлять effect поведение"
// CHANGE: Expose Effect-only public API
// WHY: Enforce Effect-first paradigm and remove Promise-based client surface
// SOURCE: n/a
// PURITY: SHELL (re-exports)
// COMPLEXITY: O(1)

// Promise-based client (openapi-fetch compatible)
export { default } from "openapi-fetch"
export { default as createClient } from "openapi-fetch"
export * from "openapi-fetch"

// Effect-based client (opt-in)
export * as FetchHttpClient from "@effect/platform/FetchHttpClient"

// Strict Effect client (advanced)
export type * from "./core/api-client/index.js"
export { assertNever } from "./core/api-client/index.js"

export type {
ClientOptions,
DispatchersFor,
StrictApiClient,
StrictApiClientWithDispatchers
Expand All @@ -26,17 +19,29 @@ export type {
export type { Decoder, Dispatcher, RawResponse, StrictClient, StrictRequestInit } from "./shell/api-client/index.js"

export {
createClient as createClientStrict,
createClient,
createClientEffect,
createDispatcher,
createFinalURL,
createPathBasedClient,
createQuerySerializer,
createStrictClient,
createUniversalDispatcher,
defaultBodySerializer,
defaultPathSerializer,
executeRequest,
mergeHeaders,
parseJSON,
registerDefaultDispatchers,
removeTrailingSlash,
serializeArrayParam,
serializeObjectParam,
serializePrimitiveParam,
unexpectedContentType,
unexpectedStatus
} from "./shell/api-client/index.js"

export { createClient as default } from "./shell/api-client/index.js"

// Generated dispatchers (auto-generated from OpenAPI schema)
export * from "./generated/index.js"
Loading