From b1fac9dcfe342d52a2a7f5eb754614b3a9e31b58 Mon Sep 17 00:00:00 2001 From: houfeng Date: Thu, 24 Jun 2021 16:38:21 +0800 Subject: [PATCH] chore: reduce size by using TS const enum (#812) --- src/core/current.ts | 9 ++++---- src/core/finalize.ts | 10 ++++----- src/core/proxy.ts | 11 +++++----- src/core/scope.ts | 7 +++--- src/plugins/es5.ts | 15 ++++++------- src/plugins/mapset.ts | 7 +++--- src/plugins/patches.ts | 44 +++++++++++++++---------------------- src/types/types-internal.ts | 24 +++++++++++--------- src/utils/common.ts | 28 ++++++++++------------- src/utils/plugins.ts | 13 +++++------ 10 files changed, 75 insertions(+), 93 deletions(-) diff --git a/src/core/current.ts b/src/core/current.ts index 9e49fd70..3a201988 100644 --- a/src/core/current.ts +++ b/src/core/current.ts @@ -8,8 +8,7 @@ import { set, ImmerState, isDraftable, - ArchtypeMap, - ArchtypeSet, + Archtype, getArchtype, getPlugin } from "../internal" @@ -45,15 +44,15 @@ function currentImpl(value: any): any { set(copy, key, currentImpl(childValue)) }) // In the future, we might consider freezing here, based on the current settings - return archType === ArchtypeSet ? new Set(copy) : copy + return archType === Archtype.Set ? new Set(copy) : copy } function copyHelper(value: any, archType: number): any { // creates a shallow copy, even if it is a map or set switch (archType) { - case ArchtypeMap: + case Archtype.Map: return new Map(value) - case ArchtypeSet: + case Archtype.Set: // Set will be cloned as array temporarily, so that we can replace individual items return Array.from(value) } diff --git a/src/core/finalize.ts b/src/core/finalize.ts index 273c6386..67842fa3 100644 --- a/src/core/finalize.ts +++ b/src/core/finalize.ts @@ -11,9 +11,7 @@ import { isDraft, SetState, set, - ProxyTypeES5Object, - ProxyTypeES5Array, - ProxyTypeSet, + ProxyType, getPlugin, die, revokeScope, @@ -84,7 +82,7 @@ function finalize(rootScope: ImmerScope, value: any, path?: PatchPath) { state.scope_.unfinalizedDrafts_-- const result = // For ES5, create a good copy from the draft first, with added keys and without deleted keys. - state.type_ === ProxyTypeES5Object || state.type_ === ProxyTypeES5Array + state.type_ === ProxyType.ES5Object || state.type_ === ProxyType.ES5Array ? (state.copy_ = shallowCopy(state.draft_)) : state.copy_ // Finalize all children of the copy @@ -92,7 +90,7 @@ function finalize(rootScope: ImmerScope, value: any, path?: PatchPath) { // Although the original test case doesn't seem valid anyway, so if this in the way we can turn the next line // back to each(result, ....) each( - state.type_ === ProxyTypeSet ? new Set(result) : result, + state.type_ === ProxyType.Set ? new Set(result) : result, (key, childValue) => finalizeProperty(rootScope, state, result, key, childValue, path) ) @@ -124,7 +122,7 @@ function finalizeProperty( const path = rootPath && parentState && - parentState!.type_ !== ProxyTypeSet && // Set objects are atomic since they have no keys. + parentState!.type_ !== ProxyType.Set && // Set objects are atomic since they have no keys. !has((parentState as Exclude).assigned_!, prop) // Skip deep patches for assigned keys. ? rootPath!.concat(prop) : undefined diff --git a/src/core/proxy.ts b/src/core/proxy.ts index b906ff4c..00254366 100644 --- a/src/core/proxy.ts +++ b/src/core/proxy.ts @@ -15,8 +15,7 @@ import { DRAFT_STATE, die, createProxy, - ProxyTypeProxyObject, - ProxyTypeProxyArray + ProxyType } from "../internal" interface ProxyBaseState extends ImmerBaseState { @@ -28,14 +27,14 @@ interface ProxyBaseState extends ImmerBaseState { } export interface ProxyObjectState extends ProxyBaseState { - type_: typeof ProxyTypeProxyObject + type_: ProxyType.ProxyObject base_: any copy_: any draft_: Drafted } export interface ProxyArrayState extends ProxyBaseState { - type_: typeof ProxyTypeProxyArray + type_: ProxyType.ProxyArray base_: AnyArray copy_: AnyArray | null draft_: Drafted @@ -54,7 +53,7 @@ export function createProxyProxy( ): Drafted { const isArray = Array.isArray(base) const state: ProxyState = { - type_: isArray ? ProxyTypeProxyArray : (ProxyTypeProxyObject as any), + type_: isArray ? ProxyType.ProxyArray : (ProxyType.ProxyObject as any), // Track which produce call this is associated with. scope_: parent ? parent.scope_ : getCurrentScope()!, // True for both shallow and deep changes. @@ -187,7 +186,7 @@ export const objectTraps: ProxyHandler = { if (!desc) return desc return { writable: true, - configurable: state.type_ !== ProxyTypeProxyArray || prop !== "length", + configurable: state.type_ !== ProxyType.ProxyArray || prop !== "length", enumerable: desc.enumerable, value: owner[prop] } diff --git a/src/core/scope.ts b/src/core/scope.ts index 4505ea63..9cfd9ae9 100644 --- a/src/core/scope.ts +++ b/src/core/scope.ts @@ -5,8 +5,7 @@ import { Immer, DRAFT_STATE, ImmerState, - ProxyTypeProxyObject, - ProxyTypeProxyArray, + ProxyType, getPlugin } from "../internal" import {die} from "../utils/errors" @@ -78,8 +77,8 @@ export function enterScope(immer: Immer) { function revokeDraft(draft: Drafted) { const state: ImmerState = draft[DRAFT_STATE] if ( - state.type_ === ProxyTypeProxyObject || - state.type_ === ProxyTypeProxyArray + state.type_ === ProxyType.ProxyObject || + state.type_ === ProxyType.ProxyArray ) state.revoke_() else state.revoked_ = true diff --git a/src/plugins/es5.ts b/src/plugins/es5.ts index d0c3e02d..5cfa77f4 100644 --- a/src/plugins/es5.ts +++ b/src/plugins/es5.ts @@ -11,8 +11,7 @@ import { is, loadPlugin, ImmerScope, - ProxyTypeES5Array, - ProxyTypeES5Object, + ProxyType, getCurrentScope, die, markChanged, @@ -74,7 +73,7 @@ export function enableES5() { const draft = createES5Draft(isArray, base) const state: ES5ObjectState | ES5ArrayState = { - type_: isArray ? ProxyTypeES5Array : (ProxyTypeES5Object as any), + type_: isArray ? ProxyType.ES5Array : (ProxyType.ES5Object as any), scope_: parent ? parent.scope_ : getCurrentScope(), modified_: false, finalized_: false, @@ -139,10 +138,10 @@ export function enableES5() { const state: ES5State = drafts[i][DRAFT_STATE] if (!state.modified_) { switch (state.type_) { - case ProxyTypeES5Array: + case ProxyType.ES5Array: if (hasArrayChanges(state)) markChanged(state) break - case ProxyTypeES5Object: + case ProxyType.ES5Object: if (hasObjectChanges(state)) markChanged(state) break } @@ -155,7 +154,7 @@ export function enableES5() { const state: ES5State | undefined = object[DRAFT_STATE] if (!state) return const {base_, draft_, assigned_, type_} = state - if (type_ === ProxyTypeES5Object) { + if (type_ === ProxyType.ES5Object) { // Look for added keys. // probably there is a faster way to detect changes, as sweep + recurse seems to do some // unnecessary work. @@ -179,7 +178,7 @@ export function enableES5() { markChanged(state) } }) - } else if (type_ === ProxyTypeES5Array) { + } else if (type_ === ProxyType.ES5Array) { if (hasArrayChanges(state as ES5ArrayState)) { markChanged(state) assigned_.length = true @@ -253,7 +252,7 @@ export function enableES5() { } function hasChanges_(state: ES5State) { - return state.type_ === ProxyTypeES5Object + return state.type_ === ProxyType.ES5Object ? hasObjectChanges(state) : hasArrayChanges(state) } diff --git a/src/plugins/mapset.ts b/src/plugins/mapset.ts index 0be2ef67..6fbfd572 100644 --- a/src/plugins/mapset.ts +++ b/src/plugins/mapset.ts @@ -13,8 +13,7 @@ import { createProxy, loadPlugin, markChanged, - ProxyTypeMap, - ProxyTypeSet, + ProxyType, die, each } from "../internal" @@ -50,7 +49,7 @@ export function enableMapSet() { // Create class manually, cause #502 function DraftMap(this: any, target: AnyMap, parent?: ImmerState): any { this[DRAFT_STATE] = { - type_: ProxyTypeMap, + type_: ProxyType.Map, parent_: parent, scope_: parent ? parent.scope_ : getCurrentScope()!, modified_: false, @@ -208,7 +207,7 @@ export function enableMapSet() { // Create class manually, cause #502 function DraftSet(this: any, target: AnySet, parent?: ImmerState) { this[DRAFT_STATE] = { - type_: ProxyTypeSet, + type_: ProxyType.Set, parent_: parent, scope_: parent ? parent.scope_ : getCurrentScope()!, modified_: false, diff --git a/src/plugins/patches.ts b/src/plugins/patches.ts index bc3ba282..baa1516c 100644 --- a/src/plugins/patches.ts +++ b/src/plugins/patches.ts @@ -16,19 +16,11 @@ import { isSet, isMap, loadPlugin, - ProxyTypeProxyObject, - ProxyTypeES5Object, - ProxyTypeMap, - ProxyTypeES5Array, - ProxyTypeProxyArray, - ProxyTypeSet, - ArchtypeMap, - ArchtypeSet, - ArchtypeArray, + ProxyType, + Archtype, die, isDraft, - isDraftable, - ArchtypeObject + isDraftable } from "../internal" export function enablePatches() { @@ -43,19 +35,19 @@ export function enablePatches() { inversePatches: Patch[] ): void { switch (state.type_) { - case ProxyTypeProxyObject: - case ProxyTypeES5Object: - case ProxyTypeMap: + case ProxyType.ProxyObject: + case ProxyType.ES5Object: + case ProxyType.Map: return generatePatchesFromAssigned( state, basePath, patches, inversePatches ) - case ProxyTypeES5Array: - case ProxyTypeProxyArray: + case ProxyType.ES5Array: + case ProxyType.ProxyArray: return generateArrayPatches(state, basePath, patches, inversePatches) - case ProxyTypeSet: + case ProxyType.Set: return generateSetPatches( (state as any) as SetState, basePath, @@ -217,7 +209,7 @@ export function enablePatches() { const p = path[i] // See #738, avoid prototype pollution if ( - (parentType === ArchtypeObject || parentType === ArchtypeArray) && + (parentType === Archtype.Object || parentType === Archtype.Array) && (p === "__proto__" || p === "constructor") ) die(24) @@ -232,10 +224,10 @@ export function enablePatches() { switch (op) { case REPLACE: switch (type) { - case ArchtypeMap: + case Archtype.Map: return base.set(key, value) /* istanbul ignore next */ - case ArchtypeSet: + case Archtype.Set: die(16) default: // if value is an object, then it's assigned by reference @@ -246,22 +238,22 @@ export function enablePatches() { } case ADD: switch (type) { - case ArchtypeArray: + case Archtype.Array: return base.splice(key as any, 0, value) - case ArchtypeMap: + case Archtype.Map: return base.set(key, value) - case ArchtypeSet: + case Archtype.Set: return base.add(value) default: return (base[key] = value) } case REMOVE: switch (type) { - case ArchtypeArray: + case Archtype.Array: return base.splice(key as any, 1) - case ArchtypeMap: + case Archtype.Map: return base.delete(key) - case ArchtypeSet: + case Archtype.Set: return base.delete(patch.value) default: return delete base[key] diff --git a/src/types/types-internal.ts b/src/types/types-internal.ts index 7ebc7d81..d3bc5612 100644 --- a/src/types/types-internal.ts +++ b/src/types/types-internal.ts @@ -17,17 +17,21 @@ export type AnyArray = Array export type AnySet = Set export type AnyMap = Map -export const ArchtypeObject = 0 -export const ArchtypeArray = 1 -export const ArchtypeMap = 2 -export const ArchtypeSet = 3 +export const enum Archtype { + Object, + Array, + Map, + Set +} -export const ProxyTypeProxyObject = 0 -export const ProxyTypeProxyArray = 1 -export const ProxyTypeES5Object = 4 -export const ProxyTypeES5Array = 5 -export const ProxyTypeMap = 2 -export const ProxyTypeSet = 3 +export const enum ProxyType { + ProxyObject, + ProxyArray, + Map, + Set, + ES5Object, + ES5Array +} export interface ImmerBaseState { parent_?: ImmerState diff --git a/src/utils/common.ts b/src/utils/common.ts index f41ee0aa..dae5064e 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -9,10 +9,7 @@ import { AnySet, ImmerState, hasMap, - ArchtypeObject, - ArchtypeArray, - ArchtypeMap, - ArchtypeSet, + Archtype, die } from "../internal" @@ -47,8 +44,7 @@ export function isPlainObject(value: any): boolean { const Ctor = Object.hasOwnProperty.call(proto, "constructor") && proto.constructor - if (Ctor === Object) - return true + if (Ctor === Object) return true return ( typeof Ctor == "function" && @@ -92,7 +88,7 @@ export function each( enumerableOnly?: boolean ): void export function each(obj: any, iter: any, enumerableOnly = false) { - if (getArchtype(obj) === ArchtypeObject) { + if (getArchtype(obj) === Archtype.Object) { ;(enumerableOnly ? Object.keys : ownKeys)(obj).forEach(key => { if (!enumerableOnly || typeof key !== "symbol") iter(key, obj[key], obj) }) @@ -102,7 +98,7 @@ export function each(obj: any, iter: any, enumerableOnly = false) { } /*#__PURE__*/ -export function getArchtype(thing: any): 0 | 1 | 2 | 3 { +export function getArchtype(thing: any): Archtype { /* istanbul ignore next */ const state: undefined | ImmerState = thing[DRAFT_STATE] return state @@ -110,17 +106,17 @@ export function getArchtype(thing: any): 0 | 1 | 2 | 3 { ? state.type_ - 4 // cause Object and Array map back from 4 and 5 : (state.type_ as any) // others are the same : Array.isArray(thing) - ? ArchtypeArray + ? Archtype.Array : isMap(thing) - ? ArchtypeMap + ? Archtype.Map : isSet(thing) - ? ArchtypeSet - : ArchtypeObject + ? Archtype.Set + : Archtype.Object } /*#__PURE__*/ export function has(thing: any, prop: PropertyKey): boolean { - return getArchtype(thing) === ArchtypeMap + return getArchtype(thing) === Archtype.Map ? thing.has(prop) : Object.prototype.hasOwnProperty.call(thing, prop) } @@ -128,14 +124,14 @@ export function has(thing: any, prop: PropertyKey): boolean { /*#__PURE__*/ export function get(thing: AnyMap | AnyObject, prop: PropertyKey): any { // @ts-ignore - return getArchtype(thing) === ArchtypeMap ? thing.get(prop) : thing[prop] + return getArchtype(thing) === Archtype.Map ? thing.get(prop) : thing[prop] } /*#__PURE__*/ export function set(thing: any, propOrOldValue: PropertyKey, value: any) { const t = getArchtype(thing) - if (t === ArchtypeMap) thing.set(propOrOldValue, value) - else if (t === ArchtypeSet) { + if (t === Archtype.Map) thing.set(propOrOldValue, value) + else if (t === Archtype.Set) { thing.delete(propOrOldValue) thing.add(value) } else thing[propOrOldValue] = value diff --git a/src/utils/plugins.ts b/src/utils/plugins.ts index 6b2568ab..6c959acc 100644 --- a/src/utils/plugins.ts +++ b/src/utils/plugins.ts @@ -7,10 +7,7 @@ import { ImmerBaseState, AnyMap, AnySet, - ProxyTypeES5Array, - ProxyTypeES5Object, - ProxyTypeMap, - ProxyTypeSet, + ProxyType, die } from "../internal" @@ -74,14 +71,14 @@ interface ES5BaseState extends ImmerBaseState { } export interface ES5ObjectState extends ES5BaseState { - type_: typeof ProxyTypeES5Object + type_: ProxyType.ES5Object draft_: Drafted base_: AnyObject copy_: AnyObject | null } export interface ES5ArrayState extends ES5BaseState { - type_: typeof ProxyTypeES5Array + type_: ProxyType.ES5Array draft_: Drafted base_: any copy_: any @@ -90,7 +87,7 @@ export interface ES5ArrayState extends ES5BaseState { /** Map / Set plugin */ export interface MapState extends ImmerBaseState { - type_: typeof ProxyTypeMap + type_: ProxyType.Map copy_: AnyMap | undefined assigned_: Map | undefined base_: AnyMap @@ -99,7 +96,7 @@ export interface MapState extends ImmerBaseState { } export interface SetState extends ImmerBaseState { - type_: typeof ProxyTypeSet + type_: ProxyType.Set copy_: AnySet | undefined base_: AnySet drafts_: Map // maps the original value to the draft value in the new set