diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e6c4076..e8a1b21 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -12,19 +12,20 @@ concurrency:
 
 jobs:
   test:
-    name: "Test ${{ matrix.testenv.name }}"
+    name: 'Test ${{ matrix.testenv.name }}'
     runs-on: ubuntu-latest
     timeout-minutes: 5
-    strategy: 
+    strategy:
       matrix:
-        testenv: 
-        - { name: "Node", args: '' }
-        - { name: "Chrome", args: '--browser.name=chrome --browser.headless' }
-        - { name: "Firefox", args: '--browser.name=firefox --browser.headless' }
+        testenv:
+          - {name: 'Node', args: ''}
+          - {name: 'Chrome', args: '--browser.name=chrome --browser.headless'}
+          - {name: 'Firefox', args: '--browser.name=firefox --browser.headless'}
 
     steps:
       - uses: actions/checkout@v4
       - uses: wyvox/action-setup-pnpm@v3
       - run: pnpm install --no-lockfile
+      - run: pnpm lint
       - run: pnpm build
       - run: pnpm vitest ${{ matrix.testenv.args }}
diff --git a/.github/workflows/plan-release.yml b/.github/workflows/plan-release.yml
index 8b27a47..37d4f97 100644
--- a/.github/workflows/plan-release.yml
+++ b/.github/workflows/plan-release.yml
@@ -14,7 +14,7 @@ concurrency:
 
 jobs:
   check-plan:
-    name: "Check Release Plan"
+    name: 'Check Release Plan'
     runs-on: ubuntu-latest
     outputs:
       command: ${{ steps.check-release.outputs.command }}
@@ -52,14 +52,14 @@ jobs:
           ref: 'main'
       - uses: wyvox/action-setup-pnpm@v3
       - run: pnpm install --frozen-lockfile
-      
-      - name: "Generate Explanation and Prep Changelogs"
+
+      - name: 'Generate Explanation and Prep Changelogs'
         id: explanation
         run: |
           set +e
-          
+
           pnpm release-plan prepare 2> >(tee -a release-plan-stderr.txt >&2)
-          
+
 
           if [ $? -ne 0 ]; then
             echo 'text<<EOF' >> $GITHUB_OUTPUT
@@ -77,7 +77,7 @@ jobs:
       - uses: peter-evans/create-pull-request@v6
         with:
           commit-message: "Prepare Release using 'release-plan'"
-          labels: "internal"
+          labels: 'internal'
           branch: release-preview
           title: Prepare Release
           body: |
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 903a41c..638cdc9 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -17,7 +17,7 @@ concurrency:
 
 jobs:
   check-plan:
-    name: "Check Release Plan"
+    name: 'Check Release Plan'
     runs-on: ubuntu-latest
     outputs:
       command: ${{ steps.check-release.outputs.command }}
@@ -34,7 +34,7 @@ jobs:
         run: if git diff --name-only HEAD HEAD~1 | grep -w -q ".release-plan.json"; then echo "command=release"; fi >> $GITHUB_OUTPUT
 
   publish:
-    name: "NPM Publish"
+    name: 'NPM Publish'
     runs-on: ubuntu-latest
     needs: check-plan
     if: needs.check-plan.outputs.command == 'release'
@@ -51,7 +51,7 @@ jobs:
       - run: pnpm install --frozen-lockfile
       - name: npm publish
         run: pnpm release-plan publish
-      
+
         env:
           GITHUB_AUTH: ${{ secrets.GITHUB_TOKEN }}
           NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
diff --git a/.prettierrc.json b/.prettierrc.json
new file mode 100644
index 0000000..34169f3
--- /dev/null
+++ b/.prettierrc.json
@@ -0,0 +1,10 @@
+{
+  "printWidth": 100,
+  "tabWidth": 2,
+  "useTabs": false,
+  "embeddedLanguageFormatting": "off",
+  "singleQuote": true,
+  "semi": true,
+  "quoteProps": "preserve",
+  "bracketSpacing": false
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c861814..2cdc209 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,10 +5,12 @@
 signal-polyfill 0.1.1 (patch)
 
 #### :house: Internal
-* `signal-polyfill`
-  * [#6](https://github.com/proposal-signals/signal-polyfill/pull/6) Fix repo references ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
-  * [#4](https://github.com/proposal-signals/signal-polyfill/pull/4) Setup release automation ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
-  * [#1](https://github.com/proposal-signals/signal-polyfill/pull/1) Fix CI ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
+
+- `signal-polyfill`
+  - [#6](https://github.com/proposal-signals/signal-polyfill/pull/6) Fix repo references ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
+  - [#4](https://github.com/proposal-signals/signal-polyfill/pull/4) Setup release automation ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
+  - [#1](https://github.com/proposal-signals/signal-polyfill/pull/1) Fix CI ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
 
 #### Committers: 1
+
 - [@NullVoxPopuli](https://github.com/NullVoxPopuli)
diff --git a/README.md b/README.md
index ff8f908..578c18e 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # Signal Polyfill
 
-## ⚠️  This polyfill is a preview of an in-progress proposal and could change at any time. Do not use this in production. ⚠️
+## ⚠️ This polyfill is a preview of an in-progress proposal and could change at any time. Do not use this in production. ⚠️
 
 A "signal" is [a proposed first-class JavaScript data type](https://github.com/tc39/proposal-signals) that enables one-way data flow through cells of state or computations derived from other state/computations.
 
@@ -10,8 +10,8 @@ This is a polyfill for the `Signal` API.
 
 ### Using signals
 
-* Use `Signal.State(value)` to create a single "cell" of data that can flow through the unidirectional state graph.
-* Use `Signal.Computed(callback)` to define a computation based on state or other computations flowing through the graph.
+- Use `Signal.State(value)` to create a single "cell" of data that can flow through the unidirectional state graph.
+- Use `Signal.Computed(callback)` to define a computation based on state or other computations flowing through the graph.
 
 ```js
 import { Signal } from "signal-polyfill";
@@ -19,7 +19,7 @@ import { effect } from "./effect.js";
 
 const counter = new Signal.State(0);
 const isEven = new Signal.Computed(() => (counter.get() & 1) == 0);
-const parity = new Signal.Computed(() => isEven.get() ? "even" : "odd");
+const parity = new Signal.Computed(() => (isEven.get() ? "even" : "odd"));
 
 effect(() => console.log(parity.get())); // Console logs "even" immediately.
 setInterval(() => counter.set(counter.get() + 1), 1000); // Changes the counter every 1000ms.
@@ -44,11 +44,11 @@ Depending on how the effect is implemented, the above code could result in an in
 
 ### Creating a simple effect
 
-* You can use `Signal.subtle.Watch(callback)` combined with `Signal.Computed(callback)` to create a simple _effect_ implementation.
-* The `Signal.subtle.Watch` `callback` is invoked synchronously when a watched signal becomes dirty.
-* To batch effect updates, library authors are expected to implement their own schedulers.
-* Use `Signal.subtle.Watch#getPending()` to retrieve an array of dirty signals.
-* Calling `Signal.subtle.Watch#watch()` with no arguments will re-watch the list of tracked signals again.
+- You can use `Signal.subtle.Watch(callback)` combined with `Signal.Computed(callback)` to create a simple _effect_ implementation.
+- The `Signal.subtle.Watch` `callback` is invoked synchronously when a watched signal becomes dirty.
+- To batch effect updates, library authors are expected to implement their own schedulers.
+- Use `Signal.subtle.Watch#getPending()` to retrieve an array of dirty signals.
+- Calling `Signal.subtle.Watch#watch()` with no arguments will re-watch the list of tracked signals again.
 
 ```js
 import { Signal } from "signal-polyfill";
@@ -64,7 +64,7 @@ const w = new Signal.subtle.Watcher(() => {
 
 function processPending() {
   needsEnqueue = true;
-    
+
   for (const s of w.getPending()) {
     s.get();
   }
@@ -74,15 +74,15 @@ function processPending() {
 
 export function effect(callback) {
   let cleanup;
-  
+
   const computed = new Signal.Computed(() => {
     typeof cleanup === "function" && cleanup();
     cleanup = callback();
   });
-  
+
   w.watch(computed);
   computed.get();
-  
+
   return () => {
     w.unwatch(computed);
     typeof cleanup === "function" && cleanup();
@@ -112,7 +112,7 @@ export function signal(target) {
     set(value) {
       get.call(this).set(value);
     },
-    
+
     init(value) {
       return new Signal.State(value);
     },
diff --git a/RELEASE.md b/RELEASE.md
index 3c51885..5ffd224 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -4,21 +4,21 @@ Releases in this repo are mostly automated using [release-plan](https://github.c
 
 ## Preparation
 
-Since the majority of the actual release process is automated, the remaining tasks before releasing are: 
+Since the majority of the actual release process is automated, the remaining tasks before releasing are:
 
--  correctly labeling **all** pull requests that have been merged since the last release
--  updating pull request titles so they make sense to our users
+- correctly labeling **all** pull requests that have been merged since the last release
+- updating pull request titles so they make sense to our users
 
 Some great information on why this is important can be found at [keepachangelog.com](https://keepachangelog.com/en/1.1.0/), but the overall
 guiding principle here is that changelogs are for humans, not machines.
 
 When reviewing merged PR's the labels to be used are:
 
-* breaking - Used when the PR is considered a breaking change.
-* enhancement - Used when the PR adds a new feature or enhancement.
-* bug - Used when the PR fixes a bug included in a previous release.
-* documentation - Used when the PR adds or updates documentation.
-* internal - Internal changes or things that don't fit in any other category.
+- breaking - Used when the PR is considered a breaking change.
+- enhancement - Used when the PR adds a new feature or enhancement.
+- bug - Used when the PR fixes a bug included in a previous release.
+- documentation - Used when the PR adds or updates documentation.
+- internal - Internal changes or things that don't fit in any other category.
 
 **Note:** `release-plan` requires that **all** PRs are labeled. If a PR doesn't fit in a category it's fine to label it as `internal`
 
diff --git a/package.json b/package.json
index 2b96126..891dd57 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,8 @@
     "build": "tsc && vite build",
     "dev": "vite",
     "prepack": "npm run build",
+    "lint": "prettier --check .",
+    "lint:fix": "prettier --write .",
     "test": "vitest"
   },
   "devDependencies": {
diff --git a/src/computed.ts b/src/computed.ts
index 50b3e85..6d99595 100644
--- a/src/computed.ts
+++ b/src/computed.ts
@@ -7,8 +7,15 @@
  */
 
 import {defaultEquals, ValueEqualityFn} from './equality.js';
-import {consumerAfterComputation, consumerBeforeComputation, producerAccessed, producerUpdateValueVersion, REACTIVE_NODE, ReactiveNode, SIGNAL} from './graph.js';
-
+import {
+  consumerAfterComputation,
+  consumerBeforeComputation,
+  producerAccessed,
+  producerUpdateValueVersion,
+  REACTIVE_NODE,
+  ReactiveNode,
+  SIGNAL,
+} from './graph.js';
 
 /**
  * A computation, which derives a value from a declarative reactive expression.
@@ -36,7 +43,7 @@ export interface ComputedNode<T> extends ReactiveNode {
   equal: ValueEqualityFn<T>;
 }
 
-export type ComputedGetter<T> = (() => T)&{
+export type ComputedGetter<T> = (() => T) & {
   [SIGNAL]: ComputedNode<T>;
 };
 
diff --git a/src/equality.ts b/src/equality.ts
index 55cb94c..20f9b9f 100644
--- a/src/equality.ts
+++ b/src/equality.ts
@@ -16,4 +16,4 @@ export type ValueEqualityFn<T> = (a: T, b: T) => boolean;
  */
 export function defaultEquals<T>(a: T, b: T) {
   return Object.is(a, b);
-}
\ No newline at end of file
+}
diff --git a/src/errors.ts b/src/errors.ts
index dbfba19..0f58fe9 100644
--- a/src/errors.ts
+++ b/src/errors.ts
@@ -18,4 +18,4 @@ export function throwInvalidWriteToSignalError() {
 
 export function setThrowInvalidWriteToSignalError(fn: () => never): void {
   throwInvalidWriteToSignalErrorFn = fn;
-}
\ No newline at end of file
+}
diff --git a/src/graph.ts b/src/graph.ts
index f3e9dc5..3b56975 100644
--- a/src/graph.ts
+++ b/src/graph.ts
@@ -8,18 +8,17 @@
 
 // Required as the signals library is in a separate package, so we need to explicitly ensure the
 // global `ngDevMode` type is defined.
-declare const ngDevMode: boolean|undefined;
-
+declare const ngDevMode: boolean | undefined;
 
 /**
  * The currently active consumer `ReactiveNode`, if running code in a reactive context.
  *
  * Change this via `setActiveConsumer`.
  */
-let activeConsumer: ReactiveNode|null = null;
+let activeConsumer: ReactiveNode | null = null;
 let inNotificationPhase = false;
 
-type Version = number&{__brand: 'Version'};
+type Version = number & {__brand: 'Version'};
 
 /**
  * Global epoch counter. Incremented whenever a source signal is set.
@@ -33,13 +32,13 @@ let epoch: Version = 1 as Version;
  */
 export const SIGNAL = /* @__PURE__ */ Symbol('SIGNAL');
 
-export function setActiveConsumer(consumer: ReactiveNode|null): ReactiveNode|null {
+export function setActiveConsumer(consumer: ReactiveNode | null): ReactiveNode | null {
   const prev = activeConsumer;
   activeConsumer = consumer;
   return prev;
 }
 
-export function getActiveConsumer(): ReactiveNode|null {
+export function getActiveConsumer(): ReactiveNode | null {
   return activeConsumer;
 }
 
@@ -115,14 +114,14 @@ export interface ReactiveNode {
    *
    * Uses the same indices as the `producerLastReadVersion` and `producerIndexOfThis` arrays.
    */
-  producerNode: ReactiveNode[]|undefined;
+  producerNode: ReactiveNode[] | undefined;
 
   /**
    * `Version` of the value last read by a given producer.
    *
    * Uses the same indices as the `producerNode` and `producerIndexOfThis` arrays.
    */
-  producerLastReadVersion: Version[]|undefined;
+  producerLastReadVersion: Version[] | undefined;
 
   /**
    * Index of `this` (consumer) in each producer's `liveConsumers` array.
@@ -132,7 +131,7 @@ export interface ReactiveNode {
    *
    * Uses the same indices as the `producerNode` and `producerLastReadVersion` arrays.
    */
-  producerIndexOfThis: number[]|undefined;
+  producerIndexOfThis: number[] | undefined;
 
   /**
    * Index into the producer arrays that the next dependency of this node as a consumer will use.
@@ -149,14 +148,14 @@ export interface ReactiveNode {
    *
    * `liveConsumerNode.length` is effectively our reference count for this node.
    */
-  liveConsumerNode: ReactiveNode[]|undefined;
+  liveConsumerNode: ReactiveNode[] | undefined;
 
   /**
    * Index of `this` (producer) in each consumer's `producerNode` array.
    *
    * Uses the same indices as the `liveConsumerNode` array.
    */
-  liveConsumerIndexOfThis: number[]|undefined;
+  liveConsumerIndexOfThis: number[] | undefined;
 
   /**
    * Whether writes to signals are allowed when this consumer is the `activeConsumer`.
@@ -215,9 +214,10 @@ interface ProducerNode extends ReactiveNode {
 export function producerAccessed(node: ReactiveNode): void {
   if (inNotificationPhase) {
     throw new Error(
-        typeof ngDevMode !== 'undefined' && ngDevMode ?
-            `Assertion error: signal read during notification phase` :
-            '');
+      typeof ngDevMode !== 'undefined' && ngDevMode
+        ? `Assertion error: signal read during notification phase`
+        : '',
+    );
   }
 
   if (activeConsumer === null) {
@@ -255,8 +255,9 @@ export function producerAccessed(node: ReactiveNode): void {
 
     // If the active consumer is live, then add it as a live consumer. If not, then use 0 as a
     // placeholder value.
-    activeConsumer.producerIndexOfThis[idx] =
-        consumerIsLive(activeConsumer) ? producerAddLiveConsumer(node, activeConsumer, idx) : 0;
+    activeConsumer.producerIndexOfThis[idx] = consumerIsLive(activeConsumer)
+      ? producerAddLiveConsumer(node, activeConsumer, idx)
+      : 0;
   }
   activeConsumer.producerLastReadVersion[idx] = node.version;
 }
@@ -344,7 +345,7 @@ export function consumerMarkDirty(node: ReactiveNode): void {
  * Must be called by subclasses which represent reactive computations, before those computations
  * begin.
  */
-export function consumerBeforeComputation(node: ReactiveNode|null): ReactiveNode|null {
+export function consumerBeforeComputation(node: ReactiveNode | null): ReactiveNode | null {
   node && (node.nextProducerIndex = 0);
   return setActiveConsumer(node);
 }
@@ -356,11 +357,17 @@ export function consumerBeforeComputation(node: ReactiveNode|null): ReactiveNode
  * have finished.
  */
 export function consumerAfterComputation(
-    node: ReactiveNode|null, prevConsumer: ReactiveNode|null): void {
+  node: ReactiveNode | null,
+  prevConsumer: ReactiveNode | null,
+): void {
   setActiveConsumer(prevConsumer);
 
-  if (!node || node.producerNode === undefined || node.producerIndexOfThis === undefined ||
-      node.producerLastReadVersion === undefined) {
+  if (
+    !node ||
+    node.producerNode === undefined ||
+    node.producerIndexOfThis === undefined ||
+    node.producerLastReadVersion === undefined
+  ) {
     return;
   }
 
@@ -427,7 +434,9 @@ export function consumerDestroy(node: ReactiveNode): void {
   }
 
   // Truncate all the arrays to drop all connection from this node to the graph.
-  node.producerNode.length = node.producerLastReadVersion.length = node.producerIndexOfThis.length =
+  node.producerNode.length =
+    node.producerLastReadVersion.length =
+    node.producerIndexOfThis.length =
       0;
   if (node.liveConsumerNode) {
     node.liveConsumerNode.length = node.liveConsumerIndexOfThis!.length = 0;
@@ -441,7 +450,10 @@ export function consumerDestroy(node: ReactiveNode): void {
  * a live consumer of all of its current producers.
  */
 function producerAddLiveConsumer(
-    node: ReactiveNode, consumer: ReactiveNode, indexOfThis: number): number {
+  node: ReactiveNode,
+  consumer: ReactiveNode,
+  indexOfThis: number,
+): number {
   assertProducerNode(node);
   assertConsumerNode(node);
   if (node.liveConsumerNode.length === 0) {
@@ -463,8 +475,9 @@ export function producerRemoveLiveConsumerAtIndex(node: ReactiveNode, idx: numbe
   assertConsumerNode(node);
 
   if (typeof ngDevMode !== 'undefined' && ngDevMode && idx >= node.liveConsumerNode.length) {
-    throw new Error(`Assertion error: active consumer index ${idx} is out of bounds of ${
-        node.liveConsumerNode.length} consumers)`);
+    throw new Error(
+      `Assertion error: active consumer index ${idx} is out of bounds of ${node.liveConsumerNode.length} consumers)`,
+    );
   }
 
   if (node.liveConsumerNode.length === 1) {
@@ -501,7 +514,6 @@ function consumerIsLive(node: ReactiveNode): boolean {
   return node.consumerIsAlwaysLive || (node?.liveConsumerNode?.length ?? 0) > 0;
 }
 
-
 export function assertConsumerNode(node: ReactiveNode): asserts node is ConsumerNode {
   node.producerNode ??= [];
   node.producerIndexOfThis ??= [];
@@ -511,4 +523,4 @@ export function assertConsumerNode(node: ReactiveNode): asserts node is Consumer
 export function assertProducerNode(node: ReactiveNode): asserts node is ProducerNode {
   node.liveConsumerNode ??= [];
   node.liveConsumerIndexOfThis ??= [];
-}
\ No newline at end of file
+}
diff --git a/src/index.ts b/src/index.ts
index 72b9910..ecab651 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1 +1 @@
-export { Signal } from "./wrapper.js";
\ No newline at end of file
+export {Signal} from './wrapper.js';
diff --git a/src/signal.ts b/src/signal.ts
index 2bdfba3..7348c22 100644
--- a/src/signal.ts
+++ b/src/signal.ts
@@ -8,11 +8,19 @@
 
 import {defaultEquals, ValueEqualityFn} from './equality.js';
 import {throwInvalidWriteToSignalError} from './errors.js';
-import {producerAccessed, producerIncrementEpoch, producerNotifyConsumers, producerUpdatesAllowed, REACTIVE_NODE, ReactiveNode, SIGNAL} from './graph.js';
+import {
+  producerAccessed,
+  producerIncrementEpoch,
+  producerNotifyConsumers,
+  producerUpdatesAllowed,
+  REACTIVE_NODE,
+  ReactiveNode,
+  SIGNAL,
+} from './graph.js';
 
 // Required as the signals library is in a separate package, so we need to explicitly ensure the
 // global `ngDevMode` type is defined.
-declare const ngDevMode: boolean|undefined;
+declare const ngDevMode: boolean | undefined;
 
 /**
  * If set, called after `WritableSignal`s are updated.
@@ -20,19 +28,19 @@ declare const ngDevMode: boolean|undefined;
  * This hook can be used to achieve various effects, such as running effects synchronously as part
  * of setting a signal.
  */
-let postSignalSetFn: (() => void)|null = null;
+let postSignalSetFn: (() => void) | null = null;
 
 export interface SignalNode<T> extends ReactiveNode {
   value: T;
   equal: ValueEqualityFn<T>;
 }
 
-export type SignalBaseGetter<T> = (() => T)&{readonly[SIGNAL]: unknown};
+export type SignalBaseGetter<T> = (() => T) & {readonly [SIGNAL]: unknown};
 
 // Note: Closure *requires* this to be an `interface` and not a type, which is why the
 // `SignalBaseGetter` type exists to provide the correct shape.
 export interface SignalGetter<T> extends SignalBaseGetter<T> {
-  readonly[SIGNAL]: SignalNode<T>;
+  readonly [SIGNAL]: SignalNode<T>;
 }
 
 /**
@@ -42,14 +50,14 @@ export function createSignal<T>(initialValue: T): SignalGetter<T> {
   const node: SignalNode<T> = Object.create(SIGNAL_NODE);
   node.value = initialValue;
   const getter = (() => {
-                   producerAccessed(node);
-                   return node.value;
-                 }) as SignalGetter<T>;
+    producerAccessed(node);
+    return node.value;
+  }) as SignalGetter<T>;
   (getter as any)[SIGNAL] = node;
   return getter;
 }
 
-export function setPostSignalSetFn(fn: (() => void)|null): (() => void)|null {
+export function setPostSignalSetFn(fn: (() => void) | null): (() => void) | null {
   const prev = postSignalSetFn;
   postSignalSetFn = fn;
   return prev;
@@ -95,4 +103,4 @@ function signalValueChanged<T>(node: SignalNode<T>): void {
   producerIncrementEpoch();
   producerNotifyConsumers(node);
   postSignalSetFn?.();
-}
\ No newline at end of file
+}
diff --git a/src/wrapper.ts b/src/wrapper.ts
index a8eab3d..55a5e6e 100644
--- a/src/wrapper.ts
+++ b/src/wrapper.ts
@@ -15,298 +15,273 @@
  * limitations under the License.
  */
 
+import {computedGet, createComputed, type ComputedNode} from './computed.js';
 import {
-  computedGet,
-  createComputed,
-  type ComputedNode,
-} from "./computed.js";
-import {
-SIGNAL,
-getActiveConsumer,
-isInNotificationPhase,
-producerAccessed,
-assertConsumerNode,
-setActiveConsumer,
-REACTIVE_NODE,
-type ReactiveNode,
-assertProducerNode,
-producerRemoveLiveConsumerAtIndex,
-} from "./graph.js";
-import {
-createSignal,
-signalGetFn,
-signalSetFn,
-type SignalNode,
-} from "./signal.js";
-
-const NODE: unique symbol = Symbol("node");
-
-let isState: (s: any) => boolean,
-    isComputed: (s: any) => boolean,
-    isWatcher: (s: any) => boolean;
+  SIGNAL,
+  getActiveConsumer,
+  isInNotificationPhase,
+  producerAccessed,
+  assertConsumerNode,
+  setActiveConsumer,
+  REACTIVE_NODE,
+  type ReactiveNode,
+  assertProducerNode,
+  producerRemoveLiveConsumerAtIndex,
+} from './graph.js';
+import {createSignal, signalGetFn, signalSetFn, type SignalNode} from './signal.js';
+
+const NODE: unique symbol = Symbol('node');
+
+let isState: (s: any) => boolean, isComputed: (s: any) => boolean, isWatcher: (s: any) => boolean;
 
 // eslint-disable-next-line @typescript-eslint/no-namespace
 export namespace Signal {
-// A read-write Signal
-export class State<T> {
-  readonly [NODE]: SignalNode<T>;
-  #brand() {}
+  // A read-write Signal
+  export class State<T> {
+    readonly [NODE]: SignalNode<T>;
+    #brand() {}
 
-  static {
-    isState = s => #brand in s;
-  }
+    static {
+      isState = (s) => #brand in s;
+    }
 
-  constructor(initialValue: T, options: Signal.Options<T> = {}) {
-    const ref = createSignal<T>(initialValue);
-    const node: SignalNode<T> = ref[SIGNAL];
-    this[NODE] = node;
-    node.wrapper = this;
-    if (options) {
-      const equals = options.equals;
-      if (equals) {
-        node.equal = equals;
+    constructor(initialValue: T, options: Signal.Options<T> = {}) {
+      const ref = createSignal<T>(initialValue);
+      const node: SignalNode<T> = ref[SIGNAL];
+      this[NODE] = node;
+      node.wrapper = this;
+      if (options) {
+        const equals = options.equals;
+        if (equals) {
+          node.equal = equals;
+        }
+        node.watched = options[Signal.subtle.watched];
+        node.unwatched = options[Signal.subtle.unwatched];
       }
-      node.watched = options[Signal.subtle.watched];
-      node.unwatched = options[Signal.subtle.unwatched];
     }
-  }
-
-  public get(): T {
-    if (!isState(this))
-      throw new TypeError(
-        "Wrong receiver type for Signal.State.prototype.get",
-      );
-    return (signalGetFn<T>).call(this[NODE]);
-  }
 
-  public set(newValue: T): void {
-    if (!isState(this))
-      throw new TypeError(
-        "Wrong receiver type for Signal.State.prototype.set",
-      );
-    if (isInNotificationPhase()) {
-      throw new Error(
-        "Writes to signals not permitted during Watcher callback",
-      );
+    public get(): T {
+      if (!isState(this)) throw new TypeError('Wrong receiver type for Signal.State.prototype.get');
+      return (signalGetFn<T>).call(this[NODE]);
     }
-    const ref = this[NODE];
-    signalSetFn<T>(ref, newValue);
-  }
-}
-
-// A Signal which is a formula based on other Signals
-export class Computed<T> {
-  readonly [NODE]: ComputedNode<T>;
 
-  #brand() {}
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  static {
-    isComputed = (c: any) => #brand in c;
-  }
-
-  // Create a Signal which evaluates to the value returned by the callback.
-  // Callback is called with this signal as the parameter.
-  constructor(computation: () => T, options?: Signal.Options<T>) {
-    const ref = createComputed<T>(computation);
-    const node = ref[SIGNAL];
-    node.consumerAllowSignalWrites = true;
-    this[NODE] = node;
-    node.wrapper = this;
-    if (options) {
-      const equals = options.equals;
-      if (equals) {
-        node.equal = equals;
+    public set(newValue: T): void {
+      if (!isState(this)) throw new TypeError('Wrong receiver type for Signal.State.prototype.set');
+      if (isInNotificationPhase()) {
+        throw new Error('Writes to signals not permitted during Watcher callback');
       }
-      node.watched = options[Signal.subtle.watched];
-      node.unwatched = options[Signal.subtle.unwatched];
+      const ref = this[NODE];
+      signalSetFn<T>(ref, newValue);
     }
   }
 
-  get(): T {
-    if (!isComputed(this))
-      throw new TypeError(
-        "Wrong receiver type for Signal.Computed.prototype.get",
-      );
-    return computedGet(this[NODE]);
-  }
-}
+  // A Signal which is a formula based on other Signals
+  export class Computed<T> {
+    readonly [NODE]: ComputedNode<T>;
 
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-type AnySignal<T = any> = State<T> | Computed<T>;
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-type AnySink = Computed<any> | subtle.Watcher;
-
-// eslint-disable-next-line @typescript-eslint/no-namespace
-export namespace subtle {
-  // Run a callback with all tracking disabled (even for nested computed).
-  export function untrack<T>(cb: () => T): T {
-    let output: T;
-    let prevActiveConsumer = null;
-    try {
-      prevActiveConsumer = setActiveConsumer(null);
-      output = cb();
-    } finally {
-      setActiveConsumer(prevActiveConsumer);
+    #brand() {}
+    // eslint-disable-next-line @typescript-eslint/no-explicit-any
+    static {
+      isComputed = (c: any) => #brand in c;
     }
-    return output;
-  }
 
-  // Returns ordered list of all signals which this one referenced
-  // during the last time it was evaluated
-  export function introspectSources(sink: AnySink): AnySignal[] {
-    if (!isComputed(sink) && !isWatcher(sink)) {
-      throw new TypeError(
-        "Called introspectSources without a Computed or Watcher argument",
-      );
+    // Create a Signal which evaluates to the value returned by the callback.
+    // Callback is called with this signal as the parameter.
+    constructor(computation: () => T, options?: Signal.Options<T>) {
+      const ref = createComputed<T>(computation);
+      const node = ref[SIGNAL];
+      node.consumerAllowSignalWrites = true;
+      this[NODE] = node;
+      node.wrapper = this;
+      if (options) {
+        const equals = options.equals;
+        if (equals) {
+          node.equal = equals;
+        }
+        node.watched = options[Signal.subtle.watched];
+        node.unwatched = options[Signal.subtle.unwatched];
+      }
     }
-    return sink[NODE].producerNode?.map((n) => n.wrapper) ?? [];
-  }
 
-  // Returns the subset of signal sinks which recursively
-  // lead to an Effect which has not been disposed
-  // Note: Only watched Computed signals will be in this list.
-  export function introspectSinks(signal: AnySignal): AnySink[] {
-    if (!isComputed(signal) && !isState(signal)) {
-      throw new TypeError("Called introspectSinks without a Signal argument");
+    get(): T {
+      if (!isComputed(this))
+        throw new TypeError('Wrong receiver type for Signal.Computed.prototype.get');
+      return computedGet(this[NODE]);
     }
-    return signal[NODE].liveConsumerNode?.map((n) => n.wrapper) ?? [];
   }
 
-  // True iff introspectSinks() is non-empty
-  export function hasSinks(signal: AnySignal): boolean {
-    if (!isComputed(signal) && !isState(signal)) {
-      throw new TypeError("Called hasSinks without a Signal argument");
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  type AnySignal<T = any> = State<T> | Computed<T>;
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  type AnySink = Computed<any> | subtle.Watcher;
+
+  // eslint-disable-next-line @typescript-eslint/no-namespace
+  export namespace subtle {
+    // Run a callback with all tracking disabled (even for nested computed).
+    export function untrack<T>(cb: () => T): T {
+      let output: T;
+      let prevActiveConsumer = null;
+      try {
+        prevActiveConsumer = setActiveConsumer(null);
+        output = cb();
+      } finally {
+        setActiveConsumer(prevActiveConsumer);
+      }
+      return output;
     }
-    const liveConsumerNode = signal[NODE].liveConsumerNode;
-    if (!liveConsumerNode) return false;
-    return liveConsumerNode.length > 0;
-  }
 
-  // True iff introspectSources() is non-empty
-  export function hasSources(signal: AnySink): boolean {
-    if (!isComputed(signal) && !isWatcher(signal)) {
-      throw new TypeError("Called hasSources without a Computed or Watcher argument");
+    // Returns ordered list of all signals which this one referenced
+    // during the last time it was evaluated
+    export function introspectSources(sink: AnySink): AnySignal[] {
+      if (!isComputed(sink) && !isWatcher(sink)) {
+        throw new TypeError('Called introspectSources without a Computed or Watcher argument');
+      }
+      return sink[NODE].producerNode?.map((n) => n.wrapper) ?? [];
     }
-    const producerNode = signal[NODE].producerNode;
-    if (!producerNode) return false;
-    return producerNode.length > 0;
-  }
-
-  export class Watcher {
-    readonly [NODE]: ReactiveNode;
 
-    #brand() {}
-    static {
-      isWatcher = (w: any): w is Watcher => #brand in w;
+    // Returns the subset of signal sinks which recursively
+    // lead to an Effect which has not been disposed
+    // Note: Only watched Computed signals will be in this list.
+    export function introspectSinks(signal: AnySignal): AnySink[] {
+      if (!isComputed(signal) && !isState(signal)) {
+        throw new TypeError('Called introspectSinks without a Signal argument');
+      }
+      return signal[NODE].liveConsumerNode?.map((n) => n.wrapper) ?? [];
     }
 
-    // When a (recursive) source of Watcher is written to, call this callback,
-    // if it hasn't already been called since the last `watch` call.
-    // No signals may be read or written during the notify.
-    constructor(notify: (this: Watcher) => void) {
-      let node = Object.create(REACTIVE_NODE);
-      node.wrapper = this;
-      node.consumerMarkedDirty = notify;
-      node.consumerIsAlwaysLive = true;
-      node.consumerAllowSignalWrites = false;
-      node.producerNode = [];
-      this[NODE] = node;
+    // True iff introspectSinks() is non-empty
+    export function hasSinks(signal: AnySignal): boolean {
+      if (!isComputed(signal) && !isState(signal)) {
+        throw new TypeError('Called hasSinks without a Signal argument');
+      }
+      const liveConsumerNode = signal[NODE].liveConsumerNode;
+      if (!liveConsumerNode) return false;
+      return liveConsumerNode.length > 0;
     }
 
-    #assertSignals(signals: AnySignal[]): void {
-      for (const signal of signals) {
-        if (!isComputed(signal) && !isState(signal)) {
-          throw new TypeError(
-            "Called watch/unwatch without a Computed or State argument",
-          );
-        }
+    // True iff introspectSources() is non-empty
+    export function hasSources(signal: AnySink): boolean {
+      if (!isComputed(signal) && !isWatcher(signal)) {
+        throw new TypeError('Called hasSources without a Computed or Watcher argument');
       }
+      const producerNode = signal[NODE].producerNode;
+      if (!producerNode) return false;
+      return producerNode.length > 0;
     }
 
-    // Add these signals to the Watcher's set, and set the watcher to run its
-    // notify callback next time any signal in the set (or one of its dependencies) changes.
-    // Can be called with no arguments just to reset the "notified" state, so that
-    // the notify callback will be invoked again.
-    watch(...signals: AnySignal[]): void {
-      if (!isWatcher(this)) {
-        throw new TypeError("Called unwatch without Watcher receiver");
+    export class Watcher {
+      readonly [NODE]: ReactiveNode;
+
+      #brand() {}
+      static {
+        isWatcher = (w: any): w is Watcher => #brand in w;
       }
-      this.#assertSignals(signals);
 
-      const node = this[NODE];
-      node.dirty = false;  // Give the watcher a chance to trigger again
-      const prev = setActiveConsumer(node);
-      for (const signal of signals) {
-        producerAccessed(signal[NODE]);
+      // When a (recursive) source of Watcher is written to, call this callback,
+      // if it hasn't already been called since the last `watch` call.
+      // No signals may be read or written during the notify.
+      constructor(notify: (this: Watcher) => void) {
+        let node = Object.create(REACTIVE_NODE);
+        node.wrapper = this;
+        node.consumerMarkedDirty = notify;
+        node.consumerIsAlwaysLive = true;
+        node.consumerAllowSignalWrites = false;
+        node.producerNode = [];
+        this[NODE] = node;
       }
-      setActiveConsumer(prev);
-    }
 
-    // Remove these signals from the watched set (e.g., for an effect which is disposed)
-    unwatch(...signals: AnySignal[]): void {
-      if (!isWatcher(this)) {
-        throw new TypeError("Called unwatch without Watcher receiver");
+      #assertSignals(signals: AnySignal[]): void {
+        for (const signal of signals) {
+          if (!isComputed(signal) && !isState(signal)) {
+            throw new TypeError('Called watch/unwatch without a Computed or State argument');
+          }
+        }
       }
-      this.#assertSignals(signals);
 
-      const node = this[NODE];
-      assertConsumerNode(node);
+      // Add these signals to the Watcher's set, and set the watcher to run its
+      // notify callback next time any signal in the set (or one of its dependencies) changes.
+      // Can be called with no arguments just to reset the "notified" state, so that
+      // the notify callback will be invoked again.
+      watch(...signals: AnySignal[]): void {
+        if (!isWatcher(this)) {
+          throw new TypeError('Called unwatch without Watcher receiver');
+        }
+        this.#assertSignals(signals);
 
-      let indicesToShift = [];
-      for (let i = 0; i < node.producerNode.length; i++) {
+        const node = this[NODE];
+        node.dirty = false; // Give the watcher a chance to trigger again
+        const prev = setActiveConsumer(node);
+        for (const signal of signals) {
+          producerAccessed(signal[NODE]);
+        }
+        setActiveConsumer(prev);
+      }
+
+      // Remove these signals from the watched set (e.g., for an effect which is disposed)
+      unwatch(...signals: AnySignal[]): void {
+        if (!isWatcher(this)) {
+          throw new TypeError('Called unwatch without Watcher receiver');
+        }
+        this.#assertSignals(signals);
+
+        const node = this[NODE];
+        assertConsumerNode(node);
+
+        let indicesToShift = [];
+        for (let i = 0; i < node.producerNode.length; i++) {
           if (signals.includes(node.producerNode[i].wrapper)) {
             producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]);
             indicesToShift.push(i);
           }
+        }
+        for (const idx of indicesToShift) {
+          // Logic copied from producerRemoveLiveConsumerAtIndex, but reversed
+          const lastIdx = node.producerNode!.length - 1;
+          node.producerNode![idx] = node.producerNode![lastIdx];
+          node.producerIndexOfThis[idx] = node.producerIndexOfThis[lastIdx];
+
+          node.producerNode.length--;
+          node.producerIndexOfThis.length--;
+          node.nextProducerIndex--;
+
+          if (idx < node.producerNode.length) {
+            const idxConsumer = node.producerIndexOfThis[idx];
+            const producer = node.producerNode[idx];
+            assertProducerNode(producer);
+            producer.liveConsumerIndexOfThis[idxConsumer] = idx;
+          }
+        }
       }
-      for (const idx of indicesToShift) {
-        // Logic copied from producerRemoveLiveConsumerAtIndex, but reversed
-        const lastIdx = node.producerNode!.length - 1;
-        node.producerNode![idx] = node.producerNode![lastIdx];
-        node.producerIndexOfThis[idx] = node.producerIndexOfThis[lastIdx];
-
-        node.producerNode.length--;
-        node.producerIndexOfThis.length--;
-        node.nextProducerIndex--;
-
-        if (idx < node.producerNode.length) {
-          const idxConsumer = node.producerIndexOfThis[idx];
-          const producer = node.producerNode[idx];
-          assertProducerNode(producer);
-          producer.liveConsumerIndexOfThis[idxConsumer] = idx;
+
+      // Returns the set of computeds in the Watcher's set which are still yet
+      // to be re-evaluated
+      getPending(): Computed<any>[] {
+        if (!isWatcher(this)) {
+          throw new TypeError('Called getPending without Watcher receiver');
         }
+        const node = this[NODE];
+        return node.producerNode!.filter((n) => n.dirty).map((n) => n.wrapper);
       }
     }
 
-    // Returns the set of computeds in the Watcher's set which are still yet
-    // to be re-evaluated
-    getPending(): Computed<any>[] {
-      if (!isWatcher(this)) {
-        throw new TypeError("Called getPending without Watcher receiver");
-      }
-      const node = this[NODE];
-      return node.producerNode!.filter((n) => n.dirty).map((n) => n.wrapper);
+    export function currentComputed(): Computed<any> | undefined {
+      return getActiveConsumer()?.wrapper;
     }
-  }
 
-  export function currentComputed(): Computed<any> | undefined {
-    return getActiveConsumer()?.wrapper;
+    // Hooks to observe being watched or no longer watched
+    export const watched = Symbol('watched');
+    export const unwatched = Symbol('unwatched');
   }
 
-  // Hooks to observe being watched or no longer watched
-  export const watched = Symbol("watched");
-  export const unwatched = Symbol("unwatched");
-}
-
-export interface Options<T> {
-  // Custom comparison function between old and new value. Default: Object.is.
-  // The signal is passed in as an optionally-used third parameter for context.
-  equals?: (this: AnySignal<T>, t: T, t2: T) => boolean;
+  export interface Options<T> {
+    // Custom comparison function between old and new value. Default: Object.is.
+    // The signal is passed in as an optionally-used third parameter for context.
+    equals?: (this: AnySignal<T>, t: T, t2: T) => boolean;
 
-  // Callback called when hasSinks becomes true, if it was previously false
-  [Signal.subtle.watched]?: (this: AnySignal<T>) => void;
+    // Callback called when hasSinks becomes true, if it was previously false
+    [Signal.subtle.watched]?: (this: AnySignal<T>) => void;
 
-  // Callback called whenever hasSinks becomes false, if it was previously true
-  [Signal.subtle.unwatched]?: (this: AnySignal<T>) => void;
-}
+    // Callback called whenever hasSinks becomes false, if it was previously true
+    [Signal.subtle.unwatched]?: (this: AnySignal<T>) => void;
+  }
 }
diff --git a/tests/Signal/computed.test.ts b/tests/Signal/computed.test.ts
index 96b4dcf..6c02416 100644
--- a/tests/Signal/computed.test.ts
+++ b/tests/Signal/computed.test.ts
@@ -1,8 +1,8 @@
-import { describe, expect, it } from "vitest";
-import { Signal } from "../../src/wrapper.js";
+import {describe, expect, it} from 'vitest';
+import {Signal} from '../../src/wrapper.js';
 
-describe("Computed", () => {
-  it("should work", () => {
+describe('Computed', () => {
+  it('should work', () => {
     const stateSignal = new Signal.State(1);
 
     const computedSignal = new Signal.Computed(() => {
@@ -18,8 +18,8 @@ describe("Computed", () => {
     expect(computedSignal.get()).toEqual(10);
   });
 
-  describe("Comparison semantics", () => {
-    it("should track Computed by Object.is", () => {
+  describe('Comparison semantics', () => {
+    it('should track Computed by Object.is', () => {
       const state = new Signal.State(1);
       let value = 5;
       let calls = 0;
@@ -43,7 +43,7 @@ describe("Computed", () => {
       expect(calls).toBe(2);
     });
 
-    it("applies custom equality in Computed", () => {
+    it('applies custom equality in Computed', () => {
       const s = new Signal.State(5);
       let ecalls = 0;
       const c1 = new Signal.Computed(() => (s.get(), 1), {
diff --git a/tests/Signal/state.test.ts b/tests/Signal/state.test.ts
index 9593554..067830a 100644
--- a/tests/Signal/state.test.ts
+++ b/tests/Signal/state.test.ts
@@ -1,8 +1,8 @@
-import { describe, expect, it } from "vitest";
-import { Signal } from "../../src/wrapper.js";
+import {describe, expect, it} from 'vitest';
+import {Signal} from '../../src/wrapper.js';
 
-describe("Signal.State", () => {
-  it("should work", () => {
+describe('Signal.State', () => {
+  it('should work', () => {
     const stateSignal = new Signal.State(0);
     expect(stateSignal.get()).toEqual(0);
 
@@ -11,8 +11,8 @@ describe("Signal.State", () => {
     expect(stateSignal.get()).toEqual(10);
   });
 
-  describe("Comparison semantics", () => {
-    it("should cache State by Object.is", () => {
+  describe('Comparison semantics', () => {
+    it('should cache State by Object.is', () => {
       const state = new Signal.State(NaN);
       let calls = 0;
       const computed = new Signal.Computed(() => {
@@ -27,7 +27,7 @@ describe("Signal.State", () => {
       expect(calls).toBe(1);
     });
 
-    it("applies custom equality in State", () => {
+    it('applies custom equality in State', () => {
       let ecalls = 0;
       const state = new Signal.State(1, {
         equals() {
diff --git a/tests/Signal/subtle/currentComputed.test.ts b/tests/Signal/subtle/currentComputed.test.ts
index 3fcb503..a21c26d 100644
--- a/tests/Signal/subtle/currentComputed.test.ts
+++ b/tests/Signal/subtle/currentComputed.test.ts
@@ -1,13 +1,11 @@
-import { describe, expect, it } from "vitest";
-import { Signal } from "../../../src/wrapper.js";
+import {describe, expect, it} from 'vitest';
+import {Signal} from '../../../src/wrapper.js';
 
-describe("currentComputed", () => {
-  it("works", () => {
+describe('currentComputed', () => {
+  it('works', () => {
     expect(Signal.subtle.currentComputed()).toBe(undefined);
     let context;
-    let c = new Signal.Computed(
-      () => (context = Signal.subtle.currentComputed()),
-    );
+    let c = new Signal.Computed(() => (context = Signal.subtle.currentComputed()));
     c.get();
     expect(c).toBe(context);
   });
diff --git a/tests/Signal/subtle/untrack.test.ts b/tests/Signal/subtle/untrack.test.ts
index cb8d821..5e06be7 100644
--- a/tests/Signal/subtle/untrack.test.ts
+++ b/tests/Signal/subtle/untrack.test.ts
@@ -1,18 +1,16 @@
-import { describe, expect, it } from "vitest";
-import { Signal } from "../../../src/wrapper.js";
+import {describe, expect, it} from 'vitest';
+import {Signal} from '../../../src/wrapper.js';
 
-describe("Untrack", () => {
-  it("works", () => {
+describe('Untrack', () => {
+  it('works', () => {
     const state = new Signal.State(1);
-    const computed = new Signal.Computed(() =>
-      Signal.subtle.untrack(() => state.get()),
-    );
+    const computed = new Signal.Computed(() => Signal.subtle.untrack(() => state.get()));
     expect(computed.get()).toBe(1);
     state.set(2);
     expect(computed.get()).toBe(1);
   });
 
-  it("works differently without untrack", () => {
+  it('works differently without untrack', () => {
     const state = new Signal.State(1);
     const computed = new Signal.Computed(() => state.get());
     expect(computed.get()).toBe(1);
diff --git a/tests/Signal/subtle/watch-unwatch.test.ts b/tests/Signal/subtle/watch-unwatch.test.ts
index e49cdad..c1761c7 100644
--- a/tests/Signal/subtle/watch-unwatch.test.ts
+++ b/tests/Signal/subtle/watch-unwatch.test.ts
@@ -1,8 +1,8 @@
-import { describe, expect, it } from "vitest";
-import { Signal } from "../../../src/wrapper.js";
+import {describe, expect, it} from 'vitest';
+import {Signal} from '../../../src/wrapper.js';
 
-describe("watch and unwatch", () => {
-  it("handles multiple watchers well", () => {
+describe('watch and unwatch', () => {
+  it('handles multiple watchers well', () => {
     const s = new Signal.State(1);
     const s2 = new Signal.State(2);
     let n = 0;
@@ -29,7 +29,7 @@ describe("watch and unwatch", () => {
     s.set(2);
     expect(n).toBe(3);
   });
-  it("understands dynamic dependency sets", () => {
+  it('understands dynamic dependency sets', () => {
     let w1 = 0,
       u1 = 0,
       w2 = 0,
@@ -52,7 +52,7 @@ describe("watch and unwatch", () => {
         u2++;
       },
     });
-    let which: { get(): number } = s1;
+    let which: {get(): number} = s1;
     let c = new Signal.Computed(() => (d++, which.get()));
     let w = new Signal.subtle.Watcher(() => n++);
 
diff --git a/tests/Signal/subtle/watcher.test.ts b/tests/Signal/subtle/watcher.test.ts
index 8bc4651..11521e0 100644
--- a/tests/Signal/subtle/watcher.test.ts
+++ b/tests/Signal/subtle/watcher.test.ts
@@ -1,7 +1,7 @@
-import { afterEach, describe, expect, it, vi } from "vitest";
-import { Signal } from "../../../src/wrapper.js";
+import {afterEach, describe, expect, it, vi} from 'vitest';
+import {Signal} from '../../../src/wrapper.js';
 
-describe("Watcher", () => {
+describe('Watcher', () => {
   type Destructor = () => void;
   const notifySpy = vi.fn();
 
@@ -29,7 +29,7 @@ describe("Watcher", () => {
 
   afterEach(() => watcher.unwatch(...Signal.subtle.introspectSources(watcher)));
 
-  it("should work", () => {
+  it('should work', () => {
     const watchedSpy = vi.fn();
     const unwatchedSpy = vi.fn();
     const stateSignal = new Signal.State(1, {
@@ -61,7 +61,7 @@ describe("Watcher", () => {
       output = stateSignal.get();
       computedOutput = computedSignal.get();
       calls++;
-      return () => { };
+      return () => {};
     });
 
     // The signal is now watched
@@ -142,17 +142,17 @@ describe("Watcher", () => {
     // Adding any other effect after an unwatch should work as expected
     const destructor2 = effect(() => {
       output = stateSignal.get();
-      return () => { };
+      return () => {};
     });
 
     stateSignal.set(300);
     flushPending();
   });
 
-  it("provides `this` to notify as normal function", () => {
+  it('provides `this` to notify as normal function', () => {
     const mockGetPending = vi.fn();
 
-    const watcher = new Signal.subtle.Watcher(function() {
+    const watcher = new Signal.subtle.Watcher(function () {
       this.getPending();
     });
     watcher.getPending = mockGetPending;
@@ -164,7 +164,7 @@ describe("Watcher", () => {
     expect(mockGetPending).toBeCalled();
   });
 
-  it("can be closed in if needed in notify as an arrow function", () => {
+  it('can be closed in if needed in notify as an arrow function', () => {
     const mockGetPending = vi.fn();
 
     const watcher = new Signal.subtle.Watcher(() => {
diff --git a/tests/behaviors/custom-equality.test.ts b/tests/behaviors/custom-equality.test.ts
index f131851..3fc5416 100644
--- a/tests/behaviors/custom-equality.test.ts
+++ b/tests/behaviors/custom-equality.test.ts
@@ -1,8 +1,8 @@
-import { describe, expect, it, vi } from "vitest";
-import { Signal } from "../../src/wrapper.js";
+import {describe, expect, it, vi} from 'vitest';
+import {Signal} from '../../src/wrapper.js';
 
-describe("Custom equality", () => {
-  it("works for State", () => {
+describe('Custom equality', () => {
+  it('works for State', () => {
     let answer = true;
     const s = new Signal.State(1, {
       equals() {
@@ -31,7 +31,7 @@ describe("Custom equality", () => {
     expect(c.get()).toBe(2);
     expect(n).toBe(3);
   });
-  it("works for Computed", () => {
+  it('works for Computed', () => {
     let answer = true;
     let value = 1;
     const u = new Signal.State(1);
@@ -63,7 +63,7 @@ describe("Custom equality", () => {
     expect(c.get()).toBe(2);
     expect(n).toBe(3);
   });
-  it("does not leak tracking information", () => {
+  it('does not leak tracking information', () => {
     const exact = new Signal.State(1);
     const epsilon = new Signal.State(0.1);
     const counter = new Signal.State(1);
diff --git a/tests/behaviors/cycles.test.ts b/tests/behaviors/cycles.test.ts
index 837f5ac..5ebb7a4 100644
--- a/tests/behaviors/cycles.test.ts
+++ b/tests/behaviors/cycles.test.ts
@@ -1,13 +1,13 @@
-import { describe, expect, it } from "vitest";
-import { Signal } from "../../src/wrapper.js";
+import {describe, expect, it} from 'vitest';
+import {Signal} from '../../src/wrapper.js';
 
-describe("Cycles", () => {
-  it("detects trivial cycles", () => {
+describe('Cycles', () => {
+  it('detects trivial cycles', () => {
     const c = new Signal.Computed(() => c.get());
     expect(() => c.get()).toThrow();
   });
 
-  it("detects slightly larger cycles", () => {
+  it('detects slightly larger cycles', () => {
     const c = new Signal.Computed(() => c2.get());
     const c2 = new Signal.Computed(() => c.get());
     const c3 = new Signal.Computed(() => c2.get());
diff --git a/tests/behaviors/dynamic-dependencies.test.ts b/tests/behaviors/dynamic-dependencies.test.ts
index ad24e6f..fbe404e 100644
--- a/tests/behaviors/dynamic-dependencies.test.ts
+++ b/tests/behaviors/dynamic-dependencies.test.ts
@@ -1,12 +1,12 @@
-import { describe, expect, it } from "vitest";
-import { Signal } from "../../src/wrapper.js";
+import {describe, expect, it} from 'vitest';
+import {Signal} from '../../src/wrapper.js';
 
-describe("Dynamic dependencies", () => {
+describe('Dynamic dependencies', () => {
   function run(live) {
-    const states = Array.from("abcdefgh").map((s) => new Signal.State(s));
+    const states = Array.from('abcdefgh').map((s) => new Signal.State(s));
     const sources = new Signal.State(states);
     const computed = new Signal.Computed(() => {
-      let str = "";
+      let str = '';
       for (const state of sources.get()) str += state.get();
       return str;
     });
@@ -14,23 +14,17 @@ describe("Dynamic dependencies", () => {
       const w = new Signal.subtle.Watcher(() => {});
       w.watch(computed);
     }
-    expect(computed.get()).toBe("abcdefgh");
-    expect(Signal.subtle.introspectSources(computed).slice(1)).toStrictEqual(
-      states,
-    );
+    expect(computed.get()).toBe('abcdefgh');
+    expect(Signal.subtle.introspectSources(computed).slice(1)).toStrictEqual(states);
 
     sources.set(states.slice(0, 5));
-    expect(computed.get()).toBe("abcde");
-    expect(Signal.subtle.introspectSources(computed).slice(1)).toStrictEqual(
-      states.slice(0, 5),
-    );
+    expect(computed.get()).toBe('abcde');
+    expect(Signal.subtle.introspectSources(computed).slice(1)).toStrictEqual(states.slice(0, 5));
 
     sources.set(states.slice(3));
-    expect(computed.get()).toBe("defgh");
-    expect(Signal.subtle.introspectSources(computed).slice(1)).toStrictEqual(
-      states.slice(3),
-    );
+    expect(computed.get()).toBe('defgh');
+    expect(Signal.subtle.introspectSources(computed).slice(1)).toStrictEqual(states.slice(3));
   }
-  it("works live", () => run(true));
-  it("works not live", () => run(false));
+  it('works live', () => run(true));
+  it('works not live', () => run(false));
 });
diff --git a/tests/behaviors/errors.test.ts b/tests/behaviors/errors.test.ts
index 8a1bf8b..bf366a2 100644
--- a/tests/behaviors/errors.test.ts
+++ b/tests/behaviors/errors.test.ts
@@ -1,9 +1,9 @@
-import { afterEach, describe, expect, it, vi } from "vitest";
-import { Signal } from "../../src/wrapper.js";
+import {afterEach, describe, expect, it, vi} from 'vitest';
+import {Signal} from '../../src/wrapper.js';
 
-describe("Errors", () => {
-  it("are cached by computed signals", () => {
-    const s = new Signal.State("first");
+describe('Errors', () => {
+  it('are cached by computed signals', () => {
+    const s = new Signal.State('first');
     let n = 0;
     const c = new Signal.Computed(() => {
       n++;
@@ -15,26 +15,26 @@ describe("Errors", () => {
       return c.get();
     });
     expect(n).toBe(0);
-    expect(() => c.get()).toThrowError("first");
-    expect(() => c2.get()).toThrowError("first");
+    expect(() => c.get()).toThrowError('first');
+    expect(() => c2.get()).toThrowError('first');
     expect(n).toBe(1);
     expect(n2).toBe(1);
-    expect(() => c.get()).toThrowError("first");
-    expect(() => c2.get()).toThrowError("first");
+    expect(() => c.get()).toThrowError('first');
+    expect(() => c2.get()).toThrowError('first');
     expect(n).toBe(1);
     expect(n2).toBe(1);
-    s.set("second");
-    expect(() => c.get()).toThrowError("second");
-    expect(() => c2.get()).toThrowError("second");
+    s.set('second');
+    expect(() => c.get()).toThrowError('second');
+    expect(() => c2.get()).toThrowError('second');
     expect(n).toBe(2);
     expect(n2).toBe(2);
 
     // Doesn't retrigger on setting state to the same value
-    s.set("second");
+    s.set('second');
     expect(n).toBe(2);
   });
-  it("are cached by computed signals when watched", () => {
-    const s = new Signal.State("first");
+  it('are cached by computed signals when watched', () => {
+    const s = new Signal.State('first');
     let n = 0;
     const c = new Signal.Computed<unknown>(() => {
       n++;
@@ -44,23 +44,23 @@ describe("Errors", () => {
     w.watch(c);
 
     expect(n).toBe(0);
-    expect(() => c.get()).toThrowError("first");
+    expect(() => c.get()).toThrowError('first');
     expect(n).toBe(1);
-    expect(() => c.get()).toThrowError("first");
+    expect(() => c.get()).toThrowError('first');
     expect(n).toBe(1);
-    s.set("second");
-    expect(() => c.get()).toThrowError("second");
+    s.set('second');
+    expect(() => c.get()).toThrowError('second');
     expect(n).toBe(2);
 
-    s.set("second");
+    s.set('second');
     expect(n).toBe(2);
   });
-  it("are cached by computed signals when equals throws", () => {
+  it('are cached by computed signals when equals throws', () => {
     const s = new Signal.State(0);
     const cSpy = vi.fn(() => s.get());
     const c = new Signal.Computed(cSpy, {
       equals() {
-        throw new Error("equals");
+        throw new Error('equals');
       },
     });
 
@@ -68,9 +68,9 @@ describe("Errors", () => {
     s.set(1);
 
     // Error is cached; c throws again without needing to rerun.
-    expect(() => c.get()).toThrowError("equals");
+    expect(() => c.get()).toThrowError('equals');
     expect(cSpy).toBeCalledTimes(2);
-    expect(() => c.get()).toThrowError("equals");
+    expect(() => c.get()).toThrowError('equals');
     expect(cSpy).toBeCalledTimes(2);
   });
 });
diff --git a/tests/behaviors/liveness.test.ts b/tests/behaviors/liveness.test.ts
index 99fb1fb..fce1773 100644
--- a/tests/behaviors/liveness.test.ts
+++ b/tests/behaviors/liveness.test.ts
@@ -1,8 +1,8 @@
-import { describe, expect, it, vi } from "vitest";
-import { Signal } from "../../src/wrapper.js";
+import {describe, expect, it, vi} from 'vitest';
+import {Signal} from '../../src/wrapper.js';
 
-describe("liveness", () => {
-  it("only changes on first and last descendant", () => {
+describe('liveness', () => {
+  it('only changes on first and last descendant', () => {
     const watchedSpy = vi.fn();
     const unwatchedSpy = vi.fn();
     const state = new Signal.State(1, {
@@ -34,7 +34,7 @@ describe("liveness", () => {
     expect(unwatchedSpy).toBeCalledTimes(1);
   });
 
-  it("is tracked well on computed signals", () => {
+  it('is tracked well on computed signals', () => {
     const watchedSpy = vi.fn();
     const unwatchedSpy = vi.fn();
     const s = new Signal.State(1);
diff --git a/tests/behaviors/prohibited-contexts.test.ts b/tests/behaviors/prohibited-contexts.test.ts
index 64a8597..2136a1b 100644
--- a/tests/behaviors/prohibited-contexts.test.ts
+++ b/tests/behaviors/prohibited-contexts.test.ts
@@ -1,8 +1,8 @@
-import { describe, expect, it } from "vitest";
-import { Signal } from "../../src/wrapper.js";
+import {describe, expect, it} from 'vitest';
+import {Signal} from '../../src/wrapper.js';
 
-describe("Prohibited contexts", () => {
-  it("allows writes during computed", () => {
+describe('Prohibited contexts', () => {
+  it('allows writes during computed', () => {
     const s = new Signal.State(1);
     const c = new Signal.Computed(() => (s.set(s.get() + 1), s.get()));
     expect(c.get()).toBe(2);
@@ -18,7 +18,7 @@ describe("Prohibited contexts", () => {
     expect(c.get()).toBe(4);
     expect(s.get()).toBe(4);
   });
-  it("disallows reads and writes during watcher notify", () => {
+  it('disallows reads and writes during watcher notify', () => {
     const s = new Signal.State(1);
     const w = new Signal.subtle.Watcher(() => {
       s.get();
diff --git a/tests/behaviors/pruning.test.ts b/tests/behaviors/pruning.test.ts
index 48102bb..bec8175 100644
--- a/tests/behaviors/pruning.test.ts
+++ b/tests/behaviors/pruning.test.ts
@@ -1,8 +1,8 @@
-import { describe, expect, it } from "vitest";
-import { Signal } from "../../src/wrapper.js";
+import {describe, expect, it} from 'vitest';
+import {Signal} from '../../src/wrapper.js';
 
-describe("Pruning", () => {
-  it("only recalculates until things are equal", () => {
+describe('Pruning', () => {
+  it('only recalculates until things are equal', () => {
     const s = new Signal.State(0);
     let n = 0;
     const c = new Signal.Computed(() => (n++, s.get()));
@@ -30,7 +30,7 @@ describe("Pruning", () => {
     expect(n2).toBe(2);
     expect(n3).toBe(1);
   });
-  it("does similar pruning for live signals", () => {
+  it('does similar pruning for live signals', () => {
     const s = new Signal.State(0);
     let n = 0;
     const c = new Signal.Computed(() => (n++, s.get()));
diff --git a/tests/behaviors/receivers.test.ts b/tests/behaviors/receivers.test.ts
index a1c17e3..abd6683 100644
--- a/tests/behaviors/receivers.test.ts
+++ b/tests/behaviors/receivers.test.ts
@@ -1,8 +1,8 @@
-import { describe, expect, it } from "vitest";
-import { Signal } from "../../src/wrapper.js";
+import {describe, expect, it} from 'vitest';
+import {Signal} from '../../src/wrapper.js';
 
-describe("Receivers", () => {
-  it("is this for computed", () => {
+describe('Receivers', () => {
+  it('is this for computed', () => {
     let receiver;
     const c = new Signal.Computed(function () {
       receiver = this;
@@ -10,7 +10,7 @@ describe("Receivers", () => {
     expect(c.get()).toBe(undefined);
     expect(receiver).toBe(c);
   });
-  it("is this for watched/unwatched", () => {
+  it('is this for watched/unwatched', () => {
     let r1, r2;
     const s = new Signal.State(1, {
       [Signal.subtle.watched]() {
@@ -29,7 +29,7 @@ describe("Receivers", () => {
     w.unwatch(s);
     expect(r2).toBe(s);
   });
-  it("is this for equals", () => {
+  it('is this for equals', () => {
     let receiver;
     const options = {
       equals() {
diff --git a/tests/behaviors/type-checking.test.ts b/tests/behaviors/type-checking.test.ts
index 2ad4341..b66fefd 100644
--- a/tests/behaviors/type-checking.test.ts
+++ b/tests/behaviors/type-checking.test.ts
@@ -1,19 +1,19 @@
-import { describe, expect, it } from "vitest";
-import { Signal } from "../../src/wrapper.js";
+import {describe, expect, it} from 'vitest';
+import {Signal} from '../../src/wrapper.js';
 
-describe("Expected class shape", () => {
-  it("should be on the prototype", () => {
-    expect(typeof Signal.State.prototype.get).toBe("function");
-    expect(typeof Signal.State.prototype.set).toBe("function");
-    expect(typeof Signal.Computed.prototype.get).toBe("function");
-    expect(typeof Signal.subtle.Watcher.prototype.watch).toBe("function");
-    expect(typeof Signal.subtle.Watcher.prototype.unwatch).toBe("function");
-    expect(typeof Signal.subtle.Watcher.prototype.getPending).toBe("function");
+describe('Expected class shape', () => {
+  it('should be on the prototype', () => {
+    expect(typeof Signal.State.prototype.get).toBe('function');
+    expect(typeof Signal.State.prototype.set).toBe('function');
+    expect(typeof Signal.Computed.prototype.get).toBe('function');
+    expect(typeof Signal.subtle.Watcher.prototype.watch).toBe('function');
+    expect(typeof Signal.subtle.Watcher.prototype.unwatch).toBe('function');
+    expect(typeof Signal.subtle.Watcher.prototype.getPending).toBe('function');
   });
 });
 
-describe("type checks", () => {
-  it("checks types in methods", () => {
+describe('type checks', () => {
+  it('checks types in methods', () => {
     let x = {};
     let s = new Signal.State(1);
     let c = new Signal.Computed(() => {});
@@ -34,46 +34,22 @@ describe("type checks", () => {
     expect(Signal.Computed.prototype.get.call(c)).toBe(undefined);
     expect(() => Signal.Computed.prototype.get.call(w)).toThrowError(TypeError);
 
-    expect(() => Signal.subtle.Watcher.prototype.watch.call(x, s)).toThrowError(
-      TypeError,
-    );
-    expect(() => Signal.subtle.Watcher.prototype.watch.call(s, s)).toThrowError(
-      TypeError,
-    );
-    expect(() => Signal.subtle.Watcher.prototype.watch.call(c, s)).toThrowError(
-      TypeError,
-    );
+    expect(() => Signal.subtle.Watcher.prototype.watch.call(x, s)).toThrowError(TypeError);
+    expect(() => Signal.subtle.Watcher.prototype.watch.call(s, s)).toThrowError(TypeError);
+    expect(() => Signal.subtle.Watcher.prototype.watch.call(c, s)).toThrowError(TypeError);
     expect(Signal.subtle.Watcher.prototype.watch.call(w, s)).toBe(undefined);
-    expect(() => Signal.subtle.Watcher.prototype.watch.call(w, w)).toThrowError(
-      TypeError,
-    );
+    expect(() => Signal.subtle.Watcher.prototype.watch.call(w, w)).toThrowError(TypeError);
 
-    expect(() =>
-      Signal.subtle.Watcher.prototype.unwatch.call(x, s),
-    ).toThrowError(TypeError);
-    expect(() =>
-      Signal.subtle.Watcher.prototype.unwatch.call(s, s),
-    ).toThrowError(TypeError);
-    expect(() =>
-      Signal.subtle.Watcher.prototype.unwatch.call(c, s),
-    ).toThrowError(TypeError);
+    expect(() => Signal.subtle.Watcher.prototype.unwatch.call(x, s)).toThrowError(TypeError);
+    expect(() => Signal.subtle.Watcher.prototype.unwatch.call(s, s)).toThrowError(TypeError);
+    expect(() => Signal.subtle.Watcher.prototype.unwatch.call(c, s)).toThrowError(TypeError);
     expect(Signal.subtle.Watcher.prototype.unwatch.call(w, s)).toBe(undefined);
-    expect(() =>
-      Signal.subtle.Watcher.prototype.unwatch.call(w, w),
-    ).toThrowError(TypeError);
+    expect(() => Signal.subtle.Watcher.prototype.unwatch.call(w, w)).toThrowError(TypeError);
 
-    expect(() =>
-      Signal.subtle.Watcher.prototype.getPending.call(x, s),
-    ).toThrowError(TypeError);
-    expect(() =>
-      Signal.subtle.Watcher.prototype.getPending.call(s, s),
-    ).toThrowError(TypeError);
-    expect(() =>
-      Signal.subtle.Watcher.prototype.getPending.call(c, s),
-    ).toThrowError(TypeError);
-    expect(Signal.subtle.Watcher.prototype.getPending.call(w, s)).toStrictEqual(
-      [],
-    );
+    expect(() => Signal.subtle.Watcher.prototype.getPending.call(x, s)).toThrowError(TypeError);
+    expect(() => Signal.subtle.Watcher.prototype.getPending.call(s, s)).toThrowError(TypeError);
+    expect(() => Signal.subtle.Watcher.prototype.getPending.call(c, s)).toThrowError(TypeError);
+    expect(Signal.subtle.Watcher.prototype.getPending.call(w, s)).toStrictEqual([]);
 
     // @ts-expect-error
     expect(() => Signal.subtle.introspectSources(x)).toThrowError(TypeError);
diff --git a/tsconfig.json b/tsconfig.json
index f223b6e..4a66bd8 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -10,20 +10,11 @@
     "declaration": true,
     "declarationMap": true,
     "noEmitOnError": false,
-    "lib": [
-      "DOM",
-      "ES2021"
-    ],
+    "lib": ["DOM", "ES2021"],
     "strict": true,
     "composite": true,
     "forceConsistentCasingInFileNames": true
   },
-  "exclude": [
-    "**/node_modules/**",
-    "**/*.spec.ts",
-    "**/dist/**/*"
-  ],
-  "include": [
-    "src"
-  ]
-}
\ No newline at end of file
+  "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/dist/**/*"],
+  "include": ["src"]
+}
diff --git a/vite.config.ts b/vite.config.ts
index c3885d2..ed7e667 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,7 +1,7 @@
-import { dirname, join } from "node:path";
-import { fileURLToPath } from "node:url";
-import { defineConfig } from "vite";
-import dts from "vite-plugin-dts";
+import {dirname, join} from 'node:path';
+import {fileURLToPath} from 'node:url';
+import {defineConfig} from 'vite';
+import dts from 'vite-plugin-dts';
 
 const entry = join(dirname(fileURLToPath(import.meta.url)), './src/index.ts');
 
@@ -10,8 +10,8 @@ export default defineConfig({
   build: {
     lib: {
       entry,
-      formats: ["es"],
-      fileName: "index"
-    }
-  }
+      formats: ['es'],
+      fileName: 'index',
+    },
+  },
 });