-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Chris Garrett
committed
May 10, 2020
1 parent
68757d6
commit 2e06a87
Showing
11 changed files
with
279 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,27 @@ | ||
'use strict'; | ||
|
||
module.exports = { | ||
name: require('./package').name | ||
name: require('./package').name, | ||
|
||
included() { | ||
this._super.included.apply(this, arguments); | ||
|
||
this.import('vendor/ember-cache-primitive-polyfill.js'); | ||
}, | ||
|
||
treeForVendor(rawVendorTree) { | ||
let babelAddon = this.addons.find( | ||
addon => addon.name === 'ember-cli-babel' | ||
); | ||
|
||
let transpiledVendorTree = babelAddon.transpileTree(rawVendorTree, { | ||
babel: this.options.babel, | ||
|
||
'ember-cli-babel': { | ||
compileModules: false, | ||
}, | ||
}); | ||
|
||
return transpiledVendorTree; | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import { module, test } from 'qunit'; | ||
|
||
import { DEBUG } from '@glimmer/env'; | ||
import { tracked } from '@glimmer/tracking'; | ||
import { createCache, getValue, isConst } from '@glimmer/tracking/primitives/cache'; | ||
|
||
class Tag { | ||
@tracked __tag__; | ||
} | ||
|
||
function createTag() { | ||
return new Tag(); | ||
} | ||
|
||
function consumeTag(tag) { | ||
tag.__tag__; | ||
} | ||
|
||
function dirtyTag(tag) { | ||
tag.__tag__ = undefined; | ||
} | ||
|
||
module('tracking cache', () => { | ||
test('it memoizes based on tags that are consumed within a track frame', assert => { | ||
let tag1 = createTag(); | ||
let tag2 = createTag(); | ||
let count = 0; | ||
|
||
let cache = createCache(() => { | ||
consumeTag(tag1); | ||
consumeTag(tag2); | ||
|
||
return ++count; | ||
}); | ||
|
||
assert.equal(getValue(cache), 1, 'called correctly the first time'); | ||
assert.equal(getValue(cache), 1, 'memoized result returned second time'); | ||
|
||
dirtyTag(tag1); | ||
assert.equal(getValue(cache), 2, 'cache busted when tag1 dirtied'); | ||
assert.equal(getValue(cache), 2, 'memoized result returned when nothing dirtied'); | ||
|
||
dirtyTag(tag2); | ||
assert.equal(getValue(cache), 3, 'cache busted when tag2 dirtied'); | ||
assert.equal(getValue(cache), 3, 'memoized result returned when nothing dirtied'); | ||
}); | ||
|
||
test('nested memoizations work, and automatically propogate', assert => { | ||
let innerTag = createTag(); | ||
let outerTag = createTag(); | ||
|
||
let innerCount = 0; | ||
let outerCount = 0; | ||
|
||
let innerCache = createCache(() => { | ||
consumeTag(innerTag); | ||
|
||
return ++innerCount; | ||
}); | ||
|
||
let outerCache = createCache(() => { | ||
consumeTag(outerTag); | ||
|
||
return [++outerCount, getValue(innerCache)]; | ||
}); | ||
|
||
assert.deepEqual( | ||
getValue(outerCache), | ||
[1, 1], | ||
'both functions called correctly the first time' | ||
); | ||
assert.deepEqual(getValue(outerCache), [1, 1], 'memoized result returned correctly'); | ||
|
||
dirtyTag(outerTag); | ||
|
||
assert.deepEqual( | ||
getValue(outerCache), | ||
[2, 1], | ||
'outer result updated, inner result still memoized' | ||
); | ||
assert.deepEqual(getValue(outerCache), [2, 1], 'memoized result returned correctly'); | ||
|
||
dirtyTag(innerTag); | ||
|
||
assert.deepEqual(getValue(outerCache), [3, 2], 'both inner and outer result updated'); | ||
assert.deepEqual(getValue(outerCache), [3, 2], 'memoized result returned correctly'); | ||
}); | ||
|
||
test('isConst allows users to check if a memoized function is constant', assert => { | ||
let tag = createTag(); | ||
|
||
let constCache = createCache(() => { | ||
// do nothing; | ||
}); | ||
|
||
let nonConstCache = createCache(() => { | ||
consumeTag(tag); | ||
}); | ||
|
||
getValue(constCache); | ||
getValue(nonConstCache); | ||
|
||
assert.ok(isConst(constCache), 'constant cache returns true'); | ||
assert.notOk(isConst(nonConstCache), 'non-constant cache returns false'); | ||
}); | ||
|
||
if (DEBUG) { | ||
test('isConst throws an error in DEBUG mode if users attempt to check a function before it has been called', assert => { | ||
let cache = createCache(() => { | ||
// do nothing; | ||
}); | ||
|
||
assert.throws( | ||
() => isConst(cache), | ||
/isConst\(\) can only be used on a cache once getValue\(\) has been called at least once/ | ||
); | ||
}); | ||
|
||
test('isConst throws an error in DEBUG mode if users attempt to use with a non-cache', assert => { | ||
assert.throws( | ||
() => isConst(123), | ||
/isConst\(\) can only be used on an instance of a cache created with createCache\(\). Called with: 123/ | ||
); | ||
}); | ||
|
||
test('getValue throws an error in DEBUG mode if users to use with a non-cache', assert => { | ||
assert.throws( | ||
() => getValue(123), | ||
/getValue\(\) can only be used on an instance of a cache created with createCache\(\). Called with: 123/ | ||
); | ||
}); | ||
} | ||
}); |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import Ember from 'ember'; | ||
import { DEBUG } from '@glimmer/env'; | ||
import { assert } from '@ember/debug'; | ||
import { gte } from 'ember-compatibility-helpers'; | ||
|
||
(function() { | ||
let track, valueForTag, validateTag, consumeTag, isConstTag; | ||
|
||
if (gte('3.17.0-beta.1')) { | ||
let validator = Ember.__loader.require('@glimmer/validator'); | ||
|
||
track = validator.track; | ||
valueForTag = validator.valueForTag || validator.value; | ||
validateTag = validator.validateTag || validator.validate; | ||
consumeTag = validator.consumeTag || validator.consume; | ||
isConstTag = validator.isConstTag; | ||
} else if (gte('3.13.0-beta.1')) { | ||
let metal = Ember.__loader.require('@ember/-internals/metal'); | ||
let reference = Ember.__loader.require('@glimmer/reference'); | ||
|
||
track = metal.track; | ||
valueForTag = reference.value; | ||
validateTag = reference.validate; | ||
consumeTag = reference.consume; | ||
isConstTag = reference.isConstTag; | ||
} else if (DEBUG) { | ||
throw new Error('Attempted to use cache polyfill with unsupported Ember version'); | ||
} | ||
|
||
let DEBUG_CACHE; | ||
|
||
if (DEBUG) { | ||
DEBUG_CACHE = Symbol('DEBUG_CACHE'); | ||
} | ||
|
||
class Cache { | ||
lastValue; | ||
tag; | ||
snapshot = -1; | ||
|
||
constructor(fn) { | ||
this.fn = fn; | ||
|
||
if (DEBUG) { | ||
return { [DEBUG_CACHE]: this }; | ||
} | ||
} | ||
} | ||
|
||
Ember._createCache = function createCache(fn) { | ||
return new Cache(fn); | ||
} | ||
|
||
Ember._cacheGetValue = function getValue(cache) { | ||
if (DEBUG) { | ||
assert( | ||
`getValue() can only be used on an instance of a cache created with createCache(). Called with: ${String( | ||
cache | ||
)}`, | ||
cache[DEBUG_CACHE] instanceof Cache | ||
); | ||
|
||
cache = cache[DEBUG_CACHE]; | ||
} | ||
|
||
let { tag, snapshot, fn } = cache; | ||
|
||
if (tag === undefined || !validateTag(tag, snapshot)) { | ||
tag = track(() => (cache.lastValue = fn())); | ||
cache.tag = tag; | ||
cache.snapshot = valueForTag(tag); | ||
consumeTag(tag); | ||
} else { | ||
consumeTag(tag); | ||
} | ||
|
||
return cache.lastValue; | ||
} | ||
|
||
Ember._cacheIsConst = function isConst(cache) { | ||
if (DEBUG) { | ||
assert( | ||
`isConst() can only be used on an instance of a cache created with createCache(). Called with: ${String( | ||
cache | ||
)}`, | ||
cache[DEBUG_CACHE] instanceof Cache | ||
); | ||
|
||
cache = cache[DEBUG_CACHE]; | ||
|
||
assert( | ||
`isConst() can only be used on a cache once getValue() has been called at least once. Called with cache function:\n\n${String( | ||
cache.fn | ||
)}`, | ||
cache.tag | ||
); | ||
} | ||
|
||
return isConstTag(cache.tag); | ||
} | ||
})(); | ||
|
||
define('@glimmer/tracking/primitives/cache', ['exports'], (exports) => { | ||
exports.createCache = Ember._createCache; | ||
exports.getValue = Ember._cacheGetValue; | ||
exports.isConst = Ember._cacheIsConst; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters