Repository navigation
fix(core): createModel to wrap class prototype methods as actions - #984
SisyphusZheng wants to merge 7 commits into
Conversation
✅ Deploy Preview for preact-signals-demo ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
🦋 Changeset detectedLatest commit: f66b612 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The following compresses better const wrapInAction = (value: Record<string, unknown>) => {
for (
let obj = value;
obj && obj !== Object.prototype;
obj =
Object.prototype.toString.call(value) === "[object Object]" &&
Object.getPrototypeOf(obj)
) {
const descs = Object.getOwnPropertyDescriptors(obj);
for (const key in descs) {
const val = descs[key].value;
if (typeof val === "function") {
if (key !== "constructor" && value[key] === val) {
value[key] = action(val as (...args: unknown[]) => unknown);
}
} else if (
obj === value &&
typeof val === "object" &&
val !== null &&
!("brand" in val)
) {
wrapInAction(val as Record<string, unknown>);
}
}
}
}; |
Co-authored-by: Jovi De Croock <decroockjovi@gmail.com>
Co-authored-by: Jovi De Croock <decroockjovi@gmail.com>
Co-authored-by: Jovi De Croock <decroockjovi@gmail.com>
Sorry, I missed the CoC requirement. I ran into this while integrating signals into a framework I'm working on. I used an LLM to help analyze the bug, draft the issue and PR description, and write the initial patch and tests. I reproduced all three failure modes myself, and I've applied your suggested change and re-ran the test suite locally. |
Fixes #983
Summary
createModelwraps model functions as actions viawrapInAction, which enumerates withfor...inand therefore only sees own enumerable properties. Class instance models keep methods on the (non-enumerable) prototype, so they are missed entirely, while the publicValidateModeltype accepts class instances. Consequences, all verified onmain(b0df09a):Cycle detectedguard throws,TypeError.Changes
In
wrapInAction:"[object Object]"-tagged values and wrap inherited methods as own properties (skippingconstructorand anything shadowed by an own property),TypeError),"[object Object]"check keeps built-ins (Map, Date, arrays, functions) untouched. This is defensive only —ValidateModelalready rejects built-ins at the type level — but keeps JS users without typechecking safe.Object-literal behavior is unchanged: all existing tests pass as-is.
Tests
Added to the
createModelsuite:Cycle detected),Verification
pnpm vitest run packages/core— 172 passed, 2 skippedpnpm lint:tsc— cleanpnpm oxlint packages/core/src/index.ts packages/core/test/signal.test.tsx— no new warnings beyond the file's pre-existingno-unused-expressionsstyleIncludes a changeset for
@preact/signals-core(patch).AI assistance
This contribution was developed with assistance from OpenAI Codex.