@shivaedev/effect-test 0.1.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.0 - 2026-10-05
4
+
5
+ ### Added
6
+
7
+ - `@shivaedev/effect-test/it.ts` exports `it`: the `it` of `@effect/vitest`, whose `effect` and `live` testers also take a generator function and run it with `Effect.gen`, so a test reads `it.effect("loads the item", function* () { … })`. They take a function that returns an Effect as well, as `@effect/vitest`'s testers do, so a file switches its import without rewriting other tests. Each tester supports `each`, `fails`, `only`, `runIf`, `skip` and `skipIf`, runs the body in a Scope, and types the yielded values, failures and requirements: a body that needs a service the test does not provide does not type-check. `effect` installs the test services, such as TestClock; `live` uses the live ones. The types are `EffectIt`, `EffectItTest` and `EffectItTester` in `@shivaedev/effect-test/types.ts`.
8
+
9
+ ## 0.2.0 - 2026-10-04
10
+
11
+ ### Changed
12
+
13
+ - Breaking: no root entry and no module that re-exports another. `exports` maps one `"./*.ts"` pattern to every module (`src` under the `source` condition, `dist` otherwise), so you import the module that defines a name, and a bundler sees only the modules you use. Where each name now lives:
14
+ - `@shivaedev/effect-test`: `@shivaedev/effect-test/eventually.ts` (`EventuallyOptions`, `eventually`), `@shivaedev/effect-test/types.ts` (`EffectClock`, `EffectTest`, `EffectTester`, `EffectTestOptions`, `MakeEffectItOptions`, `MakeEffectItResult`), `@shivaedev/effect-test/vitest.ts` (`makeEffectIt`)
15
+
3
16
  ## 0.1.3 - 2026-10-04
4
17
 
5
18
  ### Changed
package/README.md CHANGED
@@ -17,11 +17,34 @@ built for ShivaeDev applications and may change without a deprecation period.
17
17
  pnpm add --save-dev @shivaedev/effect-test @effect/vitest effect vitest
18
18
  ```
19
19
 
20
+ ## `it`
21
+
22
+ `@shivaedev/effect-test/it.ts` exports the `it` of `@effect/vitest`, whose `effect` and `live`
23
+ testers also take the generator itself and run it with `Effect.gen`:
24
+
25
+ ```ts
26
+ import { it } from "@shivaedev/effect-test/it.ts"
27
+
28
+ it.effect("starts at time zero", function* ({ task }) {
29
+ expect(yield* Clock.currentTimeMillis).toBe(0)
30
+ })
31
+
32
+ it.live("waits on the real clock", function* () {
33
+ yield* Effect.sleep("10 millis")
34
+ })
35
+ ```
36
+
37
+ The body receives the Vitest test context; destructure what it reads. `effect`
38
+ installs TestClock and the other test services, `live` keeps the live ones, and
39
+ each runs the body in a Scope. A function that returns an Effect works as well,
40
+ as with `@effect/vitest`. Each tester supports `each`, `fails`, `only`, `runIf`,
41
+ `skip` and `skipIf`; an `each` body receives the table case.
42
+
20
43
  ## `makeEffectIt`
21
44
 
22
45
  ```ts
23
46
  import { Layer } from "effect"
24
- import { makeEffectIt } from "@shivaedev/effect-test"
47
+ import { makeEffectIt } from "@shivaedev/effect-test/vitest.ts"
25
48
 
26
49
  const { effectApp } = makeEffectIt({
27
50
  layer: TestLive,
@@ -74,7 +97,7 @@ retrying under either clock. Use `Effect.try(() => expect(...))` when an
74
97
  assertion failure is intentionally a retryable condition.
75
98
 
76
99
  ```ts
77
- import { eventually } from "@shivaedev/effect-test"
100
+ import { eventually } from "@shivaedev/effect-test/eventually.ts"
78
101
 
79
102
  effectApp("sees a delayed write", function* ({ db }) {
80
103
  const row = yield* eventually(db.Job.where({ id }).first(), {
package/dist/it.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import type { EffectIt } from "./types.ts";
2
+ export declare const it: EffectIt;
3
+ //# sourceMappingURL=it.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"it.d.ts","sourceRoot":"","sources":["../src/it.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAgC,MAAM,YAAY,CAAC;AAsCzE,eAAO,MAAM,EAAE,EAAE,QAGf,CAAC"}
package/dist/it.js ADDED
@@ -0,0 +1,31 @@
1
+ import { it as effectIt } from "@effect/vitest";
2
+ import { Effect } from "effect";
3
+ function effectOf(body) {
4
+ return (...args) => {
5
+ const result = body(...args);
6
+ return Effect.isEffect(result) ? result : Effect.gen(() => result);
7
+ };
8
+ }
9
+ function bodyTest(register) {
10
+ return (name, body, options) => register(name, effectOf(body), options);
11
+ }
12
+ function bodyTester(register) {
13
+ return Object.assign(bodyTest(register), {
14
+ each: (cases) => (name, body, options) => register.each(cases)(name, effectOf(body), options),
15
+ fails: bodyTest(register.fails),
16
+ only: bodyTest(register.only),
17
+ runIf: (condition) => bodyTest(register.runIf(condition)),
18
+ skip: bodyTest(register.skip),
19
+ skipIf: (condition) => bodyTest(register.skipIf(condition)),
20
+ });
21
+ }
22
+ const testers = {};
23
+ const vitestTests = new Proxy(effectIt, {
24
+ get: (target, key, receiver) => (Object.hasOwn(testers, key) ? testers[key] : Reflect.get(target, key, receiver)),
25
+ set: (_target, key, value) => Reflect.set(testers, key, value),
26
+ });
27
+ export const it = Object.assign(vitestTests, {
28
+ effect: bodyTester(effectIt.effect),
29
+ live: bodyTester(effectIt.live),
30
+ });
31
+ //# sourceMappingURL=it.js.map
package/dist/it.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"it.js","sourceRoot":"","sources":["../src/it.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,IAAI,QAAQ,EAAmD,MAAM,gBAAgB,CAAC;AACjG,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAQhC,SAAS,QAAQ,CAAsC,IAAoB;IAC1E,OAAO,CAAC,GAAG,IAAW,EAAsC,EAAE;QAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QAC7B,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC;IACpE,CAAC,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAI,QAAwB;IAC5C,OAAO,CAAC,IAAY,EAAE,IAAqC,EAAE,OAA8B,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;AACzI,CAAC;AAED,SAAS,UAAU,CAAI,QAA0B;IAChD,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;QACxC,IAAI,EACH,CAAQ,KAAuB,EAAkC,EAAE,CACnE,CAAC,IAAY,EAAE,IAA4B,EAAE,OAA8B,EAAE,EAAE,CAC9E,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QACrD,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC;QAC/B,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC;QAC7B,KAAK,EAAE,CAAC,SAAkB,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAClE,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC;QAC7B,MAAM,EAAE,CAAC,SAAkB,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;KACpE,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,GAAiC,EAAE,CAAC;AAEjD,MAAM,WAAW,GAAG,IAAI,KAAK,CAAU,QAAQ,EAAE;IAChD,GAAG,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;IACjH,GAAG,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC;CAC9D,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,EAAE,GAAa,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE;IACtD,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC;IACnC,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC;CAC/B,CAAC,CAAC"}
package/dist/types.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { TestContext, TestOptions } from "@effect/vitest";
2
- import type { Effect, Layer } from "effect";
2
+ import type { Effect, Layer, Scope } from "effect";
3
+ import type { TestAPI } from "vitest";
3
4
  import type { AnyTestLayer } from "./any-test-layer.ts";
4
5
  export type EffectClock = "test" | "live";
5
6
  export type EffectTestOptions = TestOptions & {
@@ -23,4 +24,20 @@ export interface MakeEffectItOptions<Harness, TestLayer extends AnyTestLayer> {
23
24
  export interface MakeEffectItResult<Harness, Provided> {
24
25
  readonly effectApp: EffectTester<Harness, Provided>;
25
26
  }
27
+ export interface EffectItTest<R, TArgs extends readonly unknown[] = [context: TestContext]> {
28
+ <TEffect extends Effect.Effect<unknown, unknown, R>, A>(name: string, body: (...args: TArgs) => Generator<TEffect, A, never>, options?: number | TestOptions): void;
29
+ <A, E>(name: string, body: (...args: TArgs) => Effect.Effect<A, E, R>, options?: number | TestOptions): void;
30
+ }
31
+ export interface EffectItTester<R> extends EffectItTest<R> {
32
+ readonly each: <TItem>(cases: readonly TItem[]) => EffectItTest<R, [item: TItem]>;
33
+ readonly fails: EffectItTest<R>;
34
+ readonly only: EffectItTest<R>;
35
+ readonly runIf: (condition: unknown) => EffectItTest<R>;
36
+ readonly skip: EffectItTest<R>;
37
+ readonly skipIf: (condition: unknown) => EffectItTest<R>;
38
+ }
39
+ export type EffectIt = TestAPI & {
40
+ readonly effect: EffectItTester<Scope.Scope>;
41
+ readonly live: EffectItTester<Scope.Scope>;
42
+ };
26
43
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,CAAC;AAE1C,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG;IAC7C,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,UAAU,CAAC,OAAO,EAAE,QAAQ,IAAI,CAAC,CAAC,EAAE,GAAG,SAAS,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EACpG,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,KAAK,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,CAAC,EAC1E,OAAO,CAAC,EAAE,MAAM,GAAG,iBAAiB,KAChC,IAAI,CAAC;AAEV,MAAM,WAAW,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAE,SAAQ,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC;IACrF,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EACnB,KAAK,EAAE,SAAS,IAAI,EAAE,KAClB,CAAC,CAAC,EAAE,GAAG,SAAS,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAC7D,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,KAAK,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,CAAC,EACtF,OAAO,CAAC,EAAE,MAAM,GAAG,iBAAiB,KAChC,IAAI,CAAC;IACV,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC9C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC7C,QAAQ,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACtE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC7C,QAAQ,CAAC,MAAM,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;CACvE;AAED,MAAM,WAAW,mBAAmB,CAAC,OAAO,EAAE,SAAS,SAAS,YAAY;IAC3E,QAAQ,CAAC,MAAM,CAAC,EACb,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,GACtH,SAAS,CAAC;IACb,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;CAC1G;AAED,MAAM,WAAW,kBAAkB,CAAC,OAAO,EAAE,QAAQ;IACpD,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;CACpD"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/effect-test",
3
- "version": "0.1.3",
3
+ "version": "0.3.0",
4
4
  "description": "Generic Effect Vitest runner with worker-scoped Layers and TestClock",
5
5
  "homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/effect-test#readme",
6
6
  "bugs": {
@@ -15,7 +15,7 @@
15
15
  "sideEffects": false,
16
16
  "type": "module",
17
17
  "imports": {
18
- "#test/*": "./test/*",
18
+ "#test/*": "./src/test-support/*",
19
19
  "#*.ts": {
20
20
  "source": "./src/*.ts",
21
21
  "types": "./dist/*.d.ts",
@@ -23,28 +23,31 @@
23
23
  }
24
24
  },
25
25
  "exports": {
26
- ".": {
27
- "types": "./dist/index.d.ts",
28
- "source": "./src/index.ts",
29
- "import": "./dist/index.js",
30
- "default": "./dist/index.js"
26
+ "./*.ts": {
27
+ "types": "./dist/*.d.ts",
28
+ "source": "./src/*.ts",
29
+ "import": "./dist/*.js",
30
+ "default": "./dist/*.js"
31
31
  },
32
32
  "./package.json": "./package.json"
33
33
  },
34
34
  "files": [
35
35
  "dist",
36
36
  "src",
37
+ "!src/**/*.test.ts",
38
+ "!src/**/*.spec.ts",
39
+ "!src/**/test-support",
37
40
  "CHANGELOG.md",
38
41
  "README.md"
39
42
  ],
40
43
  "devDependencies": {
41
44
  "@effect/vitest": "4.0.0-rc.112",
42
- "@shivaedev/quality": "0.7.3",
45
+ "@shivaedev/quality": "0.14.0",
43
46
  "@types/node": "24.10.1",
44
47
  "@typescript/native": "npm:typescript@7.0.2",
45
48
  "effect": "4.0.0-rc.112",
46
49
  "typescript": "npm:@typescript/typescript6@6.0.2",
47
- "vitest": "4.1.9"
50
+ "vitest": "4.1.11"
48
51
  },
49
52
  "peerDependencies": {
50
53
  "@effect/vitest": "4.0.0-rc.112",
package/src/it.ts ADDED
@@ -0,0 +1,45 @@
1
+ import { it as effectIt, type TestContext, type TestOptions, type Vitest } from "@effect/vitest";
2
+ import { Effect } from "effect";
3
+ import type { TestAPI } from "vitest";
4
+ import type { EffectIt, EffectItTest, EffectItTester } from "./types.ts";
5
+
6
+ type Body<TArgs extends readonly unknown[], R> = (
7
+ ...args: TArgs
8
+ ) => Effect.Effect<unknown, unknown, R> | Generator<Effect.Effect<unknown, unknown, R>, unknown, never>;
9
+
10
+ function effectOf<TArgs extends readonly unknown[], R>(body: Body<TArgs, R>) {
11
+ return (...args: TArgs): Effect.Effect<unknown, unknown, R> => {
12
+ const result = body(...args);
13
+ return Effect.isEffect(result) ? result : Effect.gen(() => result);
14
+ };
15
+ }
16
+
17
+ function bodyTest<R>(register: Vitest.Test<R>): EffectItTest<R> {
18
+ return (name: string, body: Body<[context: TestContext], R>, options?: number | TestOptions) => register(name, effectOf(body), options);
19
+ }
20
+
21
+ function bodyTester<R>(register: Vitest.Tester<R>): EffectItTester<R> {
22
+ return Object.assign(bodyTest(register), {
23
+ each:
24
+ <TItem>(cases: readonly TItem[]): EffectItTest<R, [item: TItem]> =>
25
+ (name: string, body: Body<[item: TItem], R>, options?: number | TestOptions) =>
26
+ register.each(cases)(name, effectOf(body), options),
27
+ fails: bodyTest(register.fails),
28
+ only: bodyTest(register.only),
29
+ runIf: (condition: unknown) => bodyTest(register.runIf(condition)),
30
+ skip: bodyTest(register.skip),
31
+ skipIf: (condition: unknown) => bodyTest(register.skipIf(condition)),
32
+ });
33
+ }
34
+
35
+ const testers: Record<PropertyKey, unknown> = {};
36
+
37
+ const vitestTests = new Proxy<TestAPI>(effectIt, {
38
+ get: (target, key, receiver) => (Object.hasOwn(testers, key) ? testers[key] : Reflect.get(target, key, receiver)),
39
+ set: (_target, key, value) => Reflect.set(testers, key, value),
40
+ });
41
+
42
+ export const it: EffectIt = Object.assign(vitestTests, {
43
+ effect: bodyTester(effectIt.effect),
44
+ live: bodyTester(effectIt.live),
45
+ });
package/src/types.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { TestContext, TestOptions } from "@effect/vitest";
2
- import type { Effect, Layer } from "effect";
2
+ import type { Effect, Layer, Scope } from "effect";
3
+ import type { TestAPI } from "vitest";
3
4
  import type { AnyTestLayer } from "./any-test-layer.ts";
4
5
 
5
6
  export type EffectClock = "test" | "live";
@@ -41,3 +42,26 @@ export interface MakeEffectItOptions<Harness, TestLayer extends AnyTestLayer> {
41
42
  export interface MakeEffectItResult<Harness, Provided> {
42
43
  readonly effectApp: EffectTester<Harness, Provided>;
43
44
  }
45
+
46
+ export interface EffectItTest<R, TArgs extends readonly unknown[] = [context: TestContext]> {
47
+ <TEffect extends Effect.Effect<unknown, unknown, R>, A>(
48
+ name: string,
49
+ body: (...args: TArgs) => Generator<TEffect, A, never>,
50
+ options?: number | TestOptions,
51
+ ): void;
52
+ <A, E>(name: string, body: (...args: TArgs) => Effect.Effect<A, E, R>, options?: number | TestOptions): void;
53
+ }
54
+
55
+ export interface EffectItTester<R> extends EffectItTest<R> {
56
+ readonly each: <TItem>(cases: readonly TItem[]) => EffectItTest<R, [item: TItem]>;
57
+ readonly fails: EffectItTest<R>;
58
+ readonly only: EffectItTest<R>;
59
+ readonly runIf: (condition: unknown) => EffectItTest<R>;
60
+ readonly skip: EffectItTest<R>;
61
+ readonly skipIf: (condition: unknown) => EffectItTest<R>;
62
+ }
63
+
64
+ export type EffectIt = TestAPI & {
65
+ readonly effect: EffectItTester<Scope.Scope>;
66
+ readonly live: EffectItTester<Scope.Scope>;
67
+ };
package/dist/index.d.ts DELETED
@@ -1,4 +0,0 @@
1
- export { type EventuallyOptions, eventually } from "./eventually.ts";
2
- export type { EffectClock, EffectTest, EffectTester, EffectTestOptions, MakeEffectItOptions, MakeEffectItResult, } from "./types.ts";
3
- export { makeEffectIt } from "./vitest.ts";
4
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACrE,YAAY,EACX,WAAW,EACX,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js DELETED
@@ -1,3 +0,0 @@
1
- export { eventually } from "./eventually.js";
2
- export { makeEffectIt } from "./vitest.js";
3
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,UAAU,EAAE,MAAM,iBAAiB,CAAC;AASrE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
package/src/index.ts DELETED
@@ -1,10 +0,0 @@
1
- export { type EventuallyOptions, eventually } from "./eventually.ts";
2
- export type {
3
- EffectClock,
4
- EffectTest,
5
- EffectTester,
6
- EffectTestOptions,
7
- MakeEffectItOptions,
8
- MakeEffectItResult,
9
- } from "./types.ts";
10
- export { makeEffectIt } from "./vitest.ts";