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
5 changes: 5 additions & 0 deletions .changeset/typecheck-tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@effex/dom": patch
---

Fix the `renderToString` return-type inference so provided dependencies (`RendererContext`, `ControlCtx`, `SuspenseBoundaryCtx`, `Scope`) are properly subtracted from the output `R`. Previously the signature used `Deps | R`, which TypeScript can't do set-subtraction from, so those tags leaked into the returned Effect's requirements — callers whose element required `Scope` (from `Signal.make`) or the other provided tags saw them appear in `Effect.runPromise` arguments even though `renderToString` itself provides them internally. Switched to `Exclude<R, Deps>`; the runtime behaviour is unchanged.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ jobs:

- run: pnpm install --frozen-lockfile

- run: pnpm typecheck

- run: pnpm build

- run: pnpm test -- --run
4 changes: 2 additions & 2 deletions packages/core/src/AsyncReadable.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Effect, Option, Scope } from "effect";
import { describe, expect, it } from "vitest";

import { AsyncReadable } from "./AsyncReadable";
import { Signal } from "./Signal";
import { AsyncReadable } from "./AsyncReadable.js";
import { Signal } from "./Signal.js";

const runTest = <A>(effect: Effect.Effect<A, never, Scope.Scope>): Promise<A> =>
Effect.runPromise(Effect.scoped(effect));
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/Mutation.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Effect, Option, Scope } from "effect";
import { describe, expect, it } from "vitest";

import { Mutation } from "./Mutation";
import { Signal } from "./Signal";
import { Mutation } from "./Mutation.js";
import { Signal } from "./Signal.js";

const runTest = <A>(effect: Effect.Effect<A, never, Scope.Scope>): Promise<A> =>
Effect.runPromise(Effect.scoped(effect));
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/Readable.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Chunk, Effect, Stream } from "effect";
import { describe, expect, it } from "vitest";

import * as Readable from "./Readable";
import * as Signal from "./Signal";
import * as Readable from "./Readable.js";
import * as Signal from "./Signal.js";

describe("Readable", () => {
describe("make", () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/Ref.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Effect, Fiber } from "effect";
import { describe, expect, it } from "vitest";

import { Ref } from "./Ref";
import { Ref } from "./Ref.js";

describe("Ref", () => {
it("should create a ref with null current initially", async () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/Signal.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Effect, Stream } from "effect";
import { describe, expect, it } from "vitest";

import { Readable } from "./Readable";
import { Signal } from "./Signal";
import { Readable } from "./Readable.js";
import { Signal } from "./Signal.js";

describe("Signal.fromNullable", () => {
it("should return existing signal when provided", async () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/SignalArray.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Effect, Fiber, Option, Scope, Stream } from "effect";
import { describe, expect, it } from "vitest";

import { Readable } from "./Readable";
import { Signal } from "./Signal";
import { Readable } from "./Readable.js";
import { Signal } from "./Signal.js";

const runTest = <A>(effect: Effect.Effect<A, never, Scope.Scope>): Promise<A> =>
Effect.runPromise(Effect.scoped(effect));
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/SignalMap.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Effect, Fiber, Option, Scope, Stream } from "effect";
import { describe, expect, it } from "vitest";

import { combine } from "./Readable";
import { Signal } from "./Signal";
import { combine } from "./Readable.js";
import { Signal } from "./Signal.js";

const runTest = <A>(effect: Effect.Effect<A, never, Scope.Scope>): Promise<A> =>
Effect.runPromise(Effect.scoped(effect));
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/SignalSet.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Effect, Fiber, Scope, Stream } from "effect";
import { describe, expect, it } from "vitest";

import { combine } from "./Readable";
import { Signal } from "./Signal";
import { combine } from "./Readable.js";
import { Signal } from "./Signal.js";

const runTest = <A>(effect: Effect.Effect<A, never, Scope.Scope>): Promise<A> =>
Effect.runPromise(Effect.scoped(effect));
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/SignalStruct.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Effect, Fiber, Scope, Stream } from "effect";
import { describe, expect, it } from "vitest";

import { combine } from "./Readable";
import { Signal } from "./Signal";
import { combine } from "./Readable.js";
import { Signal } from "./Signal.js";

const runTest = <A>(effect: Effect.Effect<A, never, Scope.Scope>): Promise<A> =>
Effect.runPromise(Effect.scoped(effect));
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/Transition.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Effect } from "effect";
import { describe, expect, it } from "vitest";

import { Signal } from "./Signal";
import { InvalidTransition, Transition } from "./Transition";
import { Signal } from "./Signal.js";
import { InvalidTransition, Transition } from "./Transition.js";

describe("Transition", () => {
describe("make", () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/dom/src/Animation/Animation.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Effect } from "effect";
import { beforeEach, describe, expect, it, vi } from "vitest";

import { runEnterAnimation, runExitAnimation } from "./core";
import { runEnterAnimation, runExitAnimation } from "./core.js";
import {
calculateStaggerDelay,
stagger,
staggerEased,
staggerFromCenter,
} from "./index";
} from "./index.js";

// Mock window.matchMedia for reduced motion tests
const mockMatchMedia = (matches: boolean) => {
Expand Down
8 changes: 4 additions & 4 deletions packages/dom/src/Boundary.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Effect, Layer } from "effect";
import { beforeEach, describe, expect, it } from "vitest";

import { Boundary } from "./Boundary";
import { $ } from "./Element";
import { DOMRendererLive } from "./Render/DOMRenderer";
import { ClientSuspenseBoundaryCtx } from "./SuspenseBoundaryCtx";
import { Boundary } from "./Boundary.js";
import { $ } from "./Element/index.js";
import { DOMRendererLive } from "./Render/DOMRenderer.js";
import { ClientSuspenseBoundaryCtx } from "./SuspenseBoundaryCtx/index.js";

// ClientSuspenseBoundaryCtx depends on DOMRendererLive
const TestLayer = Layer.provideMerge(
Expand Down
8 changes: 4 additions & 4 deletions packages/dom/src/Control/Control.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { beforeEach, expect } from "vitest";

import { Readable, Signal } from "@effex/core";

import { ClientControlCtx, each, match, when } from ".";
import { collect } from "../Collect";
import { $ } from "../Element";
import { DOMRendererLive } from "../Render/DOMRenderer";
import { collect } from "../Collect.js";
import { $ } from "../Element/index.js";
import { DOMRendererLive } from "../Render/DOMRenderer.js";
import { ClientControlCtx, each, match, when } from "./index.js";

const TestLayer = Layer.mergeAll(ClientControlCtx, DOMRendererLive);

Expand Down
6 changes: 3 additions & 3 deletions packages/dom/src/Element/core.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { beforeEach, describe, expect, it } from "vitest";

import { RendererContext, Signal } from "@effex/core";

import { DOMRendererLive } from "../Render/DOMRenderer";
import * as Core from "./core";
import { make as makeRef } from "./ref";
import { DOMRendererLive } from "../Render/DOMRenderer.js";
import * as Core from "./core.js";
import { make as makeRef } from "./ref.js";

const runTest = <A, E>(
effect: Effect.Effect<A, E, Scope.Scope | RendererContext>,
Expand Down
2 changes: 1 addition & 1 deletion packages/dom/src/Element/ref.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { describe, expect, it } from "vitest";

import { Readable } from "@effex/core";

import { bindElementToRef, make } from "./ref";
import { bindElementToRef, make } from "./ref.js";

const runTest = <A>(effect: Effect.Effect<A, never, Scope.Scope>): Promise<A> =>
Effect.runPromise(Effect.scoped(effect));
Expand Down
8 changes: 4 additions & 4 deletions packages/dom/src/Portal.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Effect, Exit, Scope } from "effect";
import { afterEach, beforeEach, describe, expect, it } from "vitest";

import { collect } from "./Collect";
import { $ } from "./Element";
import { Portal } from "./Portal";
import { DOMRendererLive } from "./Render/DOMRenderer";
import { collect } from "./Collect.js";
import { $ } from "./Element/index.js";
import { Portal } from "./Portal.js";
import { DOMRendererLive } from "./Render/DOMRenderer.js";

describe("Portal", () => {
let portalRoot: HTMLDivElement;
Expand Down
2 changes: 1 addition & 1 deletion packages/dom/src/Render/DOMRenderer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { beforeEach, describe, expect, it } from "vitest";

import { RendererContext } from "@effex/core";

import { DOMRenderer, DOMRendererLive } from "./DOMRenderer";
import { DOMRenderer, DOMRendererLive } from "./DOMRenderer.js";

const runTest = <A>(effect: Effect.Effect<A, never, RendererContext>) =>
Effect.runPromise(effect.pipe(Effect.provide(DOMRendererLive)));
Expand Down
8 changes: 4 additions & 4 deletions packages/dom/src/Render/client/client.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Effect, Fiber } from "effect";
import { afterEach, beforeEach, describe, expect, it } from "vitest";

import { collect } from "../../Collect";
import { $ } from "../../Element";
import { DOMRendererLive } from "../DOMRenderer";
import { mount } from "./client";
import { collect } from "../../Collect.js";
import { $ } from "../../Element/index.js";
import { DOMRendererLive } from "../DOMRenderer.js";
import { mount } from "./client.js";

describe("mount", () => {
let container: HTMLElement;
Expand Down
12 changes: 6 additions & 6 deletions packages/dom/src/Render/hydrate/hydrate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";

import { Readable, Signal } from "@effex/core";

import { Boundary } from "../../Boundary";
import { collect } from "../../Collect";
import { each, match, when } from "../../Control";
import { $ } from "../../Element";
import { renderToString } from "../server";
import { hydrate } from "./index";
import { Boundary } from "../../Boundary.js";
import { collect } from "../../Collect.js";
import { each, match, when } from "../../Control/index.js";
import { $ } from "../../Element/index.js";
import { renderToString } from "../server/index.js";
import { hydrate } from "./index.js";

describe("Hydration", () => {
let container: HTMLElement;
Expand Down
20 changes: 12 additions & 8 deletions packages/dom/src/Render/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
* @module
*/

import { Effect, Layer } from "effect";
import { Effect, Layer, type Scope } from "effect";

import {
RendererContext,
Expand Down Expand Up @@ -73,13 +73,13 @@ export const renderToString = <
E = never,
R = never,
>(
element: Element.Element<
A,
E,
RendererContext | ControlCtx | SuspenseBoundaryCtx | R
>,
element: Element.Element<A, E, R>,
_options: RenderToStringOptions = {},
): Effect.Effect<string, E, R> => {
): Effect.Effect<
string,
E,
Exclude<R, RendererContext | ControlCtx | SuspenseBoundaryCtx | Scope.Scope>
> => {
const StringRendererLayer = Layer.succeed(
RendererContext,
StringRenderer as Renderer<unknown>,
Expand All @@ -105,7 +105,11 @@ export const renderToString = <
Effect.provide(StringRendererLayer),
Effect.provide(SSRControlCtx),
withSSRContext,
);
) as Effect.Effect<
string,
E,
Exclude<R, RendererContext | ControlCtx | SuspenseBoundaryCtx | Scope.Scope>
>;
};

// Re-export types and utilities
Expand Down
10 changes: 5 additions & 5 deletions packages/dom/src/Render/server/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { describe, expect, it } from "vitest";

import { Readable, Signal } from "@effex/core";

import { Boundary } from "../../Boundary";
import { collect } from "../../Collect";
import { each, match, when } from "../../Control";
import { $ } from "../../Element";
import { renderToString } from "./index";
import { Boundary } from "../../Boundary.js";
import { collect } from "../../Collect.js";
import { each, match, when } from "../../Control/index.js";
import { $ } from "../../Element/index.js";
import { renderToString } from "./index.js";

describe("SSR", () => {
describe("renderToString", () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/dom/src/Template.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { describe, expect, it } from "vitest";

import { Readable, Signal } from "@effex/core";

import { t } from "./Template";
import { t } from "./Template.js";

describe("Template (t)", () => {
describe("static templates", () => {
Expand Down
8 changes: 4 additions & 4 deletions packages/dom/src/VirtualList/VirtualList.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ import { beforeEach, describe, expect, it, vi } from "vitest";

import { Readable, Signal } from "@effex/core";

import { $ } from "../Element";
import { DOMRendererLive } from "../Render/DOMRenderer";
import { $ } from "../Element/index.js";
import { DOMRendererLive } from "../Render/DOMRenderer.js";
import {
calculateItemOffset,
calculateScrollToPosition,
calculateTotalHeight,
calculateVisibleRange,
parseHeight,
rangesEqual,
} from "./helpers";
import { ClientVirtualListCtx, virtualEach, VirtualListRef } from "./index";
} from "./helpers.js";
import { ClientVirtualListCtx, virtualEach, VirtualListRef } from "./index.js";

const runTest = <A, R>(effect: Effect.Effect<A, never, R>) =>
Effect.runPromise(
Expand Down
2 changes: 1 addition & 1 deletion packages/dom/src/helpers/strings.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";

import { toCamelCase, toKebabCase } from "./strings";
import { toCamelCase, toKebabCase } from "./strings.js";

describe("toKebabCase", () => {
it("should convert camelCase to kebab-case", () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/router/src/Link.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ describe("Link", () => {

const el = await Effect.runPromise(
Link(
{ to: UserRoute, params: { id: "123" } },
{ to: UserRoute as LinkProps["to"], params: { id: "123" } },
Effect.succeed("User"),
).pipe(Effect.scoped, Effect.provide(layer)),
);
Expand Down
2 changes: 1 addition & 1 deletion packages/router/src/Navigation.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Effect, Option, Schema } from "effect";
import { Effect, Schema } from "effect";
import { beforeEach, describe, expect, it, vi } from "vitest";

import {
Expand Down
Loading
Loading