diff --git a/packages/@ember/-internals/glimmer/tests/integration/components/contextual-components-test.js b/packages/@ember/-internals/glimmer/tests/integration/components/contextual-components-test.js index ffc53313e27..3942709d539 100644 --- a/packages/@ember/-internals/glimmer/tests/integration/components/contextual-components-test.js +++ b/packages/@ember/-internals/glimmer/tests/integration/components/contextual-components-test.js @@ -1,7 +1,6 @@ import { DEBUG } from '@glimmer/env'; import { moduleFor, RenderingTestCase, applyMixins, strip, runTask } from 'internal-test-helpers'; -import { isEmpty } from '@ember/utils'; import { action } from '@ember/object'; import { A as emberA } from '@ember/array'; @@ -956,35 +955,35 @@ moduleFor( } ); - assert.ok(!isEmpty(instance), 'a instance was created'); + assert.ok(instance, 'the component instance exinstance was created'); assert.equal(previousInstance, undefined, 'no previous component exists'); assert.equal(initCount, 1, 'the component was constructed exactly 1 time'); assert.equal(this.$().text(), 'open', 'the components text is "open"'); runTask(() => this.rerender()); - assert.ok(!isEmpty(instance), 'the component instance exists'); + assert.ok(instance, 'the component instance exists'); assert.equal(previousInstance, undefined, 'no previous component exists'); assert.equal(initCount, 1, 'the component was constructed exactly 1 time'); assert.equal(this.$().text(), 'open', 'the components text is "open"'); runTask(() => this.context.set('isOpen', false)); - assert.ok(!isEmpty(instance), 'the component instance exists'); + assert.ok(instance, 'the component instance exists'); assert.equal(previousInstance, undefined, 'no previous component exists'); assert.equal(initCount, 1, 'the component was constructed exactly 1 time'); assert.equal(this.$().text(), 'closed', 'the component text is "closed"'); runTask(() => this.rerender()); - assert.ok(!isEmpty(instance), 'the component instance exists'); + assert.ok(instance, 'the component instance exists'); assert.equal(previousInstance, undefined, 'no previous component exists'); assert.equal(initCount, 1, 'the component was constructed exactly 1 time'); assert.equal(this.$().text(), 'closed', 'the component text is "closed"'); runTask(() => this.context.set('isOpen', true)); - assert.ok(!isEmpty(instance), 'the component instance exists'); + assert.ok(instance, 'the component instance exists'); assert.equal(previousInstance, undefined, 'no previous component exists'); assert.equal(initCount, 1, 'the component was constructed exactly 1 time'); assert.equal(this.$().text(), 'open', 'the components text is "open"'); @@ -1021,35 +1020,35 @@ moduleFor( } ); - assert.ok(!isEmpty(instance), 'a instance was created'); + assert.ok(instance, 'a instance was created'); assert.equal(previousInstance, undefined, 'no previous component exists'); assert.equal(initCount, 1, 'the component was constructed exactly 1 time'); assert.equal(this.$().text(), 'open', 'the components text is "open"'); runTask(() => this.rerender()); - assert.ok(!isEmpty(instance), 'the component instance exists'); + assert.ok(instance, 'the component instance exists'); assert.equal(previousInstance, undefined, 'no previous component exists'); assert.equal(initCount, 1, 'the component was constructed exactly 1 time'); assert.equal(this.$().text(), 'open', 'the components text is "open"'); runTask(() => this.context.set('isOpen', false)); - assert.ok(!isEmpty(instance), 'the component instance exists'); + assert.ok(instance, 'the component instance exists'); assert.equal(previousInstance, undefined, 'no previous component exists'); assert.equal(initCount, 1, 'the component was constructed exactly 1 time'); assert.equal(this.$().text(), 'closed', 'the component text is "closed"'); runTask(() => this.rerender()); - assert.ok(!isEmpty(instance), 'the component instance exists'); + assert.ok(instance, 'the component instance exists'); assert.equal(previousInstance, undefined, 'no previous component exists'); assert.equal(initCount, 1, 'the component was constructed exactly 1 time'); assert.equal(this.$().text(), 'closed', 'the component text is "closed"'); runTask(() => this.context.set('isOpen', true)); - assert.ok(!isEmpty(instance), 'the component instance exists'); + assert.ok(instance, 'the component instance exists'); assert.equal(previousInstance, undefined, 'no previous component exists'); assert.equal(initCount, 1, 'the component was constructed exactly 1 time'); assert.equal(this.$().text(), 'open', 'the components text is "open"'); @@ -1099,22 +1098,22 @@ moduleFor( } ); - assert.ok(!isEmpty(instance), 'a instance was created'); + assert.ok(instance, 'a instance was created'); assert.equal(previousInstance, undefined, 'there is no previous instance'); assert.equal(initCount, 1, 'the component was constructed exactly 1 time'); assert.equal(this.$().text(), 'my-comp: open'); runTask(() => this.rerender()); - assert.ok(!isEmpty(instance), 'a instance exists after rerender'); + assert.ok(instance, 'a instance exists after rerender'); assert.equal(previousInstance, undefined, 'there is no previous instance after rerender'); assert.equal(initCount, 1, 'the component was constructed exactly 1 time'); assert.equal(this.$().text(), 'my-comp: open'); runTask(() => this.context.set('compName', 'your-comp')); - assert.ok(!isEmpty(instance), 'an instance was created after component name changed'); - assert.ok(!isEmpty(previousInstance), 'a previous instance now exists'); + assert.ok(instance, 'an instance was created after component name changed'); + assert.ok(previousInstance, 'a previous instance now exists'); assert.notEqual( instance, previousInstance, @@ -1125,11 +1124,8 @@ moduleFor( runTask(() => this.rerender()); - assert.ok( - !isEmpty(instance), - 'an instance was created after component name changed (rerender)' - ); - assert.ok(!isEmpty(previousInstance), 'a previous instance now exists (rerender)'); + assert.ok(instance, 'an instance was created after component name changed (rerender)'); + assert.ok(previousInstance, 'a previous instance now exists (rerender)'); assert.notEqual( instance, previousInstance, @@ -1140,8 +1136,8 @@ moduleFor( runTask(() => this.context.set('compName', 'my-comp')); - assert.ok(!isEmpty(instance), 'an instance was created after component name changed'); - assert.ok(!isEmpty(previousInstance), 'a previous instance still exists'); + assert.ok(instance, 'an instance was created after component name changed'); + assert.ok(previousInstance, 'a previous instance still exists'); assert.notEqual( instance, previousInstance, diff --git a/packages/@ember/-internals/utils/index.ts b/packages/@ember/-internals/utils/index.ts index 329a6f7e793..7562417c109 100644 --- a/packages/@ember/-internals/utils/index.ts +++ b/packages/@ember/-internals/utils/index.ts @@ -33,3 +33,5 @@ export { teardownMandatorySetter, setWithMandatorySetter, } from './lib/mandatory-setter'; +export type { TypeName } from './lib/type-of'; +export { default as typeOf } from './lib/type-of'; diff --git a/packages/@ember/-internals/utils/lib/type-of.ts b/packages/@ember/-internals/utils/lib/type-of.ts new file mode 100644 index 00000000000..356d0e5b6af --- /dev/null +++ b/packages/@ember/-internals/utils/lib/type-of.ts @@ -0,0 +1,125 @@ +// import CoreObject from '@ember/object/core'; + +export type TypeName = + | 'undefined' + | 'null' + | 'string' + | 'number' + | 'boolean' + | 'function' + | 'array' + | 'regexp' + | 'date' + | 'filelist' + | 'class' + | 'instance' + | 'error' + | 'object'; + +// ........................................ +// TYPING & ARRAY MESSAGING +// +const TYPE_MAP: Record = { + '[object Boolean]': 'boolean', + '[object Number]': 'number', + '[object String]': 'string', + '[object Function]': 'function', + '[object AsyncFunction]': 'function', + '[object Array]': 'array', + '[object Date]': 'date', + '[object RegExp]': 'regexp', + '[object Object]': 'object', + '[object FileList]': 'filelist', +} as const; + +const { toString } = Object.prototype; + +/** + @module @ember/utils +*/ +/** + Returns a consistent type for the passed object. + + Use this instead of the built-in `typeof` to get the type of an item. + It will return the same result across all browsers and includes a bit + more detail. Here is what will be returned: + + | Return Value | Meaning | + |---------------|------------------------------------------------------| + | 'string' | String primitive or String object. | + | 'number' | Number primitive or Number object. | + | 'boolean' | Boolean primitive or Boolean object. | + | 'null' | Null value | + | 'undefined' | Undefined value | + | 'function' | A function | + | 'array' | An instance of Array | + | 'regexp' | An instance of RegExp | + | 'date' | An instance of Date | + | 'filelist' | An instance of FileList | + | 'class' | An Ember class (created using EmberObject.extend()) | + | 'instance' | An Ember object instance | + | 'error' | An instance of the Error object | + | 'object' | A JavaScript object not inheriting from EmberObject | + + Examples: + + ```javascript + import { A } from '@ember/array'; + import { typeOf } from '@ember/utils'; + import EmberObject from '@ember/object'; + + typeOf(); // 'undefined' + typeOf(null); // 'null' + typeOf(undefined); // 'undefined' + typeOf('michael'); // 'string' + typeOf(new String('michael')); // 'string' + typeOf(101); // 'number' + typeOf(new Number(101)); // 'number' + typeOf(true); // 'boolean' + typeOf(new Boolean(true)); // 'boolean' + typeOf(A); // 'function' + typeOf(A()); // 'array' + typeOf([1, 2, 90]); // 'array' + typeOf(/abc/); // 'regexp' + typeOf(new Date()); // 'date' + typeOf(event.target.files); // 'filelist' + typeOf(EmberObject.extend()); // 'class' + typeOf(EmberObject.create()); // 'instance' + typeOf(new Error('teamocil')); // 'error' + + // 'normal' JavaScript object + typeOf({ a: 'b' }); // 'object' + ``` + + @method typeOf + @for @ember/-internals/utils + @param item the item to check + @return {String} the type + @public + @static +*/ +export default function typeOf(item: unknown): TypeName { + if (item === null) { + return 'null'; + } + if (item === undefined) { + return 'undefined'; + } + let ret = TYPE_MAP[toString.call(item)] || 'object'; + + if (ret === 'function') { + // if (CoreObject.detect(item)) { + // ret = 'class'; + // } + } else if (ret === 'object') { + if (item instanceof Error) { + ret = 'error'; + // } else if (item instanceof CoreObject) { + // ret = 'instance'; + } else if (item instanceof Date) { + ret = 'date'; + } + } + + return ret; +} diff --git a/packages/@ember/array/index.ts b/packages/@ember/array/index.ts index bdff2a18e4b..351a9ebc201 100644 --- a/packages/@ember/array/index.ts +++ b/packages/@ember/array/index.ts @@ -16,7 +16,8 @@ import Mixin from '@ember/object/mixin'; import { assert } from '@ember/debug'; import Enumerable from '@ember/enumerable'; import MutableEnumerable from '@ember/enumerable/mutable'; -import { compare, typeOf } from '@ember/utils'; +import { compare } from '@ember/utils'; +import { typeOf } from '@ember/-internals/utils'; import Observable from '@ember/object/observable'; import type { MethodNamesOf, MethodParams, MethodReturns } from '@ember/-internals/utility-types'; import type { ComputedPropertyCallback } from '@ember/-internals/metal'; diff --git a/packages/@ember/debug/container-debug-adapter.ts b/packages/@ember/debug/container-debug-adapter.ts index e62fcb0ed7b..a3c14d77d0e 100644 --- a/packages/@ember/debug/container-debug-adapter.ts +++ b/packages/@ember/debug/container-debug-adapter.ts @@ -1,6 +1,6 @@ import { classify, dasherize } from '@ember/-internals/string'; import EmberObject from '@ember/object'; -import { typeOf } from '@ember/utils'; +import { typeOf } from '@ember/-internals/utils'; import type Owner from '@ember/owner'; import { getOwner } from '@ember/-internals/owner'; import type { Resolver } from '@ember/owner'; diff --git a/packages/@ember/object/lib/computed/computed_macros.ts b/packages/@ember/object/lib/computed/computed_macros.ts index 0c71a2967e0..5cfcb97197b 100644 --- a/packages/@ember/object/lib/computed/computed_macros.ts +++ b/packages/@ember/object/lib/computed/computed_macros.ts @@ -96,6 +96,13 @@ function generateComputedWithPredicate(name: string, predicate: (value: unknown) @public */ export function empty(dependentKey: string) { + deprecate('empty is deprecated. Define your own property using @ember/legacy-utils.', false, { + id: 'ember-object.deprecate-empty', + until: '7.0.0', + for: 'ember-source', + since: { available: '6.8.0' }, + }); + assert( 'You attempted to use @empty as a decorator directly, but it requires a `dependentKey` parameter', !isElementDescriptor(Array.prototype.slice.call(arguments)) @@ -142,6 +149,13 @@ export function empty(dependentKey: string) { @public */ export function notEmpty(dependentKey: string) { + deprecate('notEmpty is deprecated. Define your own property using @ember/legacy-utils.', false, { + id: 'ember-object.deprecate-not-empty', + until: '7.0.0', + for: 'ember-source', + since: { available: '6.8.0' }, + }); + assert( 'You attempted to use @notEmpty as a decorator directly, but it requires a `dependentKey` parameter', !isElementDescriptor(Array.prototype.slice.call(arguments)) @@ -185,6 +199,13 @@ export function notEmpty(dependentKey: string) { @public */ export function none(dependentKey: string) { + deprecate('none is deprecated. Define your own property using @ember/legacy-utils.', false, { + id: 'ember-object.deprecate-none', + until: '7.0.0', + for: 'ember-source', + since: { available: '6.8.0' }, + }); + assert( 'You attempted to use @none as a decorator directly, but it requires a `dependentKey` parameter', !isElementDescriptor(Array.prototype.slice.call(arguments)) diff --git a/packages/@ember/routing/route.ts b/packages/@ember/routing/route.ts index 7b4a8f24eac..f791f04c89b 100644 --- a/packages/@ember/routing/route.ts +++ b/packages/@ember/routing/route.ts @@ -12,8 +12,7 @@ import EmberObject, { computed, get, set, getProperties, setProperties } from '@ import Evented from '@ember/object/evented'; import { A as emberA } from '@ember/array'; import { ActionHandler } from '@ember/-internals/runtime'; -import { typeOf } from '@ember/utils'; -import { isProxy, lookupDescriptor } from '@ember/-internals/utils'; +import { isProxy, lookupDescriptor, typeOf } from '@ember/-internals/utils'; import type { AnyFn } from '@ember/-internals/utility-types'; import Controller from '@ember/controller'; import type { ControllerQueryParamType } from '@ember/controller'; diff --git a/packages/@ember/routing/router.ts b/packages/@ember/routing/router.ts index a52b28f0a32..3c3e4b77b81 100644 --- a/packages/@ember/routing/router.ts +++ b/packages/@ember/routing/router.ts @@ -21,7 +21,7 @@ import type { import type RouterService from '@ember/routing/router-service'; import EmberObject from '@ember/object'; import { A as emberA } from '@ember/array'; -import { typeOf } from '@ember/utils'; +import { typeOf } from '@ember/-internals/utils'; import Evented from '@ember/object/evented'; import { assert, info } from '@ember/debug'; import { cancel, once, run, scheduleOnce } from '@ember/runloop'; diff --git a/packages/@ember/utils/lib/compare.ts b/packages/@ember/utils/lib/compare.ts index ed070317f29..5ada287cafa 100644 --- a/packages/@ember/utils/lib/compare.ts +++ b/packages/@ember/utils/lib/compare.ts @@ -1,7 +1,7 @@ import type { TypeName } from './type-of'; import typeOf from './type-of'; import { Comparable } from '@ember/-internals/runtime'; -import { assert } from '@ember/debug'; +import { assert, deprecate } from '@ember/debug'; const TYPE_ORDER: Record = { undefined: 0, @@ -97,6 +97,13 @@ function spaceship(a: number, b: number): Compare { @public */ export default function compare(v: T, w: T): Compare { + deprecate('compare is deprecated. Use @ember/legacy-utils instead.', false, { + for: 'ember-source', + id: 'ember-utils.deprecate-compare', + since: { available: '6.8.0' }, + until: '7.0.0', + }); + if (v === w) { return 0; } diff --git a/packages/@ember/utils/lib/is-equal.ts b/packages/@ember/utils/lib/is-equal.ts index a6180c27292..49e7ecfe957 100644 --- a/packages/@ember/utils/lib/is-equal.ts +++ b/packages/@ember/utils/lib/is-equal.ts @@ -1,6 +1,9 @@ /** @module @ember/utils */ + +import { deprecate } from '@ember/debug'; + /** Compares two objects, returning true if they are equal. @@ -48,6 +51,13 @@ @public */ export default function isEqual(a: unknown, b: unknown): boolean { + deprecate('isEqual is deprecated. Use @ember/legacy-utils instead.', false, { + for: 'ember-source', + id: 'ember-utils.deprecate-isEqual', + since: { available: '6.8.0' }, + until: '7.0.0', + }); + if (a && typeof (a as IsEqual).isEqual === 'function') { return (a as IsEqual).isEqual(b); } diff --git a/packages/@ember/utils/lib/is_blank.ts b/packages/@ember/utils/lib/is_blank.ts index 2caef0a9043..fad63119c41 100644 --- a/packages/@ember/utils/lib/is_blank.ts +++ b/packages/@ember/utils/lib/is_blank.ts @@ -1,3 +1,4 @@ +import { deprecate } from '@ember/debug'; import isEmpty from './is_empty'; /** @module @ember/utils @@ -29,5 +30,12 @@ import isEmpty from './is_empty'; @public */ export default function isBlank(obj: unknown): boolean { + deprecate('isBlank is deprecated. Use @ember/legacy-utils instead.', false, { + for: 'ember-source', + id: 'ember-utils.deprecate-isBlank', + since: { available: '6.8.0' }, + until: '7.0.0', + }); + return isEmpty(obj) || (typeof obj === 'string' && /\S/.test(obj) === false); } diff --git a/packages/@ember/utils/lib/is_empty.ts b/packages/@ember/utils/lib/is_empty.ts index 9bc46e82c08..7f12ca961a6 100644 --- a/packages/@ember/utils/lib/is_empty.ts +++ b/packages/@ember/utils/lib/is_empty.ts @@ -1,5 +1,6 @@ import { get } from '@ember/object'; import { hasUnknownProperty } from '@ember/-internals/metal'; +import { deprecate } from '@ember/debug'; /** @module @ember/utils */ @@ -36,6 +37,13 @@ import { hasUnknownProperty } from '@ember/-internals/metal'; @public */ export default function isEmpty(obj: unknown): boolean { + deprecate('isEmpty is deprecated. Use @ember/legacy-utils instead.', false, { + for: 'ember-source', + id: 'ember-utils.deprecate-isEmpty', + since: { available: '6.8.0' }, + until: '7.0.0', + }); + if (obj === null || obj === undefined) { return true; } diff --git a/packages/@ember/utils/lib/is_none.ts b/packages/@ember/utils/lib/is_none.ts index 2b29252a21b..3b4dacdf44d 100644 --- a/packages/@ember/utils/lib/is_none.ts +++ b/packages/@ember/utils/lib/is_none.ts @@ -1,6 +1,9 @@ /** @module @ember/utils */ + +import { deprecate } from '@ember/debug'; + /** Returns true if the passed value is null or undefined. This avoids errors from JSLint complaining about use of ==, which can be technically @@ -22,5 +25,12 @@ @public */ export default function isNone(obj: any): obj is null | undefined { + deprecate('isNone is deprecated. Use @ember/legacy-utils instead.', false, { + for: 'ember-source', + id: 'ember-utils.deprecate-isNone', + since: { available: '6.8.0' }, + until: '7.0.0', + }); + return obj === null || obj === undefined; } diff --git a/packages/@ember/utils/lib/is_present.ts b/packages/@ember/utils/lib/is_present.ts index 62327739e65..56b7b53d030 100644 --- a/packages/@ember/utils/lib/is_present.ts +++ b/packages/@ember/utils/lib/is_present.ts @@ -1,3 +1,4 @@ +import { deprecate } from '@ember/debug'; import isBlank from './is_blank'; /** @module @ember/utils @@ -32,5 +33,12 @@ import isBlank from './is_blank'; @public */ export default function isPresent(obj: T | null | undefined): obj is T { + deprecate('isPresent is deprecated. Use @ember/legacy-utils instead.', false, { + for: 'ember-source', + id: 'ember-utils.deprecate-isPresent', + since: { available: '6.8.0' }, + until: '7.0.0', + }); + return !isBlank(obj); } diff --git a/packages/@ember/utils/lib/type-of.ts b/packages/@ember/utils/lib/type-of.ts index b43888a3bf8..8f7aa0ab21f 100644 --- a/packages/@ember/utils/lib/type-of.ts +++ b/packages/@ember/utils/lib/type-of.ts @@ -1,38 +1,8 @@ -import CoreObject from '@ember/object/core'; +import { deprecate } from '@ember/debug'; +import type { TypeName } from '@ember/-internals/utils'; +import typeOfInternal from '@ember/-internals/utils/lib/type-of'; -export type TypeName = - | 'undefined' - | 'null' - | 'string' - | 'number' - | 'boolean' - | 'function' - | 'array' - | 'regexp' - | 'date' - | 'filelist' - | 'class' - | 'instance' - | 'error' - | 'object'; - -// ........................................ -// TYPING & ARRAY MESSAGING -// -const TYPE_MAP: Record = { - '[object Boolean]': 'boolean', - '[object Number]': 'number', - '[object String]': 'string', - '[object Function]': 'function', - '[object AsyncFunction]': 'function', - '[object Array]': 'array', - '[object Date]': 'date', - '[object RegExp]': 'regexp', - '[object Object]': 'object', - '[object FileList]': 'filelist', -} as const; - -const { toString } = Object.prototype; +export type { TypeName }; /** @module @ember/utils @@ -99,27 +69,12 @@ const { toString } = Object.prototype; @static */ export default function typeOf(item: unknown): TypeName { - if (item === null) { - return 'null'; - } - if (item === undefined) { - return 'undefined'; - } - let ret = TYPE_MAP[toString.call(item)] || 'object'; - - if (ret === 'function') { - if (CoreObject.detect(item)) { - ret = 'class'; - } - } else if (ret === 'object') { - if (item instanceof Error) { - ret = 'error'; - } else if (item instanceof CoreObject) { - ret = 'instance'; - } else if (item instanceof Date) { - ret = 'date'; - } - } + deprecate('typeOf is deprecated. Use @ember/legacy-utils instead.', false, { + for: 'ember-source', + id: 'ember-utils.deprecate-typeOf', + since: { available: '6.8.0' }, + until: '7.0.0', + }); - return ret; + return typeOfInternal(item); }