Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/devtools-plugin/tests/utils/create-devtools.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { NgxsDevtoolsOptions } from '@ngxs/devtools-plugin';
import { ɵdefineProperty } from '@ngxs/store/internals';

import { ReduxDevtoolsMockConnector } from './redux-connector';

export function createReduxDevtoolsExtension(connector: ReduxDevtoolsMockConnector): void {
Object.defineProperty(window, '__REDUX_DEVTOOLS_EXTENSION__', {
ɵdefineProperty(window, '__REDUX_DEVTOOLS_EXTENSION__', {
writable: true,
configurable: true,
value: {
Expand Down
4 changes: 2 additions & 2 deletions packages/storage-plugin/internals/src/storage-key.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { InjectionToken, Type } from '@angular/core';
import { StateToken } from '@ngxs/store';
import { ɵMETA_OPTIONS_KEY, ɵStateClass } from '@ngxs/store/internals';
import { ɵhasOwnProperty, ɵMETA_OPTIONS_KEY, ɵStateClass } from '@ngxs/store/internals';

import { StorageEngine } from './symbols';

Expand Down Expand Up @@ -30,7 +30,7 @@ export function ɵextractStringKey(storageKey: StorageKey): string {
// Given the `storageKey` is a class, for instance, `AuthState`.
// We should retrieve its metadata and the `name` property.
// The `name` property might be a string (state name) or a state token.
if (storageKey.hasOwnProperty(ɵMETA_OPTIONS_KEY)) {
if (ɵhasOwnProperty(storageKey, ɵMETA_OPTIONS_KEY)) {
storageKey = (storageKey as any)[ɵMETA_OPTIONS_KEY].name;
}

Expand Down
8 changes: 3 additions & 5 deletions packages/storage-plugin/src/storage.plugin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Injectable, inject } from '@angular/core';
import { ɵPlainObject } from '@ngxs/store/internals';
import { ɵhasOwnProperty, ɵPlainObject } from '@ngxs/store/internals';
import {
NgxsPlugin,
setValue,
Expand Down Expand Up @@ -55,9 +55,7 @@ export class NgxsStoragePlugin implements NgxsPlugin {
// Given the `key` is `myState.myProperty`, the `addedStates` will only contain `myState`.
const dotNotationIndex = key.indexOf(DOT);
const stateName = dotNotationIndex > -1 ? key.slice(0, dotNotationIndex) : key;
if (!addedStates.hasOwnProperty(stateName)) {
continue;
}
if (!ɵhasOwnProperty(addedStates, stateName)) continue;
}

const storageKey = getStorageKey(key, this._options);
Expand Down Expand Up @@ -166,7 +164,7 @@ export class NgxsStoragePlugin implements NgxsPlugin {
// avoiding unnecessary rehydration of the `counter` state.
return Object.keys(addedStates).reduce(
(accumulator, addedState) => {
if (storedValue.hasOwnProperty(addedState)) {
if (ɵhasOwnProperty(storedValue, addedState)) {
accumulator[addedState] = storedValue[addedState];
}
return accumulator;
Expand Down
1 change: 1 addition & 0 deletions packages/store/internals/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export { ɵOrderedSubject, ɵOrderedBehaviorSubject } from './custom-rxjs-subjec
export { ɵwrapObserverCalls } from './custom-rxjs-operators';
export { ɵStateStream } from './state-stream';
export { ɵof } from './rxjs';
export { ɵhasOwnProperty, ɵdefineProperty } from './object-utils';
9 changes: 5 additions & 4 deletions packages/store/internals/src/metadata.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ɵdefineProperty, ɵhasOwnProperty } from './object-utils';
import {
ɵMETA_KEY,
ɵSELECTOR_META_KEY,
Expand All @@ -13,7 +14,7 @@ import {
* @ignore
*/
export function ɵensureStoreMetadata(target: ɵStateClassInternal): ɵMetaDataModel {
if (!target.hasOwnProperty(ɵMETA_KEY)) {
if (!ɵhasOwnProperty(target, ɵMETA_KEY)) {
const defaultMetadata: ɵMetaDataModel = {
name: null,
actions: {},
Expand All @@ -25,7 +26,7 @@ export function ɵensureStoreMetadata(target: ɵStateClassInternal): ɵMetaDataM
children: []
};

Object.defineProperty(target, ɵMETA_KEY, { value: defaultMetadata });
ɵdefineProperty(target, ɵMETA_KEY, { value: defaultMetadata });
}
return ɵgetStoreMetadata(target);
}
Expand All @@ -45,7 +46,7 @@ export function ɵgetStoreMetadata(target: ɵStateClassInternal): ɵMetaDataMode
* @ignore
*/
export function ɵensureSelectorMetadata(target: Function): ɵSelectorMetaDataModel {
if (!target.hasOwnProperty(ɵSELECTOR_META_KEY)) {
if (!ɵhasOwnProperty(target, ɵSELECTOR_META_KEY)) {
const defaultMetadata: ɵSelectorMetaDataModel = {
makeRootSelector: null,
originalFn: null,
Expand All @@ -54,7 +55,7 @@ export function ɵensureSelectorMetadata(target: Function): ɵSelectorMetaDataMo
getSelectorOptions: () => ({})
};

Object.defineProperty(target, ɵSELECTOR_META_KEY, { value: defaultMetadata });
ɵdefineProperty(target, ɵSELECTOR_META_KEY, { value: defaultMetadata });
}

return ɵgetSelectorMetadata(target);
Expand Down
7 changes: 7 additions & 0 deletions packages/store/internals/src/object-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Property reads are not minified.
// It's smaller to read it once and use a function.
const _hasOwnProperty = Object.prototype.hasOwnProperty;
export const ɵhasOwnProperty = (target: any, key: PropertyKey) =>
_hasOwnProperty.call(target, key);

export const ɵdefineProperty = Object.defineProperty;
4 changes: 2 additions & 2 deletions packages/store/src/decorators/action.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ɵActionOptions, ɵensureStoreMetadata } from '@ngxs/store/internals';
import { ɵActionOptions, ɵensureStoreMetadata, ɵhasOwnProperty } from '@ngxs/store/internals';

import { ActionDef, ActionType } from '../actions/symbols';
import { throwActionDecoratorError } from '../configs/messages.config';
Expand Down Expand Up @@ -62,7 +62,7 @@ export function Action<ActionOrActions extends ActionType | ActionType[]>(
_descriptor: HandlerTypedPropertyDescriptor<ActionOrActions>
): void => {
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
const isStaticMethod = target.hasOwnProperty('prototype');
const isStaticMethod = ɵhasOwnProperty(target, 'prototype');

if (isStaticMethod) {
throwActionDecoratorError();
Expand Down
52 changes: 20 additions & 32 deletions packages/store/src/decorators/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,59 +5,47 @@ import {
ɵMetaDataModel,
ɵStateClassInternal,
ɵStoreOptions,
ɵensureStoreMetadata
ɵensureStoreMetadata,
ɵhasOwnProperty
} from '@ngxs/store/internals';

import { ensureStateNameIsValid } from '../utils/store-validators';

interface MutateMetaOptions<T> {
meta: ɵMetaDataModel;
inheritedStateClass: ɵStateClassInternal;
optionsWithInheritance: ɵStoreOptions<T>;
}

/**
* Decorates a class with ngxs state information.
*/
export function State<T>(options: ɵStoreOptions<T>) {
return (target: ɵStateClass): void => {
const stateClass: ɵStateClassInternal = target;
const meta: ɵMetaDataModel = ɵensureStoreMetadata(stateClass);
const inheritedStateClass: ɵStateClassInternal = Object.getPrototypeOf(stateClass);
const optionsWithInheritance: ɵStoreOptions<T> = getStateOptions(
inheritedStateClass,
options
);
mutateMetaData<T>({ meta, inheritedStateClass, optionsWithInheritance });
stateClass[ɵMETA_OPTIONS_KEY] = optionsWithInheritance;
const inherited = Object.getPrototypeOf(stateClass) as ɵStateClassInternal;
const meta = ɵensureStoreMetadata(stateClass);
const mergedOptions = { ...(inherited[ɵMETA_OPTIONS_KEY] || {}), ...options };

// Apply merged options to metadata.
mutateMetaData(meta, inherited, mergedOptions);
stateClass[ɵMETA_OPTIONS_KEY] = mergedOptions;
};
}

function getStateOptions<T>(
inheritedStateClass: ɵStateClassInternal,
// Updates metadata using inherited and current options
function mutateMetaData<T>(
meta: ɵMetaDataModel,
inherited: ɵStateClassInternal,
options: ɵStoreOptions<T>
): ɵStoreOptions<T> {
const inheritanceOptions: Partial<ɵStoreOptions<T>> =
inheritedStateClass[ɵMETA_OPTIONS_KEY] || {};
return { ...inheritanceOptions, ...options } as ɵStoreOptions<T>;
}

function mutateMetaData<T>(params: MutateMetaOptions<T>): void {
const { meta, inheritedStateClass, optionsWithInheritance } = params;
const { children, defaults, name } = optionsWithInheritance;
const stateName: string | null =
typeof name === 'string' ? name : (name && name.getName()) || null;
): void {
const { name, defaults, children } = options;
const stateName = typeof name === 'string' ? name : name?.getName?.() || null;

if (typeof ngDevMode !== 'undefined' && ngDevMode) {
ensureStateNameIsValid(stateName);
}

if (inheritedStateClass.hasOwnProperty(ɵMETA_KEY)) {
const inheritedMeta: Partial<ɵMetaDataModel> = inheritedStateClass[ɵMETA_KEY] || {};
if (ɵhasOwnProperty(inherited, ɵMETA_KEY)) {
const inheritedMeta = inherited[ɵMETA_KEY] || <ɵMetaDataModel>{};
meta.actions = { ...meta.actions, ...inheritedMeta.actions };
}

meta.children = children;
meta.defaults = defaults;
meta.name = stateName;
meta.defaults = defaults;
meta.children = children;
}
3 changes: 2 additions & 1 deletion packages/store/src/utils/create-dispatch-map.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Observable } from 'rxjs';
import { ɵdefineProperty } from '@ngxs/store/internals';

import { dispatch } from './dispatch';

Expand All @@ -8,7 +9,7 @@ export type ActionMap = Record<string, ActionDef<any>>;

export function createDispatchMap<T extends ActionMap>(actionMap: T) {
return Object.entries(actionMap).reduce((accumulator, [key, ActionType]) => {
Object.defineProperty(accumulator, key, {
ɵdefineProperty(accumulator, key, {
enumerable: true,
value: dispatch(ActionType)
});
Expand Down
3 changes: 2 additions & 1 deletion packages/store/src/utils/create-select-map.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Signal, inject } from '@angular/core';
import { ɵdefineProperty } from '@ngxs/store/internals';

import { Store } from '../store';
import { TypedSelector, ɵSelectorReturnType } from '../selectors';
Expand All @@ -9,7 +10,7 @@ export function createSelectMap<T extends SelectorMap>(selectorMap: T) {
const store = inject(Store);

return Object.entries(selectorMap).reduce((accumulator, [key, selector]) => {
Object.defineProperty(accumulator, key, {
ɵdefineProperty(accumulator, key, {
enumerable: true,
value: store.selectSignal(selector)
});
Expand Down
5 changes: 3 additions & 2 deletions packages/store/src/utils/freeze.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ɵhasOwnProperty } from '@ngxs/store/internals';

/**
* Object freeze code
* https://github.com/jsdf/deep-freeze
Expand All @@ -6,11 +8,10 @@ export const deepFreeze = (o: any) => {
Object.freeze(o);

const oIsFunction = typeof o === 'function';
const hasOwnProp = Object.prototype.hasOwnProperty;

Object.getOwnPropertyNames(o).forEach(function (prop) {
if (
hasOwnProp.call(o, prop) &&
ɵhasOwnProperty(o, prop) &&
(oIsFunction ? prop !== 'caller' && prop !== 'callee' && prop !== 'arguments' : true) &&
o[prop] !== null &&
(typeof o[prop] === 'object' || typeof o[prop] === 'function') &&
Expand Down
Loading