From f3cea8ef0e02a1aa8bd74d719064ffae8b73d16d Mon Sep 17 00:00:00 2001 From: CCherry07 <2405693142@qq.com> Date: Thu, 16 Jan 2025 20:13:40 +0800 Subject: [PATCH] feat: update signals version --- package.json | 2 +- pnpm-lock.yaml | 20 +++-- src/computed.ts | 17 ---- src/contents.ts | 3 + src/core.ts | 212 ++++++++++++++++++++++++++++++++++++++++++++++ src/deepSignal.ts | 5 +- src/index.ts | 3 +- src/signal.ts | 26 ------ tsconfig.json | 4 +- tsup.config.ts | 1 + 10 files changed, 237 insertions(+), 56 deletions(-) delete mode 100644 src/computed.ts create mode 100644 src/contents.ts create mode 100644 src/core.ts delete mode 100644 src/signal.ts diff --git a/package.json b/package.json index fce16b9..d796c8d 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "release": "bumpp && npm run build && npm publish --registry=https://registry.npmjs.org/" }, "dependencies": { - "alien-signals": "latest" + "alien-signals": "^1.0.0" }, "devDependencies": { "bumpp": "^9.9.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 27ec4b4..74be2f4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: alien-signals: - specifier: latest - version: 0.6.0 + specifier: 1.0.0 + version: 1.0.0 devDependencies: bumpp: specifier: ^9.9.2 @@ -375,51 +375,61 @@ packages: resolution: {integrity: sha512-Py5vFd5HWYN9zxBv3WMrLAXY3yYJ6Q/aVERoeUFwiDGiMOWsMs7FokXihSOaT/PMWUty/Pj60XDQndK3eAfE6A==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.29.1': resolution: {integrity: sha512-RiWpGgbayf7LUcuSNIbahr0ys2YnEERD4gYdISA06wa0i8RALrnzflh9Wxii7zQJEB2/Eh74dX4y/sHKLWp5uQ==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.29.1': resolution: {integrity: sha512-Z80O+taYxTQITWMjm/YqNoe9d10OX6kDh8X5/rFCMuPqsKsSyDilvfg+vd3iXIqtfmp+cnfL1UrYirkaF8SBZA==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.29.1': resolution: {integrity: sha512-fOHRtF9gahwJk3QVp01a/GqS4hBEZCV1oKglVVq13kcK3NeVlS4BwIFzOHDbmKzt3i0OuHG4zfRP0YoG5OF/rA==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loongarch64-gnu@4.29.1': resolution: {integrity: sha512-5a7q3tnlbcg0OodyxcAdrrCxFi0DgXJSoOuidFUzHZ2GixZXQs6Tc3CHmlvqKAmOs5eRde+JJxeIf9DonkmYkw==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-powerpc64le-gnu@4.29.1': resolution: {integrity: sha512-9b4Mg5Yfz6mRnlSPIdROcfw1BU22FQxmfjlp/CShWwO3LilKQuMISMTtAu/bxmmrE6A902W2cZJuzx8+gJ8e9w==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.29.1': resolution: {integrity: sha512-G5pn0NChlbRM8OJWpJFMX4/i8OEU538uiSv0P6roZcbpe/WfhEO+AT8SHVKfp8qhDQzaz7Q+1/ixMy7hBRidnQ==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.29.1': resolution: {integrity: sha512-WM9lIkNdkhVwiArmLxFXpWndFGuOka4oJOZh8EP3Vb8q5lzdSCBuhjavJsw68Q9AKDGeOOIHYzYm4ZFvmWez5g==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.29.1': resolution: {integrity: sha512-87xYCwb0cPGZFoGiErT1eDcssByaLX4fc0z2nRM6eMtV9njAfEE6OW3UniAoDhX4Iq5xQVpE6qO9aJbCFumKYQ==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.29.1': resolution: {integrity: sha512-xufkSNppNOdVRCEC4WKvlR1FBDyqCSCpQeMMgv9ZyXqqtKBfkw1yfGMTUTs9Qsl6WQbJnsGboWCp7pJGkeMhKA==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.29.1': resolution: {integrity: sha512-F2OiJ42m77lSkizZQLuC+jiZ2cgueWQL5YC9tjo3AgaEw+KJmVxHGSyQfDUoYR9cci0lAywv2Clmckzulcq6ig==} @@ -476,8 +486,8 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - alien-signals@0.6.0: - resolution: {integrity: sha512-2uVYGg0IY07glpXb7uu+mGuJFxEO0Blp3c3bagwxK9E5Fh6AKcXoUb7iDaa584FW7vEKPoNoy+2UOy39/eLiwg==} + alien-signals@1.0.0: + resolution: {integrity: sha512-Fd2sYMdyjWD6VKxeewCYHXsIYAiELGMtQzGJ6vyxpxtQ1exXYiNTynSqGllkk+mOqhtBFYcC1Qvb49FbCSvsQw==} ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} @@ -1386,7 +1396,7 @@ snapshots: acorn@8.14.0: {} - alien-signals@0.6.0: {} + alien-signals@1.0.0: {} ansi-regex@5.0.1: {} diff --git a/src/computed.ts b/src/computed.ts deleted file mode 100644 index 881474c..0000000 --- a/src/computed.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Computed as AlienComputed } from 'alien-signals'; - -export function computed(getter: (cachedValue?: T) => T): Computed { - return new Computed(getter); -} - -export class Computed extends AlienComputed { - constructor(getter: (cachedValue?: T) => T) { - super(getter); - } - get value(): T { - return this.get(); - } - peek(): T { - return this.currentValue; - } -} diff --git a/src/contents.ts b/src/contents.ts new file mode 100644 index 0000000..0da03de --- /dev/null +++ b/src/contents.ts @@ -0,0 +1,3 @@ +export enum ReactiveFlags { + IS_REFERENCE = '__v_isReference', +} diff --git a/src/core.ts b/src/core.ts new file mode 100644 index 0000000..e573468 --- /dev/null +++ b/src/core.ts @@ -0,0 +1,212 @@ +import { createReactiveSystem, Dependency, Link, Subscriber, SubscriberFlags } from 'alien-signals'; +import { ReactiveFlags } from "./contents" +const { + link, + propagate, + endTracking, + startTracking, + updateDirtyFlag, + processComputedUpdate, + processEffectNotifications, +} = createReactiveSystem({ + updateComputed(computed: Computed) { + return computed.update(); + }, + notifyEffect(effect: Effect) { + effect.notify(); + return true; + }, +}); + +let activeSub: Subscriber | undefined = undefined; +let batchDepth = 0; + +export function startBatch(): void { + ++batchDepth; +} + +export function endBatch(): void { + if (!--batchDepth) { + processEffectNotifications(); + } +} + +export function signal(): Signal; +export function signal(oldValue: T): Signal; +export function signal(oldValue?: T): Signal { + return new Signal(oldValue); +} + +export class Signal implements Dependency { + public readonly [ReactiveFlags.IS_REFERENCE] = true + // Dependency fields + subs: Link | undefined = undefined; + subsTail: Link | undefined = undefined; + + constructor( + public currentValue: T + ) { } + + get(): T { + if (activeSub !== undefined) { + link(this, activeSub); + } + return this.currentValue; + } + + set(value: T): void { + if (this.currentValue !== value) { + this.currentValue = value; + const subs = this.subs; + if (subs !== undefined) { + propagate(subs); + if (!batchDepth) { + processEffectNotifications(); + } + } + } + } + + value(): T { + return this.get(); + } + + peek(): T { + return this.currentValue; + } +} + +export function computed(getter: () => T): Computed { + return new Computed(getter); +} + +export class Computed implements Subscriber, Dependency { + readonly [ReactiveFlags.IS_REFERENCE] = true + currentValue: T | undefined = undefined; + + // Dependency fields + subs: Link | undefined = undefined; + subsTail: Link | undefined = undefined; + + // Subscriber fields + deps: Link | undefined = undefined; + depsTail: Link | undefined = undefined; + flags: SubscriberFlags = SubscriberFlags.Computed | SubscriberFlags.Dirty; + + constructor( + public getter: () => T + ) { } + + get(): T { + const flags = this.flags; + if (flags & (SubscriberFlags.PendingComputed | SubscriberFlags.Dirty)) { + processComputedUpdate(this, flags); + } + if (activeSub !== undefined) { + link(this, activeSub); + } + return this.currentValue!; + } + + update(): boolean { + const prevSub = activeSub; + activeSub = this; + startTracking(this); + try { + const oldValue = this.currentValue; + const newValue = this.getter(); + if (oldValue !== newValue) { + this.currentValue = newValue; + return true; + } + return false; + } finally { + activeSub = prevSub; + endTracking(this); + } + } + + peek(): T { + return this.currentValue!; + } + + value(): Readonly { + return this.get(); + } +} + +export function effect(fn: () => T): Effect { + const e = new Effect(fn); + e.run(); + return e; +} + +export class Effect implements Subscriber { + readonly [ReactiveFlags.IS_REFERENCE] = true + // Subscriber fields + deps: Link | undefined = undefined; + depsTail: Link | undefined = undefined; + flags: SubscriberFlags = SubscriberFlags.Effect; + + constructor( + public fn: () => T + ) { } + + notify(): void { + const flags = this.flags; + if ( + flags & SubscriberFlags.Dirty + || (flags & SubscriberFlags.PendingComputed && updateDirtyFlag(this, flags)) + ) { + this.run(); + } + } + + run(): T { + const prevSub = activeSub; + activeSub = this; + startTracking(this); + try { + return this.fn(); + } finally { + activeSub = prevSub; + endTracking(this); + } + } + + stop(): void { + startTracking(this); + endTracking(this); + } +} + +export function batch(fn: () => T): T { + startBatch(); + try { + return fn(); + } finally { + endBatch(); + } +} + +export function isSignal(r: Signal | unknown): r is Signal +export function isSignal(r: any): r is Signal { + return r ? r[ReactiveFlags.IS_REFERENCE] === true : false +} + +export type MaybeSignal = + | T + | Signal + +export type MaybeSignalOrGetter = MaybeSignal | Computed | (() => T) + +export function unSignal(signal: MaybeSignal | Computed): T { + return (isSignal(signal) ? signal.value : signal) as T; +} + +export const isFunction = (val: unknown): val is Function => + typeof val === 'function' + +export function toValue(source: MaybeSignalOrGetter): T { + return isFunction(source) ? source() : unSignal(source) +} diff --git a/src/deepSignal.ts b/src/deepSignal.ts index 885a1c3..0f51f3c 100644 --- a/src/deepSignal.ts +++ b/src/deepSignal.ts @@ -1,5 +1,4 @@ -import { computed } from "./computed"; -import { signal, Signal } from "./signal" +import { computed, Signal, signal } from "./core"; const proxyToSignals = new WeakMap(); const objToProxy = new WeakMap(); @@ -99,7 +98,7 @@ const objectHandlers = { if (!(val instanceof Signal)) throwOnMutation(); const key = fullKey.replace(rg, ""); signals.set(key, val); - return Reflect.set(target, key, val.peek(), receiver); + return Reflect.set(target, key, val(), receiver); } else { let internal = val; if (shouldProxy(val)) { diff --git a/src/index.ts b/src/index.ts index 6c80ee2..fa69a31 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,2 @@ -export * from "./computed"; -export * from "./signal"; +export * from "./core"; export * from "./deepSignal"; diff --git a/src/signal.ts b/src/signal.ts deleted file mode 100644 index ec91662..0000000 --- a/src/signal.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Signal as AlienSignal } from 'alien-signals'; -export function signal(): Signal; -export function signal(oldValue: T): Signal; -export function signal(oldValue?: T): Signal { - return new Signal(oldValue); -} - -export class Signal extends AlienSignal { - constructor( - currentValue: T - ) { - super(currentValue); - } - - get value(): T { - return this.get() - } - - set value(value: T) { - this.set(value) - } - - peek(): T { - return this.currentValue; - } -} diff --git a/tsconfig.json b/tsconfig.json index 7f25630..4c3cc80 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,13 +11,13 @@ "moduleResolution": "bundler", "allowImportingTsExtensions": true, "resolveJsonModule": true, - "isolatedModules": true, + "isolatedModules": false, "noEmit": true, /* Linting */ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, }, "include": [ "src" diff --git a/tsup.config.ts b/tsup.config.ts index fcd9ab4..ffb3961 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -9,5 +9,6 @@ export const tsup: Options = { splitting: true, clean: true, shims: false, + minify: false, external: ['alien-signals'], }