From 8539f04c72d96757a7b6c6d3cf7c101cbf1daa60 Mon Sep 17 00:00:00 2001 From: Peter Wagenet Date: Thu, 10 Feb 2022 08:45:33 -0800 Subject: [PATCH 1/5] Convert @ember/-internals/extension-support to TS --- .../extension-support/{index.js => index.ts} | 0 ..._adapter.js => container_debug_adapter.ts} | 36 +-- .../lib/{data_adapter.js => data_adapter.ts} | 233 ++++++++++-------- .../runtime/lib/system/namespace.d.ts | 4 +- 4 files changed, 157 insertions(+), 116 deletions(-) rename packages/@ember/-internals/extension-support/{index.js => index.ts} (100%) rename packages/@ember/-internals/extension-support/lib/{container_debug_adapter.js => container_debug_adapter.ts} (78%) rename packages/@ember/-internals/extension-support/lib/{data_adapter.js => data_adapter.ts} (74%) diff --git a/packages/@ember/-internals/extension-support/index.js b/packages/@ember/-internals/extension-support/index.ts similarity index 100% rename from packages/@ember/-internals/extension-support/index.js rename to packages/@ember/-internals/extension-support/index.ts diff --git a/packages/@ember/-internals/extension-support/lib/container_debug_adapter.js b/packages/@ember/-internals/extension-support/lib/container_debug_adapter.ts similarity index 78% rename from packages/@ember/-internals/extension-support/lib/container_debug_adapter.js rename to packages/@ember/-internals/extension-support/lib/container_debug_adapter.ts index 2d352fc15ab..39f9f6c161f 100644 --- a/packages/@ember/-internals/extension-support/lib/container_debug_adapter.js +++ b/packages/@ember/-internals/extension-support/lib/container_debug_adapter.ts @@ -1,6 +1,13 @@ import { classify, dasherize } from '@ember/string'; -import { A as emberA, typeOf, Namespace, Object as EmberObject } from '@ember/-internals/runtime'; -import { getOwner } from '@ember/-internals/owner'; +import { + A as emberA, + typeOf, + Namespace, + Object as EmberObject, + NativeArray, +} from '@ember/-internals/runtime'; +import { getOwner, Owner } from '@ember/-internals/owner'; +import { Resolver } from '@ember/-internals/container/lib/registry'; /** @module @ember/debug @@ -40,12 +47,12 @@ import { getOwner } from '@ember/-internals/owner'; @since 1.5.0 @public */ -export default EmberObject.extend({ - init() { - this._super(...arguments); +export default class ContainerDebugAdapter extends EmberObject { + constructor(owner: Owner) { + super(owner); - this.resolver = getOwner(this).lookup('resolver-for-debugging:main'); - }, + this.resolver = getOwner(this)!.lookup('resolver-for-debugging:main') as Resolver; + } /** The resolver instance of the application @@ -53,10 +60,9 @@ export default EmberObject.extend({ on creation. @property resolver - @default null @public */ - resolver: null, + declare resolver: Resolver; /** Returns true if it is possible to catalog a list of available @@ -67,13 +73,13 @@ export default EmberObject.extend({ @return {boolean} whether a list is available for this type. @public */ - canCatalogEntriesByType(type) { + canCatalogEntriesByType(type: string) { if (type === 'model' || type === 'template') { return false; } return true; - }, + } /** Returns the available classes a given type. @@ -83,9 +89,9 @@ export default EmberObject.extend({ @return {Array} An array of strings. @public */ - catalogEntriesByType(type) { + catalogEntriesByType(type: string): NativeArray { let namespaces = emberA(Namespace.NAMESPACES); - let types = emberA(); + let types = emberA(); let typeSuffixRegex = new RegExp(`${classify(type)}$`); namespaces.forEach((namespace) => { @@ -102,5 +108,5 @@ export default EmberObject.extend({ } }); return types; - }, -}); + } +} diff --git a/packages/@ember/-internals/extension-support/lib/data_adapter.js b/packages/@ember/-internals/extension-support/lib/data_adapter.ts similarity index 74% rename from packages/@ember/-internals/extension-support/lib/data_adapter.js rename to packages/@ember/-internals/extension-support/lib/data_adapter.ts index 48dfa90647e..8874c4c2c62 100644 --- a/packages/@ember/-internals/extension-support/lib/data_adapter.js +++ b/packages/@ember/-internals/extension-support/lib/data_adapter.ts @@ -1,11 +1,36 @@ -import { getOwner } from '@ember/-internals/owner'; +import { getOwner, Owner } from '@ember/-internals/owner'; import { _backburner } from '@ember/runloop'; import { get } from '@ember/-internals/metal'; import { dasherize } from '@ember/string'; -import { Namespace, Object as EmberObject, A as emberA } from '@ember/-internals/runtime'; -import { consumeTag, createCache, getValue, tagFor, untrack } from '@glimmer/validator'; - -function iterate(arr, fn) { +import { + Namespace, + Object as EmberObject, + A as emberA, + NativeArray, +} from '@ember/-internals/runtime'; +import { consumeTag, createCache, getValue, tagFor, untrack, Cache } from '@glimmer/validator'; +import { ContainerDebugAdapter } from '..'; + +type RecordColor = 'black' | 'red' | 'blue' | 'green'; + +type WrappedType = { + name: N; + count: number; + columns: unknown[]; + object: unknown; +}; + +type WrappedRecord = { + object: T; + columnValues: object; + searchKeywords: NativeArray; + filterValues: object; + color: RecordColor | null; +}; + +type RecordCallback = (records: Array<{ columnValues: object; object: T }>) => void; + +function iterate(arr: Array, fn: (value: T) => void): void { if (Symbol.iterator in arr) { for (let item of arr) { fn(item); @@ -15,14 +40,16 @@ function iterate(arr, fn) { } } -class RecordsWatcher { - recordCaches = new Map(); +class RecordsWatcher { + recordCaches: Map> = new Map(); + + added: WrappedRecord[] = []; + updated: WrappedRecord[] = []; + removed: WrappedRecord[] = []; - added = []; - updated = []; - removed = []; + declare recordArrayCache: Cache; - getCacheForItem(record) { + getCacheForItem(record: T) { let recordCache = this.recordCaches.get(record); if (!recordCache) { @@ -43,10 +70,14 @@ class RecordsWatcher { return recordCache; } - constructor(records, recordsAdded, recordsUpdated, recordsRemoved, wrapRecord, release) { - this.release = release; - this.wrapRecord = wrapRecord; - + constructor( + records: NativeArray, + recordsAdded: RecordCallback, + recordsUpdated: RecordCallback, + recordsRemoved: RecordCallback, + public wrapRecord: (record: T) => WrappedRecord, + public release: () => void + ) { this.recordArrayCache = createCache(() => { let seen = new Set(); @@ -61,7 +92,7 @@ class RecordsWatcher { // Untrack this operation because these records are being removed, they // should not be polled again in the future untrack(() => { - this.recordCaches.forEach((cache, record) => { + this.recordCaches.forEach((_cache, record) => { if (!seen.has(record)) { this.removed.push(wrapRecord(record)); this.recordCaches.delete(record); @@ -92,7 +123,9 @@ class RecordsWatcher { } class TypeWatcher { - constructor(records, onChange, release) { + declare cache: Cache; + + constructor(records: unknown[], onChange: () => void, public release: () => void) { let hasBeenAccessed = false; this.cache = createCache(() => { @@ -162,17 +195,21 @@ class TypeWatcher { @extends EmberObject @public */ -export default EmberObject.extend({ - init() { - this._super(...arguments); - - this.containerDebugAdapter = getOwner(this).lookup('container-debug-adapter:main'); - - this.releaseMethods = emberA(); - this.recordsWatchers = new Map(); - this.typeWatchers = new Map(); - this.flushWatchers = null; - }, +export default class DataAdapter extends EmberObject { + releaseMethods = emberA<() => void>(); + recordsWatchers: Map void; revalidate: () => void }> = new Map(); + typeWatchers: Map void; revalidate: () => void }> = new Map(); + flushWatchers: (() => void) | null = null; + + // TODO: Revisit this + declare containerDebugAdapter: ContainerDebugAdapter; + + constructor(owner: Owner) { + super(owner); + this.containerDebugAdapter = getOwner(this)!.lookup( + 'container-debug-adapter:main' + ) as ContainerDebugAdapter; + } /** The container-debug-adapter which is used @@ -194,7 +231,7 @@ export default EmberObject.extend({ @default 3 @since 1.3.0 */ - attributeLimit: 3, + attributeLimit = 3; /** Ember Data > v1.0.0-beta.18 @@ -208,7 +245,7 @@ export default EmberObject.extend({ @public @property acceptsModelName */ - acceptsModelName: true, + acceptsModelName = true; /** Map from records arrays to RecordsWatcher instances @@ -257,7 +294,7 @@ export default EmberObject.extend({ */ getFilters() { return emberA(); - }, + } /** Fetch the model types and observe them for changes. @@ -273,9 +310,12 @@ export default EmberObject.extend({ @return {Function} Method to call to remove all observers */ - watchModelTypes(typesAdded, typesUpdated) { + watchModelTypes( + typesAdded: (types: WrappedType[]) => void, + typesUpdated: (types: WrappedType[]) => void + ) { let modelTypes = this.getModelTypes(); - let releaseMethods = emberA(); + let releaseMethods = emberA<() => void>(); let typesToSend; typesToSend = modelTypes.map((type) => { @@ -293,16 +333,16 @@ export default EmberObject.extend({ }; this.releaseMethods.pushObject(release); return release; - }, + } - _nameToClass(type) { + _nameToClass(type: unknown): unknown { if (typeof type === 'string') { - let owner = getOwner(this); + let owner = getOwner(this)!; let Factory = owner.factoryFor(`model:${type}`); type = Factory && Factory.class; } return type; - }, + } /** Fetch the records of a given type and observe them for changes. @@ -326,7 +366,12 @@ export default EmberObject.extend({ @return {Function} Method to call to remove all observers. */ - watchRecords(modelName, recordsAdded, recordsUpdated, recordsRemoved) { + watchRecords( + modelName: string, + recordsAdded: RecordCallback, + recordsUpdated: RecordCallback, + recordsRemoved: RecordCallback + ) { let klass = this._nameToClass(modelName); let records = this.getRecords(klass, modelName); let { recordsWatchers } = this; @@ -334,12 +379,12 @@ export default EmberObject.extend({ let recordsWatcher = recordsWatchers.get(records); if (!recordsWatcher) { - recordsWatcher = new RecordsWatcher( + recordsWatcher = new RecordsWatcher( records, recordsAdded, recordsUpdated, recordsRemoved, - (record) => this.wrapRecord(record), + (record: T) => this.wrapRecord(record), () => { recordsWatchers.delete(records); this.updateFlushWatchers(); @@ -353,7 +398,7 @@ export default EmberObject.extend({ } return recordsWatcher.release; - }, + } updateFlushWatchers() { if (this.flushWatchers === null) { @@ -369,7 +414,7 @@ export default EmberObject.extend({ _backburner.off('end', this.flushWatchers); this.flushWatchers = null; } - }, + } /** Clear all observers before destruction @@ -387,7 +432,7 @@ export default EmberObject.extend({ if (this.flushWatchers) { _backburner.off('end', this.flushWatchers); } - }, + } /** Detect whether a class is a model. @@ -399,9 +444,9 @@ export default EmberObject.extend({ @method detect @return boolean Whether the class is a model class or not. */ - detect() { + detect(_klass: unknown): boolean { return false; - }, + } /** Get the columns for a given model type. @@ -412,9 +457,9 @@ export default EmberObject.extend({ name: {String} The name of the column. desc: {String} Humanized description (what would show in a table column name). */ - columnsForType() { + columnsForType(_klass: unknown) { return emberA(); - }, + } /** Adds observers to a model type class. @@ -426,7 +471,7 @@ export default EmberObject.extend({ @return {Function} The function to call to remove observers. */ - observeModelType(modelName, typesUpdated) { + observeModelType(modelName: string, typesUpdated: (types: WrappedType[]) => void) { let klass = this._nameToClass(modelName); let records = this.getRecords(klass, modelName); @@ -451,7 +496,7 @@ export default EmberObject.extend({ } return typeWatcher.release; - }, + } /** Wraps a given model type and observes changes to it. @@ -460,29 +505,22 @@ export default EmberObject.extend({ @method wrapModelType @param {Class} klass A model class. @param {String} modelName Name of the class. - @return {Object} Contains the wrapped type and the function to remove observers - Format: - type: {Object} The wrapped type. - The wrapped type has the following format: - name: {String} The name of the type. - count: {Integer} The number of records available. - columns: {Columns} An array of columns to describe the record. - object: {Class} The actual Model type class. - release: {Function} The function to remove observers. + @return {Object} The wrapped type has the following format: + name: {String} The name of the type. + count: {Integer} The number of records available. + columns: {Columns} An array of columns to describe the record. + object: {Class} The actual Model type class. */ - wrapModelType(klass, name) { + wrapModelType(klass: unknown, name: N): WrappedType { let records = this.getRecords(klass, name); - let typeToSend; - typeToSend = { + return { name, count: get(records, 'length'), columns: this.columnsForType(klass), object: klass, }; - - return typeToSend; - }, + } /** Fetches all models defined in the application. @@ -491,27 +529,23 @@ export default EmberObject.extend({ @method getModelTypes @return {Array} Array of model types. */ - getModelTypes() { - let containerDebugAdapter = this.get('containerDebugAdapter'); - let types; - - if (containerDebugAdapter.canCatalogEntriesByType('model')) { - types = containerDebugAdapter.catalogEntriesByType('model'); - } else { - types = this._getObjectsOnNamespaces(); - } + getModelTypes(): NativeArray<{ klass: unknown; name: string }> { + let containerDebugAdapter = this.containerDebugAdapter; + + let stringTypes = containerDebugAdapter.canCatalogEntriesByType('model') + ? containerDebugAdapter.catalogEntriesByType('model') + : this._getObjectsOnNamespaces(); // New adapters return strings instead of classes. - types = emberA(types).map((name) => { + let klassTypes = emberA(stringTypes).map((name) => { return { klass: this._nameToClass(name), name, }; }); - types = emberA(types).filter((type) => this.detect(type.klass)); - return emberA(types); - }, + return emberA(klassTypes).filter((type) => this.detect(type.klass)); + } /** Loops over all namespaces and all objects @@ -523,7 +557,7 @@ export default EmberObject.extend({ */ _getObjectsOnNamespaces() { let namespaces = emberA(Namespace.NAMESPACES); - let types = emberA(); + let types = emberA(); namespaces.forEach((namespace) => { for (let key in namespace) { @@ -540,7 +574,7 @@ export default EmberObject.extend({ } }); return types; - }, + } /** Fetches all loaded records for a given type. @@ -551,9 +585,9 @@ export default EmberObject.extend({ This array will be observed for changes, so it should update when new records are added/removed. */ - getRecords() { + getRecords(_klass: unknown, _name: string): NativeArray { return emberA(); - }, + } /** Wraps a record and observers changes to it. @@ -565,16 +599,15 @@ export default EmberObject.extend({ columnValues: {Array} searchKeywords: {Array} */ - wrapRecord(record) { - let recordToSend = { object: record }; - - recordToSend.columnValues = this.getRecordColumnValues(record); - recordToSend.searchKeywords = this.getRecordKeywords(record); - recordToSend.filterValues = this.getRecordFilterValues(record); - recordToSend.color = this.getRecordColor(record); - - return recordToSend; - }, + wrapRecord(record: T): WrappedRecord { + return { + object: record, + columnValues: this.getRecordColumnValues(record), + searchKeywords: this.getRecordKeywords(record), + filterValues: this.getRecordFilterValues(record), + color: this.getRecordColor(record), + }; + } /** Gets the values for each column. @@ -584,9 +617,9 @@ export default EmberObject.extend({ @return {Object} Keys should match column names defined by the model type. */ - getRecordColumnValues() { + getRecordColumnValues(_record: T) { return {}; - }, + } /** Returns keywords to match when searching records. @@ -595,9 +628,9 @@ export default EmberObject.extend({ @method getRecordKeywords @return {Array} Relevant keywords for search. */ - getRecordKeywords() { + getRecordKeywords(_record: T) { return emberA(); - }, + } /** Returns the values of filters defined by `getFilters`. @@ -607,9 +640,9 @@ export default EmberObject.extend({ @param {Object} record The record instance. @return {Object} The filter values. */ - getRecordFilterValues() { + getRecordFilterValues(_record: T): object { return {}; - }, + } /** Each record can have a color that represents its state. @@ -620,7 +653,7 @@ export default EmberObject.extend({ @return {String} The records color. Possible options: black, red, blue, green. */ - getRecordColor() { + getRecordColor(_record: T): RecordColor | null { return null; - }, -}); + } +} diff --git a/packages/@ember/-internals/runtime/lib/system/namespace.d.ts b/packages/@ember/-internals/runtime/lib/system/namespace.d.ts index 601adb8f8d2..d660535fbdf 100644 --- a/packages/@ember/-internals/runtime/lib/system/namespace.d.ts +++ b/packages/@ember/-internals/runtime/lib/system/namespace.d.ts @@ -1,3 +1,5 @@ import EmberObject from './object'; -export default class Namespace extends EmberObject {} +export default class Namespace extends EmberObject { + static NAMESPACES: Namespace[]; +} From cd40a6be39e99664c13293a87c900ccb68f38d1c Mon Sep 17 00:00:00 2001 From: Peter Wagenet Date: Thu, 10 Feb 2022 10:19:27 -0800 Subject: [PATCH 2/5] Convert @ember/-internals/overrides to TS --- packages/@ember/-internals/overrides/index.js | 1 - packages/@ember/-internals/overrides/index.ts | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 packages/@ember/-internals/overrides/index.js create mode 100644 packages/@ember/-internals/overrides/index.ts diff --git a/packages/@ember/-internals/overrides/index.js b/packages/@ember/-internals/overrides/index.js deleted file mode 100644 index e016036f95e..00000000000 --- a/packages/@ember/-internals/overrides/index.js +++ /dev/null @@ -1 +0,0 @@ -export let onEmberGlobalAccess; diff --git a/packages/@ember/-internals/overrides/index.ts b/packages/@ember/-internals/overrides/index.ts new file mode 100644 index 00000000000..a940eb1661d --- /dev/null +++ b/packages/@ember/-internals/overrides/index.ts @@ -0,0 +1 @@ +export let onEmberGlobalAccess: any; From d62c50959caf37a9a91ea6306619be446ef671cb Mon Sep 17 00:00:00 2001 From: Peter Wagenet Date: Thu, 10 Feb 2022 10:31:03 -0800 Subject: [PATCH 3/5] Convert @ember/-internals/runtime/lib/ext/rsvp to TS --- .../@ember/-internals/runtime/lib/ext/rsvp.js | 59 --------------- .../@ember/-internals/runtime/lib/ext/rsvp.ts | 75 +++++++++++++++++++ 2 files changed, 75 insertions(+), 59 deletions(-) delete mode 100644 packages/@ember/-internals/runtime/lib/ext/rsvp.js create mode 100644 packages/@ember/-internals/runtime/lib/ext/rsvp.ts diff --git a/packages/@ember/-internals/runtime/lib/ext/rsvp.js b/packages/@ember/-internals/runtime/lib/ext/rsvp.js deleted file mode 100644 index e6bbfc241e5..00000000000 --- a/packages/@ember/-internals/runtime/lib/ext/rsvp.js +++ /dev/null @@ -1,59 +0,0 @@ -import * as RSVP from 'rsvp'; -import { _backburner, _rsvpErrorQueue } from '@ember/runloop'; -import { getDispatchOverride } from '@ember/-internals/error-handling'; -import { assert } from '@ember/debug'; - -RSVP.configure('async', (callback, promise) => { - _backburner.schedule('actions', null, callback, promise); -}); - -RSVP.configure('after', (cb) => { - _backburner.schedule(_rsvpErrorQueue, null, cb); -}); - -RSVP.on('error', onerrorDefault); - -export function onerrorDefault(reason) { - let error = errorFor(reason); - if (error) { - let overrideDispatch = getDispatchOverride(); - if (overrideDispatch) { - overrideDispatch(error); - } else { - throw error; - } - } -} - -function errorFor(reason) { - if (!reason) return; - - if (reason.errorThrown) { - return unwrapErrorThrown(reason); - } - - if (reason.name === 'UnrecognizedURLError') { - assert(`The URL '${reason.message}' did not match any routes in your application`, false); - return; - } - - if (reason.name === 'TransitionAborted') { - return; - } - - return reason; -} - -function unwrapErrorThrown(reason) { - let error = reason.errorThrown; - if (typeof error === 'string') { - error = new Error(error); - } - Object.defineProperty(error, '__reason_with_error_thrown__', { - value: reason, - enumerable: false, - }); - return error; -} - -export default RSVP; diff --git a/packages/@ember/-internals/runtime/lib/ext/rsvp.ts b/packages/@ember/-internals/runtime/lib/ext/rsvp.ts new file mode 100644 index 00000000000..a8f5a92b62d --- /dev/null +++ b/packages/@ember/-internals/runtime/lib/ext/rsvp.ts @@ -0,0 +1,75 @@ +import * as RSVP from 'rsvp'; +import { _backburner, _rsvpErrorQueue } from '@ember/runloop'; +import { getDispatchOverride } from '@ember/-internals/error-handling'; +import { assert } from '@ember/debug'; + +RSVP.configure('async', (callback: unknown, promise: unknown) => { + _backburner.schedule('actions', null, callback, promise); +}); + +RSVP.configure('after', (cb: unknown) => { + _backburner.schedule(_rsvpErrorQueue, null, cb); +}); + +RSVP.on('error', onerrorDefault); + +export function onerrorDefault(reason: unknown) { + let error = errorFor(reason); + if (error) { + let overrideDispatch = getDispatchOverride(); + if (overrideDispatch) { + overrideDispatch(error); + } else { + throw error; + } + } +} + +interface ReasonWithErrorThrown { + errorThrown: unknown; +} + +interface ReasonWithName { + name: unknown; +} + +interface UnrecognizedURLError { + name: 'UnrecognizedURLError'; + message: string; +} + +function errorFor(reason: unknown) { + if (!reason) return; + + let withErrorThrown = reason as ReasonWithErrorThrown; + if (withErrorThrown?.errorThrown) { + return unwrapErrorThrown(withErrorThrown); + } + + let withName = reason as UnrecognizedURLError; + if (withName.name === 'UnrecognizedURLError') { + assert(`The URL '${withName.message}' did not match any routes in your application`, false); + // @ts-expect-error We'll hit this if the assert is stripped + return; + } + + if ((reason as ReasonWithName).name === 'TransitionAborted') { + return; + } + + return reason; +} + +function unwrapErrorThrown(reason: ReasonWithErrorThrown) { + let error = reason.errorThrown; + if (typeof error === 'string') { + error = new Error(error); + } + Object.defineProperty(error, '__reason_with_error_thrown__', { + value: reason, + enumerable: false, + }); + return error; +} + +export default RSVP; From 2485aba0d858a5a13a4a5718d01b3a49de45dbf7 Mon Sep 17 00:00:00 2001 From: Peter Wagenet Date: Thu, 10 Feb 2022 14:03:57 -0800 Subject: [PATCH 4/5] Add types for runtime mixins --- CHANGELOG.md | 2 +- .../-internals/container/lib/container.ts | 15 ++++------ .../-internals/container/lib/registry.ts | 14 ++++++++-- .../-internals/metal/lib/property_get.ts | 3 +- .../-internals/runtime/lib/mixins/-proxy.d.ts | 28 +++++++++++++++++++ .../runtime/lib/mixins/action_handler.d.ts | 5 +++- .../-internals/runtime/lib/mixins/array.d.ts | 6 ++-- .../-internals/runtime/lib/mixins/array.js | 2 +- .../runtime/lib/mixins/container_proxy.d.ts | 6 ++-- .../runtime/lib/mixins/enumerable.d.ts | 7 +++++ .../lib/mixins/mutable_enumerable.d.ts | 8 ++++++ .../runtime/lib/mixins/promise_proxy.d.ts | 24 ++++++++++++++++ .../runtime/lib/system/core_object.d.ts | 6 +++- .../runtime/lib/system/object_proxy.d.ts | 8 ++++++ .../@ember/-internals/utils/lib/is_proxy.ts | 5 ++-- .../object/type-tests/core/index.test.ts | 4 +-- 16 files changed, 116 insertions(+), 27 deletions(-) create mode 100644 packages/@ember/-internals/runtime/lib/mixins/-proxy.d.ts create mode 100644 packages/@ember/-internals/runtime/lib/mixins/enumerable.d.ts create mode 100644 packages/@ember/-internals/runtime/lib/mixins/mutable_enumerable.d.ts create mode 100644 packages/@ember/-internals/runtime/lib/mixins/promise_proxy.d.ts create mode 100644 packages/@ember/-internals/runtime/lib/system/object_proxy.d.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index be276d530ed..a765466ab0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3144,7 +3144,7 @@ Clearly, `component-a` has subscribed to `some-other-component`'s `action`. Prev * CollectionView context is now its content * Various enhancements to bound helpers: adds multiple property support to bound helpers, adds bind-able options hash properties, adds {{unbound}} helper support to render unbound form of helpers. * Add App.inject -* Add Ember.EnumberableUtils.intersection +* Add Ember.EnumerableUtils.intersection * Deprecate Controller#controllerFor in favor of Controller#needs * Adds `bubbles` property to Ember.TextField * Allow overriding of Ember.Router#handleURL diff --git a/packages/@ember/-internals/container/lib/container.ts b/packages/@ember/-internals/container/lib/container.ts index da224b31077..9911051d29b 100644 --- a/packages/@ember/-internals/container/lib/container.ts +++ b/packages/@ember/-internals/container/lib/container.ts @@ -308,15 +308,10 @@ function factoryFor( return manager; } -interface FactoryOptions { - instantiate?: boolean; - singleton?: boolean; -} - function isSingletonClass( container: Container, fullName: string, - { instantiate, singleton }: FactoryOptions + { instantiate, singleton }: TypeOptions ) { return ( singleton !== false && @@ -329,7 +324,7 @@ function isSingletonClass( function isSingletonInstance( container: Container, fullName: string, - { instantiate, singleton }: FactoryOptions + { instantiate, singleton }: TypeOptions ) { return ( singleton !== false && @@ -342,7 +337,7 @@ function isSingletonInstance( function isFactoryClass( container: Container, fullname: string, - { instantiate, singleton }: FactoryOptions + { instantiate, singleton }: TypeOptions ) { return ( instantiate === false && @@ -354,7 +349,7 @@ function isFactoryClass( function isFactoryInstance( container: Container, fullName: string, - { instantiate, singleton }: FactoryOptions + { instantiate, singleton }: TypeOptions ) { return ( instantiate !== false && @@ -367,7 +362,7 @@ function instantiateFactory( container: Container, normalizedName: string, fullName: string, - options: FactoryOptions + options: TypeOptions ) { let factoryManager = factoryFor(container, normalizedName, fullName); diff --git a/packages/@ember/-internals/container/lib/registry.ts b/packages/@ember/-internals/container/lib/registry.ts index d976f984756..e9ca8e25a96 100644 --- a/packages/@ember/-internals/container/lib/registry.ts +++ b/packages/@ember/-internals/container/lib/registry.ts @@ -1,9 +1,9 @@ import { Factory } from '@ember/-internals/owner'; import { dictionary, intern } from '@ember/-internals/utils'; import { assert, deprecate } from '@ember/debug'; +import { set } from '@ember/object'; import { DEBUG } from '@glimmer/env'; import Container, { ContainerOptions, LazyInjection } from './container'; - export interface Injection { property: string; specifier: string; @@ -46,6 +46,10 @@ export type NotResolver = { export type Resolve = (name: string) => Factory | undefined; +export interface ResolverClass { + create(...args: unknown[]): Resolver; +} + export interface Resolver { knownForType?: (type: string) => KnownForTypeResult; lookupDescription?: (fullName: string) => string; @@ -77,7 +81,7 @@ const VALID_FULL_NAME_REGEXP = /^[^:]+:[^:]+$/; */ export default class Registry implements IRegistry { readonly _failSet: Set; - resolver: Resolver | (Resolve & NotResolver) | null; + resolver: Resolver | null; readonly fallback: IRegistry | null; readonly registrations: Record; _localLookupCache: Record; @@ -86,6 +90,8 @@ export default class Registry implements IRegistry { readonly _resolveCache: Record; readonly _typeOptions: Record; + set?: typeof set; + constructor(options: RegistryOptions = {}) { this.fallback = options.fallback || null; this.resolver = options.resolver || null; @@ -182,7 +188,9 @@ export default class Registry implements IRegistry { @param {Function} factory @param {Object} options */ - register(fullName: string, factory: Factory, options: TypeOptions = {}): void { + register(fullName: string, factory: object, options: TypeOptions & { instantiate: false }): void; + register(fullName: string, factory: Factory, options?: TypeOptions): void; + register(fullName: string, factory: object, options: TypeOptions = {}): void { assert('fullName must be a proper full name', this.isValidFullName(fullName)); assert(`Attempting to register an unknown factory: '${fullName}'`, factory !== undefined); diff --git a/packages/@ember/-internals/metal/lib/property_get.ts b/packages/@ember/-internals/metal/lib/property_get.ts index b8abcc10c99..e032a30b1a2 100644 --- a/packages/@ember/-internals/metal/lib/property_get.ts +++ b/packages/@ember/-internals/metal/lib/property_get.ts @@ -1,6 +1,7 @@ /** @module @ember/object */ +import ProxyMixin from '@ember/-internals/runtime/lib/mixins/-proxy'; import { isEmberArray, setProxy, symbol } from '@ember/-internals/utils'; import { assert } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; @@ -159,7 +160,7 @@ _getProp({ unknownProperty() {} }, 1 as any); get({}, 'foo'); get({}, 'foo.bar'); -let fakeProxy = {}; +let fakeProxy = {} as ProxyMixin; setProxy(fakeProxy); track(() => _getProp({}, 'a')); diff --git a/packages/@ember/-internals/runtime/lib/mixins/-proxy.d.ts b/packages/@ember/-internals/runtime/lib/mixins/-proxy.d.ts new file mode 100644 index 00000000000..bc3b5a0944f --- /dev/null +++ b/packages/@ember/-internals/runtime/lib/mixins/-proxy.d.ts @@ -0,0 +1,28 @@ +import { Mixin } from '@ember/-internals/metal'; + +export function contentFor(proxy: ProxyMixin): T | null; + +interface ProxyMixin { + /** + The object whose properties will be forwarded. + + @property content + @type {unknown} + @default null + @public + */ + content: T | null; + + willDestroy(): void; + + isTruthy: boolean; + + unknownProperty(key: K): T[K] | undefined; + unknownProperty(key: string): unknown; + + setUnknownProperty(key: K, value: T[K]): T[K]; + setUnknownProperty(key: string, value: V): V; +} +declare const ProxyMixin: Mixin; + +export default ProxyMixin; diff --git a/packages/@ember/-internals/runtime/lib/mixins/action_handler.d.ts b/packages/@ember/-internals/runtime/lib/mixins/action_handler.d.ts index a4aac4e466a..c917912e49e 100644 --- a/packages/@ember/-internals/runtime/lib/mixins/action_handler.d.ts +++ b/packages/@ember/-internals/runtime/lib/mixins/action_handler.d.ts @@ -1,6 +1,9 @@ import { Mixin } from '@ember/-internals/metal'; -export default class ActionHandler extends Mixin { +interface ActionHandler { actions?: Record unknown>; send(actionName: string, ...args: unknown[]): void; } +declare const ActionHandler: Mixin; + +export default ActionHandler; diff --git a/packages/@ember/-internals/runtime/lib/mixins/array.d.ts b/packages/@ember/-internals/runtime/lib/mixins/array.d.ts index ae0d538d305..c637c03e709 100644 --- a/packages/@ember/-internals/runtime/lib/mixins/array.d.ts +++ b/packages/@ember/-internals/runtime/lib/mixins/array.d.ts @@ -1,8 +1,10 @@ import { Mixin } from '@ember/-internals/metal'; +import Enumerable from './enumerable'; +import MutableEnumerable from './mutable_enumerable'; type Value = K extends keyof T ? T[K] : unknown; -interface EmberArray { +interface EmberArray extends Enumerable { length: number; objectAt(idx: number): T | undefined; objectsAt(indexes: number[]): Array; @@ -67,7 +69,7 @@ interface EmberArray { declare const EmberArray: Mixin; export default EmberArray; -interface MutableArray extends EmberArray { +interface MutableArray extends EmberArray, MutableEnumerable { replace(idx: number, amt: number, objects: T[]): void; clear(): this; insertAt(idx: number, object: T): this; diff --git a/packages/@ember/-internals/runtime/lib/mixins/array.js b/packages/@ember/-internals/runtime/lib/mixins/array.js index 3c87ff82abf..e1c75bc09f4 100644 --- a/packages/@ember/-internals/runtime/lib/mixins/array.js +++ b/packages/@ember/-internals/runtime/lib/mixins/array.js @@ -1561,7 +1561,7 @@ const MutableArray = Mixin.create(ArrayMixin, MutableEnumerable, { ``` @method unshiftObjects - @param {Enumberable} objects the objects to add + @param {Enumerable} objects the objects to add @return {EmberArray} receiver @public */ diff --git a/packages/@ember/-internals/runtime/lib/mixins/container_proxy.d.ts b/packages/@ember/-internals/runtime/lib/mixins/container_proxy.d.ts index 74549deec9f..49d53cf649e 100644 --- a/packages/@ember/-internals/runtime/lib/mixins/container_proxy.d.ts +++ b/packages/@ember/-internals/runtime/lib/mixins/container_proxy.d.ts @@ -3,7 +3,7 @@ import { TypeOptions } from '@ember/-internals/container/lib/registry'; import { Mixin } from '@ember/-internals/metal'; import { Factory } from '@ember/-internals/owner'; -interface ContainerProxy { +interface ContainerProxyMixin { /** @internal */ __container__: Container; @@ -11,6 +11,6 @@ interface ContainerProxy { lookup(fullName: string, options?: TypeOptions): unknown; factoryFor(fullName: string): Factory | undefined; } -declare const ContainerProxy: Mixin; +declare const ContainerProxyMixin: Mixin; -export default ContainerProxy; +export default ContainerProxyMixin; diff --git a/packages/@ember/-internals/runtime/lib/mixins/enumerable.d.ts b/packages/@ember/-internals/runtime/lib/mixins/enumerable.d.ts new file mode 100644 index 00000000000..f72ec8e1c1d --- /dev/null +++ b/packages/@ember/-internals/runtime/lib/mixins/enumerable.d.ts @@ -0,0 +1,7 @@ +import { Mixin } from '@ember/-internals/metal'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +interface Enumerable {} +declare const Enumerable: Mixin; + +export default Enumerable; diff --git a/packages/@ember/-internals/runtime/lib/mixins/mutable_enumerable.d.ts b/packages/@ember/-internals/runtime/lib/mixins/mutable_enumerable.d.ts new file mode 100644 index 00000000000..12a7d5a4db4 --- /dev/null +++ b/packages/@ember/-internals/runtime/lib/mixins/mutable_enumerable.d.ts @@ -0,0 +1,8 @@ +import { Mixin } from '@ember/-internals/metal'; +import Enumerable from './enumerable'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +interface MutableEnumerable extends Enumerable {} +declare const MutableEnumerable: Mixin; + +export default MutableEnumerable; diff --git a/packages/@ember/-internals/runtime/lib/mixins/promise_proxy.d.ts b/packages/@ember/-internals/runtime/lib/mixins/promise_proxy.d.ts new file mode 100644 index 00000000000..b0015973608 --- /dev/null +++ b/packages/@ember/-internals/runtime/lib/mixins/promise_proxy.d.ts @@ -0,0 +1,24 @@ +import { Mixin } from '@ember/-internals/metal'; + +interface PromiseProxyMixin { + reason: null; + + readonly isPending: boolean; + + readonly isSettled: boolean; + + isRejected: boolean; + + isFulfilled: boolean; + + promise: Promise; + + then: this['promise']['then']; + + catch: this['promise']['catch']; + + finally: this['promise']['finally']; +} +declare const PromiseProxyMixin: Mixin; + +export default PromiseProxyMixin; diff --git a/packages/@ember/-internals/runtime/lib/system/core_object.d.ts b/packages/@ember/-internals/runtime/lib/system/core_object.d.ts index 6b302f2b597..10cf42c53b2 100644 --- a/packages/@ember/-internals/runtime/lib/system/core_object.d.ts +++ b/packages/@ember/-internals/runtime/lib/system/core_object.d.ts @@ -86,6 +86,7 @@ export default class CoreObject { */ isDestroying: boolean; + // NOTE That the actual CoreObject#destroy returns `this`; /** * Destroys an object by setting the `isDestroyed` flag and removing its * metadata, which effectively destroys observers and bindings. @@ -95,7 +96,7 @@ export default class CoreObject { * happen immediately. It will set an isDestroying flag immediately. * @return receiver */ - destroy(): CoreObject; + destroy(): void; /** * Override to implement teardown. @@ -141,4 +142,7 @@ export default class CoreObject { /** @internal */ static isMethod: boolean; + + /** @internal */ + static superclass: unknown; } diff --git a/packages/@ember/-internals/runtime/lib/system/object_proxy.d.ts b/packages/@ember/-internals/runtime/lib/system/object_proxy.d.ts new file mode 100644 index 00000000000..7d9462851b7 --- /dev/null +++ b/packages/@ember/-internals/runtime/lib/system/object_proxy.d.ts @@ -0,0 +1,8 @@ +import FrameworkObject from './object'; +import _ProxyMixin from '../mixins/-proxy'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +interface ObjectProxy extends _ProxyMixin {} +declare class ObjectProxy extends FrameworkObject {} + +export default ObjectProxy; diff --git a/packages/@ember/-internals/utils/lib/is_proxy.ts b/packages/@ember/-internals/utils/lib/is_proxy.ts index f01a84eda53..c83ba8186d2 100644 --- a/packages/@ember/-internals/utils/lib/is_proxy.ts +++ b/packages/@ember/-internals/utils/lib/is_proxy.ts @@ -1,16 +1,17 @@ +import ProxyMixin from '@ember/-internals/runtime/lib/mixins/-proxy'; import { _WeakSet as WeakSet } from '@glimmer/util'; import { isObject } from './spec'; const PROXIES = new WeakSet(); -export function isProxy(value: any | undefined | null): value is object { +export function isProxy(value: unknown): value is ProxyMixin { if (isObject(value)) { return PROXIES.has(value); } return false; } -export function setProxy(object: object): void { +export function setProxy(object: ProxyMixin): void { if (isObject(object)) { PROXIES.add(object); } diff --git a/packages/@ember/object/type-tests/core/index.test.ts b/packages/@ember/object/type-tests/core/index.test.ts index d11b365e5fa..dd875ccec75 100644 --- a/packages/@ember/object/type-tests/core/index.test.ts +++ b/packages/@ember/object/type-tests/core/index.test.ts @@ -13,7 +13,7 @@ const co1 = new CoreObject(owner); expectTypeOf(co1.concatenatedProperties).toEqualTypeOf(); expectTypeOf(co1.isDestroyed).toEqualTypeOf(); expectTypeOf(co1.isDestroying).toEqualTypeOf(); -expectTypeOf(co1.destroy()).toEqualTypeOf(); +expectTypeOf(co1.destroy()).toEqualTypeOf(); expectTypeOf(co1.toString()).toEqualTypeOf(); /** .create tests */ @@ -21,7 +21,7 @@ const co2 = CoreObject.create(); expectTypeOf(co2.concatenatedProperties).toEqualTypeOf(); expectTypeOf(co2.isDestroyed).toEqualTypeOf(); expectTypeOf(co2.isDestroying).toEqualTypeOf(); -expectTypeOf(co2.destroy()).toEqualTypeOf(); +expectTypeOf(co2.destroy()).toEqualTypeOf(); expectTypeOf(co2.toString()).toEqualTypeOf(); /** .create tests w/ initial instance data passed in */ From c857f97c2bee11de19a190849d0aae859a75e313 Mon Sep 17 00:00:00 2001 From: Peter Wagenet Date: Wed, 23 Feb 2022 16:50:31 -0800 Subject: [PATCH 5/5] Clean up some more internal types --- .../@ember/-internals/container/lib/registry.ts | 14 ++------------ .../lib/container_debug_adapter.ts | 2 +- packages/@ember/-internals/runtime/lib/ext/rsvp.ts | 2 +- .../runtime/lib/mixins/promise_proxy.d.ts | 2 +- 4 files changed, 5 insertions(+), 15 deletions(-) diff --git a/packages/@ember/-internals/container/lib/registry.ts b/packages/@ember/-internals/container/lib/registry.ts index e9ca8e25a96..373ed93c1f5 100644 --- a/packages/@ember/-internals/container/lib/registry.ts +++ b/packages/@ember/-internals/container/lib/registry.ts @@ -36,16 +36,6 @@ export interface IRegistry { resolve(fullName: string, options?: ResolveOptions): Factory | undefined; } -export type NotResolver = { - knownForType: never; - lookupDescription: never; - makeToString: never; - normalize: never; - resolve: never; -}; - -export type Resolve = (name: string) => Factory | undefined; - export interface ResolverClass { create(...args: unknown[]): Resolver; } @@ -55,13 +45,13 @@ export interface Resolver { lookupDescription?: (fullName: string) => string; makeToString?: (factory: Factory, fullName: string) => string; normalize?: (fullName: string) => string; - resolve: Resolve; + resolve(name: string): Factory | undefined; } export interface RegistryOptions { fallback?: IRegistry; registrations?: { [key: string]: object }; - resolver?: Resolver | (Resolve & NotResolver); + resolver?: Resolver; } const VALID_FULL_NAME_REGEXP = /^[^:]+:[^:]+$/; diff --git a/packages/@ember/-internals/extension-support/lib/container_debug_adapter.ts b/packages/@ember/-internals/extension-support/lib/container_debug_adapter.ts index 39f9f6c161f..c7937c66f4b 100644 --- a/packages/@ember/-internals/extension-support/lib/container_debug_adapter.ts +++ b/packages/@ember/-internals/extension-support/lib/container_debug_adapter.ts @@ -62,7 +62,7 @@ export default class ContainerDebugAdapter extends EmberObject { @property resolver @public */ - declare resolver: Resolver; + resolver: Resolver; /** Returns true if it is possible to catalog a list of available diff --git a/packages/@ember/-internals/runtime/lib/ext/rsvp.ts b/packages/@ember/-internals/runtime/lib/ext/rsvp.ts index a8f5a92b62d..45419961a9a 100644 --- a/packages/@ember/-internals/runtime/lib/ext/rsvp.ts +++ b/packages/@ember/-internals/runtime/lib/ext/rsvp.ts @@ -42,7 +42,7 @@ function errorFor(reason: unknown) { if (!reason) return; let withErrorThrown = reason as ReasonWithErrorThrown; - if (withErrorThrown?.errorThrown) { + if (withErrorThrown.errorThrown) { return unwrapErrorThrown(withErrorThrown); } diff --git a/packages/@ember/-internals/runtime/lib/mixins/promise_proxy.d.ts b/packages/@ember/-internals/runtime/lib/mixins/promise_proxy.d.ts index b0015973608..5c685022b69 100644 --- a/packages/@ember/-internals/runtime/lib/mixins/promise_proxy.d.ts +++ b/packages/@ember/-internals/runtime/lib/mixins/promise_proxy.d.ts @@ -1,7 +1,7 @@ import { Mixin } from '@ember/-internals/metal'; interface PromiseProxyMixin { - reason: null; + reason: unknown; readonly isPending: boolean;