From 87d299f462328e5a995f409517bc50e698785811 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 16 Dec 2018 03:02:23 -0500 Subject: [PATCH 01/12] Remove extra .gitkeep files. --- addon/.gitkeep | 0 app/.gitkeep | 0 vendor/.gitkeep | 0 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 addon/.gitkeep delete mode 100644 app/.gitkeep delete mode 100644 vendor/.gitkeep diff --git a/addon/.gitkeep b/addon/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/app/.gitkeep b/app/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/vendor/.gitkeep b/vendor/.gitkeep deleted file mode 100644 index e69de29..0000000 From 9b30b6482f22796e2f68607ea3aace76c5e71a95 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 16 Dec 2018 03:02:37 -0500 Subject: [PATCH 02/12] Add basic vendor transpilation and shouldPolyyfill... --- index.js | 40 +++++++++++++++++++++++ package.json | 4 ++- vendor/ember-modifier-manager-polyfill.js | 6 ++++ yarn.lock | 13 ++++++-- 4 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 vendor/ember-modifier-manager-polyfill.js diff --git a/index.js b/index.js index 0ca063d..375c837 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,45 @@ 'use strict'; +const VersionChecker = require('ember-cli-version-checker'); + module.exports = { name: require('./package').name, + + init() { + this._super.init && this._super.init.apply(this, arguments); + + let checker = new VersionChecker(this.project); + let emberVersion = checker.forEmber(); + + this.shouldPolyfill = emberVersion.lt('3.8.0-alpha.1'); + }, + + included() { + this._super.included.apply(this, arguments); + + if (!this.shouldPolyfill) { + return; + } + + this.import('vendor/ember-modifier-manager-polyfill.js'); + }, + + treeForVendor(rawVendorTree) { + if (!this.shouldPolyfill) { + return; + } + + 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; + }, }; + diff --git a/package.json b/package.json index f0b1c7a..399c4c9 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,9 @@ "test:all": "ember try:each" }, "dependencies": { - "ember-cli-babel": "^7.4.0" + "ember-cli-babel": "^7.4.0", + "ember-cli-version-checker": "^2.1.2", + "ember-compatibility-helpers": "^1.2.0-beta.1" }, "devDependencies": { "@ember/optional-features": "^0.7.0", diff --git a/vendor/ember-modifier-manager-polyfill.js b/vendor/ember-modifier-manager-polyfill.js new file mode 100644 index 0000000..58c75f1 --- /dev/null +++ b/vendor/ember-modifier-manager-polyfill.js @@ -0,0 +1,6 @@ +import { lte, gte } from 'ember-compatibility-helpers'; + +(() => { + 'use strict'; + +})(); diff --git a/yarn.lock b/yarn.lock index e2ecd12..2b97377 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1153,7 +1153,7 @@ babel-plugin-debug-macros@^0.1.10: dependencies: semver "^5.3.0" -babel-plugin-debug-macros@^0.2.0-beta.6: +babel-plugin-debug-macros@^0.2.0, babel-plugin-debug-macros@^0.2.0-beta.6: version "0.2.0" resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.2.0.tgz#0120ac20ce06ccc57bf493b667cf24b85c28da7a" integrity sha512-Wpmw4TbhR3Eq2t3W51eBAQSdKlr+uAyF0GI4GtPfMCD12Y4cIdpKC9l0RjNTH/P9isFypSqqewMPm7//fnZlNA== @@ -2953,7 +2953,7 @@ ember-cli-test-loader@^2.2.0: dependencies: ember-cli-babel "^6.8.1" -ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-version-checker@^2.1.2: +ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-version-checker@^2.1.1, ember-cli-version-checker@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-2.1.2.tgz#305ce102390c66e4e0f1432dea9dc5c7c19fed98" integrity sha512-sjkHGr4IGXnO3EUcY21380Xo9Qf6bC8HWH4D62bVnrQop/8uha5XgMQRoAflMCeH6suMrezQL287JUoYc2smEw== @@ -3057,6 +3057,15 @@ ember-cli@~3.7.1: watch-detector "^0.1.0" yam "^1.0.0" +ember-compatibility-helpers@^1.2.0-beta.1: + version "1.2.0-beta.1" + resolved "https://registry.yarnpkg.com/ember-compatibility-helpers/-/ember-compatibility-helpers-1.2.0-beta.1.tgz#cd5898734f398f977707cbf8d448689377449180" + integrity sha512-ewKxBP0DIcbuMyGR8P+ned3H6vgCI5+2t+5MOwcaIFxRYUx6Bm0Dqk6Y8UWzwVgkxlZspC34k8QE/QLlSI7oiA== + dependencies: + babel-plugin-debug-macros "^0.2.0" + ember-cli-version-checker "^2.1.1" + semver "^5.4.1" + ember-disable-prototype-extensions@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e" From 75049e87c7ca508d8965c12528e2af97eb16b515 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 16 Dec 2018 03:18:01 -0500 Subject: [PATCH 03/12] Add basic test for modifier manager API. --- .../components/modifier-manager-test.js | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 tests/integration/components/modifier-manager-test.js diff --git a/tests/integration/components/modifier-manager-test.js b/tests/integration/components/modifier-manager-test.js new file mode 100644 index 0000000..49801a7 --- /dev/null +++ b/tests/integration/components/modifier-manager-test.js @@ -0,0 +1,47 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; +import Ember from 'ember'; + +module('Integration | Component | modifier-manager', function(hooks) { + setupRenderingTest(hooks); + + class ModifierManager { + constructor(owner) { + this.owner = owner; + } + + createModifier(factory, args) { + return factory.create(args); + } + + installModifier(instance, element, args) { + instance.element = element; + let { positional, named } = args; + instance.didInsertElement(positional, named); + } + + updateModifier(instance, args) { + let { positional, named } = args; + instance.didUpdate(positional, named); + } + + destroyModifier(instance) { + instance.willDestroyElement(); + } + } + + test('it basically works', async function(assert) { + Ember._setModifierManager( + owner => new ModifierManager(owner), + class DidInsertModifier { + } + ); + this.owner.register('modifier-manager:did-insert'); + + await render(hbs`
`); + + assert.equal(this.element.textContent.trim(), ''); + }); +}); From 1f38ebf6137038f1ac9503970580966c9e3daa8b Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 27 Jan 2019 15:47:12 -0500 Subject: [PATCH 04/12] Linting fixups. --- index.js | 1 - tests/integration/components/modifier-manager-test.js | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/index.js b/index.js index 375c837..77a51e2 100644 --- a/index.js +++ b/index.js @@ -42,4 +42,3 @@ module.exports = { return transpiledVendorTree; }, }; - diff --git a/tests/integration/components/modifier-manager-test.js b/tests/integration/components/modifier-manager-test.js index 49801a7..2694563 100644 --- a/tests/integration/components/modifier-manager-test.js +++ b/tests/integration/components/modifier-manager-test.js @@ -33,11 +33,7 @@ module('Integration | Component | modifier-manager', function(hooks) { } test('it basically works', async function(assert) { - Ember._setModifierManager( - owner => new ModifierManager(owner), - class DidInsertModifier { - } - ); + Ember._setModifierManager(owner => new ModifierManager(owner), class DidInsertModifier {}); this.owner.register('modifier-manager:did-insert'); await render(hbs`
`); From 2d1ff0c884c1b70950450ea0b330afc2a577c2dc Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 27 Jan 2019 18:13:02 -0500 Subject: [PATCH 05/12] Implement basic functionality for 3.7 --- .../components/modifier-manager-test.js | 203 +++++++++++++++--- vendor/ember-modifier-manager-polyfill.js | 155 ++++++++++++- 2 files changed, 325 insertions(+), 33 deletions(-) diff --git a/tests/integration/components/modifier-manager-test.js b/tests/integration/components/modifier-manager-test.js index 2694563..83ea967 100644 --- a/tests/integration/components/modifier-manager-test.js +++ b/tests/integration/components/modifier-manager-test.js @@ -7,37 +7,176 @@ import Ember from 'ember'; module('Integration | Component | modifier-manager', function(hooks) { setupRenderingTest(hooks); - class ModifierManager { - constructor(owner) { - this.owner = owner; - } - - createModifier(factory, args) { - return factory.create(args); - } - - installModifier(instance, element, args) { - instance.element = element; - let { positional, named } = args; - instance.didInsertElement(positional, named); - } - - updateModifier(instance, args) { - let { positional, named } = args; - instance.didUpdate(positional, named); - } - - destroyModifier(instance) { - instance.willDestroyElement(); - } - } - - test('it basically works', async function(assert) { - Ember._setModifierManager(owner => new ModifierManager(owner), class DidInsertModifier {}); - this.owner.register('modifier-manager:did-insert'); - - await render(hbs`
`); - - assert.equal(this.element.textContent.trim(), ''); + module('installModifier', function(hooks) { + hooks.beforeEach(function() { + class DidInsertModifier {} + + Ember._setModifierManager(DidInsertModifier, () => ({ + createModifier(_factory, args) { + return args.positional[0]; + }, + + installModifier(_state, element, args) { + let [fn, ...positional] = args.positional; + + fn(element, positional, args.named); + }, + + updateModifier() {}, + destroyModifier() {}, + })); + this.owner.register('modifier:did-insert', DidInsertModifier); + }); + + test('it basically works', async function(assert) { + assert.expect(2); + + this.someMethod = element => { + assert.equal(element.tagName, 'DIV', 'correct element tagName'); + assert.dom(element).hasAttribute('data-foo', 'some-thing'); + }; + await render(hbs`
`); + }); + + test('it can accept arguments', async function(assert) { + assert.expect(4); + + this.someMethod = (element, positional, named) => { + assert.equal(element.tagName, 'DIV', 'correct element tagName'); + assert.dom(element).hasAttribute('data-foo', 'some-thing'); + + assert.deepEqual(named, { some: 'hash-value' }, 'named args match'); + assert.deepEqual(positional, ['some-positional-value'], 'positional args match'); + }; + + await render( + hbs`
` + ); + }); + + test('it is not invoked again when arguments change', async function(assert) { + assert.expect(4); + + this.someMethod = (element, positional, named) => { + assert.equal(element.tagName, 'DIV', 'correct element tagName'); + assert.dom(element).hasAttribute('data-foo', 'some-thing'); + + assert.deepEqual(named, {}, 'named args match'); + assert.deepEqual(positional, ['initial'], 'positional args match'); + }; + + this.set('firstArg', 'initial'); + await render( + hbs`
` + ); + this.set('firstArg', 'updated'); + }); + }); + + module('updateModifier', function(hooks) { + hooks.beforeEach(function() { + class DidUpdateModifier {} + + Ember._setModifierManager(DidUpdateModifier, () => ({ + createModifier() { + return {}; + }, + installModifier(state, element) { + state.element = element; + }, + + updateModifier({ element }, args) { + let [fn, ...positional] = args.positional; + + fn(element, positional, args.named); + }, + + destroyModifier() {}, + })); + this.owner.register('modifier:did-update', DidUpdateModifier); + }); + + test('it basically works', async function(assert) { + assert.expect(4); + + this.someMethod = (element, positional, named) => { + assert.equal(element.tagName, 'DIV', 'correct element tagName'); + assert.dom(element).hasAttribute('data-foo', 'some-thing'); + + assert.deepEqual(named, {}, 'named args match'); + assert.deepEqual(positional, ['update'], 'positional args match'); + }; + + this.set('boundValue', 'initial'); + await render( + hbs`
` + ); + + this.set('boundValue', 'update'); + }); + }); + + module('destroyModifier', function(hooks) { + hooks.beforeEach(function() { + class WillDestroyModifier {} + + Ember._setModifierManager(WillDestroyModifier, () => ({ + createModifier() { + return {}; + }, + + installModifier(state, element) { + state.element = element; + }, + + updateModifier() {}, + + destroyModifier({ element }, args) { + let [fn, ...positional] = args.positional; + + fn(element, positional, args.named); + }, + })); + + this.owner.register('modifier:will-destroy', WillDestroyModifier); + }); + + test('it basically works', async function(assert) { + assert.expect(2); + + this.someMethod = element => { + assert.equal(element.tagName, 'DIV', 'correct element tagName'); + assert.dom(element).hasAttribute('data-foo', 'some-thing'); + }; + this.set('show', true); + + await render( + hbs`{{#if show}}
{{/if}}` + ); + + // trigger destroy + this.set('show', false); + }); + + test('it can accept arguments', async function(assert) { + assert.expect(4); + + this.someMethod = (element, positional, named) => { + assert.equal(element.tagName, 'DIV', 'correct element tagName'); + assert.dom(element).hasAttribute('data-foo', 'some-thing'); + + assert.deepEqual(named, { some: 'hash-value' }, 'named args match'); + assert.deepEqual(positional, ['some-positional-value'], 'positional args match'); + }; + + this.set('show', true); + + await render( + hbs`{{#if show}}
{{/if}}` + ); + + // trigger destroy + this.set('show', false); + }); }); }); diff --git a/vendor/ember-modifier-manager-polyfill.js b/vendor/ember-modifier-manager-polyfill.js index 58c75f1..d3b7b17 100644 --- a/vendor/ember-modifier-manager-polyfill.js +++ b/vendor/ember-modifier-manager-polyfill.js @@ -1,6 +1,159 @@ -import { lte, gte } from 'ember-compatibility-helpers'; +/* globals Ember */ +/* eslint-disable ember/new-module-imports */ + +import { gte } from 'ember-compatibility-helpers'; (() => { 'use strict'; + const getPrototypeOf = Object.getPrototypeOf; + const { Application } = Ember; + let MODIFIER_MANAGERS = new WeakMap(); + Ember._setModifierManager = function Polyfilled_setModifierManager(modifier, managerFactory) { + MODIFIER_MANAGERS.set(modifier, managerFactory); + }; + + let getModifierManager = obj => { + let pointer = obj; + while (pointer !== undefined && pointer !== null) { + if (MODIFIER_MANAGERS.has(pointer)) { + return MODIFIER_MANAGERS.get(pointer); + } + + pointer = getPrototypeOf(pointer); + } + + return; + }; + + if (gte('3.1.0-beta.1')) { + let valueForCapturedArgs = function valueForCapturedArgs(args) { + return { + named: args.named.value(), + positional: args.positional.value(), + }; + }; + + Application.reopenClass({ + buildRegistry() { + let registry = this._super(...arguments); + + let containerModule = gte('3.6.0-alpha.1') ? '@ember/-internals/container' : 'container'; + const P = Ember.__loader.require(containerModule).privatize; + + let compilerName = gte('3.2.0-alpha.1') + ? P`template-compiler:main` + : P`template-options:main`; + let TemplateCompiler = registry.resolve(compilerName); + + let ORIGINAL_TEMPLATE_COMPILER_CREATE = TemplateCompiler.create; + if (ORIGINAL_TEMPLATE_COMPILER_CREATE.__MODIFIER_MANAGER_PATCHED === true) { + return registry; + } + + TemplateCompiler.create = function() { + let compiler = ORIGINAL_TEMPLATE_COMPILER_CREATE(...arguments); + let compileTimeLookup = compiler.resolver; + let runtimeResolver = compileTimeLookup.resolver; + + let CustomModifierDefinition; + if (gte('3.6.0-alpha.1')) { + class CustomModifierState { + constructor(element, delegate, modifier, args) { + this.element = element; + this.delegate = delegate; + this.modifier = modifier; + this.args = args; + } + + destroy() { + const { delegate, modifier, args } = this; + let modifierArgs = valueForCapturedArgs(args); + delegate.destroyModifier(modifier, modifierArgs); + } + } + + class Polyfilled_CustomModifierManager { + //create(element: Simple.Element, state: ModifierDefinitionState, args: IArguments, dynamicScope: DynamicScope, dom: DOMChanges): ModifierInstanceState; + create(element, definition, args) { + const capturedArgs = args.capture(); + let modifierArgs = valueForCapturedArgs(capturedArgs); + let instance = definition.delegate.createModifier( + definition.ModifierClass, + modifierArgs + ); + + return new CustomModifierState( + element, + definition.delegate, + instance, + capturedArgs + ); + } + + //getTag(modifier: ModifierInstanceState): Tag; + getTag({ args }) { + return args.tag; + } + + //install(modifier: ModifierInstanceState): void; + install(state) { + let { element, args, delegate, modifier } = state; + let modifierArgs = valueForCapturedArgs(args); + delegate.installModifier(modifier, element, modifierArgs); + } + + //update(modifier: ModifierInstanceState): void; + update(state) { + let { args, delegate, modifier } = state; + let modifierArgs = valueForCapturedArgs(args); + delegate.updateModifier(modifier, modifierArgs); + } + + //getDestructor(modifier: ModifierInstanceState): Option; + getDestructor(state) { + return state; + } + } + + CustomModifierDefinition = class Polyfilled_CustomModifierDefinition { + constructor(name, ModifierClass, delegate) { + this.name = name; + this.state = { + ModifierClass, + name, + delegate, + }; + this.manager = new Polyfilled_CustomModifierManager(); + } + }; + } else { + // TODO: rwjblue implement 3.1 - 3.5 + } + + runtimeResolver._lookupModifier = function(name, meta) { + let builtin = this.builtInModifiers[name]; + + if (builtin === undefined) { + let { owner } = meta; + let modifier = owner.factoryFor(`modifier:${name}`); + if (modifier !== undefined) { + let managerFactory = getModifierManager(modifier.class); + let manager = managerFactory(owner); + + return new CustomModifierDefinition(name, modifier.class, manager); + } + } + + return builtin; + }; + + return compiler; + }; + TemplateCompiler.create.__MODIFIER_MANAGER_PATCHED = true; + + return registry; + }, + }); + } })(); From 5df19bc49e7021ac6d4116cabfbd46d98cd28718 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 27 Jan 2019 18:48:58 -0500 Subject: [PATCH 06/12] Add support for Ember 3.4 --- vendor/ember-modifier-manager-polyfill.js | 147 ++++++++++++---------- 1 file changed, 82 insertions(+), 65 deletions(-) diff --git a/vendor/ember-modifier-manager-polyfill.js b/vendor/ember-modifier-manager-polyfill.js index d3b7b17..8d86d1e 100644 --- a/vendor/ember-modifier-manager-polyfill.js +++ b/vendor/ember-modifier-manager-polyfill.js @@ -1,7 +1,7 @@ /* globals Ember */ /* eslint-disable ember/new-module-imports */ -import { gte } from 'ember-compatibility-helpers'; +import { lte, gte } from 'ember-compatibility-helpers'; (() => { 'use strict'; @@ -56,79 +56,76 @@ import { gte } from 'ember-compatibility-helpers'; let compileTimeLookup = compiler.resolver; let runtimeResolver = compileTimeLookup.resolver; - let CustomModifierDefinition; - if (gte('3.6.0-alpha.1')) { - class CustomModifierState { - constructor(element, delegate, modifier, args) { - this.element = element; - this.delegate = delegate; - this.modifier = modifier; - this.args = args; - } + class CustomModifierState { + constructor(element, delegate, modifier, args) { + this.element = element; + this.delegate = delegate; + this.modifier = modifier; + this.args = args; + } - destroy() { - const { delegate, modifier, args } = this; - let modifierArgs = valueForCapturedArgs(args); - delegate.destroyModifier(modifier, modifierArgs); - } + destroy() { + const { delegate, modifier, args } = this; + let modifierArgs = valueForCapturedArgs(args); + delegate.destroyModifier(modifier, modifierArgs); } + } - class Polyfilled_CustomModifierManager { - //create(element: Simple.Element, state: ModifierDefinitionState, args: IArguments, dynamicScope: DynamicScope, dom: DOMChanges): ModifierInstanceState; - create(element, definition, args) { - const capturedArgs = args.capture(); - let modifierArgs = valueForCapturedArgs(capturedArgs); - let instance = definition.delegate.createModifier( - definition.ModifierClass, - modifierArgs - ); - - return new CustomModifierState( - element, - definition.delegate, - instance, - capturedArgs - ); - } + class Polyfilled_CustomModifierManager { + //create(element: Simple.Element, state: ModifierDefinitionState, args: IArguments, dynamicScope: DynamicScope, dom: DOMChanges): ModifierInstanceState; + create(element, definition, args) { + const capturedArgs = args.capture(); + let modifierArgs = valueForCapturedArgs(capturedArgs); + let instance = definition.delegate.createModifier( + definition.ModifierClass, + modifierArgs + ); + + return new CustomModifierState(element, definition.delegate, instance, capturedArgs); + } - //getTag(modifier: ModifierInstanceState): Tag; - getTag({ args }) { - return args.tag; - } + //getTag(modifier: ModifierInstanceState): Tag; + getTag({ args }) { + return args.tag; + } - //install(modifier: ModifierInstanceState): void; - install(state) { - let { element, args, delegate, modifier } = state; - let modifierArgs = valueForCapturedArgs(args); - delegate.installModifier(modifier, element, modifierArgs); - } + //install(modifier: ModifierInstanceState): void; + install(state) { + let { element, args, delegate, modifier } = state; + let modifierArgs = valueForCapturedArgs(args); + delegate.installModifier(modifier, element, modifierArgs); + } - //update(modifier: ModifierInstanceState): void; - update(state) { - let { args, delegate, modifier } = state; - let modifierArgs = valueForCapturedArgs(args); - delegate.updateModifier(modifier, modifierArgs); - } + //update(modifier: ModifierInstanceState): void; + update(state) { + let { args, delegate, modifier } = state; + let modifierArgs = valueForCapturedArgs(args); + delegate.updateModifier(modifier, modifierArgs); + } - //getDestructor(modifier: ModifierInstanceState): Option; - getDestructor(state) { - return state; - } + //getDestructor(modifier: ModifierInstanceState): Option; + getDestructor(state) { + return state; } + } - CustomModifierDefinition = class Polyfilled_CustomModifierDefinition { - constructor(name, ModifierClass, delegate) { - this.name = name; - this.state = { - ModifierClass, - name, - delegate, - }; - this.manager = new Polyfilled_CustomModifierManager(); - } + class Polyfilled_CustomModifierDefinition { + constructor(name, ModifierClass, delegate) { + this.name = name; + this.state = { + ModifierClass, + name, + delegate, + }; + this.manager = new Polyfilled_CustomModifierManager(); + } + } + + // meta was not passed to `_lookupModifier` until 3.7 + if (lte('3.7.0-alpha.1')) { + runtimeResolver.lookupModifier = function(name, meta) { + return this.handle(this._lookupModifier(name, meta)); }; - } else { - // TODO: rwjblue implement 3.1 - 3.5 } runtimeResolver._lookupModifier = function(name, meta) { @@ -141,7 +138,27 @@ import { gte } from 'ember-compatibility-helpers'; let managerFactory = getModifierManager(modifier.class); let manager = managerFactory(owner); - return new CustomModifierDefinition(name, modifier.class, manager); + if (gte('3.6.0-alpha.1')) { + return new Polyfilled_CustomModifierDefinition(name, modifier.class, manager); + } else { + class Polyfilled_CustomModifierManagerLt36 extends Polyfilled_CustomModifierManager { + constructor(name, ModifierClass, manager) { + super(); + + this.state = { + ModifierClass, + delegate: manager, + }; + } + + // create(element: Simple.Element, args: Arguments, _dynamicScope: DynamicScope, dom: any) { + create(element, args) { + return super.create(element, this.state, args); + } + } + + return new Polyfilled_CustomModifierManagerLt36(name, modifier.class, manager); + } } } From ae6425c32e026a23eb009541cf04bf0fbbb9c8dc Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 27 Jan 2019 18:50:49 -0500 Subject: [PATCH 07/12] Add 3.5 / 3.6 / 3.7 explicitly to ember-try config. --- .travis.yml | 3 +++ config/ember-try.js | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/.travis.yml b/.travis.yml index c8cec19..87f983a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,6 +51,9 @@ jobs: - stage: "Additional Tests" env: EMBER_TRY_SCENARIO=ember-lts-2.18 - env: EMBER_TRY_SCENARIO=ember-lts-3.4 + - env: EMBER_TRY_SCENARIO=ember-3.5 + - env: EMBER_TRY_SCENARIO=ember-3.6 + - env: EMBER_TRY_SCENARIO=ember-3.7 - env: EMBER_TRY_SCENARIO=ember-release - env: EMBER_TRY_SCENARIO=ember-beta - env: EMBER_TRY_SCENARIO=ember-canary diff --git a/config/ember-try.js b/config/ember-try.js index ec08a5b..281eb80 100644 --- a/config/ember-try.js +++ b/config/ember-try.js @@ -31,6 +31,30 @@ module.exports = function() { }, }, }, + { + name: 'ember-3.5', + npm: { + devDependencies: { + 'ember-source': '~3.5.0', + }, + }, + }, + { + name: 'ember-3.6', + npm: { + devDependencies: { + 'ember-source': '~3.6.0', + }, + }, + }, + { + name: 'ember-3.7', + npm: { + devDependencies: { + 'ember-source': '~3.7.0', + }, + }, + }, { name: 'ember-release', npm: { From 0582781ac95767cc770fc85b194db01feade3aa8 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 27 Jan 2019 19:04:53 -0500 Subject: [PATCH 08/12] Fix argument ordering issue with Ember._setModifierManager. --- .../components/modifier-manager-test.js | 89 ++++++++++--------- vendor/ember-modifier-manager-polyfill.js | 2 +- 2 files changed, 50 insertions(+), 41 deletions(-) diff --git a/tests/integration/components/modifier-manager-test.js b/tests/integration/components/modifier-manager-test.js index 83ea967..3e73b12 100644 --- a/tests/integration/components/modifier-manager-test.js +++ b/tests/integration/components/modifier-manager-test.js @@ -11,20 +11,23 @@ module('Integration | Component | modifier-manager', function(hooks) { hooks.beforeEach(function() { class DidInsertModifier {} - Ember._setModifierManager(DidInsertModifier, () => ({ - createModifier(_factory, args) { - return args.positional[0]; - }, - - installModifier(_state, element, args) { - let [fn, ...positional] = args.positional; - - fn(element, positional, args.named); - }, - - updateModifier() {}, - destroyModifier() {}, - })); + Ember._setModifierManager( + () => ({ + createModifier(_factory, args) { + return args.positional[0]; + }, + + installModifier(_state, element, args) { + let [fn, ...positional] = args.positional; + + fn(element, positional, args.named); + }, + + updateModifier() {}, + destroyModifier() {}, + }), + DidInsertModifier + ); this.owner.register('modifier:did-insert', DidInsertModifier); }); @@ -77,22 +80,25 @@ module('Integration | Component | modifier-manager', function(hooks) { hooks.beforeEach(function() { class DidUpdateModifier {} - Ember._setModifierManager(DidUpdateModifier, () => ({ - createModifier() { - return {}; - }, - installModifier(state, element) { - state.element = element; - }, + Ember._setModifierManager( + () => ({ + createModifier() { + return {}; + }, + installModifier(state, element) { + state.element = element; + }, - updateModifier({ element }, args) { - let [fn, ...positional] = args.positional; + updateModifier({ element }, args) { + let [fn, ...positional] = args.positional; - fn(element, positional, args.named); - }, + fn(element, positional, args.named); + }, - destroyModifier() {}, - })); + destroyModifier() {}, + }), + DidUpdateModifier + ); this.owner.register('modifier:did-update', DidUpdateModifier); }); @@ -120,23 +126,26 @@ module('Integration | Component | modifier-manager', function(hooks) { hooks.beforeEach(function() { class WillDestroyModifier {} - Ember._setModifierManager(WillDestroyModifier, () => ({ - createModifier() { - return {}; - }, + Ember._setModifierManager( + () => ({ + createModifier() { + return {}; + }, - installModifier(state, element) { - state.element = element; - }, + installModifier(state, element) { + state.element = element; + }, - updateModifier() {}, + updateModifier() {}, - destroyModifier({ element }, args) { - let [fn, ...positional] = args.positional; + destroyModifier({ element }, args) { + let [fn, ...positional] = args.positional; - fn(element, positional, args.named); - }, - })); + fn(element, positional, args.named); + }, + }), + WillDestroyModifier + ); this.owner.register('modifier:will-destroy', WillDestroyModifier); }); diff --git a/vendor/ember-modifier-manager-polyfill.js b/vendor/ember-modifier-manager-polyfill.js index 8d86d1e..be72d6c 100644 --- a/vendor/ember-modifier-manager-polyfill.js +++ b/vendor/ember-modifier-manager-polyfill.js @@ -9,7 +9,7 @@ import { lte, gte } from 'ember-compatibility-helpers'; const getPrototypeOf = Object.getPrototypeOf; const { Application } = Ember; let MODIFIER_MANAGERS = new WeakMap(); - Ember._setModifierManager = function Polyfilled_setModifierManager(modifier, managerFactory) { + Ember._setModifierManager = function Polyfilled_setModifierManager(managerFactory, modifier) { MODIFIER_MANAGERS.set(modifier, managerFactory); }; From 20f460cc7ab92964e48ec5fbfd6a9b41d450dc42 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 27 Jan 2019 19:30:54 -0500 Subject: [PATCH 09/12] Refactor to work on 2.18+. --- .../components/modifier-manager-test.js | 19 +- vendor/ember-modifier-manager-polyfill.js | 233 +++++++++++------- 2 files changed, 155 insertions(+), 97 deletions(-) diff --git a/tests/integration/components/modifier-manager-test.js b/tests/integration/components/modifier-manager-test.js index 3e73b12..f84fc85 100644 --- a/tests/integration/components/modifier-manager-test.js +++ b/tests/integration/components/modifier-manager-test.js @@ -3,10 +3,21 @@ import { setupRenderingTest } from 'ember-qunit'; import { render } from '@ember/test-helpers'; import hbs from 'htmlbars-inline-precompile'; import Ember from 'ember'; +import { assign } from '@ember/polyfills'; module('Integration | Component | modifier-manager', function(hooks) { setupRenderingTest(hooks); + hooks.beforeEach(function(assert) { + assert.namedEquals = function(actual, expected, message) { + // this is needed because older versions of Ember pass an `EmptyObject` + // based object and QUnit fails due to the prototypes not matching + let sanitizedActual = assign({}, actual); + + assert.deepEqual(sanitizedActual, expected, message); + }; + }); + module('installModifier', function(hooks) { hooks.beforeEach(function() { class DidInsertModifier {} @@ -48,7 +59,7 @@ module('Integration | Component | modifier-manager', function(hooks) { assert.equal(element.tagName, 'DIV', 'correct element tagName'); assert.dom(element).hasAttribute('data-foo', 'some-thing'); - assert.deepEqual(named, { some: 'hash-value' }, 'named args match'); + assert.namedEquals(named, { some: 'hash-value' }, 'named args match'); assert.deepEqual(positional, ['some-positional-value'], 'positional args match'); }; @@ -64,7 +75,7 @@ module('Integration | Component | modifier-manager', function(hooks) { assert.equal(element.tagName, 'DIV', 'correct element tagName'); assert.dom(element).hasAttribute('data-foo', 'some-thing'); - assert.deepEqual(named, {}, 'named args match'); + assert.namedEquals(named, {}, 'named args match'); assert.deepEqual(positional, ['initial'], 'positional args match'); }; @@ -109,7 +120,7 @@ module('Integration | Component | modifier-manager', function(hooks) { assert.equal(element.tagName, 'DIV', 'correct element tagName'); assert.dom(element).hasAttribute('data-foo', 'some-thing'); - assert.deepEqual(named, {}, 'named args match'); + assert.namedEquals(named, {}, 'named args match'); assert.deepEqual(positional, ['update'], 'positional args match'); }; @@ -174,7 +185,7 @@ module('Integration | Component | modifier-manager', function(hooks) { assert.equal(element.tagName, 'DIV', 'correct element tagName'); assert.dom(element).hasAttribute('data-foo', 'some-thing'); - assert.deepEqual(named, { some: 'hash-value' }, 'named args match'); + assert.namedEquals(named, { some: 'hash-value' }, 'named args match'); assert.deepEqual(positional, ['some-positional-value'], 'positional args match'); }; diff --git a/vendor/ember-modifier-manager-polyfill.js b/vendor/ember-modifier-manager-polyfill.js index be72d6c..68cbbcc 100644 --- a/vendor/ember-modifier-manager-polyfill.js +++ b/vendor/ember-modifier-manager-polyfill.js @@ -26,18 +26,99 @@ import { lte, gte } from 'ember-compatibility-helpers'; return; }; - if (gte('3.1.0-beta.1')) { - let valueForCapturedArgs = function valueForCapturedArgs(args) { - return { - named: args.named.value(), - positional: args.positional.value(), - }; + let valueForCapturedArgs = function valueForCapturedArgs(args) { + return { + named: args.named.value(), + positional: args.positional.value(), }; + }; + + Application.reopenClass({ + buildRegistry() { + let registry = this._super(...arguments); + + class CustomModifierState { + constructor(element, delegate, modifier, args) { + this.element = element; + this.delegate = delegate; + this.modifier = modifier; + this.args = args; + } + + destroy() { + const { delegate, modifier, args } = this; + let modifierArgs = valueForCapturedArgs(args); + delegate.destroyModifier(modifier, modifierArgs); + } + } + + class Polyfilled_CustomModifierManager { + //create(element: Simple.Element, state: ModifierDefinitionState, args: IArguments, dynamicScope: DynamicScope, dom: DOMChanges): ModifierInstanceState; + create(element, definition, args) { + const capturedArgs = args.capture(); + let modifierArgs = valueForCapturedArgs(capturedArgs); + let instance = definition.delegate.createModifier(definition.ModifierClass, modifierArgs); + + return new CustomModifierState(element, definition.delegate, instance, capturedArgs); + } + + //getTag(modifier: ModifierInstanceState): Tag; + getTag({ args }) { + return args.tag; + } + + //install(modifier: ModifierInstanceState): void; + install(state) { + let { element, args, delegate, modifier } = state; + let modifierArgs = valueForCapturedArgs(args); + delegate.installModifier(modifier, element, modifierArgs); + } + + //update(modifier: ModifierInstanceState): void; + update(state) { + let { args, delegate, modifier } = state; + let modifierArgs = valueForCapturedArgs(args); + delegate.updateModifier(modifier, modifierArgs); + } + + //getDestructor(modifier: ModifierInstanceState): Option; + getDestructor(state) { + return state; + } + } - Application.reopenClass({ - buildRegistry() { - let registry = this._super(...arguments); + let Polyfilled_CustomModifierManagerLt36; + if (lte('3.6.0-alpha.1')) { + Polyfilled_CustomModifierManagerLt36 = class Polyfilled_CustomModifierManagerLt36 extends Polyfilled_CustomModifierManager { + constructor(name, ModifierClass, manager) { + super(); + this.state = { + ModifierClass, + delegate: manager, + }; + } + + // create(element: Simple.Element, args: Arguments, _dynamicScope: DynamicScope, dom: any) { + create(element, args) { + return super.create(element, this.state, args); + } + }; + } + + class Polyfilled_CustomModifierDefinition { + constructor(name, ModifierClass, delegate) { + this.name = name; + this.state = { + ModifierClass, + name, + delegate, + }; + this.manager = new Polyfilled_CustomModifierManager(); + } + } + + if (gte('3.1.0-beta.1')) { let containerModule = gte('3.6.0-alpha.1') ? '@ember/-internals/container' : 'container'; const P = Ember.__loader.require(containerModule).privatize; @@ -56,71 +137,6 @@ import { lte, gte } from 'ember-compatibility-helpers'; let compileTimeLookup = compiler.resolver; let runtimeResolver = compileTimeLookup.resolver; - class CustomModifierState { - constructor(element, delegate, modifier, args) { - this.element = element; - this.delegate = delegate; - this.modifier = modifier; - this.args = args; - } - - destroy() { - const { delegate, modifier, args } = this; - let modifierArgs = valueForCapturedArgs(args); - delegate.destroyModifier(modifier, modifierArgs); - } - } - - class Polyfilled_CustomModifierManager { - //create(element: Simple.Element, state: ModifierDefinitionState, args: IArguments, dynamicScope: DynamicScope, dom: DOMChanges): ModifierInstanceState; - create(element, definition, args) { - const capturedArgs = args.capture(); - let modifierArgs = valueForCapturedArgs(capturedArgs); - let instance = definition.delegate.createModifier( - definition.ModifierClass, - modifierArgs - ); - - return new CustomModifierState(element, definition.delegate, instance, capturedArgs); - } - - //getTag(modifier: ModifierInstanceState): Tag; - getTag({ args }) { - return args.tag; - } - - //install(modifier: ModifierInstanceState): void; - install(state) { - let { element, args, delegate, modifier } = state; - let modifierArgs = valueForCapturedArgs(args); - delegate.installModifier(modifier, element, modifierArgs); - } - - //update(modifier: ModifierInstanceState): void; - update(state) { - let { args, delegate, modifier } = state; - let modifierArgs = valueForCapturedArgs(args); - delegate.updateModifier(modifier, modifierArgs); - } - - //getDestructor(modifier: ModifierInstanceState): Option; - getDestructor(state) { - return state; - } - } - - class Polyfilled_CustomModifierDefinition { - constructor(name, ModifierClass, delegate) { - this.name = name; - this.state = { - ModifierClass, - name, - delegate, - }; - this.manager = new Polyfilled_CustomModifierManager(); - } - } - // meta was not passed to `_lookupModifier` until 3.7 if (lte('3.7.0-alpha.1')) { runtimeResolver.lookupModifier = function(name, meta) { @@ -141,22 +157,6 @@ import { lte, gte } from 'ember-compatibility-helpers'; if (gte('3.6.0-alpha.1')) { return new Polyfilled_CustomModifierDefinition(name, modifier.class, manager); } else { - class Polyfilled_CustomModifierManagerLt36 extends Polyfilled_CustomModifierManager { - constructor(name, ModifierClass, manager) { - super(); - - this.state = { - ModifierClass, - delegate: manager, - }; - } - - // create(element: Simple.Element, args: Arguments, _dynamicScope: DynamicScope, dom: any) { - create(element, args) { - return super.create(element, this.state, args); - } - } - return new Polyfilled_CustomModifierManagerLt36(name, modifier.class, manager); } } @@ -168,9 +168,56 @@ import { lte, gte } from 'ember-compatibility-helpers'; return compiler; }; TemplateCompiler.create.__MODIFIER_MANAGER_PATCHED = true; + } else if (gte('2.12.0-beta.1')) { + let Environment = registry.resolve('service:-glimmer-environment'); + let ORIGINAL_ENVIRONMENT_CREATE = Environment.create; + if (ORIGINAL_ENVIRONMENT_CREATE.__MODIFIER_MANAGER_PATCHED === true) { + return registry; + } + + let factoryForMethodName = 'factoryFor'; + if (lte('2.13.99999999')) { + factoryForMethodName = Ember.__loader.require('container').FACTORY_FOR; + } + + Environment.create = function Polyfilled_EnvironmentCreate() { + let environment = ORIGINAL_ENVIRONMENT_CREATE.apply(this, arguments); + + environment.hasModifier = function(name, meta) { + let { owner } = meta; + + return !!this.builtInModifiers[name] || !!owner.hasRegistration(`modifier:${name}`); + }; + + environment.lookupModifier = function(name, meta) { + let modifier = this.builtInModifiers[name]; + + if (!modifier) { + let { owner } = meta; + let modifier = owner[factoryForMethodName](`modifier:${name}`); + if (modifier !== undefined) { + let managerFactory = getModifierManager(modifier.class); + let manager = managerFactory(owner); + + return new Polyfilled_CustomModifierManagerLt36(name, modifier.class, manager); + } + } + + if (!modifier) { + throw new Error(`${name} is not a modifier`); + } + + return modifier; + }; + + return environment; + }; + Environment.create.__MODIFIER_MANAGER_PATCHED = true; return registry; - }, - }); - } + } + + return registry; + }, + }); })(); From 3d47368f3ed87688a0ea5a59f3514d729fac2d9d Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 27 Jan 2019 19:32:14 -0500 Subject: [PATCH 10/12] Add 2.12 and 2.16 to .travis.yml. --- .travis.yml | 2 ++ config/ember-try.js | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/.travis.yml b/.travis.yml index 87f983a..5eca90e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,6 +49,8 @@ jobs: # we recommend new addons test the current and previous LTS # as well as latest stable release (bonus points to beta/canary) - stage: "Additional Tests" + env: EMBER_TRY_SCENARIO=ember-lts-2.12 + env: EMBER_TRY_SCENARIO=ember-lts-2.16 env: EMBER_TRY_SCENARIO=ember-lts-2.18 - env: EMBER_TRY_SCENARIO=ember-lts-3.4 - env: EMBER_TRY_SCENARIO=ember-3.5 diff --git a/config/ember-try.js b/config/ember-try.js index 281eb80..62a0538 100644 --- a/config/ember-try.js +++ b/config/ember-try.js @@ -11,6 +11,30 @@ module.exports = function() { return { useYarn: true, scenarios: [ + { + name: 'ember-lts-2.12', + env: { + EMBER_OPTIONAL_FEATURES: JSON.stringify({ 'jquery-integration': true }), + }, + npm: { + devDependencies: { + '@ember/jquery': '^0.5.1', + 'ember-source': '~2.12.0', + }, + }, + }, + { + name: 'ember-lts-2.16', + env: { + EMBER_OPTIONAL_FEATURES: JSON.stringify({ 'jquery-integration': true }), + }, + npm: { + devDependencies: { + '@ember/jquery': '^0.5.1', + 'ember-source': '~2.16.0', + }, + }, + }, { name: 'ember-lts-2.18', env: { From dcc462d08748a6c00861b999f2dbe80cb27b52e2 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 27 Jan 2019 21:03:21 -0500 Subject: [PATCH 11/12] Fix issues with 2.12. --- vendor/ember-modifier-manager-polyfill.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/vendor/ember-modifier-manager-polyfill.js b/vendor/ember-modifier-manager-polyfill.js index 68cbbcc..d058a32 100644 --- a/vendor/ember-modifier-manager-polyfill.js +++ b/vendor/ember-modifier-manager-polyfill.js @@ -55,8 +55,9 @@ import { lte, gte } from 'ember-compatibility-helpers'; class Polyfilled_CustomModifierManager { //create(element: Simple.Element, state: ModifierDefinitionState, args: IArguments, dynamicScope: DynamicScope, dom: DOMChanges): ModifierInstanceState; create(element, definition, args) { - const capturedArgs = args.capture(); + let capturedArgs = gte('2.15.0-alpha.1') ? args.capture() : args; let modifierArgs = valueForCapturedArgs(capturedArgs); + let instance = definition.delegate.createModifier(definition.ModifierClass, modifierArgs); return new CustomModifierState(element, definition.delegate, instance, capturedArgs); @@ -183,17 +184,21 @@ import { lte, gte } from 'ember-compatibility-helpers'; Environment.create = function Polyfilled_EnvironmentCreate() { let environment = ORIGINAL_ENVIRONMENT_CREATE.apply(this, arguments); - environment.hasModifier = function(name, meta) { - let { owner } = meta; + environment.hasModifier = function(name, metaOrSymbolTable) { + let owner = gte('2.15.0-alpha.1') + ? metaOrSymbolTable.owner + : metaOrSymbolTable.getMeta().owner; return !!this.builtInModifiers[name] || !!owner.hasRegistration(`modifier:${name}`); }; - environment.lookupModifier = function(name, meta) { + environment.lookupModifier = function(name, metaOrSymbolTable) { let modifier = this.builtInModifiers[name]; if (!modifier) { - let { owner } = meta; + let owner = gte('2.15.0-alpha.1') + ? metaOrSymbolTable.owner + : metaOrSymbolTable.getMeta().owner; let modifier = owner[factoryForMethodName](`modifier:${name}`); if (modifier !== undefined) { let managerFactory = getModifierManager(modifier.class); From 6f53e3f4e71d8b1682001340bd20aaba7717bb43 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 27 Jan 2019 21:04:38 -0500 Subject: [PATCH 12/12] Fix stages config in .travis.yml for 2.12 and 2.16. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5eca90e..3c2e1e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,8 +50,8 @@ jobs: # as well as latest stable release (bonus points to beta/canary) - stage: "Additional Tests" env: EMBER_TRY_SCENARIO=ember-lts-2.12 - env: EMBER_TRY_SCENARIO=ember-lts-2.16 - env: EMBER_TRY_SCENARIO=ember-lts-2.18 + - env: EMBER_TRY_SCENARIO=ember-lts-2.16 + - env: EMBER_TRY_SCENARIO=ember-lts-2.18 - env: EMBER_TRY_SCENARIO=ember-lts-3.4 - env: EMBER_TRY_SCENARIO=ember-3.5 - env: EMBER_TRY_SCENARIO=ember-3.6