Skip to content

Commit

Permalink
fix: Map and Set instantions won't work on certain environments, fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
mweststrate committed Jan 10, 2020
2 parents 49ff121 + 7639c29 commit 9f4711a
Show file tree
Hide file tree
Showing 18 changed files with 309 additions and 186 deletions.
16 changes: 15 additions & 1 deletion __tests__/base.js
@@ -1,6 +1,6 @@
"use strict"
import {Immer, nothing, original, isDraft, immerable} from "../src/index"
import {each, shallowCopy, isEnumerable, DRAFT_STATE} from "../src/common"
import {each, shallowCopy, isEnumerable, DRAFT_STATE} from "../src/internal"
import deepFreeze from "deep-freeze"
import cloneDeep from "lodash.clonedeep"
import * as lodash from "lodash"
Expand Down Expand Up @@ -582,6 +582,13 @@ function runBaseTest(name, useProxies, autoFreeze, useListener) {
expect(entries[0][0]).toBe(key)
expect(entries[0][0].a).toBe(2)
})

it("does support instanceof Map", () => {
const map = new Map()
produce(map, d => {
expect(d instanceof Map).toBeTruthy()
})
})
})

describe("set drafts", () => {
Expand Down Expand Up @@ -849,6 +856,13 @@ function runBaseTest(name, useProxies, autoFreeze, useListener) {
"Cannot use a proxy that has been revoked"
)
})

it("does support instanceof Set", () => {
const set = new Set()
produce(set, d => {
expect(d instanceof Set).toBeTruthy()
})
})
})

it("supports `immerable` symbol on constructor", () => {
Expand Down
3 changes: 2 additions & 1 deletion __tests__/empty.ts
@@ -1,5 +1,5 @@
import {produce, produceWithPatches, setUseProxies} from "../src"
import {DRAFT_STATE} from "../src/common"
import {DRAFT_STATE} from "../src/internal"

test("empty stub test", () => {
expect(true).toBe(true)
Expand All @@ -10,6 +10,7 @@ describe("map set - es5", () => {
setUseProxies(false)

const baseState = new Map([["x", 1]])
debugger
const nextState = produce(baseState, s => {
s.set("x", 2)
})
Expand Down
2 changes: 1 addition & 1 deletion __tests__/polyfills.js
Expand Up @@ -7,7 +7,7 @@ Object.assign = undefined
Reflect.ownKeys = undefined

jest.resetModules()
const common = require("../src/common")
const common = require("../src/internal")

// Reset the globals to avoid unintended effects.
Symbol = SymbolConstructor
Expand Down
46 changes: 6 additions & 40 deletions src/common.ts
@@ -1,4 +1,7 @@
import {
DRAFT_STATE,
DRAFTABLE,
hasSet,
Objectish,
Drafted,
AnyObject,
Expand All @@ -7,46 +10,9 @@ import {
AnySet,
ImmerState,
ProxyType,
Archtype
} from "./types"

/** Use a class type for `nothing` so its type is unique */
export class Nothing {
// This lets us do `Exclude<T, Nothing>`
// @ts-ignore
private _!: unique symbol
}

const hasSymbol = typeof Symbol !== "undefined"
export const hasMap = typeof Map !== "undefined"
export const hasSet = typeof Set !== "undefined"

/**
* The sentinel value returned by producers to replace the draft with undefined.
*/
export const NOTHING: Nothing = hasSymbol
? Symbol("immer-nothing")
: ({["immer-nothing"]: true} as any)

/**
* To let Immer treat your class instances as plain immutable objects
* (albeit with a custom prototype), you must define either an instance property
* or a static property on each of your custom classes.
*
* Otherwise, your class instance will never be drafted, which means it won't be
* safe to mutate in a produce callback.
*/
export const DRAFTABLE: unique symbol = hasSymbol
? Symbol("immer-draftable")
: ("__$immer_draftable" as any)

export const DRAFT_STATE: unique symbol = hasSymbol
? Symbol("immer-state")
: ("__$immer_state" as any)

export const iteratorSymbol: typeof Symbol.iterator = hasSymbol
? Symbol.iterator
: ("@@iterator" as any)
Archtype,
hasMap
} from "./internal"

/** Returns true if the given value is an Immer draft */
export function isDraft(value: any): boolean {
Expand Down
40 changes: 40 additions & 0 deletions src/env.ts
@@ -0,0 +1,40 @@
// Should be no imports here!

// SOme things that should be evaluated before all else...
const hasSymbol = typeof Symbol !== "undefined"
export const hasMap = typeof Map !== "undefined"
export const hasSet = typeof Set !== "undefined"

/**
* The sentinel value returned by producers to replace the draft with undefined.
*/
export const NOTHING: Nothing = hasSymbol
? Symbol("immer-nothing")
: ({["immer-nothing"]: true} as any)

/**
* To let Immer treat your class instances as plain immutable objects
* (albeit with a custom prototype), you must define either an instance property
* or a static property on each of your custom classes.
*
* Otherwise, your class instance will never be drafted, which means it won't be
* safe to mutate in a produce callback.
*/
export const DRAFTABLE: unique symbol = hasSymbol
? Symbol("immer-draftable")
: ("__$immer_draftable" as any)

export const DRAFT_STATE: unique symbol = hasSymbol
? Symbol("immer-state")
: ("__$immer_state" as any)

export const iteratorSymbol: typeof Symbol.iterator = hasSymbol
? Symbol.iterator
: ("@@iterator" as any)

/** Use a class type for `nothing` so its type is unique */
export class Nothing {
// This lets us do `Exclude<T, Nothing>`
// @ts-ignore
private _!: unique symbol
}
17 changes: 7 additions & 10 deletions src/es5.ts
Expand Up @@ -7,23 +7,20 @@ import {
isDraftable,
isEnumerable,
shallowCopy,
DRAFT_STATE,
latest,
createHiddenProperty
} from "./common"

import {ImmerScope} from "./scope"
import {
createHiddenProperty,
ImmerScope,
ImmerState,
Drafted,
AnyObject,
Objectish,
ImmerBaseState,
AnyArray,
ProxyType
} from "./types"
import {MapState} from "./map"
import {SetState} from "./set"
ProxyType,
MapState,
SetState,
DRAFT_STATE
} from "./internal"

interface ES5BaseState extends ImmerBaseState {
finalizing: boolean
Expand Down
23 changes: 23 additions & 0 deletions src/extends.ts
@@ -0,0 +1,23 @@
var extendStatics = function(d: any, b: any): any {
extendStatics =
Object.setPrototypeOf ||
({__proto__: []} instanceof Array &&
function(d, b) {
d.__proto__ = b
}) ||
function(d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]
}
return extendStatics(d, b)
}

// Ugly hack to resolve #502 and inherit built in Map / Set
export function __extends(d: any, b: any): any {
extendStatics(d, b)
function __(this: any): any {
this.constructor = d
}
d.prototype =
// @ts-ignore
((__.prototype = b.prototype), new __())
}
30 changes: 17 additions & 13 deletions src/finalize.ts
@@ -1,21 +1,25 @@
import {Immer} from "./immer"
import {ImmerState, Drafted, ProxyType} from "./types"
import {ImmerScope} from "./scope"
import {
isSet,
has,
is,
get,
each,
Immer,
ImmerScope,
DRAFT_STATE,
isDraftable,
NOTHING,
Drafted,
PatchPath,
ProxyType,
each,
has,
freeze,
generatePatches,
shallowCopy,
set
} from "./common"
import {isDraft, isDraftable} from "./index"
import {SetState} from "./set"
import {generatePatches, PatchPath} from "./patches"
ImmerState,
isSet,
isDraft,
SetState,
set,
is,
get
} from "./internal"

export function processResult(immer: Immer, result: any, scope: ImmerScope) {
const baseDraft = scope.drafts![0]
Expand Down
45 changes: 23 additions & 22 deletions src/immer.ts
@@ -1,31 +1,32 @@
import {createES5Proxy, willFinalizeES5, markChangedES5} from "./es5"
import {createProxy, markChanged} from "./proxy"

import {applyPatches} from "./patches"
import {
createES5Proxy,
willFinalizeES5,
markChangedES5,
IProduceWithPatches,
IProduce,
ImmerState,
each,
isDraft,
isSet,
isMap,
Drafted,
isDraftable,
DRAFT_STATE,
ImmerScope,
processResult,
NOTHING,
die
} from "./common"
import {ImmerScope} from "./scope"
import {
ImmerState,
IProduce,
IProduceWithPatches,
maybeFreeze,
die,
Patch,
Objectish,
PatchListener,
DRAFT_STATE,
Draft,
Patch,
Drafted
} from "./types"
import {proxyMap} from "./map"
import {proxySet} from "./set"
import {processResult, maybeFreeze} from "./finalize"
PatchListener,
isDraft,
applyPatches,
isMap,
proxyMap,
isSet,
proxySet,
createProxy,
markChanged
} from "./internal"

/* istanbul ignore next */
function verifyMinified() {}
Expand Down
23 changes: 12 additions & 11 deletions src/index.ts
@@ -1,7 +1,16 @@
import {Immer} from "./immer"
import {IProduce, IProduceWithPatches} from "./types"
import {IProduce, IProduceWithPatches, Immer} from "./internal"

export {Draft, Immutable, Patch, PatchListener} from "./types"
export {
Draft,
Immutable,
Patch,
PatchListener,
original,
isDraft,
isDraftable,
NOTHING as nothing,
DRAFTABLE as immerable
} from "./internal"

const immer = new Immer()

Expand Down Expand Up @@ -73,12 +82,4 @@ export const createDraft = immer.createDraft.bind(immer)
*/
export const finishDraft = immer.finishDraft.bind(immer)

export {
original,
isDraft,
isDraftable,
NOTHING as nothing,
DRAFTABLE as immerable
} from "./common"

export {Immer}
12 changes: 12 additions & 0 deletions src/internal.ts
@@ -0,0 +1,12 @@
export * from "./env"
export * from "./extends"
export * from "./types"
export * from "./common"
export * from "./scope"
export * from "./finalize"
export * from "./proxy"
export * from "./es5"
export * from "./map"
export * from "./set"
export * from "./patches"
export * from "./immer"

0 comments on commit 9f4711a

Please sign in to comment.