Skip to content

Commit

Permalink
Fix potential memory leak issue (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
lukePeavey authored Jul 3, 2022
1 parent 80910ae commit 4924584
Show file tree
Hide file tree
Showing 12 changed files with 200 additions and 122 deletions.
4 changes: 4 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ umd/*
dist/*
es/*
node_modules/*
storybook-static/*
private/*
examples/*
.vscode/*
__stories__/*
__tests__/*

1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"parserOptions": { "ecmaVersion": 12, "sourceType": "module" },
"rules": {
"no-lonely-if": 0,
"no-console": 0,
"no-plusplus": 0,
"no-param-reassign": 0,
"no-else-return": 0,
Expand Down
7 changes: 1 addition & 6 deletions __stories__/assets/stories.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,14 @@ body {
color: var(--color-default-fg);
}

.container {
margin: 16px;
padding: 16px;
}

*,
*::before,
*::after {
box-sizing: border-box;
}

.container {
margin: 16px;
margin: 0;
padding: 16px;
width: 100%;
max-width: 732px;
Expand Down
3 changes: 2 additions & 1 deletion __stories__/components/Example.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,11 @@
// Split the the target element(s) using the provided options
instance = SplitType.create('.target', options)
resizeObserver.observe(containerElement)
console.log(instance)
})
onDestroy(() => {
// Cleanup splitType instance
instance.revert()
resizeObserver.disconnect()
})
</script>
Expand Down
53 changes: 50 additions & 3 deletions __tests__/utils/Data.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,54 @@
import { Data, removeData } from '../../lib/Data'
import * as data from '../../lib/Data'

const owner = document.createElement('div')

afterEach(() => {
data.remove(owner)
})

describe(`Data(owner)`, () => {
it(`Returns empty object when owner is undefined`, () => {
expect(Data(undefined)).toEqual({})
it(`data.get(undefined) returns empty object`, () => {
expect(data.get(undefined)).toEqual({})
})
it(`data.set(owner, key, value) works as expected`, () => {
// Make sure data store is empty at start of test
expect(data.cache).toEqual({})
data.set(owner, 'foo', 'bar')
expect(data.cache[owner[data.expando]]).toEqual({ foo: 'bar' })
data.set(owner, 'hello', 'world')
expect(data.cache[owner[data.expando]]).toEqual({
foo: 'bar',
hello: 'world',
})
})
it(`data.set(owner, objectMap) works as expected`, () => {
// Make sure data store is empty at start of test
expect(data.cache).toEqual({})
data.set(owner, {
foo: 'bar',
hello: 'world',
})
expect(data.cache[owner[data.expando]]).toEqual({
foo: 'bar',
hello: 'world',
})
})

it(`data.get(owner) returns data object `, () => {
// Make sure data store is empty at start of test
expect(data.get(owner)).toEqual({})
// Set multiple properties by passing an object as the second arg
data.set(owner, {
foo: 'bar',
hello: 'world',
})
// Set an additional property using the (owner, key, value) syntax
data.set(owner, 'other', 'value')
// data.get(owner) should return an object with the the expected props
expect(data.get(owner)).toEqual({
foo: 'bar',
hello: 'world',
other: 'value',
})
})
})
64 changes: 42 additions & 22 deletions lib/Data.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import isObject from './utils/isObject'
import { entries } from './utils/object'

export const expando = `_splittype`
export const cache = {}
let uid = 0

/**
* Stores data associated with DOM elements or other objects. This is a
Expand All @@ -23,37 +28,52 @@ import isObject from './utils/isObject'
* @param {string} key
* @param {any} value
*/
export function Data(owner, key, value) {
let data = {}
let id = null

if (isObject(owner)) {
id = owner[Data.expando] || (owner[Data.expando] = ++Data.uid)
data = Data.cache[id] || (Data.cache[id] = {})
export function set(owner, key, value) {
if (!isObject(owner)) {
console.warn('[data.set] owner is not an object')
return null
}
// Get data
const id = owner[expando] || (owner[expando] = ++uid)
const data = cache[id] || (cache[id] = {})

if (value === undefined) {
if (key === undefined) {
return data
if (!!key && Object.getPrototypeOf(key) === Object.prototype) {
cache[id] = { ...data, ...key }
}
return data[key]
}
// Set data
else if (key !== undefined) {
} else if (key !== undefined) {
data[key] = value
return value
}
return value
}

Data.expando = `splitType${new Date() * 1}`
Data.cache = {}
Data.uid = 0
export function get(owner, key) {
const id = isObject(owner) ? owner[expando] : null
const data = (id && cache[id]) || {}
if (key === undefined) {
return data
}
return data[key]
}

// Remove all data associated with the given element
export function RemoveData(element) {
const id = element && element[Data.expando]
/**
* Remove all data associated with the given element
*/
export function remove(element) {
const id = element && element[expando]
if (id) {
delete element[id]
delete Data.cache[id]
delete cache[id]
}
}

/**
* Remove all temporary data from the store.
*/
export function cleanup() {
entries(cache).forEach(([id, { isRoot, isSplit }]) => {
if (!isRoot || !isSplit) {
cache[id] = null
delete cache[id]
}
})
}
Loading

0 comments on commit 4924584

Please sign in to comment.