From d8b8dd5ef5f491c4c3660264cce30d03d168ebea Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 27 Nov 2025 14:51:43 +0000 Subject: [PATCH 1/2] Initial plan From a20ddfafea8ad8245d6de6e0718680e27e44a0b3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 27 Nov 2025 14:58:08 +0000 Subject: [PATCH 2/2] refactor: rename ShadowObjectParams to ShadowObjectCreationAPI Co-authored-by: spearwolf <12805+spearwolf@users.noreply.github.com> --- packages/shadow-objects/CHANGELOG.md | 3 +- packages/shadow-objects/README.md | 14 ++-- .../src/in-the-dark/Kernel.spec.ts | 78 +++++++++---------- packages/shadow-objects/src/types.ts | 6 +- .../shadow-objects/src/view/ShadowEnv.spec.ts | 6 +- 5 files changed, 54 insertions(+), 53 deletions(-) diff --git a/packages/shadow-objects/CHANGELOG.md b/packages/shadow-objects/CHANGELOG.md index 499dbfc..54a9214 100644 --- a/packages/shadow-objects/CHANGELOG.md +++ b/packages/shadow-objects/CHANGELOG.md @@ -7,7 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -- renamed `useResource()` to `createResource()` in `ShadowObjectParams` interface +- renamed interface `ShadowObjectParams` to `ShadowObjectCreationAPI` for clarity and consistency with the concept of the _Shadow Object Creation API_ +- renamed `useResource()` to `createResource()` in `ShadowObjectCreationAPI` interface ## [0.23.0] - 2025-11-26 diff --git a/packages/shadow-objects/README.md b/packages/shadow-objects/README.md index cccfbad..81e5c42 100644 --- a/packages/shadow-objects/README.md +++ b/packages/shadow-objects/README.md @@ -37,12 +37,12 @@ The **Registry** maps **Tokens** to **Shadow Object Constructors**. ### 1. Defining Shadow Objects -You can define a Shadow Object as a **Function** or a **Class**. Both receive a `ShadowObjectParams` object containing the API methods. +You can define a Shadow Object as a **Function** or a **Class**. Both receive a `ShadowObjectCreationAPI` object containing the API methods. #### Function-based (Recommended) ```typescript -import { ShadowObjectParams } from "@spearwolf/shadow-objects"; +import { ShadowObjectCreationAPI } from "@spearwolf/shadow-objects"; export function MyShadowObject({ useProperty, @@ -50,7 +50,7 @@ export function MyShadowObject({ createEffect, on, onDestroy -}: ShadowObjectParams) { +}: ShadowObjectCreationAPI) { // 1. Read Properties const title = useProperty("title"); @@ -75,10 +75,10 @@ export function MyShadowObject({ #### Class-based ```typescript -import { ShadowObjectParams } from "@spearwolf/shadow-objects"; +import { ShadowObjectCreationAPI } from "@spearwolf/shadow-objects"; export class MyShadowObject { - constructor({ useProperty, createEffect, onDestroy }: ShadowObjectParams) { + constructor({ useProperty, createEffect, onDestroy }: ShadowObjectCreationAPI) { const title = useProperty("title"); createEffect(() => { @@ -94,9 +94,9 @@ export class MyShadowObject { } ``` -### 2. The `ShadowObjectParams` API +### 2. The Shadow Object Creation API -The `ShadowObjectParams` object provides all necessary tools to interact with the Entity, the View, and the Context system. +The `ShadowObjectCreationAPI` object provides all necessary tools to interact with the Entity, the View, and the Context system. | Method | Description | | :--- | :--- | diff --git a/packages/shadow-objects/src/in-the-dark/Kernel.spec.ts b/packages/shadow-objects/src/in-the-dark/Kernel.spec.ts index 4ecf272..5f83046 100644 --- a/packages/shadow-objects/src/in-the-dark/Kernel.spec.ts +++ b/packages/shadow-objects/src/in-the-dark/Kernel.spec.ts @@ -2,7 +2,7 @@ import {emit, on} from '@spearwolf/eventize'; import {createSignal, type Signal, type SignalReader, value} from '@spearwolf/signalize'; import {afterEach, describe, expect, it, vi} from 'vitest'; import {MessageToView} from '../constants.js'; -import type {ShadowObjectParams} from '../types.js'; +import type {ShadowObjectCreationAPI} from '../types.js'; import {generateUUID} from '../utils/generateUUID.js'; import {onCreate, onDestroy} from './events.js'; import {Kernel, type MessageToViewEvent} from './Kernel.js'; @@ -246,17 +246,17 @@ describe('Kernel', () => { }); }); - describe('ShadowObjectParams API', () => { + describe('Shadow Object Creation API', () => { describe('useProperty', () => { it('should return a signal reader for entity property', () => { const registry = new Registry(); const kernel = new Kernel(registry); - let capturedPropertyReader: ReturnType | undefined; + let capturedPropertyReader: ReturnType | undefined; @ShadowObject({registry, token: 'testUseProperty'}) class TestUseProperty { - constructor({useProperty}: ShadowObjectParams) { + constructor({useProperty}: ShadowObjectCreationAPI) { capturedPropertyReader = useProperty('testProp'); } } @@ -278,12 +278,12 @@ describe('Kernel', () => { const registry = new Registry(); const kernel = new Kernel(registry); - let reader1: ReturnType | undefined; - let reader2: ReturnType | undefined; + let reader1: ReturnType | undefined; + let reader2: ReturnType | undefined; @ShadowObject({registry, token: 'testUsePropertyCache'}) class TestUsePropertyCache { - constructor({useProperty}: ShadowObjectParams) { + constructor({useProperty}: ShadowObjectCreationAPI) { reader1 = useProperty('testProp'); reader2 = useProperty('testProp'); } @@ -304,11 +304,11 @@ describe('Kernel', () => { const registry = new Registry(); const kernel = new Kernel(registry); - let capturedProps: Record> | undefined; + let capturedProps: Record> | undefined; @ShadowObject({registry, token: 'testUseProperties'}) class TestUseProperties { - constructor({useProperties}: ShadowObjectParams) { + constructor({useProperties}: ShadowObjectCreationAPI) { capturedProps = useProperties({foo: 'propA', bar: 'propB'}); } } @@ -334,11 +334,11 @@ describe('Kernel', () => { const kernel = new Kernel(registry); const contextName = Symbol('testContext'); - let capturedContext: ReturnType | undefined; + let capturedContext: ReturnType | undefined; @ShadowObject({registry, token: 'parentProvider'}) class ParentProvider { - constructor({provideContext}: ShadowObjectParams) { + constructor({provideContext}: ShadowObjectCreationAPI) { provideContext(contextName, 'contextValue'); } } @@ -346,7 +346,7 @@ describe('Kernel', () => { @ShadowObject({registry, token: 'childConsumer'}) class ChildConsumer { - constructor({useContext}: ShadowObjectParams) { + constructor({useContext}: ShadowObjectCreationAPI) { capturedContext = useContext(contextName); } } @@ -373,11 +373,11 @@ describe('Kernel', () => { const contextName = 'signalContext'; const sourceSignal = createSignal('initial'); - let capturedContext: ReturnType | undefined; + let capturedContext: ReturnType | undefined; @ShadowObject({registry, token: 'signalProvider'}) class SignalProvider { - constructor({provideContext}: ShadowObjectParams) { + constructor({provideContext}: ShadowObjectCreationAPI) { provideContext(contextName, sourceSignal.get); } } @@ -385,7 +385,7 @@ describe('Kernel', () => { @ShadowObject({registry, token: 'signalConsumer'}) class SignalConsumer { - constructor({useContext}: ShadowObjectParams) { + constructor({useContext}: ShadowObjectCreationAPI) { capturedContext = useContext(contextName); } } @@ -411,12 +411,12 @@ describe('Kernel', () => { const registry = new Registry(); const kernel = new Kernel(registry); - let ctx1: ReturnType | undefined; - let ctx2: ReturnType | undefined; + let ctx1: ReturnType | undefined; + let ctx2: ReturnType | undefined; @ShadowObject({registry, token: 'testContextCache'}) class TestContextCache { - constructor({useContext}: ShadowObjectParams) { + constructor({useContext}: ShadowObjectCreationAPI) { ctx1 = useContext('myContext'); ctx2 = useContext('myContext'); } @@ -438,11 +438,11 @@ describe('Kernel', () => { const kernel = new Kernel(registry); const contextName = 'parentOnlyContext'; - let capturedParentContext: ReturnType | undefined; + let capturedParentContext: ReturnType | undefined; @ShadowObject({registry, token: 'parentCtxProvider'}) class ParentCtxProvider { - constructor({provideContext}: ShadowObjectParams) { + constructor({provideContext}: ShadowObjectCreationAPI) { provideContext(contextName, 'parentValue'); } } @@ -450,7 +450,7 @@ describe('Kernel', () => { @ShadowObject({registry, token: 'childCtxConsumer'}) class ChildCtxConsumer { - constructor({useParentContext}: ShadowObjectParams) { + constructor({useParentContext}: ShadowObjectCreationAPI) { capturedParentContext = useParentContext(contextName); } } @@ -475,11 +475,11 @@ describe('Kernel', () => { const kernel = new Kernel(registry); const globalCtxName = 'globalContext'; - let capturedGlobalCtx: ReturnType | undefined; + let capturedGlobalCtx: ReturnType | undefined; @ShadowObject({registry, token: 'globalProvider'}) class GlobalProvider { - constructor({provideGlobalContext}: ShadowObjectParams) { + constructor({provideGlobalContext}: ShadowObjectCreationAPI) { provideGlobalContext(globalCtxName, 'globalValue'); } } @@ -487,7 +487,7 @@ describe('Kernel', () => { @ShadowObject({registry, token: 'globalConsumer'}) class GlobalConsumer { - constructor({useContext}: ShadowObjectParams) { + constructor({useContext}: ShadowObjectCreationAPI) { capturedGlobalCtx = useContext(globalCtxName); } } @@ -512,11 +512,11 @@ describe('Kernel', () => { const globalCtxName = 'globalSignalContext'; const sourceSignal = createSignal('globalInitial'); - let capturedGlobalCtx: ReturnType | undefined; + let capturedGlobalCtx: ReturnType | undefined; @ShadowObject({registry, token: 'globalSignalProvider'}) class GlobalSignalProvider { - constructor({provideGlobalContext}: ShadowObjectParams) { + constructor({provideGlobalContext}: ShadowObjectCreationAPI) { provideGlobalContext(globalCtxName, sourceSignal.get); } } @@ -524,7 +524,7 @@ describe('Kernel', () => { @ShadowObject({registry, token: 'globalSignalConsumer'}) class GlobalSignalConsumer { - constructor({useContext}: ShadowObjectParams) { + constructor({useContext}: ShadowObjectCreationAPI) { capturedGlobalCtx = useContext(globalCtxName); } } @@ -559,7 +559,7 @@ describe('Kernel', () => { @ShadowObject({registry, token: 'testResource'}) class TestResource { - constructor({createResource}: ShadowObjectParams) { + constructor({createResource}: ShadowObjectCreationAPI) { resourceSignal = createResource(createFn, cleanupFn); } } @@ -587,7 +587,7 @@ describe('Kernel', () => { @ShadowObject({registry, token: 'testUndefinedResource'}) class TestUndefinedResource { - constructor({createResource}: ShadowObjectParams) { + constructor({createResource}: ShadowObjectCreationAPI) { createResource(createFn, cleanupFn); } } @@ -611,7 +611,7 @@ describe('Kernel', () => { @ShadowObject({registry, token: 'testEffect'}) class TestEffect { - constructor({createEffect}: ShadowObjectParams) { + constructor({createEffect}: ShadowObjectCreationAPI) { createEffect(() => { effectFn(testSignal.get()); }); @@ -639,7 +639,7 @@ describe('Kernel', () => { @ShadowObject({registry, token: 'testEffectDestroy'}) class TestEffectDestroy { - constructor({createEffect}: ShadowObjectParams) { + constructor({createEffect}: ShadowObjectCreationAPI) { createEffect(() => { effectFn(testSignal.get()); }); @@ -669,7 +669,7 @@ describe('Kernel', () => { @ShadowObject({registry, token: 'testCreateSignal'}) class TestCreateSignal { - constructor({createSignal: cs}: ShadowObjectParams) { + constructor({createSignal: cs}: ShadowObjectCreationAPI) { createdSignal = cs('initial'); } } @@ -695,7 +695,7 @@ describe('Kernel', () => { @ShadowObject({registry, token: 'testSignalDestroy'}) class TestSignalDestroy { - constructor({createSignal: cs}: ShadowObjectParams) { + constructor({createSignal: cs}: ShadowObjectCreationAPI) { createdSignal = cs('test'); } } @@ -724,7 +724,7 @@ describe('Kernel', () => { @ShadowObject({registry, token: 'testMemo'}) class TestMemo { - constructor({createMemo}: ShadowObjectParams) { + constructor({createMemo}: ShadowObjectCreationAPI) { memoReader = createMemo(() => sourceSignal.get() * 2); } } @@ -753,7 +753,7 @@ describe('Kernel', () => { @ShadowObject({registry, token: 'testOn'}) class TestOn { - constructor({on: subscribe}: ShadowObjectParams) { + constructor({on: subscribe}: ShadowObjectCreationAPI) { subscribe(emitter, 'testEvent', eventHandler); } } @@ -783,7 +783,7 @@ describe('Kernel', () => { @ShadowObject({registry, token: 'testOnce'}) class TestOnce { - constructor({once: subscribeOnce}: ShadowObjectParams) { + constructor({once: subscribeOnce}: ShadowObjectCreationAPI) { subscribeOnce(emitter, 'singleEvent', eventHandler); } } @@ -812,7 +812,7 @@ describe('Kernel', () => { @ShadowObject({registry, token: 'testOnceNoFire'}) class TestOnceNoFire { - constructor({once: subscribeOnce}: ShadowObjectParams) { + constructor({once: subscribeOnce}: ShadowObjectCreationAPI) { subscribeOnce(emitter, 'neverFiredEvent', eventHandler); } } @@ -837,7 +837,7 @@ describe('Kernel', () => { @ShadowObject({registry, token: 'testOnDestroy'}) class TestOnDestroy { - constructor({onDestroy: registerDestroy}: ShadowObjectParams) { + constructor({onDestroy: registerDestroy}: ShadowObjectCreationAPI) { registerDestroy(destroyCallback); } } @@ -861,7 +861,7 @@ describe('Kernel', () => { @ShadowObject({registry, token: 'testMultipleOnDestroy'}) class TestMultipleOnDestroy { - constructor({onDestroy: registerDestroy}: ShadowObjectParams) { + constructor({onDestroy: registerDestroy}: ShadowObjectCreationAPI) { registerDestroy(() => callOrder.push(1)); registerDestroy(() => callOrder.push(2)); registerDestroy(() => callOrder.push(3)); diff --git a/packages/shadow-objects/src/types.ts b/packages/shadow-objects/src/types.ts index 61d0e89..8038cef 100644 --- a/packages/shadow-objects/src/types.ts +++ b/packages/shadow-objects/src/types.ts @@ -93,7 +93,7 @@ export type EntityApi = Pick< traverse(callback: (entity: EntityApi) => any): void; }; -export interface ShadowObjectParams { +export interface ShadowObjectCreationAPI { entity: EntityApi; provideContext( @@ -125,12 +125,12 @@ export interface ShadowObjectParams { } export interface ShadowObjectConstructor { - new (params: ShadowObjectParams): {}; + new (params: ShadowObjectCreationAPI): {}; displayName?: string; } export interface ShadowObjectConstructorFunc { - (params: ShadowObjectParams): object | undefined | void; + (params: ShadowObjectCreationAPI): object | undefined | void; displayName?: string; } diff --git a/packages/shadow-objects/src/view/ShadowEnv.spec.ts b/packages/shadow-objects/src/view/ShadowEnv.spec.ts index eaa7c10..45b5878 100644 --- a/packages/shadow-objects/src/view/ShadowEnv.spec.ts +++ b/packages/shadow-objects/src/view/ShadowEnv.spec.ts @@ -2,7 +2,7 @@ import {on, once} from '@spearwolf/eventize'; import {afterEach, describe, expect, it, vi} from 'vitest'; import {Registry} from '../in-the-dark/Registry.js'; import {ShadowObject} from '../in-the-dark/ShadowObject.js'; -import type {ShadowObjectParams} from '../types.js'; +import type {ShadowObjectCreationAPI} from '../types.js'; import {ComponentContext} from './ComponentContext.js'; import {LocalShadowObjectEnv} from './LocalShadowObjectEnv.js'; import {ShadowEnv} from './ShadowEnv.js'; @@ -118,7 +118,7 @@ describe('ShadowEnv', () => { @ShadowObject({token: 'parent'}) class ParentShadowObject { - constructor({entity}: ShadowObjectParams) { + constructor({entity}: ShadowObjectCreationAPI) { entityRef = entity; } } @@ -175,7 +175,7 @@ describe('ShadowEnv', () => { @ShadowObject({token: 'parent2'}) class Parent2ShadowObject { - constructor({entity}: ShadowObjectParams) { + constructor({entity}: ShadowObjectCreationAPI) { entityRef = entity; } }