Skip to content

Commit

Permalink
chore: reduce size by using TS const enum (#812)
Browse files Browse the repository at this point in the history
  • Loading branch information
houfeng0923 committed Jun 24, 2021
1 parent 0dc1d2e commit b1fac9d
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 93 deletions.
9 changes: 4 additions & 5 deletions src/core/current.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import {
set,
ImmerState,
isDraftable,
ArchtypeMap,
ArchtypeSet,
Archtype,
getArchtype,
getPlugin
} from "../internal"
Expand Down Expand Up @@ -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)
}
Expand Down
10 changes: 4 additions & 6 deletions src/core/finalize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ import {
isDraft,
SetState,
set,
ProxyTypeES5Object,
ProxyTypeES5Array,
ProxyTypeSet,
ProxyType,
getPlugin,
die,
revokeScope,
Expand Down Expand Up @@ -84,15 +82,15 @@ 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
// For sets we clone before iterating, otherwise we can get in endless loop due to modifying during iteration, see #628
// 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)
)
Expand Down Expand Up @@ -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<ImmerState, SetState>).assigned_!, prop) // Skip deep patches for assigned keys.
? rootPath!.concat(prop)
: undefined
Expand Down
11 changes: 5 additions & 6 deletions src/core/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ import {
DRAFT_STATE,
die,
createProxy,
ProxyTypeProxyObject,
ProxyTypeProxyArray
ProxyType
} from "../internal"

interface ProxyBaseState extends ImmerBaseState {
Expand All @@ -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<AnyObject, ProxyObjectState>
}

export interface ProxyArrayState extends ProxyBaseState {
type_: typeof ProxyTypeProxyArray
type_: ProxyType.ProxyArray
base_: AnyArray
copy_: AnyArray | null
draft_: Drafted<AnyArray, ProxyArrayState>
Expand All @@ -54,7 +53,7 @@ export function createProxyProxy<T extends Objectish>(
): Drafted<T, ProxyState> {
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.
Expand Down Expand Up @@ -187,7 +186,7 @@ export const objectTraps: ProxyHandler<ProxyState> = {
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]
}
Expand Down
7 changes: 3 additions & 4 deletions src/core/scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import {
Immer,
DRAFT_STATE,
ImmerState,
ProxyTypeProxyObject,
ProxyTypeProxyArray,
ProxyType,
getPlugin
} from "../internal"
import {die} from "../utils/errors"
Expand Down Expand Up @@ -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
Expand Down
15 changes: 7 additions & 8 deletions src/plugins/es5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import {
is,
loadPlugin,
ImmerScope,
ProxyTypeES5Array,
ProxyTypeES5Object,
ProxyType,
getCurrentScope,
die,
markChanged,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
}
Expand All @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -253,7 +252,7 @@ export function enableES5() {
}

function hasChanges_(state: ES5State) {
return state.type_ === ProxyTypeES5Object
return state.type_ === ProxyType.ES5Object
? hasObjectChanges(state)
: hasArrayChanges(state)
}
Expand Down
7 changes: 3 additions & 4 deletions src/plugins/mapset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import {
createProxy,
loadPlugin,
markChanged,
ProxyTypeMap,
ProxyTypeSet,
ProxyType,
die,
each
} from "../internal"
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
44 changes: 18 additions & 26 deletions src/plugins/patches.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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,
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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]
Expand Down
24 changes: 14 additions & 10 deletions src/types/types-internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,21 @@ export type AnyArray = Array<any>
export type AnySet = Set<any>
export type AnyMap = Map<any, any>

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
Expand Down
Loading

0 comments on commit b1fac9d

Please sign in to comment.