-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Updated example that tracks a complex object
- Loading branch information
1 parent
478b2bf
commit b71b57d
Showing
18 changed files
with
609 additions
and
81 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 8 additions & 2 deletions
10
examples/shopping-cart/lwc/checkoutButton/checkoutButton.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
118 changes: 117 additions & 1 deletion
118
force-app/lwc/signals/observable-membrane/base-handler.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,132 @@ | ||
/* eslint-disable */ | ||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
// @ts-nocheck | ||
/* | ||
* Copyright (c) 2023, Salesforce.com, Inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: MIT | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT | ||
*/ | ||
import { ArrayConcat, getPrototypeOf, getOwnPropertyNames, getOwnPropertySymbols, getOwnPropertyDescriptor, isUndefined, isExtensible, hasOwnProperty, ObjectDefineProperty, preventExtensions, ArrayPush, ObjectCreate, } from './shared'; | ||
export class BaseProxyHandler { | ||
constructor(membrane, value) { | ||
this.originalTarget = value; | ||
this.membrane = membrane; | ||
} | ||
// Shared utility methods | ||
wrapDescriptor(descriptor) { | ||
if (hasOwnProperty.call(descriptor, 'value')) { | ||
descriptor.value = this.wrapValue(descriptor.value); | ||
} | ||
else { | ||
const { set: originalSet, get: originalGet } = descriptor; | ||
if (!isUndefined(originalGet)) { | ||
descriptor.get = this.wrapGetter(originalGet); | ||
} | ||
if (!isUndefined(originalSet)) { | ||
descriptor.set = this.wrapSetter(originalSet); | ||
} | ||
} | ||
return descriptor; | ||
} | ||
copyDescriptorIntoShadowTarget(shadowTarget, key) { | ||
const { originalTarget } = this; | ||
// Note: a property might get defined multiple times in the shadowTarget | ||
// but it will always be compatible with the previous descriptor | ||
// to preserve the object invariants, which makes these lines safe. | ||
const originalDescriptor = getOwnPropertyDescriptor(originalTarget, key); | ||
// TODO: it should be impossible for the originalDescriptor to ever be undefined, this `if` can be removed | ||
/* istanbul ignore else */ | ||
if (!isUndefined(originalDescriptor)) { | ||
const wrappedDesc = this.wrapDescriptor(originalDescriptor); | ||
ObjectDefineProperty(shadowTarget, key, wrappedDesc); | ||
} | ||
} | ||
lockShadowTarget(shadowTarget) { | ||
const { originalTarget } = this; | ||
const targetKeys = ArrayConcat.call(getOwnPropertyNames(originalTarget), getOwnPropertySymbols(originalTarget)); | ||
targetKeys.forEach((key) => { | ||
this.copyDescriptorIntoShadowTarget(shadowTarget, key); | ||
}); | ||
const { membrane: { tagPropertyKey }, } = this; | ||
if (!isUndefined(tagPropertyKey) && !hasOwnProperty.call(shadowTarget, tagPropertyKey)) { | ||
ObjectDefineProperty(shadowTarget, tagPropertyKey, ObjectCreate(null)); | ||
} | ||
preventExtensions(shadowTarget); | ||
} | ||
// Shared Traps | ||
get(_shadowTarget, key) { | ||
// TODO: apply() is never called | ||
/* istanbul ignore next */ | ||
apply(shadowTarget, thisArg, argArray) { | ||
/* No op */ | ||
} | ||
// TODO: construct() is never called | ||
/* istanbul ignore next */ | ||
construct(shadowTarget, argArray, newTarget) { | ||
/* No op */ | ||
} | ||
get(shadowTarget, key) { | ||
const { originalTarget, membrane: { valueObserved }, } = this; | ||
const value = originalTarget[key]; | ||
valueObserved(originalTarget, key); | ||
return this.wrapValue(value); | ||
} | ||
has(shadowTarget, key) { | ||
const { originalTarget, membrane: { tagPropertyKey, valueObserved }, } = this; | ||
valueObserved(originalTarget, key); | ||
// since key is never going to be undefined, and tagPropertyKey might be undefined | ||
// we can simply compare them as the second part of the condition. | ||
return key in originalTarget || key === tagPropertyKey; | ||
} | ||
ownKeys(shadowTarget) { | ||
const { originalTarget, membrane: { tagPropertyKey }, } = this; | ||
// if the membrane tag key exists and it is not in the original target, we add it to the keys. | ||
const keys = isUndefined(tagPropertyKey) || hasOwnProperty.call(originalTarget, tagPropertyKey) | ||
? [] | ||
: [tagPropertyKey]; | ||
// small perf optimization using push instead of concat to avoid creating an extra array | ||
ArrayPush.apply(keys, getOwnPropertyNames(originalTarget)); | ||
ArrayPush.apply(keys, getOwnPropertySymbols(originalTarget)); | ||
return keys; | ||
} | ||
isExtensible(shadowTarget) { | ||
const { originalTarget } = this; | ||
// optimization to avoid attempting to lock down the shadowTarget multiple times | ||
if (!isExtensible(shadowTarget)) { | ||
return false; // was already locked down | ||
} | ||
if (!isExtensible(originalTarget)) { | ||
this.lockShadowTarget(shadowTarget); | ||
return false; | ||
} | ||
return true; | ||
} | ||
getPrototypeOf(shadowTarget) { | ||
const { originalTarget } = this; | ||
return getPrototypeOf(originalTarget); | ||
} | ||
getOwnPropertyDescriptor(shadowTarget, key) { | ||
const { originalTarget, membrane: { valueObserved, tagPropertyKey }, } = this; | ||
// keys looked up via getOwnPropertyDescriptor need to be reactive | ||
valueObserved(originalTarget, key); | ||
let desc = getOwnPropertyDescriptor(originalTarget, key); | ||
if (isUndefined(desc)) { | ||
if (key !== tagPropertyKey) { | ||
return undefined; | ||
} | ||
// if the key is the membrane tag key, and is not in the original target, | ||
// we produce a synthetic descriptor and install it on the shadow target | ||
desc = { value: undefined, writable: false, configurable: false, enumerable: false }; | ||
ObjectDefineProperty(shadowTarget, tagPropertyKey, desc); | ||
return desc; | ||
} | ||
if (desc.configurable === false) { | ||
// updating the descriptor to non-configurable on the shadow | ||
this.copyDescriptorIntoShadowTarget(shadowTarget, key); | ||
} | ||
// Note: by accessing the descriptor, the key is marked as observed | ||
// but access to the value, setter or getter (if available) cannot observe | ||
// mutations, just like regular methods, in which case we just do nothing. | ||
return this.wrapDescriptor(desc); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.