diff --git a/addon/-task-group.js b/addon/-task-group.js index ff682d40e..8ea1002cb 100644 --- a/addon/-task-group.js +++ b/addon/-task-group.js @@ -2,11 +2,8 @@ import { or, bool } from '@ember/object/computed'; import EmberObject from '@ember/object'; import { objectAssign, _ComputedProperty } from './utils'; import TaskStateMixin from './-task-state-mixin'; -import { - propertyModifiers, - resolveScheduler -} from './-property-modifiers-mixin'; - +import { propertyModifiers } from './-property-modifiers-mixin'; +import { gte } from 'ember-compatibility-helpers'; export const TaskGroup = EmberObject.extend(TaskStateMixin, { isTaskGroup: true, @@ -17,24 +14,15 @@ export const TaskGroup = EmberObject.extend(TaskStateMixin, { _numRunningOrNumQueued: or('numRunning', 'numQueued'), isRunning: bool('_numRunningOrNumQueued'), - isQueued: false + isQueued: false, }); -export class TaskGroupProperty extends _ComputedProperty { - constructor(taskFn) { - let tp; - super(function(_propertyName) { - return TaskGroup.create({ - fn: taskFn, - context: this, - _origin: this, - _taskGroupPath: tp._taskGroupPath, - _scheduler: resolveScheduler(tp, this, TaskGroup), - _propertyName, - }); - }); - tp = this; - } +export let TaskGroupProperty; + +if (gte('3.10.0-alpha.1')) { + TaskGroupProperty = class {}; +} else { + TaskGroupProperty = class extends _ComputedProperty {}; } objectAssign(TaskGroupProperty.prototype, propertyModifiers); diff --git a/addon/-task-property.js b/addon/-task-property.js index eac00d7b0..1620529b6 100644 --- a/addon/-task-property.js +++ b/addon/-task-property.js @@ -3,29 +3,23 @@ import { addObserver } from '@ember/object/observers'; import { addListener } from '@ember/object/events'; import EmberObject from '@ember/object'; import { getOwner } from '@ember/application'; -import { - default as TaskInstance, - getRunningInstance -} from './-task-instance'; +import { default as TaskInstance, getRunningInstance } from './-task-instance'; import { PERFORM_TYPE_DEFAULT, PERFORM_TYPE_UNLINKED, - PERFORM_TYPE_LINKED + PERFORM_TYPE_LINKED, } from './-task-instance'; import TaskStateMixin from './-task-state-mixin'; -import { TaskGroup } from './-task-group'; -import { - propertyModifiers, - resolveScheduler -} from './-property-modifiers-mixin'; +import { propertyModifiers } from './-property-modifiers-mixin'; import { objectAssign, INVOKE, _cleanupOnDestroy, - _ComputedProperty + _ComputedProperty, } from './utils'; import EncapsulatedTask from './-encapsulated-task'; import { deprecate } from '@ember/debug'; +import { gte } from 'ember-compatibility-helpers'; const PerformProxy = EmberObject.extend({ _task: null, @@ -33,7 +27,11 @@ const PerformProxy = EmberObject.extend({ _linkedObject: null, perform(...args) { - return this._task._performShared(args, this._performType, this._linkedObject); + return this._task._performShared( + args, + this._performType, + this._linkedObject + ); }, }); @@ -184,10 +182,15 @@ export const Task = EmberObject.extend(TaskStateMixin, { if (typeof this.fn === 'object') { let owner = getOwner(this.context); let ownerInjection = owner ? owner.ownerInjection() : {}; - this._taskInstanceFactory = EncapsulatedTask.extend(ownerInjection, this.fn); + this._taskInstanceFactory = EncapsulatedTask.extend( + ownerInjection, + this.fn + ); } - _cleanupOnDestroy(this.context, this, 'cancelAll', { reason: 'the object it lives on was destroyed or unrendered' }); + _cleanupOnDestroy(this.context, this, 'cancelAll', { + reason: 'the object it lives on was destroyed or unrendered', + }); }, _curry(...args) { @@ -315,7 +318,6 @@ export const Task = EmberObject.extend(TaskStateMixin, { * @readOnly */ - /** * The current number of active running task instances. This * number will never exceed maxConcurrency. @@ -413,42 +415,62 @@ export const Task = EmberObject.extend(TaskStateMixin, { @class TaskProperty */ -export class TaskProperty extends _ComputedProperty { - constructor(taskFn) { - let tp; - super(function(_propertyName) { - taskFn.displayName = `${_propertyName} (task)`; - return Task.create({ - fn: tp.taskFn, - context: this, - _origin: this, - _taskGroupPath: tp._taskGroupPath, - _scheduler: resolveScheduler(tp, this, TaskGroup), - _propertyName, - _debug: tp._debug, - _hasEnabledEvents: tp._hasEnabledEvents - }); - }); - tp = this; - this.taskFn = taskFn; - this.eventNames = null; - this.cancelEventNames = null; - this._observes = null; - } +export let TaskProperty; + +if (gte('3.10.0')) { + TaskProperty = class {}; +} else { + // Prior to the 3.10.0 refactors, we had to extend the _ComputedProprety class + // for a classic decorator/descriptor to run correctly. + TaskProperty = class extends _ComputedProperty { + callSuperSetup() { + if (super.setup) { + super.setup(...arguments); + } + } + }; +} +objectAssign(TaskProperty.prototype, { setup(proto, taskName) { - if (super.setup) { - super.setup(...arguments); + if (this.callSuperSetup) { + this.callSuperSetup(...arguments); } + if (this._maxConcurrency !== Infinity && !this._hasSetBufferPolicy) { // eslint-disable-next-line no-console - console.warn(`The use of maxConcurrency() without a specified task modifier is deprecated and won't be supported in future versions of ember-concurrency. Please specify a task modifier instead, e.g. \`${taskName}: task(...).enqueue().maxConcurrency(${this._maxConcurrency})\``); + console.warn( + `The use of maxConcurrency() without a specified task modifier is deprecated and won't be supported in future versions of ember-concurrency. Please specify a task modifier instead, e.g. \`${taskName}: task(...).enqueue().maxConcurrency(${ + this._maxConcurrency + })\`` + ); } - registerOnPrototype(addListener, proto, this.eventNames, taskName, 'perform', false); - registerOnPrototype(addListener, proto, this.cancelEventNames, taskName, 'cancelAll', false); - registerOnPrototype(addObserver, proto, this._observes, taskName, 'perform', true); - } + registerOnPrototype( + addListener, + proto, + this.eventNames, + taskName, + 'perform', + false + ); + registerOnPrototype( + addListener, + proto, + this.cancelEventNames, + taskName, + 'cancelAll', + false + ); + registerOnPrototype( + addObserver, + proto, + this._observes, + taskName, + 'perform', + true + ); + }, /** * Calling `task(...).on(eventName)` configures the task to be @@ -485,7 +507,7 @@ export class TaskProperty extends _ComputedProperty { this.eventNames = this.eventNames || []; this.eventNames.push.apply(this.eventNames, arguments); return this; - } + }, /** * This behaves like the {@linkcode TaskProperty#on task(...).on() modifier}, @@ -503,12 +525,12 @@ export class TaskProperty extends _ComputedProperty { this.cancelEventNames = this.cancelEventNames || []; this.cancelEventNames.push.apply(this.cancelEventNames, arguments); return this; - } + }, observes(...properties) { this._observes = properties; return this; - } + }, /** * Configures the task to cancel old currently task instances @@ -630,25 +652,34 @@ export class TaskProperty extends _ComputedProperty { */ perform() { - deprecate(`[DEPRECATED] An ember-concurrency task property was not set on its object via 'defineProperty'. - You probably used 'set(obj, "myTask", task(function* () { ... }) )'. + deprecate( + `[DEPRECATED] An ember-concurrency task property was not set on its object via 'defineProperty'. + You probably used 'set(obj, "myTask", task(function* () { ... }) )'. Unfortunately due to this we can't tell you the name of the task.`, false, { id: 'ember-meta.descriptor-on-object', until: '3.5.0', - url: 'https://emberjs.com/deprecations/v3.x#toc_use-defineProperty-to-define-computed-properties', + url: + 'https://emberjs.com/deprecations/v3.x#toc_use-defineProperty-to-define-computed-properties', } ); - throw new Error("An ember-concurrency task property was not set on its object via 'defineProperty'. See deprecation warning for details."); - } -} + throw new Error( + "An ember-concurrency task property was not set on its object via 'defineProperty'. See deprecation warning for details." + ); + }, +}); objectAssign(TaskProperty.prototype, propertyModifiers); -let handlerCounter = 0; - -function registerOnPrototype(addListenerOrObserver, proto, names, taskName, taskMethod, once) { +function registerOnPrototype( + addListenerOrObserver, + proto, + names, + taskName, + taskMethod, + once +) { if (names) { for (let i = 0; i < names.length; ++i) { let name = names[i]; @@ -671,3 +702,5 @@ function makeTaskCallback(taskName, method, once) { } }; } + +let handlerCounter = 0; diff --git a/addon/index.js b/addon/index.js index c607a6e9a..ae9ec01a2 100644 --- a/addon/index.js +++ b/addon/index.js @@ -1,9 +1,31 @@ +import Ember from 'ember'; +import { computed } from '@ember/object'; import { timeout, forever } from './utils'; -import { TaskProperty } from './-task-property'; +import { Task, TaskProperty } from './-task-property'; import { didCancel } from './-task-instance'; -import { TaskGroupProperty } from './-task-group'; +import { TaskGroup, TaskGroupProperty } from './-task-group'; import { all, allSettled, hash, race } from './-cancelable-promise-helpers'; import { waitForQueue, waitForEvent, waitForProperty } from './-wait-for'; +import { resolveScheduler } from './-property-modifiers-mixin'; +import { gte } from 'ember-compatibility-helpers'; + +function _computed(fn) { + if (gte('3.10.0')) { + let cp = function(proto, key) { + if (cp.setup !== undefined) { + cp.setup(proto, key); + } + + return computed(fn)(...arguments); + }; + + Ember._setComputedDecorator(cp); + + return cp; + } else { + return computed(fn); + } +} /** * A Task is a cancelable, restartable, asynchronous operation that @@ -50,8 +72,26 @@ import { waitForQueue, waitForEvent, waitForProperty } from './-wait-for'; * @param {function} generatorFunction the generator function backing the task. * @returns {TaskProperty} */ -export function task(...args) { - return new TaskProperty(...args); +export function task(taskFn) { + let tp = _computed(function(_propertyName) { + tp.taskFn.displayName = `${_propertyName} (task)`; + return Task.create({ + fn: tp.taskFn, + context: this, + _origin: this, + _taskGroupPath: tp._taskGroupPath, + _scheduler: resolveScheduler(tp, this, TaskGroup), + _propertyName, + _debug: tp._debug, + _hasEnabledEvents: tp._hasEnabledEvents, + }); + }); + + tp.taskFn = taskFn; + + Object.setPrototypeOf(tp, TaskProperty.prototype); + + return tp; } /** @@ -74,9 +114,24 @@ export function task(...args) { * ``` * * @returns {TaskGroup} -*/ -export function taskGroup(...args) { - return new TaskGroupProperty(...args); + */ +export function taskGroup(taskFn) { + let tp = _computed(function(_propertyName) { + return TaskGroup.create({ + fn: tp.taskFn, + context: this, + _origin: this, + _taskGroupPath: tp._taskGroupPath, + _scheduler: resolveScheduler(tp, this, TaskGroup), + _propertyName, + }); + }); + + tp.taskFn = taskFn; + + Object.setPrototypeOf(tp, TaskGroupProperty.prototype); + + return tp; } export { @@ -89,5 +144,5 @@ export { waitForQueue, waitForEvent, waitForProperty, - forever + forever, }; diff --git a/package.json b/package.json index 0deeaf94d..683a199ef 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,6 @@ "ember-cli-htmlbars": "^2.0.1", "ember-cli-htmlbars-inline-precompile": "^1.0.0", "ember-cli-inject-live-reload": "^1.4.1", - "ember-qunit": "^4.1.2", "ember-cli-release": "1.0.0-beta.2", "ember-cli-sass": "^7.1.3", "ember-cli-shims": "^1.2.0", @@ -48,14 +47,15 @@ "ember-load-initializers": "^1.0.0", "ember-maybe-import-regenerator": "^0.1.6", "ember-notify": "~5.2.1", + "ember-qunit": "4.1.2", "ember-resolver": "^4.0.0", "ember-sinon": "^2.1.0", "ember-source": "~3.6.0", "ember-source-channel-url": "^1.0.1", "ember-try": "^1.1.0", - "jsdom": "^11.6.2", - "eslint-plugin-node": "^6.0.1", "eslint-plugin-ember": "^5.1.0", + "eslint-plugin-node": "^6.0.1", + "jsdom": "^11.6.2", "loader.js": "^4.2.3", "prember": "0.3.0-alpha.3" }, @@ -70,6 +70,7 @@ "dependencies": { "babel-core": "^6.24.1", "ember-cli-babel": "^6.8.2", + "ember-compatibility-helpers": "^1.2.0", "ember-maybe-import-regenerator": "^0.1.5" }, "resolutions": { diff --git a/yarn.lock b/yarn.lock index 17cddb084..4bb24dab7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -528,6 +528,7 @@ "@ember/test-helpers@1.0.1", "@ember/test-helpers@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@ember/test-helpers/-/test-helpers-1.0.1.tgz#8d322bc3b02d38f2796558537da239438cadf0a2" + integrity sha512-frGgWAYwRfZJGwbBz8eZONYpnwsHraFQtsRaLO9XmBfX2O/3Yw91+DC9YuSlkant4JZw2W66NGvudyWjwCsfwg== dependencies: broccoli-debug "^0.6.5" broccoli-funnel "^2.0.1" @@ -1262,7 +1263,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" dependencies: @@ -3673,6 +3674,14 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-ve resolve "^1.3.3" semver "^5.3.0" +ember-cli-version-checker@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-2.2.0.tgz#47771b731fe0962705e27c8199a9e3825709f3b3" + integrity sha512-G+KtYIVlSOWGcNaTFHk76xR4GdzDLzAS4uxZUKdASuFX0KJE43C6DaqL+y3VTpUFLI2FIkAS6HZ4I1YBi+S3hg== + dependencies: + resolve "^1.3.3" + semver "^5.3.0" + ember-cli@~3.1.2: version "3.1.4" resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-3.1.4.tgz#95f7ff4302d535619b5d5ff1c7040877a67d4468" @@ -3774,6 +3783,15 @@ ember-code-snippet@^1.8.1: glob "^4.0.4" highlight.js "^9.5.0" +ember-compatibility-helpers@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ember-compatibility-helpers/-/ember-compatibility-helpers-1.2.0.tgz#feee16c5e9ef1b1f1e53903b241740ad4b01097e" + integrity sha512-pUW4MzJdcaQtwGsErYmitFRs0rlCYBAnunVzlFFUBr4xhjlCjgHJo0b53gFnhTgenNM3d3/NqLarzRhDTjXRTg== + 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.2: version "1.1.3" resolved "https://registry.yarnpkg.com/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e" @@ -3814,9 +3832,10 @@ ember-notify@~5.2.1: ember-string-ishtmlsafe-polyfill "^1.1.0" object-assign "^4.1.0" -ember-qunit@^4.1.2: +ember-qunit@4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-4.1.2.tgz#8013fb046342a70cb35845ca59a5a7fb344f3d90" + integrity sha512-okuqoURuM9MSk6JF7a3lz+8Nz0K3ldjd9bn0iQLADyOwObPEuj1APrRYw3TuoP5O4yOfC7uAy+spq39CNuR2sQ== dependencies: "@ember/test-helpers" "^1.0.1" broccoli-funnel "^2.0.1" @@ -5580,6 +5599,11 @@ invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= + ipaddr.js@1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e"