diff --git a/types/ember/index.d.ts b/types/ember/index.d.ts index 93babaa0a7..7564e56a0e 100755 --- a/types/ember/index.d.ts +++ b/types/ember/index.d.ts @@ -1,4 +1,4 @@ -// Type definitions for Ember.js 2.8 +// Type definitions for Ember.js 3.0 // Project: http://emberjs.com/ // Definitions by: Jed Mao // bttf diff --git a/types/ember/v2/index.d.ts b/types/ember/v2/index.d.ts new file mode 100755 index 0000000000..93babaa0a7 --- /dev/null +++ b/types/ember/v2/index.d.ts @@ -0,0 +1,3898 @@ +// Type definitions for Ember.js 2.8 +// Project: http://emberjs.com/ +// Definitions by: Jed Mao +// bttf +// Derek Wickern +// Chris Krycho +// Theron Cross +// Martin Feckie +// Alex LaFroscia +// Mike North +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.4 + +/// +/// + +declare module 'ember' { + // Capitalization is intentional: this makes it much easier to re-export RSVP on + // the Ember namespace. + import Rsvp from 'rsvp'; + import { TemplateFactory } from 'htmlbars-inline-precompile'; + + import { Registry as ServiceRegistry } from '@ember/service'; + import { Registry as ControllerRegistry } from '@ember/controller'; + import ModuleComputed from '@ember/object/computed'; + + // Get an alias to the global Array type to use in inner scope below. + type GlobalArray = T[]; + + /** + * Deconstructs computed properties into the types which would be returned by `.get()`. + */ + type ComputedPropertyGetters = { [K in keyof T]: Ember.ComputedProperty | ModuleComputed | T[K] }; + type ComputedPropertySetters = { [K in keyof T]: Ember.ComputedProperty | ModuleComputed | T[K] }; + + /** + * Check that any arguments to `create()` match the type's properties. + * + * Accept any additional properties and add merge them into the instance. + */ + type EmberInstanceArguments = Partial & { + [key: string]: any; + }; + + /** + * Accept any additional properties and add merge them into the prototype. + */ + interface EmberClassArguments { + [key: string]: any; + } + + /** + * Map type `T` to a plain object hash with the identity mapping. + * + * Discards any additional object identity like the ability to `new()` up the class. + * The `new()` capability is added back later by merging `EmberClassConstructor` + * + * Implementation is carefully chosen for the reasons described in + * https://github.com/typed-ember/ember-typings/pull/29 + */ + type Objectify = Readonly; + + type Fix = { [K in keyof T]: T[K] }; + + /** + * Ember.Object.extend(...) accepts any number of mixins or literals. + */ + type MixinOrLiteral = Ember.Mixin | T; + + /** + * Used to infer the type of ember classes of type `T`. + * + * Generally you would use `EmberClass.create()` instead of `new EmberClass()`. + * + * The single-arg constructor is required by the typescript compiler. + * The multi-arg constructor is included for better ergonomics. + * + * Implementation is carefully chosen for the reasons described in + * https://github.com/typed-ember/ember-typings/pull/29 + */ + type EmberClassConstructor = (new (properties?: object) => T) & (new (...args: any[]) => T); + + type ComputedPropertyGetterFunction = (this: any, key: string) => T; + + interface ComputedPropertyGet { + get(this: any, key: string): T; + } + + interface ComputedPropertySet { + set(this: any, key: string, value: T): T; + } + + type ComputedPropertyCallback = + | ComputedPropertyGetterFunction + | ComputedPropertyGet + | ComputedPropertySet + | (ComputedPropertyGet & ComputedPropertySet); + + interface ActionsHash { + [index: string]: (...params: any[]) => any; + } + + interface EmberRunTimer { + __ember_run_timer_brand__: any; + } + + type RunMethod = ((this: Target, ...args: any[]) => Ret) | keyof Target; + type EmberRunQueues = + | 'sync' + | 'actions' + | 'routerTransitions' + | 'render' + | 'afterRender' + | 'destroy'; + type QueryParamTypes = 'boolean' | 'number' | 'array' | 'string'; + type QueryParamScopeTypes = 'controller' | 'model'; + + type ObserverMethod = + | (keyof Target) + | ((this: Target, sender: Sender, key: keyof Sender, value: any, rev: number) => void); + + interface RenderOptions { + into?: string; + controller?: string; + model?: any; + outlet?: string; + view?: string; + } + + interface RouteQueryParam { + refreshModel?: boolean; + replace?: boolean; + as?: string; + } + + interface EventDispatcherEvents { + touchstart?: string | null; + touchmove?: string | null; + touchend?: string | null; + touchcancel?: string | null; + keydown?: string | null; + keyup?: string | null; + keypress?: string | null; + mousedown?: string | null; + mouseup?: string | null; + contextmenu?: string | null; + click?: string | null; + dblclick?: string | null; + mousemove?: string | null; + focusin?: string | null; + focusout?: string | null; + mouseenter?: string | null; + mouseleave?: string | null; + submit?: string | null; + input?: string | null; + change?: string | null; + dragstart?: string | null; + drag?: string | null; + dragenter?: string | null; + dragleave?: string | null; + dragover?: string | null; + drop?: string | null; + dragend?: string | null; + [event: string]: string | null | undefined; + } + + interface ViewMixin { + /** + * A list of properties of the view to apply as attributes. If the property + * is a string value, the value of that string will be applied as the value + * for an attribute of the property's name. + */ + attributeBindings: string[]; + /** + * Returns the current DOM element for the view. + */ + element: Element; + /** + * Returns a jQuery object for this view's element. If you pass in a selector + * string, this method will return a jQuery object, using the current element + * as its buffer. + */ + $: JQueryStatic; + /** + * The HTML `id` of the view's element in the DOM. You can provide this + * value yourself but it must be unique (just as in HTML): + */ + elementId: string; + /** + * Tag name for the view's outer element. The tag name is only used when an + * element is first created. If you change the `tagName` for an element, you + * must destroy and recreate the view element. + */ + tagName: string; + /** + * Renders the view again. This will work regardless of whether the + * view is already in the DOM or not. If the view is in the DOM, the + * rendering process will be deferred to give bindings a chance + * to synchronize. + */ + rerender(): void; + /** + * Called when a view is going to insert an element into the DOM. + */ + willInsertElement(): void; + /** + * Called when the element of the view has been inserted into the DOM. + * Override this function to do any set up that requires an element + * in the document body. + */ + didInsertElement(): void; + /** + * Called when the view is about to rerender, but before anything has + * been torn down. This is a good opportunity to tear down any manual + * observers you have installed based on the DOM state + */ + willClearRender(): void; + /** + * Called when the element of the view is going to be destroyed. Override + * this function to do any teardown that requires an element, like removing + * event listeners. + */ + willDestroyElement(): void; + } + const ViewMixin: Ember.Mixin; + + /** + Ember.CoreView is an abstract class that exists to give view-like behavior to both Ember's main + view class Ember.Component and other classes that don't need the full functionality of Ember.Component. + + Unless you have specific needs for CoreView, you will use Ember.Component in your applications. + **/ + class CoreView extends Ember.Object.extend(Ember.Evented, Ember.ActionHandler) {} + interface ActionSupport { + sendAction(action: string, ...params: any[]): void; + } + const ActionSupport: Ember.Mixin; + + interface ClassNamesSupport { + /** + A list of properties of the view to apply as class names. If the property is a string value, + the value of that string will be applied as a class name. + + If the value of the property is a Boolean, the name of that property is added as a dasherized + class name. + + If you would prefer to use a custom value instead of the dasherized property name, you can + pass a binding like this: `classNameBindings: ['isUrgent:urgent']` + + This list of properties is inherited from the component's superclasses as well. + */ + classNameBindings: string[]; + /** + * Standard CSS class names to apply to the view's outer element. This + * property automatically inherits any class names defined by the view's + * superclasses as well. + */ + classNames: string[]; + } + const ClassNamesSupport: Ember.Mixin; + + interface TriggerActionOptions { + action?: string; + target?: Ember.Object; + actionContext?: Ember.Object; + } + /** + Ember.TargetActionSupport is a mixin that can be included in a class to add a triggerAction method + with semantics similar to the Handlebars {{action}} helper. In normal Ember usage, the {{action}} + helper is usually the best choice. This mixin is most often useful when you are doing more + complex event handling in Components. + **/ + interface TargetActionSupport { + triggerAction(opts: TriggerActionOptions): boolean; + } + + export namespace Ember { + interface FunctionPrototypeExtensions { + /** + * The `property` extension of Javascript's Function prototype is available + * when `EmberENV.EXTEND_PROTOTYPES` or `EmberENV.EXTEND_PROTOTYPES.Function` is + * `true`, which is the default. + */ + property(...args: string[]): ComputedProperty; + /** + * The `observes` extension of Javascript's Function prototype is available + * when `EmberENV.EXTEND_PROTOTYPES` or `EmberENV.EXTEND_PROTOTYPES.Function` is + * true, which is the default. + */ + observes(...args: string[]): this; + /** + * The `on` extension of Javascript's Function prototype is available + * when `EmberENV.EXTEND_PROTOTYPES` or `EmberENV.EXTEND_PROTOTYPES.Function` is + * true, which is the default. + */ + on(...args: string[]): this; + } + + interface ArrayPrototypeExtensions extends MutableArray, Observable, Copyable {} + + /** + * Given a fullName return a factory manager. + */ + interface _ContainerProxyMixin { + /** + * Returns an object that can be used to provide an owner to a + * manually created instance. + */ + ownerInjection(): {}; + /** + * Given a fullName return a corresponding instance. + */ + lookup(fullName: string, options?: {}): any; + /** + * Given a fullName return a corresponding factory. + */ + factoryFor(fullName: string, options?: {}): any; + } + const _ContainerProxyMixin: Mixin<_ContainerProxyMixin>; + + /** + * RegistryProxyMixin is used to provide public access to specific + * registry functionality. + */ + interface _RegistryProxyMixin { + /** + * Given a fullName return the corresponding factory. + */ + resolveRegistration(fullName: string): Function; + /** + * Registers a factory or value that can be used for dependency injection (with + * `inject`) or for service lookup. Each factory is registered with + * a full name including two parts: `type:name`. + */ + register(fullName: string, factory: any, options?: { singleton?: boolean, instantiate?: boolean }): any; + /** + * Unregister a factory. + */ + unregister(fullName: string): any; + /** + * Check if a factory is registered. + */ + hasRegistration(fullName: string): boolean; + /** + * Register an option for a particular factory. + */ + registerOption(fullName: string, optionName: string, options: {}): any; + /** + * Return a specific registered option for a particular factory. + */ + registeredOption(fullName: string, optionName: string): {}; + /** + * Register options for a particular factory. + */ + registerOptions(fullName: string, options: {}): any; + /** + * Return registered options for a particular factory. + */ + registeredOptions(fullName: string): {}; + /** + * Allow registering options for all factories of a type. + */ + registerOptionsForType(type: string, options: {}): any; + /** + * Return the registered options for all factories of a type. + */ + registeredOptionsForType(type: string): {}; + /** + * Define a dependency injection onto a specific factory or all factories + * of a type. + */ + inject(factoryNameOrType: string, property: string, injectionName: string): any; + } + const _RegistryProxyMixin: Mixin<_RegistryProxyMixin>; + /** + Ember.ActionHandler is available on some familiar classes including Ember.Route, + Ember.Component, and Ember.Controller. (Internally the mixin is used by Ember.CoreView, + Ember.ControllerMixin, and Ember.Route and available to the above classes through inheritance.) + **/ + interface ActionHandler { + /** + Triggers a named action on the ActionHandler. Any parameters supplied after the actionName + string will be passed as arguments to the action target function. + + If the ActionHandler has its target property set, actions may bubble to the target. + Bubbling happens when an actionName can not be found in the ActionHandler's actions + hash or if the action target function returns true. + **/ + send(actionName: string, ...args: any[]): void; + /** + The collection of functions, keyed by name, available on this ActionHandler as action targets. + **/ + actions: ActionsHash; + } + const ActionHandler: Ember.Mixin; + /** + An instance of Ember.Application is the starting point for every Ember application. It helps to + instantiate, initialize and coordinate the many objects that make up your app. + **/ + class Application extends Engine { + /** + Call advanceReadiness after any asynchronous setup logic has completed. + Each call to deferReadiness must be matched by a call to advanceReadiness + or the application will never become ready and routing will not begin. + **/ + advanceReadiness(): void; + /** + Use this to defer readiness until some condition is true. + + This allows you to perform asynchronous setup logic and defer + booting your application until the setup has finished. + + However, if the setup requires a loading UI, it might be better + to use the router for this purpose. + */ + deferReadiness(): void; + /** + defines an injection or typeInjection + **/ + inject(factoryNameOrType: string, property: string, injectionName: string): void; + /** + This injects the test helpers into the window's scope. If a function of the + same name has already been defined it will be cached (so that it can be reset + if the helper is removed with `unregisterHelper` or `removeTestHelpers`). + Any callbacks registered with `onInjectHelpers` will be called once the + helpers have been injected. + **/ + injectTestHelpers(): void; + /** + registers a factory for later injection + @param fullName type:name (e.g., 'model:user') + @param factory (e.g., App.Person) + **/ + register(fullName: string, factory: Function, options?: {}): void; + /** + This removes all helpers that have been registered, and resets and functions + that were overridden by the helpers. + **/ + removeTestHelpers(): void; + /** + Reset the application. This is typically used only in tests. + **/ + reset(): void; + /** + This hook defers the readiness of the application, so that you can start + the app when your tests are ready to run. It also sets the router's + location to 'none', so that the window's location will not be modified + (preventing both accidental leaking of state between tests and interference + with your testing framework). + **/ + setupForTesting(): void; + /** + The DOM events for which the event dispatcher should listen. + */ + customEvents: EventDispatcherEvents; + /** + The Ember.EventDispatcher responsible for delegating events to this application's views. + **/ + eventDispatcher: EventDispatcher; + /** + Set this to provide an alternate class to Ember.DefaultResolver + **/ + resolver: DefaultResolver; + /** + The root DOM element of the Application. This can be specified as an + element or a jQuery-compatible selector string. + + This is the element that will be passed to the Application's, eventDispatcher, + which sets up the listeners for event delegation. Every view in your application + should be a child of the element you specify here. + **/ + rootElement: HTMLElement | string; + /** + Called when the Application has become ready. + The call will be delayed until the DOM has become ready. + **/ + ready: Function; + /** + Application's router. + **/ + Router: Router; + registry: Registry; + /** + * Initialize the application and return a promise that resolves with the `Application` + * object when the boot process is complete. + */ + boot(): Promise; + } + /** + The `ApplicationInstance` encapsulates all of the stateful aspects of a + running `Application`. + **/ + class ApplicationInstance extends EngineInstance {} + /** + This module implements Observer-friendly Array-like behavior. This mixin is picked up by the + Array class as well as other controllers, etc. that want to appear to be arrays. + **/ + interface Array extends Enumerable { + /** + * __Required.__ You must implement this method to apply this mixin. + */ + length: number | ComputedProperty; + /** + * Returns the object at the given `index`. If the given `index` is negative + * or is greater or equal than the array length, returns `undefined`. + */ + objectAt(idx: number): T | undefined; + /** + * This returns the objects at the specified indexes, using `objectAt`. + */ + objectsAt(indexes: number[]): Ember.Array; + /** + * Returns a new array that is a slice of the receiver. This implementation + * uses the observable array methods to retrieve the objects for the new + * slice. + */ + slice(beginIndex?: number, endIndex?: number): T[]; + /** + * Returns the index of the given object's first occurrence. + * If no `startAt` argument is given, the starting location to + * search is 0. If it's negative, will count backward from + * the end of the array. Returns -1 if no match is found. + */ + indexOf(searchElement: T, fromIndex?: number): number; + /** + * Returns the index of the given object's last occurrence. + * If no `startAt` argument is given, the search starts from + * the last position. If it's negative, will count backward + * from the end of the array. Returns -1 if no match is found. + */ + lastIndexOf(searchElement: T, fromIndex?: number): number; + /** + * Adds an array observer to the receiving array. The array observer object + * normally must implement two methods: + */ + addArrayObserver(target: {}, opts: {}): this; + /** + * Removes an array observer from the object if the observer is current + * registered. Calling this method multiple times with the same object will + * have no effect. + */ + removeArrayObserver(target: {}, opts: {}): this; + /** + * Becomes true whenever the array currently has observers watching changes + * on the array. + */ + hasArrayObservers: ComputedProperty; + /** + * If you are implementing an object that supports `Ember.Array`, call this + * method just before the array content changes to notify any observers and + * invalidate any related properties. Pass the starting index of the change + * as well as a delta of the amounts to change. + */ + arrayContentWillChange(startIdx: number, removeAmt: number, addAmt: number): this; + /** + * If you are implementing an object that supports `Ember.Array`, call this + * method just after the array content changes to notify any observers and + * invalidate any related properties. Pass the starting index of the change + * as well as a delta of the amounts to change. + */ + arrayContentDidChange(startIdx: number, removeAmt: number, addAmt: number): this; + /** + * Returns a special object that can be used to observe individual properties + * on the array. Just get an equivalent property on this object and it will + * return an enumerable that maps automatically to the named key on the + * member objects. + */ + '@each': ComputedProperty; + } + // Ember.Array rather than Array because the `array-type` lint rule doesn't realize the global is shadowed + const Array: Mixin>; + + /** + An ArrayProxy wraps any other object that implements Ember.Array and/or Ember.MutableArray, + forwarding all requests. This makes it very useful for a number of binding use cases or other cases + where being able to swap out the underlying array is useful. + **/ + interface ArrayProxy extends MutableArray {} + class ArrayProxy extends Object.extend(MutableArray as {}) { + content: NativeArray; + + /** + * Should actually retrieve the object at the specified index from the + * content. You can override this method in subclasses to transform the + * content item to something new. + */ + objectAtContent(idx: number): T | undefined; + } + /** + AutoLocation will select the best location option based off browser support with the priority order: history, hash, none. + **/ + class AutoLocation extends Object {} + /** + * Connects the properties of two objects so that whenever the value of one property changes, + * the other property will be changed also. + * + * @deprecated https://emberjs.com/deprecations/v2.x#toc_ember-binding + **/ + class Binding { + constructor(toPath: string, fromPath: string); + connect(obj: any): Binding; + copy(): Binding; + disconnect(): Binding; + from(path: string): Binding; + to(path: string | string[]): Binding; + toString(): string; + } + /** + The internal class used to create text inputs when the {{input}} helper is used + with type of checkbox. See Handlebars.helpers.input for usage details. + **/ + class Checkbox extends Component {} + /** + * Implements some standard methods for comparing objects. Add this mixin to + * any class you create that can compare its instances. + */ + interface Comparable { + compare(a: any, b: any): number; + } + const Comparable: Mixin; + /** + A view that is completely isolated. Property access in its templates go to the view object + and actions are targeted at the view object. There is no access to the surrounding context or + outer controller; all contextual information is passed in. + **/ + class Component extends CoreView.extend(ViewMixin, ActionSupport, ClassNamesSupport) { + // methods + readDOMAttr(name: string): string; + // properties + /** + * The WAI-ARIA role of the control represented by this view. For example, a button may have a + * role of type 'button', or a pane may have a role of type 'alertdialog'. This property is + * used by assistive software to help visually challenged users navigate rich web applications. + */ + ariaRole: string; + /** + * The HTML id of the component's element in the DOM. You can provide this value yourself but + * it must be unique (just as in HTML): + * + * If not manually set a default value will be provided by the framework. Once rendered an + * element's elementId is considered immutable and you should never change it. If you need + * to compute a dynamic value for the elementId, you should do this when the component or + * element is being instantiated: + */ + elementId: string; + /** + * If false, the view will appear hidden in DOM. + */ + isVisible: boolean; + /** + * A component may contain a layout. A layout is a regular template but supersedes the template + * property during rendering. It is the responsibility of the layout template to retrieve the + * template property from the component (or alternatively, call Handlebars.helpers.yield, + * {{yield}}) to render it in the correct location. This is useful for a component that has a + * shared wrapper, but which delegates the rendering of the contents of the wrapper to the + * template property on a subclass. + */ + layout: TemplateFactory | string; + /** + * Enables components to take a list of parameters as arguments. + */ + static positionalParams: string[] | string; + // events + /** + * Called when the attributes passed into the component have been updated. Called both during the + * initial render of a container and during a rerender. Can be used in place of an observer; code + * placed here will be executed every time any attribute updates. + */ + didReceiveAttrs(): void; + /** + * Called after a component has been rendered, both on initial render and in subsequent rerenders. + */ + didRender(): void; + /** + * Called when the component has updated and rerendered itself. Called only during a rerender, + * not during an initial render. + */ + didUpdate(): void; + /** + * Called when the attributes passed into the component have been changed. Called only during a + * rerender, not during an initial render. + */ + didUpdateAttrs(): void; + /** + * Called before a component has been rendered, both on initial render and in subsequent rerenders. + */ + willRender(): void; + /** + * Called when the component is about to update and rerender itself. Called only during a rerender, + * not during an initial render. + */ + willUpdate(): void; + } + /** + A computed property transforms an objects function into a property. + By default the function backing the computed property will only be called once and the result + will be cached. You can specify various properties that your computed property is dependent on. + This will force the cached result to be recomputed if the dependencies are modified. + **/ + class ComputedProperty { + /** + * Call on a computed property to set it into non-cached mode. When in this + * mode the computed property will not automatically cache the return value. + */ + volatile(): this; + /** + * Call on a computed property to set it into read-only mode. When in this + * mode the computed property will throw an error when set. + */ + readOnly(): this; + /** + * Sets the dependent keys on this computed property. Pass any number of + * arguments containing key paths that this computed property depends on. + */ + property(...path: string[]): this; + /** + * In some cases, you may want to annotate computed properties with additional + * metadata about how they function or what values they operate on. For example, + * computed property functions may close over variables that are then no longer + * available for introspection. + */ + meta(meta: {}): this; + meta(): {}; + } + /** + * A container used to instantiate and cache objects. + */ + class Container { + /** + * Given a fullName, return the corresponding factory. The consumer of the factory + * is responsible for the destruction of any factory instances, as there is no + * way for the container to ensure instances are destroyed when it itself is + * destroyed. + */ + factoryFor(fullName: string, options?: {}): any; + } + /** + The ContainerDebugAdapter helps the container and resolver interface + with tools that debug Ember such as the Ember Inspector for Chrome and Firefox. + **/ + class ContainerDebugAdapter extends Object { + resolver: Resolver; + canCatalogEntriesByType(type: string): boolean; + catalogEntriesByType(type: string): any[]; + } + /** + * Additional methods for the Controller. + */ + interface ControllerMixin extends ActionHandler { + replaceRoute(name: string, ...args: any[]): void; + transitionToRoute(name: string, ...args: any[]): void; + model: any; + queryParams: string | string[] | Array<{ [key: string]: { + type?: QueryParamTypes, + scope?: QueryParamScopeTypes, + as?: string + }}>; + target: Object; + } + const ControllerMixin: Ember.Mixin; + class Controller extends Object.extend(ControllerMixin) {} + /** + * Implements some standard methods for copying an object. Add this mixin to + * any object you create that can create a copy of itself. This mixin is + * added automatically to the built-in array. + */ + interface Copyable { + /** + * __Required.__ You must implement this method to apply this mixin. + */ + copy(deep: boolean): Copyable; + /** + * If the object implements `Ember.Freezable`, then this will return a new + * copy if the object is not frozen and the receiver if the object is frozen. + */ + frozenCopy(): Copyable; + } + const Copyable: Ember.Mixin; + class CoreObject { + /** + * As of Ember 3.1, CoreObject constructor takes initial object properties as an argument. + * See: https://github.com/emberjs/ember.js/commit/4709935854d4c29b0d2c054614d53fa2c55309b1 + **/ + constructor(properties?: object); + + _super(...args: any[]): any; + + /** + An overridable method called when objects are instantiated. By default, + does nothing unless it is overridden during class definition. + **/ + init(): void; + + /** + * Defines the properties that will be concatenated from the superclass (instead of overridden). + * @default null + */ + concatenatedProperties: any[]; + + /** + Destroyed object property flag. If this property is true the observers and bindings were + already removed by the effect of calling the destroy() method. + @default false + **/ + isDestroyed: boolean; + /** + Destruction scheduled flag. The destroy() method has been called. The object stays intact + until the end of the run loop at which point the isDestroyed flag is set. + @default false + **/ + isDestroying: boolean; + + /** + Destroys an object by setting the `isDestroyed` flag and removing its + metadata, which effectively destroys observers and bindings. + If you try to set a property on a destroyed object, an exception will be + raised. + Note that destruction is scheduled for the end of the run loop and does not + happen immediately. It will set an isDestroying flag immediately. + @return receiver + */ + destroy(): CoreObject; + + /** + Override to implement teardown. + */ + willDestroy(): void; + + /** + Returns a string representation which attempts to provide more information than Javascript's toString + typically does, in a generic way for all Ember objects (e.g., ""). + @return string representation + **/ + toString(): string; + + static create(this: EmberClassConstructor): Fix; + + static create>( + this: EmberClassConstructor>, + arg1: T1 & ThisType> + ): Fix; + + static create< + Instance, + Args, + T1 extends EmberInstanceArguments, + T2 extends EmberInstanceArguments + >( + this: EmberClassConstructor>, + arg1: T1 & ThisType>, + arg2: T2 & ThisType> + ): Fix; + + static create< + Instance, + Args, + T1 extends EmberInstanceArguments, + T2 extends EmberInstanceArguments, + T3 extends EmberInstanceArguments + >( + this: EmberClassConstructor>, + arg1: T1 & ThisType>, + arg2: T2 & ThisType>, + arg3: T3 & ThisType> + ): Fix; + + static extend( + this: Statics & EmberClassConstructor + ): Objectify & EmberClassConstructor; + + static extend( + this: Statics & EmberClassConstructor, + arg1: MixinOrLiteral & ThisType> + ): Objectify & EmberClassConstructor; + + static extend< + Statics, + Instance extends B1 & B2, + T1 extends EmberClassArguments, + B1, + T2 extends EmberClassArguments, + B2 + >( + this: Statics & EmberClassConstructor, + arg1: MixinOrLiteral & ThisType>, + arg2: MixinOrLiteral & ThisType> + ): Objectify & EmberClassConstructor; + + static extend< + Statics, + Instance extends B1 & B2 & B3, + T1 extends EmberClassArguments, + B1, + T2 extends EmberClassArguments, + B2, + T3 extends EmberClassArguments, + B3 + >( + this: Statics & EmberClassConstructor, + arg1: MixinOrLiteral & ThisType>, + arg2: MixinOrLiteral & ThisType>, + arg3: MixinOrLiteral & ThisType> + ): Objectify & EmberClassConstructor; + + static extend< + Statics, + Instance extends B1 & B2 & B3 & B4, + T1 extends EmberClassArguments, + B1, + T2 extends EmberClassArguments, + B2, + T3 extends EmberClassArguments, + B3, + T4 extends EmberClassArguments, + B4 + >( + this: Statics & EmberClassConstructor, + arg1: MixinOrLiteral & ThisType>, + arg2: MixinOrLiteral & ThisType>, + arg3: MixinOrLiteral & ThisType>, + arg4: MixinOrLiteral & ThisType> + ): Objectify & EmberClassConstructor; + + static reopen( + this: Statics & EmberClassConstructor + ): Objectify & EmberClassConstructor; + + static reopen( + this: Statics & EmberClassConstructor, + arg1: MixinOrLiteral & ThisType> + ): Objectify & EmberClassConstructor; + + static reopen< + Statics, + Instance extends B1 & B2, + T1 extends EmberClassArguments, + B1, + T2 extends EmberClassArguments, + B2 + >( + this: Statics & EmberClassConstructor, + arg1: MixinOrLiteral & ThisType>, + arg2: MixinOrLiteral & ThisType> + ): Objectify & EmberClassConstructor; + + static reopen< + Statics, + Instance extends B1 & B2 & B3, + T1 extends EmberClassArguments, + B1, + T2 extends EmberClassArguments, + B2, + T3 extends EmberClassArguments, + B3 + >( + this: Statics & EmberClassConstructor, + arg1: MixinOrLiteral & ThisType>, + arg2: MixinOrLiteral & ThisType>, + arg3: MixinOrLiteral & ThisType> + ): Objectify & EmberClassConstructor; + + static reopenClass(this: Statics): Statics; + + static reopenClass( + this: Statics, + arg1: T1 + ): Statics & T1; + + static reopenClass< + Statics, + T1 extends EmberClassArguments, + T2 extends EmberClassArguments + >(this: Statics, arg1: T1, arg2: T2): Statics & T1 & T2; + + static reopenClass< + Statics, + T1 extends EmberClassArguments, + T2 extends EmberClassArguments, + T3 extends EmberClassArguments + >(this: Statics, arg1: T1, arg2: T2, arg3: T3): Statics & T1 & T2 & T3; + + static detect( + this: Statics & EmberClassConstructor, + obj: any + ): obj is Objectify & EmberClassConstructor; + + static detectInstance( + this: EmberClassConstructor, + obj: any + ): obj is Instance; + + /** + Iterate over each computed property for the class, passing its name and any + associated metadata (see metaForProperty) to the callback. + **/ + static eachComputedProperty(callback: Function, binding: {}): void; + /** + Returns the original hash that was passed to meta(). + @param key property name + **/ + static metaForProperty(key: string): {}; + static isClass: boolean; + static isMethod: boolean; + } + /** + * The `DataAdapter` helps a data persistence library + * interface with tools that debug Ember such as Chrome and Firefox. + */ + class DataAdapter extends Object { + /** + * The container-debug-adapter which is used + * to list all models. + */ + containerDebugAdapter: any; + /** + * Ember Data > v1.0.0-beta.18 + * requires string model names to be passed + * around instead of the actual factories. + */ + acceptsModelName: any; + /** + * Specifies how records can be filtered. + * Records returned will need to have a `filterValues` + * property with a key for every name in the returned array. + */ + getFilters(): any[]; + /** + * Fetch the model types and observe them for changes. + */ + watchModelTypes(typesAdded: Function, typesUpdated: Function): Function; + /** + * Fetch the records of a given type and observe them for changes. + */ + watchRecords( + modelName: string, + recordsAdded: Function, + recordsUpdated: Function, + recordsRemoved: Function + ): Function; + } + const Debug: { + /** + * Allows for runtime registration of handler functions that override the default deprecation behavior. + * Deprecations are invoked by calls to [Ember.deprecate](http://emberjs.com/api/classes/Ember.html#method_deprecate). + * The following example demonstrates its usage by registering a handler that throws an error if the + * message contains the word "should", otherwise defers to the default handler. + */ + registerDeprecationHandler(handler: Function): any; + /** + * Allows for runtime registration of handler functions that override the default warning behavior. + * Warnings are invoked by calls made to [Ember.warn](http://emberjs.com/api/classes/Ember.html#method_warn). + * The following example demonstrates its usage by registering a handler that does nothing overriding Ember's + * default warning behavior. + */ + registerWarnHandler(handler: Function): any; + }; + /** + * The DefaultResolver defines the default lookup rules to resolve + * container lookups before consulting the container for registered + * items: + */ + class DefaultResolver extends Resolver { + /** + * This method is called via the container's resolver method. + * It parses the provided `fullName` and then looks up and + * returns the appropriate template or class. + */ + resolve(fullName: string): {}; + /** + * This will be set to the Application instance when it is + * created. + */ + namespace: Application; + } + interface Initializer { + name: string; + before?: string[]; + after?: string[]; + initialize(application: T): void; + } + /** + * The `Engine` class contains core functionality for both applications and + * engines. + */ + class Engine extends Namespace.extend(_RegistryProxyMixin) { + /** + * The goal of initializers should be to register dependencies and injections. + * This phase runs once. Because these initializers may load code, they are + * allowed to defer application readiness and advance it. If you need to access + * the container or store you should use an InstanceInitializer that will be run + * after all initializers and therefore after all code is loaded and the app is + * ready. + */ + static initializer(initializer: Initializer): void; + /** + * Instance initializers run after all initializers have run. Because + * instance initializers run after the app is fully set up. We have access + * to the store, container, and other items. However, these initializers run + * after code has loaded and are not allowed to defer readiness. + */ + static instanceInitializer(instanceInitializer: Initializer): void; + /** + * Set this to provide an alternate class to `Ember.DefaultResolver` + */ + resolver: Resolver; + } + /** + * The `EngineInstance` encapsulates all of the stateful aspects of a + * running `Engine`. + */ + class EngineInstance extends Ember.Object.extend( + _RegistryProxyMixin, + _ContainerProxyMixin + ) { + /** + * Unregister a factory. + */ + unregister(fullName: string): any; + + /** + * Initialize the `EngineInstance` and return a promise that resolves + * with the instance itself when the boot process is complete. + */ + boot(): Promise; + } + /** + * This mixin defines the common interface implemented by enumerable objects + * in Ember. Most of these methods follow the standard Array iteration + * API defined up to JavaScript 1.8 (excluding language-specific features that + * cannot be emulated in older versions of JavaScript). + */ + interface Enumerable { + /** + * Helper method returns the first object from a collection. This is usually + * used by bindings and other parts of the framework to extract a single + * object if the enumerable contains only one item. + */ + firstObject: ComputedProperty; + /** + * Helper method returns the last object from a collection. If your enumerable + * contains only one object, this method should always return that object. + * If your enumerable is empty, this method should return `undefined`. + */ + lastObject: ComputedProperty; + /** + * @deprecated Use `Enumerable#includes` instead. + */ + contains(obj: T): boolean; + /** + * Iterates through the enumerable, calling the passed function on each + * item. This method corresponds to the `forEach()` method defined in + * JavaScript 1.6. + */ + forEach: GlobalArray['forEach']; + /** + * Alias for `mapBy` + */ + getEach(key: string): any[]; + /** + * Sets the value on the named property for each member. This is more + * ergonomic than using other methods defined on this helper. If the object + * implements Ember.Observable, the value will be changed to `set(),` otherwise + * it will be set directly. `null` objects are skipped. + */ + setEach(key: string, value: any): any; + /** + * Maps all of the items in the enumeration to another value, returning + * a new array. This method corresponds to `map()` defined in JavaScript 1.6. + */ + map: GlobalArray['map']; + /** + * Similar to map, this specialized function returns the value of the named + * property on all items in the enumeration. + */ + mapBy(key: string): any[]; + /** + * Returns an array with all of the items in the enumeration that the passed + * function returns true for. This method corresponds to `filter()` defined in + * JavaScript 1.6. + */ + filter: GlobalArray['filter']; + /** + * Returns an array with all of the items in the enumeration where the passed + * function returns false. This method is the inverse of filter(). + */ + reject(callbackfn: (value: T, index: number, array: T[]) => any, thisArg?: any): NativeArray; + /** + * Returns an array with just the items with the matched property. You + * can pass an optional second argument with the target value. Otherwise + * this will match any property that evaluates to `true`. + */ + filterBy(key: string, value?: any): NativeArray; + /** + * Returns an array with the items that do not have truthy values for + * key. You can pass an optional second argument with the target value. Otherwise + * this will match any property that evaluates to false. + */ + rejectBy(key: string, value?: any): NativeArray; + /** + * Returns the first item in the array for which the callback returns true. + * This method works similar to the `filter()` method defined in JavaScript 1.6 + * except that it will stop working on the array once a match is found. + */ + find: GlobalArray['find']; + /** + * Returns the first item with a property matching the passed value. You + * can pass an optional second argument with the target value. Otherwise + * this will match any property that evaluates to `true`. + */ + findBy(key: string, value?: any): T | undefined; + /** + * Returns `true` if the passed function returns true for every item in the + * enumeration. This corresponds with the `every()` method in JavaScript 1.6. + */ + every: GlobalArray['every']; + /** + * Returns `true` if the passed property resolves to the value of the second + * argument for all items in the enumerable. This method is often simpler/faster + * than using a callback. + */ + isEvery(key: string, value?: any): boolean; + /** + * Returns `true` if the passed function returns true for any item in the + * enumeration. + */ + any(callback: (value: T, index: number, array: T[]) => boolean, target?: {}): boolean; + /** + * Returns `true` if the passed property resolves to the value of the second + * argument for any item in the enumerable. This method is often simpler/faster + * than using a callback. + */ + isAny(key: string, value?: any): boolean; + /** + * This will combine the values of the enumerator into a single value. It + * is a useful way to collect a summary value from an enumeration. This + * corresponds to the `reduce()` method defined in JavaScript 1.8. + */ + reduce: GlobalArray['reduce']; + /** + * Invokes the named method on every object in the receiver that + * implements it. This method corresponds to the implementation in + * Prototype 1.6. + */ + invoke(methodName: keyof T, ...args: any[]): any[]; + /** + * Simply converts the enumerable into a genuine array. The order is not + * guaranteed. Corresponds to the method implemented by Prototype. + */ + toArray(): T[]; + /** + * Returns a copy of the array with all `null` and `undefined` elements removed. + */ + compact(): NativeArray; + /** + * Returns a new enumerable that excludes the passed value. The default + * implementation returns an array regardless of the receiver type. + * If the receiver does not contain the value it returns the original enumerable. + */ + without(value: T): NativeArray; + /** + * Returns a new enumerable that contains only unique values. The default + * implementation returns an array regardless of the receiver type. + */ + uniq(): NativeArray; + /** + * Converts the enumerable into an array and sorts by the keys + * specified in the argument. + */ + sortBy(property: string): NativeArray; + /** + * Returns a new enumerable that contains only items containing a unique property value. + * The default implementation returns an array regardless of the receiver type. + */ + uniqBy(property: string): NativeArray; + /** + * Returns `true` if the passed object can be found in the enumerable. + */ + includes(searchElement: T, fromIndex?: number): boolean; + /** + * This is the handler for the special array content property. If you get + * this property, it will return this. If you set this property to a new + * array, it will replace the current content. + */ + '[]': ComputedProperty; + } + const Enumerable: Mixin>; + /** + A subclass of the JavaScript Error object for use in Ember. + **/ + const Error: ErrorConstructor; + /** + * `Ember.EventDispatcher` handles delegating browser events to their + * corresponding `Ember.Views.` For example, when you click on a view, + * `Ember.EventDispatcher` ensures that that view's `mouseDown` method gets + * called. + */ + class EventDispatcher extends Object { + /** + * The set of events names (and associated handler function names) to be setup + * and dispatched by the `EventDispatcher`. Modifications to this list can be done + * at setup time, generally via the `Ember.Application.customEvents` hash. + */ + events: EventDispatcherEvents; + } + /** + * This mixin allows for Ember objects to subscribe to and emit events. + */ + interface Evented { + /** + * Subscribes to a named event with given function. + */ + on( + name: string, + target: Target, + method: (this: Target, ...args: any[]) => void + ): this; + on(name: string, method: (...args: any[]) => void): this; + /** + * Subscribes a function to a named event and then cancels the subscription + * after the first time the event is triggered. It is good to use ``one`` when + * you only care about the first time an event has taken place. + */ + one( + name: string, + target: Target, + method: (this: Target, ...args: any[]) => void + ): this; + one(name: string, method: (...args: any[]) => void): this; + /** + * Triggers a named event for the object. Any additional arguments + * will be passed as parameters to the functions that are subscribed to the + * event. + */ + trigger(name: string, ...args: any[]): any; + /** + * Cancels subscription for given name, target, and method. + */ + off( + name: string, + target: Target, + method: (this: Target, ...args: any[]) => void + ): this; + off(name: string, method: (...args: any[]) => void): this; + /** + * Checks to see if object has any subscriptions for named event. + */ + has(name: string): boolean; + } + const Evented: Mixin; + /** + * The `Ember.Freezable` mixin implements some basic methods for marking an + * object as frozen. Once an object is frozen it should be read only. No changes + * may be made the internal state of the object. + * @deprecated Use `Object.freeze` instead. + */ + interface Freezable { + freeze(): Freezable; + isFrozen: boolean; + } + const Freezable: Mixin; + /** + * `Ember.HashLocation` implements the location API using the browser's + * hash. At present, it relies on a `hashchange` event existing in the + * browser. + */ + class HashLocation extends Object {} + /** + * Ember.HistoryLocation implements the location API using the browser's + * history.pushState API. + */ + class HistoryLocation extends Object {} + /** + * Ember Helpers are functions that can compute values, and are used in templates. + * For example, this code calls a helper named `format-currency`: + */ + class Helper extends Object { + /** + * In many cases, the ceremony of a full `Ember.Helper` class is not required. + * The `helper` method create pure-function helpers without instances. For + * example: + */ + static helper(helper: (params: any[], hash?: object) => any): Helper; + /** + * Override this function when writing a class-based helper. + */ + compute(params: any[], hash: object): any; + /** + * On a class-based helper, it may be useful to force a recomputation of that + * helpers value. This is akin to `rerender` on a component. + */ + recompute(): any; + } + /** + * The purpose of the Ember Instrumentation module is + * to provide efficient, general-purpose instrumentation + * for Ember. + */ + const Instrumentation: { + instrument(name: string, payload: any, callback: Function, binding: any): void; + reset(): void; + subscribe(pattern: string, object: any): void; + unsubscribe(subscriber: any): void; + }; + /** + * `Ember.LinkComponent` renders an element whose `click` event triggers a + * transition of the application's instance of `Ember.Router` to + * a supplied route by name. + */ + class LinkComponent extends Component { + /** + * Used to determine when this `LinkComponent` is active. + */ + currentWhen: any; + /** + * Sets the `title` attribute of the `LinkComponent`'s HTML element. + */ + title: string | null; + /** + * Sets the `rel` attribute of the `LinkComponent`'s HTML element. + */ + rel: string | null; + /** + * Sets the `tabindex` attribute of the `LinkComponent`'s HTML element. + */ + tabindex: string | null; + /** + * Sets the `target` attribute of the `LinkComponent`'s HTML element. + */ + target: string | null; + /** + * The CSS class to apply to `LinkComponent`'s element when its `active` + * property is `true`. + */ + activeClass: string; + /** + * Determines whether the `LinkComponent` will trigger routing via + * the `replaceWith` routing strategy. + */ + replace: boolean; + } + /** + * Ember.Location returns an instance of the correct implementation of + * the `location` API. + */ + const Location: { + /** + * This is deprecated in favor of using the container to lookup the location + * implementation as desired. + * @deprecated Use the container to lookup the location implementation that you need. + */ + create(options?: {}): any; + }; + /** + * Inside Ember-Metal, simply uses the methods from `imports.console`. + * Override this to provide more robust logging functionality. + */ + const Logger: { + /** + * If the value passed into `Ember.Logger.assert` is not truthy it will throw an error with a stack trace. + */ + assert(test: boolean, message?: string): void; + /** + * Logs the arguments to the console in blue text. + */ + debug(...args: any[]): void; + /** + * Prints the arguments to the console with an error icon, red text and a stack trace. + */ + error(...args: any[]): void; + /** + * Logs the arguments to the console. + */ + info(...args: any[]): void; + /** + * Logs the arguments to the console. + */ + log(...args: any[]): void; + /** + * Prints the arguments to the console with a warning icon. + */ + warn(...args: any[]): void; + }; + /** + * A Map stores values indexed by keys. Unlike JavaScript's + * default Objects, the keys of a Map can be any JavaScript + * object. + * @deprecated + */ + class Map { + copy(): Map; + static create(): Map; + forEach(callback: Function, self: any): void; + get(key: any): any; + has(key: any): boolean; + set(key: any, value: any): void; + length: number; + } + /** + * @deprecated + */ + class MapWithDefault extends Map { + copy(): MapWithDefault; + static create(): MapWithDefault; + } + /** + * The `Ember.Mixin` class allows you to create mixins, whose properties can be + * added to other classes. + */ + class Mixin { + /** + * Mixin needs to have *something* on its prototype, otherwise it's treated like an empty interface. + * It cannot be private, sadly. + */ + __ember_mixin__: never; + + static create( + args?: MixinOrLiteral & ThisType> + ): Mixin; + + static create( + arg1: MixinOrLiteral & ThisType>, + arg2: MixinOrLiteral & ThisType> + ): Mixin; + + static create( + arg1: MixinOrLiteral & ThisType>, + arg2: MixinOrLiteral & ThisType>, + arg3: MixinOrLiteral & ThisType> + ): Mixin; + + static create( + arg1: MixinOrLiteral & ThisType>, + arg2: MixinOrLiteral & ThisType>, + arg3: MixinOrLiteral & ThisType>, + arg4: MixinOrLiteral & ThisType> + ): Mixin; + } + /** + * This mixin defines the API for modifying array-like objects. These methods + * can be applied only to a collection that keeps its items in an ordered set. + * It builds upon the Array mixin and adds methods to modify the array. + * One concrete implementations of this class include ArrayProxy. + */ + interface MutableArray extends Array, MutableEnumerable { + /** + * __Required.__ You must implement this method to apply this mixin. + */ + replace(idx: number, amt: number, objects: any[]): any; + /** + * Remove all elements from the array. This is useful if you + * want to reuse an existing array without having to recreate it. + */ + clear(): this; + /** + * This will use the primitive `replace()` method to insert an object at the + * specified index. + */ + insertAt(idx: number, object: {}): this; + /** + * Remove an object at the specified index using the `replace()` primitive + * method. You can pass either a single index, or a start and a length. + */ + removeAt(start: number, len?: number): this; + /** + * Push the object onto the end of the array. Works just like `push()` but it + * is KVO-compliant. + */ + pushObject(obj: T): T; + /** + * Add the objects in the passed numerable to the end of the array. Defers + * notifying observers of the change until all objects are added. + */ + pushObjects(objects: Enumerable): this; + /** + * Pop object from array or nil if none are left. Works just like `pop()` but + * it is KVO-compliant. + */ + popObject(): T; + /** + * Shift an object from start of array or nil if none are left. Works just + * like `shift()` but it is KVO-compliant. + */ + shiftObject(): T; + /** + * Unshift an object to start of array. Works just like `unshift()` but it is + * KVO-compliant. + */ + unshiftObject(obj: T): T; + /** + * Adds the named objects to the beginning of the array. Defers notifying + * observers until all objects have been added. + */ + unshiftObjects(objects: Enumerable): this; + /** + * Reverse objects in the array. Works just like `reverse()` but it is + * KVO-compliant. + */ + reverseObjects(): this; + /** + * Replace all the receiver's content with content of the argument. + * If argument is an empty array receiver will be cleared. + */ + setObjects(objects: Ember.Array): this; + } + const MutableArray: Mixin>; + /** + * This mixin defines the API for modifying generic enumerables. These methods + * can be applied to an object regardless of whether it is ordered or + * unordered. + */ + interface MutableEnumerable extends Enumerable { + /** + * __Required.__ You must implement this method to apply this mixin. + */ + addObject(object: T): T; + /** + * Adds each object in the passed enumerable to the receiver. + */ + addObjects(objects: Enumerable): this; + /** + * __Required.__ You must implement this method to apply this mixin. + */ + removeObject(object: T): T; + /** + * Removes each object in the passed enumerable from the receiver. + */ + removeObjects(objects: Enumerable): this; + } + const MutableEnumerable: Mixin>; + /** + * A Namespace is an object usually used to contain other objects or methods + * such as an application or framework. Create a namespace anytime you want + * to define one of these new containers. + */ + class Namespace extends Object {} + /** + * The NativeArray mixin contains the properties needed to make the native + * Array support Ember.MutableArray and all of its dependent APIs. Unless you + * have `EmberENV.EXTEND_PROTOTYPES` or `EmberENV.EXTEND_PROTOTYPES.Array` set to + * false, this will be applied automatically. Otherwise you can apply the mixin + * at anytime by calling `Ember.NativeArray.apply(Array.prototype)`. + */ + interface NativeArray extends GlobalArray, MutableArray, Observable, Copyable { + /** + * __Required.__ You must implement this method to apply this mixin. + */ + length: number; + } + const NativeArray: Mixin>; + /** + * Ember.NoneLocation does not interact with the browser. It is useful for + * testing, or when you need to manage state with your Router, but temporarily + * don't want it to muck with the URL (for example when you embed your + * application in a larger page). + */ + class NoneLocation extends Object {} + /** + * `Ember.Object` is the main base class for all Ember objects. It is a subclass + * of `Ember.CoreObject` with the `Ember.Observable` mixin applied. For details, + * see the documentation for each of these. + */ + class Object extends CoreObject.extend(Observable) {} + /** + * `Ember.ObjectProxy` forwards all properties not defined by the proxy itself + * to a proxied `content` object. + */ + class ObjectProxy extends Object { + /** + The object whose properties will be forwarded. + **/ + content: Object; + } + /** + * This mixin provides properties and property observing functionality, core features of the Ember object model. + */ + interface Observable { + /** + * Retrieves the value of a property from the object. + */ + get(this: ComputedPropertyGetters, key: K): T[K]; + /** + * To get the values of multiple properties at once, call `getProperties` + * with a list of strings or an array: + */ + getProperties(this: ComputedPropertyGetters, list: K[]): Pick; + getProperties( + this: ComputedPropertyGetters, + ...list: K[] + ): Pick; + /** + * Sets the provided key or path to the value. + */ + set(this: ComputedPropertySetters, key: K, value: T[K]): T[K]; + /** + * Sets a list of properties at once. These properties are set inside + * a single `beginPropertyChanges` and `endPropertyChanges` batch, so + * observers will be buffered. + */ + setProperties( + this: ComputedPropertySetters, + hash: Pick + ): Pick; + /** + * Convenience method to call `propertyWillChange` and `propertyDidChange` in + * succession. + */ + notifyPropertyChange(keyName: string): this; + /** + * Adds an observer on a property. + */ + addObserver( + key: keyof this, + target: Target, + method: ObserverMethod + ): void; + addObserver( + key: keyof this, + method: ObserverMethod + ): void; + /** + * Remove an observer you have previously registered on this object. Pass + * the same key, target, and method you passed to `addObserver()` and your + * target will no longer receive notifications. + */ + removeObserver( + key: keyof this, + target: Target, + method: ObserverMethod + ): any; + removeObserver( + key: keyof this, + method: ObserverMethod + ): any; + /** + * Retrieves the value of a property, or a default value in the case that the + * property returns `undefined`. + */ + getWithDefault( + this: ComputedPropertyGetters, + key: K, + defaultValue: T[K] + ): T[K]; + /** + * Set the value of a property to the current value plus some amount. + */ + incrementProperty(keyName: keyof this, increment?: number): number; + /** + * Set the value of a property to the current value minus some amount. + */ + decrementProperty(keyName: keyof this, decrement?: number): number; + /** + * Set the value of a boolean property to the opposite of its + * current value. + */ + toggleProperty(keyName: keyof this): boolean; + /** + * Returns the cached value of a computed property, if it exists. + * This allows you to inspect the value of a computed property + * without accidentally invoking it if it is intended to be + * generated lazily. + */ + cacheFor(this: ComputedPropertyGetters, key: K): T[K] | undefined; + } + const Observable: Mixin; + /** + * This class is used internally by Ember and Ember Data. + * Please do not use it at this time. We plan to clean it up + * and add many tests soon. + * @deprecated + */ + class OrderedSet { + add(obj: any): void; + clear(): void; + copy(): OrderedSet; + static create(): OrderedSet; + forEach(fn: Function, self: any): void; + has(obj: any): boolean; + isEmpty(): boolean; + toArray(): any[]; + } + /** + * A low level mixin making ObjectProxy promise-aware. + */ + interface PromiseProxyMixin extends RSVP.Promise { + /** + * If the proxied promise is rejected this will contain the reason + * provided. + */ + reason: any; + /** + * Once the proxied promise has settled this will become `false`. + */ + isPending: boolean; + /** + * Once the proxied promise has settled this will become `true`. + */ + isSettled: boolean; + /** + * Will become `true` if the proxied promise is rejected. + */ + isRejected: boolean; + /** + * Will become `true` if the proxied promise is fulfilled. + */ + isFulfilled: boolean; + /** + * The promise whose fulfillment value is being proxied by this object. + */ + promise: RSVP.Promise; + } + const PromiseProxyMixin: Mixin>; + /** + * A registry used to store factory and option information keyed + * by type. + */ + class Registry { + register( + fullName: string, + factory: EmberClassConstructor, + options?: { singleton?: boolean } + ): void; + } + class Resolver extends Ember.Object {} + /** + The `Ember.Route` class is used to define individual routes. Refer to + the [routing guide](http://emberjs.com/guides/routing/) for documentation. + */ + class Route extends Object.extend(ActionHandler, Evented) { + // methods + /** + This hook is called after this route's model has resolved. + It follows identical async/promise semantics to `beforeModel` + but is provided the route's resolved model in addition to + the `transition`, and is therefore suited to performing + logic that can only take place after the model has already + resolved. + */ + afterModel(resolvedModel: any, transition: Transition): any; + + /** + This hook is the first of the route entry validation hooks + called when an attempt is made to transition into a route + or one of its children. It is called before `model` and + `afterModel`, and is appropriate for cases when: + 1) A decision can be made to redirect elsewhere without + needing to resolve the model first. + 2) Any async operations need to occur first before the + model is attempted to be resolved. + This hook is provided the current `transition` attempt + as a parameter, which can be used to `.abort()` the transition, + save it for a later `.retry()`, or retrieve values set + on it from a previous hook. You can also just call + `this.transitionTo` to another route to implicitly + abort the `transition`. + You can return a promise from this hook to pause the + transition until the promise resolves (or rejects). This could + be useful, for instance, for retrieving async code from + the server that is required to enter a route. + */ + beforeModel(transition: Transition): any; + + /** + * Returns the controller for a particular route or name. + * The controller instance must already have been created, either through entering the + * associated route or using `generateController`. + */ + controllerFor(name: K): ControllerRegistry[K]; + + /** + * Disconnects a view that has been rendered into an outlet. + */ + disconnectOutlet(options: string | { outlet?: string; parentView?: string }): void; + + /** + * A hook you can implement to convert the URL into the model for + * this route. + */ + model(params: {}, transition: Transition): any; + + /** + * Returns the model of a parent (or any ancestor) route + * in a route hierarchy. During a transition, all routes + * must resolve a model object, and if a route + * needs access to a parent route's model in order to + * resolve a model (or just reuse the model from a parent), + * it can call `this.modelFor(theNameOfParentRoute)` to + * retrieve it. + */ + modelFor(name: string): {}; + + /** + * Retrieves parameters, for current route using the state.params + * variable and getQueryParamsFor, using the supplied routeName. + */ + paramsFor(name: string): {}; + + /** + * Refresh the model on this route and any child routes, firing the + * `beforeModel`, `model`, and `afterModel` hooks in a similar fashion + * to how routes are entered when transitioning in from other route. + * The current route params (e.g. `article_id`) will be passed in + * to the respective model hooks, and if a different model is returned, + * `setupController` and associated route hooks will re-fire as well. + * An example usage of this method is re-querying the server for the + * latest information using the same parameters as when the route + * was first entered. + * Note that this will cause `model` hooks to fire even on routes + * that were provided a model object when the route was initially + * entered. + */ + redirect(): Transition; + + /** + * Refresh the model on this route and any child routes, firing the + * `beforeModel`, `model`, and `afterModel` hooks in a similar fashion + * to how routes are entered when transitioning in from other route. + * The current route params (e.g. `article_id`) will be passed in + * to the respective model hooks, and if a different model is returned, + * `setupController` and associated route hooks will re-fire as well. + * An example usage of this method is re-querying the server for the + * latest information using the same parameters as when the route + * was first entered. + * Note that this will cause `model` hooks to fire even on routes + * that were provided a model object when the route was initially + * entered. + */ + refresh(): Transition; + + /** + * `render` is used to render a template into a region of another template + * (indicated by an `{{outlet}}`). `render` is used both during the entry + * phase of routing (via the `renderTemplate` hook) and later in response to + * user interaction. + */ + render(name: string, options?: RenderOptions): void; + + /** + * A hook you can use to render the template for the current route. + * This method is called with the controller for the current route and the + * model supplied by the `model` hook. By default, it renders the route's + * template, configured with the controller for the route. + * This method can be overridden to set up and render additional or + * alternative templates. + */ + renderTemplate(controller: Controller, model: {}): void; + + /** + * Transition into another route while replacing the current URL, if possible. + * This will replace the current history entry instead of adding a new one. + * Beside that, it is identical to `transitionTo` in all other respects. See + * 'transitionTo' for additional information regarding multiple models. + */ + replaceWith(name: string, ...args: any[]): Transition; + + /** + * A hook you can use to reset controller values either when the model + * changes or the route is exiting. + */ + resetController(controller: Controller, isExiting: boolean, transition: any): void; + + /** + * Sends an action to the router, which will delegate it to the currently active + * route hierarchy per the bubbling rules explained under actions. + */ + send(name: string, ...args: any[]): void; + + /** + * A hook you can implement to convert the route's model into parameters + * for the URL. + * + * The default `serialize` method will insert the model's `id` into the + * route's dynamic segment (in this case, `:post_id`) if the segment contains '_id'. + * If the route has multiple dynamic segments or does not contain '_id', `serialize` + * will return `Ember.getProperties(model, params)` + * This method is called when `transitionTo` is called with a context + * in order to populate the URL. + */ + serialize(model: {}, params: string[]): string | object; + + /** + * A hook you can use to setup the controller for the current route. + * This method is called with the controller for the current route and the + * model supplied by the `model` hook. + * By default, the `setupController` hook sets the `model` property of + * the controller to the `model`. + * If you implement the `setupController` hook in your Route, it will + * prevent this default behavior. If you want to preserve that behavior + * when implementing your `setupController` function, make sure to call + * `_super` + */ + setupController(controller: Controller, model: {}): void; + + /** + * Transition the application into another route. The route may + * be either a single route or route path + */ + transitionTo(name: string, ...object: any[]): Transition; + + /** + * The name of the view to use by default when rendering this routes template. + * When rendering a template, the route will, by default, determine the + * template and view to use from the name of the route itself. If you need to + * define a specific view, set this property. + * This is useful when multiple routes would benefit from using the same view + * because it doesn't require a custom `renderTemplate` method. + */ + transitionTo(name: string, ...object: any[]): Transition; + + // https://emberjs.com/api/ember/3.2/classes/Route/methods/intermediateTransitionTo?anchor=intermediateTransitionTo + /** + * Perform a synchronous transition into another route without attempting to resolve promises, + * update the URL, or abort any currently active asynchronous transitions + * (i.e. regular transitions caused by transitionTo or URL changes). + * + * @param name the name of the route or a URL + * @param object the model(s) or identifier(s) to be used while + * transitioning to the route. + * @returns the Transition object associated with this attempted transition + */ + intermediateTransitionTo(name: string, ...object: any[]): Transition; + + // properties + /** + * The controller associated with this route. + */ + controller: Controller; + + /** + * The name of the controller to associate with this route. + * By default, Ember will lookup a route's controller that matches the name + * of the route (i.e. `App.PostController` for `App.PostRoute`). However, + * if you would like to define a specific controller to use, you can do so + * using this property. + * This is useful in many ways, as the controller specified will be: + * * p assed to the `setupController` method. + * * used as the controller for the view being rendered by the route. + * * returned from a call to `controllerFor` for the route. + */ + controllerName: string; + + /** + * Configuration hash for this route's queryParams. + */ + queryParams: { [key: string]: RouteQueryParam }; + + /** + * The name of the route, dot-delimited + */ + routeName: string; + + /** + * The name of the template to use by default when rendering this routes + * template. + * This is similar with `viewName`, but is useful when you just want a custom + * template without a view. + */ + templateName: string; + + // events + /** + * This hook is executed when the router enters the route. It is not executed + * when the model for the route changes. + */ + activate(): void; + + /** + * This hook is executed when the router completely exits this route. It is + * not executed when the model for the route changes. + */ + deactivate(): void; + + /** + * The didTransition action is fired after a transition has successfully been + * completed. This occurs after the normal model hooks (beforeModel, model, + * afterModel, setupController) have resolved. The didTransition action has + * no arguments, however, it can be useful for tracking page views or resetting + * state on the controller. + */ + didTransition(): void; + + /** + * When attempting to transition into a route, any of the hooks may return a promise + * that rejects, at which point an error action will be fired on the partially-entered + * routes, allowing for per-route error handling logic, or shared error handling logic + * defined on a parent route. + */ + error(error: any, transition: Transition): void; + + /** + * The loading action is fired on the route when a route's model hook returns a + * promise that is not already resolved. The current Transition object is the first + * parameter and the route that triggered the loading event is the second parameter. + */ + loading(transition: Transition, route: Route): void; + + /** + * The willTransition action is fired at the beginning of any attempted transition + * with a Transition object as the sole argument. This action can be used for aborting, + * redirecting, or decorating the transition from the currently active routes. + */ + willTransition(transition: Transition): void; + } + /** + * The `Ember.Router` class manages the application state and URLs. Refer to + * the [routing guide](http://emberjs.com/guides/routing/) for documentation. + */ + class Router extends Object.extend(Evented) { + /** + * The `Router.map` function allows you to define mappings from URLs to routes + * in your application. These mappings are defined within the + * supplied callback function using `this.route`. + */ + static map(callback: (this: RouterDSL) => void): void; + /** + * The `location` property determines the type of URL's that your + * application will use. + */ + location: string; + /** + * Represents the URL of the root of the application, often '/'. This prefix is + * assumed on all routes defined on this router. + */ + rootURL: string; + /** + * Handles updating the paths and notifying any listeners of the URL + * change. + */ + didTransition(): any; + /** + * Handles notifying any listeners of an impending URL + * change. + */ + willTransition(): any; + /** + * Transition the application into another route. The route may + * be either a single route or route path: + */ + transitionTo(name: string, options?: {}): Transition; + transitionTo(name: string, ...models: any[]): Transition; + transitionTo(name: string, options: {}): Transition; + } + class RouterDSL { + constructor(name: string, options: object); + route(name: string, callback: (this: RouterDSL) => void): void; + route( + name: string, + options?: { path?: string; resetNamespace?: boolean }, + callback?: (this: RouterDSL) => void + ): void; + mount( + name: string, + options?: { + as?: string, + path?: string, + resetNamespace?: boolean, + engineInfo?: any + } + ): void; + } + class Service extends Object {} + /** + * The internal class used to create textarea element when the `{{textarea}}` + * helper is used. + */ + class TextArea extends Component.extend(TextSupport) {} + /** + * The internal class used to create text inputs when the `{{input}}` + * helper is used with `type` of `text`. + */ + class TextField extends Component.extend(TextSupport) { + /** + * The `value` attribute of the input element. As the user inputs text, this + * property is updated live. + */ + value: string; + /** + * The `type` attribute of the input element. + */ + type: string; + /** + * The `size` of the text field in characters. + */ + size: string; + /** + * The `pattern` attribute of input element. + */ + pattern: string; + /** + * The `min` attribute of input element used with `type="number"` or `type="range"`. + */ + min: string; + /** + * The `max` attribute of input element used with `type="number"` or `type="range"`. + */ + max: string; + } + /** + * `TextSupport` is a shared mixin used by both `Ember.TextField` and + * `Ember.TextArea`. `TextSupport` adds a number of methods that allow you to + * specify a controller action to invoke when a certain event is fired on your + * text field or textarea. The specifed controller action would get the current + * value of the field passed in as the only argument unless the value of + * the field is empty. In that case, the instance of the field itself is passed + * in as the only argument. + */ + interface TextSupport extends TargetActionSupport { + cancel(event: Function): void; + focusIn(event: Function): void; + focusOut(event: Function): void; + insertNewLine(event: Function): void; + keyPress(event: Function): void; + action: string; + bubbles: boolean; + onEvent: string; + } + const TextSupport: Ember.Mixin; + interface Transition { + /** + Aborts the Transition. Note you can also implicitly abort a transition + by initiating another transition while a previous one is underway. + */ + abort(): Transition; + /** + Retries a previously-aborted transition (making sure to abort the + transition if it's still active). Returns a new transition that + represents the new attempt to transition. + */ + retry(): Transition; + } + interface ViewTargetActionSupport { + target: any; + actionContext: any; + } + const ViewTargetActionSupport: Mixin; + const ViewUtils: { + isSimpleClick(event: Event): boolean; + }; + + // FYI - RSVP source comes from https://github.com/tildeio/rsvp.js/blob/master/lib/rsvp/promise.js + const RSVP: typeof Rsvp; + namespace RSVP { + type Promise = Rsvp.Promise; + } + + /** + * This is a container for an assortment of testing related functionality + */ + namespace Test { + /** + * `registerHelper` is used to register a test helper that will be injected + * when `App.injectTestHelpers` is called. + */ + function registerHelper( + name: string, + helperMethod: (app: Application, ...args: any[]) => any, + options?: object + ): any; + /** + * `registerAsyncHelper` is used to register an async test helper that will be injected + * when `App.injectTestHelpers` is called. + */ + function registerAsyncHelper( + name: string, + helperMethod: (app: Application, ...args: any[]) => any + ): void; + /** + * Remove a previously added helper method. + */ + function unregisterHelper(name: string): void; + /** + * Used to register callbacks to be fired whenever `App.injectTestHelpers` + * is called. + */ + function onInjectHelpers(callback: (app: Application) => void): void; + /** + * This returns a thenable tailored for testing. It catches failed + * `onSuccess` callbacks and invokes the `Ember.Test.adapter.exception` + * callback in the last chained then. + */ + function promise( + resolver: ( + resolve: (value?: T | PromiseLike) => void, + reject: (reason?: any) => void + ) => void, + label?: string + ): Ember.Test.Promise; + /** + * Replacement for `Ember.RSVP.resolve` + * The only difference is this uses + * an instance of `Ember.Test.Promise` + */ + function resolve(value?: T | PromiseLike, label?: string): Ember.Test.Promise; + /** + * This allows ember-testing to play nicely with other asynchronous + * events, such as an application that is waiting for a CSS3 + * transition or an IndexDB transaction. The waiter runs periodically + * after each async helper (i.e. `click`, `andThen`, `visit`, etc) has executed, + * until the returning result is truthy. After the waiters finish, the next async helper + * is executed and the process repeats. + */ + function registerWaiter(callback: () => boolean): any; + function registerWaiter( + context: Context, + callback: (this: Context) => boolean + ): any; + /** + * `unregisterWaiter` is used to unregister a callback that was + * registered with `registerWaiter`. + */ + function unregisterWaiter(callback: () => boolean): any; + function unregisterWaiter( + context: Context, + callback: (this: Context) => boolean + ): any; + /** + * Iterates through each registered test waiter, and invokes + * its callback. If any waiter returns false, this method will return + * true indicating that the waiters have not settled yet. + */ + function checkWaiters(): boolean; + /** + * Used to allow ember-testing to communicate with a specific testing + * framework. + */ + const adapter: Adapter; + /** + * The primary purpose of this class is to create hooks that can be implemented + * by an adapter for various test frameworks. + */ + class Adapter { + /** + * This callback will be called whenever an async operation is about to start. + */ + asyncStart(): any; + /** + * This callback will be called whenever an async operation has completed. + */ + asyncEnd(): any; + /** + * Override this method with your testing framework's false assertion. + * This function is called whenever an exception occurs causing the testing + * promise to fail. + */ + exception(error: string): any; + } + /** + * This class implements the methods defined by Ember.Test.Adapter for the + * QUnit testing framework. + */ + class QUnitAdapter extends Adapter {} + class Promise extends Rsvp.Promise { + constructor( + executor: ( + resolve: (value?: T | PromiseLike) => void, + reject: (reason?: any) => void + ) => void + ); + } + } + /** + * Namespace for injection helper methods. + */ + namespace inject { + /** + * Creates a property that lazily looks up another controller in the container. + * Can only be used when defining another controller. + */ + function controller(): ComputedProperty; + function controller( + name: K + ): ComputedProperty; + /** + * Creates a property that lazily looks up a service in the container. There + * are no restrictions as to what objects a service can be injected into. + */ + function service(): ComputedProperty; + function service( + name: K + ): ComputedProperty; + } + namespace ENV { + const EXTEND_PROTOTYPES: typeof Ember.EXTEND_PROTOTYPES; + const LOG_BINDINGS: boolean; + const LOG_STACKTRACE_ON_DEPRECATION: boolean; + const LOG_VERSION: boolean; + const MODEL_FACTORY_INJECTIONS: boolean; + const RAISE_ON_DEPRECATION: boolean; + } + namespace EXTEND_PROTOTYPES { + const Array: boolean; + const Function: boolean; + const String: boolean; + } + namespace Handlebars { + function compile(string: string): Function; + function compile(environment: any, options?: any, context?: any, asObject?: any): any; + function precompile(string: string, options: any): void; + class Compiler {} + class JavaScriptCompiler {} + function registerPartial(name: string, str: any): void; + function K(): any; + function createFrame(objec: any): any; + function Exception(message: string): void; + class SafeString { + constructor(str: string); + toString(): string; + } + function parse(string: string): any; + function print(ast: any): void; + const logger: typeof Ember.Logger; + function log(level: string, str: string): void; + } + namespace String { + function camelize(str: string): string; + function capitalize(str: string): string; + function classify(str: string): string; + function dasherize(str: string): string; + function decamelize(str: string): string; + function fmt(...args: string[]): string; + function htmlSafe(str: string): void; // TODO: @returns Handlebars.SafeStringStatic; + function isHTMLSafe(str: string): boolean; + function loc(...args: string[]): string; + function underscore(str: string): string; + function w(str: string): string[]; + } + const computed: { + (cb: ComputedPropertyCallback): ComputedProperty; + (k1: string, cb: ComputedPropertyCallback): ComputedProperty; + (k1: string, k2: string, cb: ComputedPropertyCallback): ComputedProperty; + ( + k1: string, + k2: string, + k3: string, + cb: ComputedPropertyCallback + ): ComputedProperty; + ( + k1: string, + k2: string, + k3: string, + k4: string, + cb: ComputedPropertyCallback + ): ComputedProperty; + ( + k1: string, + k2: string, + k3: string, + k4: string, + k5: string, + cb: ComputedPropertyCallback + ): ComputedProperty; + ( + k1: string, + k2: string, + k3: string, + k4: string, + k5: string, + k6: string, + cb: ComputedPropertyCallback + ): ComputedProperty; + ( + k1: string, + k2: string, + k3: string, + k4: string, + k5: string, + k6: string, + k7: string, + ...rest: any[] + ): ComputedProperty; + + /** + * A computed property that returns true if the value of the dependent + * property is null, an empty string, empty array, or empty function. + */ + empty(dependentKey: string): ComputedProperty; + /** + * A computed property that returns true if the value of the dependent + * property is NOT null, an empty string, empty array, or empty function. + */ + notEmpty(dependentKey: string): ComputedProperty; + /** + * A computed property that returns true if the value of the dependent + * property is null or undefined. This avoids errors from JSLint complaining + * about use of ==, which can be technically confusing. + */ + none(dependentKey: string): ComputedProperty; + /** + * A computed property that returns the inverse boolean value + * of the original value for the dependent property. + */ + not(dependentKey: string): ComputedProperty; + /** + * A computed property that converts the provided dependent property + * into a boolean value. + */ + bool(dependentKey: string): ComputedProperty; + /** + * A computed property which matches the original value for the + * dependent property against a given RegExp, returning `true` + * if the value matches the RegExp and `false` if it does not. + */ + match(dependentKey: string, regexp: RegExp): ComputedProperty; + /** + * A computed property that returns true if the provided dependent property + * is equal to the given value. + */ + equal(dependentKey: string, value: any): ComputedProperty; + /** + * A computed property that returns true if the provided dependent property + * is greater than the provided value. + */ + gt(dependentKey: string, value: number): ComputedProperty; + /** + * A computed property that returns true if the provided dependent property + * is greater than or equal to the provided value. + */ + gte(dependentKey: string, value: number): ComputedProperty; + /** + * A computed property that returns true if the provided dependent property + * is less than the provided value. + */ + lt(dependentKey: string, value: number): ComputedProperty; + /** + * A computed property that returns true if the provided dependent property + * is less than or equal to the provided value. + */ + lte(dependentKey: string, value: number): ComputedProperty; + /** + * A computed property that performs a logical `and` on the + * original values for the provided dependent properties. + */ + and(...dependentKeys: string[]): ComputedProperty; + /** + * A computed property which performs a logical `or` on the + * original values for the provided dependent properties. + */ + or(...dependentKeys: string[]): ComputedProperty; + /** + * Creates a new property that is an alias for another property + * on an object. Calls to `get` or `set` this property behave as + * though they were called on the original property. + */ + alias(dependentKey: string): ComputedProperty; + /** + * Where `computed.alias` aliases `get` and `set`, and allows for bidirectional + * data flow, `computed.oneWay` only provides an aliased `get`. The `set` will + * not mutate the upstream property, rather causes the current property to + * become the value set. This causes the downstream property to permanently + * diverge from the upstream property. + */ + oneWay(dependentKey: string): ComputedProperty; + /** + * This is a more semantically meaningful alias of `computed.oneWay`, + * whose name is somewhat ambiguous as to which direction the data flows. + */ + reads(dependentKey: string): ComputedProperty; + /** + * Where `computed.oneWay` provides oneWay bindings, `computed.readOnly` provides + * a readOnly one way binding. Very often when using `computed.oneWay` one does + * not also want changes to propagate back up, as they will replace the value. + */ + readOnly(dependentKey: string): ComputedProperty; + /** + * Creates a new property that is an alias for another property + * on an object. Calls to `get` or `set` this property behave as + * though they were called on the original property, but also + * print a deprecation warning. + */ + deprecatingAlias( + dependentKey: string, + options: { id: string; until: string } + ): ComputedProperty; + /** + * @deprecated Missing deprecation options: https://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options + */ + deprecatingAlias( + dependentKey: string, + options?: { id?: string; until?: string } + ): ComputedProperty; + /** + * A computed property that returns the sum of the values + * in the dependent array. + */ + sum(dependentKey: string): ComputedProperty; + /** + * A computed property that calculates the maximum value in the + * dependent array. This will return `-Infinity` when the dependent + * array is empty. + */ + max(dependentKey: string): ComputedProperty; + /** + * A computed property that calculates the minimum value in the + * dependent array. This will return `Infinity` when the dependent + * array is empty. + */ + min(dependentKey: string): ComputedProperty; + /** + * Returns an array mapped via the callback + */ + map( + dependentKey: string, + callback: (value: any, index: number, array: any[]) => U + ): ComputedProperty; + /** + * Returns an array mapped to the specified key. + */ + mapBy(dependentKey: string, propertyKey: string): ComputedProperty; + /** + * Filters the array by the callback. + */ + filter( + dependentKey: string, + callback: (value: any, index: number, array: any[]) => boolean + ): ComputedProperty; + /** + * Filters the array by the property and value + */ + filterBy( + dependentKey: string, + propertyKey: string, + value?: any + ): ComputedProperty; + /** + * A computed property which returns a new array with all the unique + * elements from one or more dependent arrays. + */ + uniq(propertyKey: string): ComputedProperty; + /** + * A computed property which returns a new array with all the unique + * elements from an array, with uniqueness determined by specific key. + */ + uniqBy(dependentKey: string, propertyKey: string): ComputedProperty; + /** + * A computed property which returns a new array with all the unique + * elements from one or more dependent arrays. + */ + union(...propertyKeys: string[]): ComputedProperty; + /** + * A computed property which returns a new array with all the elements + * two or more dependent arrays have in common. + */ + intersect(...propertyKeys: string[]): ComputedProperty; + /** + * A computed property which returns a new array with all the + * properties from the first dependent array that are not in the second + * dependent array. + */ + setDiff(setAProperty: string, setBProperty: string): ComputedProperty; + /** + * A computed property that returns the array of values + * for the provided dependent properties. + */ + collect(...dependentKeys: string[]): ComputedProperty; + /** + * A computed property which returns a new array with all the + * properties from the first dependent array sorted based on a property + * or sort function. + */ + sort( + itemsKey: string, + sortDefinition: string | ((itemA: any, itemB: any) => number) + ): ComputedProperty; + }; + const run: { + /** + * Runs the passed target and method inside of a RunLoop, ensuring any + * deferred actions including bindings and views updates are flushed at the + * end. + */ + (method: (...args: any[]) => Ret): Ret; + (target: Target, method: RunMethod): Ret; + /** + * If no run-loop is present, it creates a new one. If a run loop is + * present it will queue itself to run on the existing run-loops action + * queue. + */ + join(method: (...args: any[]) => Ret, ...args: any[]): Ret | undefined; + join( + target: Target, + method: RunMethod, + ...args: any[] + ): Ret | undefined; + /** + * Allows you to specify which context to call the specified function in while + * adding the execution of that function to the Ember run loop. This ability + * makes this method a great way to asynchronously integrate third-party libraries + * into your Ember application. + */ + bind( + target: Target, + method: RunMethod, + ...args: any[] + ): (...args: any[]) => Ret; + /** + * Begins a new RunLoop. Any deferred actions invoked after the begin will + * be buffered until you invoke a matching call to `run.end()`. This is + * a lower-level way to use a RunLoop instead of using `run()`. + */ + begin(): void; + /** + * Ends a RunLoop. This must be called sometime after you call + * `run.begin()` to flush any deferred actions. This is a lower-level way + * to use a RunLoop instead of using `run()`. + */ + end(): void; + /** + * Adds the passed target/method and any optional arguments to the named + * queue to be executed at the end of the RunLoop. If you have not already + * started a RunLoop when calling this method one will be started for you + * automatically. + */ + schedule( + queue: EmberRunQueues, + target: Target, + method: RunMethod, + ...args: any[] + ): EmberRunTimer; + schedule( + queue: EmberRunQueues, + method: (args: any[]) => any, + ...args: any[] + ): EmberRunTimer; + /** + * Invokes the passed target/method and optional arguments after a specified + * period of time. The last parameter of this method must always be a number + * of milliseconds. + */ + later(method: (...args: any[]) => any, wait: number): EmberRunTimer; + later(target: Target, method: RunMethod, wait: number): EmberRunTimer; + later( + target: Target, + method: RunMethod, + arg0: any, + wait: number + ): EmberRunTimer; + later( + target: Target, + method: RunMethod, + arg0: any, + arg1: any, + wait: number + ): EmberRunTimer; + later( + target: Target, + method: RunMethod, + arg0: any, + arg1: any, + arg2: any, + wait: number + ): EmberRunTimer; + later( + target: Target, + method: RunMethod, + arg0: any, + arg1: any, + arg2: any, + arg3: any, + wait: number + ): EmberRunTimer; + later( + target: Target, + method: RunMethod, + arg0: any, + arg1: any, + arg2: any, + arg3: any, + arg4: any, + wait: number + ): EmberRunTimer; + later( + target: Target, + method: RunMethod, + arg0: any, + arg1: any, + arg2: any, + arg3: any, + arg4: any, + arg5: any, + wait: number + ): EmberRunTimer; + /** + * Schedule a function to run one time during the current RunLoop. This is equivalent + * to calling `scheduleOnce` with the "actions" queue. + */ + once(target: Target, method: RunMethod, ...args: any[]): EmberRunTimer; + /** + * Schedules a function to run one time in a given queue of the current RunLoop. + * Calling this method with the same queue/target/method combination will have + * no effect (past the initial call). + */ + scheduleOnce( + queue: EmberRunQueues, + target: Target, + method: RunMethod, + ...args: any[] + ): EmberRunTimer; + /** + * Schedules an item to run from within a separate run loop, after + * control has been returned to the system. This is equivalent to calling + * `run.later` with a wait time of 1ms. + */ + next(target: Target, method: RunMethod, ...args: any[]): EmberRunTimer; + /** + * Cancels a scheduled item. Must be a value returned by `run.later()`, + * `run.once()`, `run.scheduleOnce()`, `run.next()`, `run.debounce()`, or + * `run.throttle()`. + */ + cancel(timer: EmberRunTimer): boolean; + /** + * Delay calling the target method until the debounce period has elapsed + * with no additional debounce calls. If `debounce` is called again before + * the specified time has elapsed, the timer is reset and the entire period + * must pass again before the target method is called. + */ + debounce( + method: (...args: any[]) => any, + wait: number, + immediate?: boolean + ): EmberRunTimer; + debounce( + target: Target, + method: RunMethod, + wait: number, + immediate?: boolean + ): EmberRunTimer; + debounce( + target: Target, + method: RunMethod, + arg0: any, + wait: number, + immediate?: boolean + ): EmberRunTimer; + debounce( + target: Target, + method: RunMethod, + arg0: any, + arg1: any, + wait: number, + immediate?: boolean + ): EmberRunTimer; + debounce( + target: Target, + method: RunMethod, + arg0: any, + arg1: any, + arg2: any, + wait: number, + immediate?: boolean + ): EmberRunTimer; + debounce( + target: Target, + method: RunMethod, + arg0: any, + arg1: any, + arg2: any, + arg3: any, + wait: number, + immediate?: boolean + ): EmberRunTimer; + debounce( + target: Target, + method: RunMethod, + arg0: any, + arg1: any, + arg2: any, + arg3: any, + arg4: any, + wait: number, + immediate?: boolean + ): EmberRunTimer; + debounce( + target: Target, + method: RunMethod, + arg0: any, + arg1: any, + arg2: any, + arg3: any, + arg4: any, + arg5: any, + wait: number, + immediate?: boolean + ): EmberRunTimer; + /** + * Ensure that the target method is never called more frequently than + * the specified spacing period. The target method is called immediately. + */ + throttle( + method: (...args: any[]) => any, + spacing: number, + immediate?: boolean + ): EmberRunTimer; + throttle( + target: Target, + method: RunMethod, + spacing: number, + immediate?: boolean + ): EmberRunTimer; + throttle( + target: Target, + method: RunMethod, + arg0: any, + spacing: number, + immediate?: boolean + ): EmberRunTimer; + throttle( + target: Target, + method: RunMethod, + arg0: any, + arg1: any, + spacing: number, + immediate?: boolean + ): EmberRunTimer; + throttle( + target: Target, + method: RunMethod, + arg0: any, + arg1: any, + arg2: any, + spacing: number, + immediate?: boolean + ): EmberRunTimer; + throttle( + target: Target, + method: RunMethod, + arg0: any, + arg1: any, + arg2: any, + arg3: any, + spacing: number, + immediate?: boolean + ): EmberRunTimer; + throttle( + target: Target, + method: RunMethod, + arg0: any, + arg1: any, + arg2: any, + arg3: any, + arg4: any, + spacing: number, + immediate?: boolean + ): EmberRunTimer; + throttle( + target: Target, + method: RunMethod, + arg0: any, + arg1: any, + arg2: any, + arg3: any, + arg4: any, + arg5: any, + spacing: number, + immediate?: boolean + ): EmberRunTimer; + + queues: EmberRunQueues[]; + }; + const platform: { + defineProperty: boolean; + hasPropertyAccessors: boolean; + }; + + /** + * `getEngineParent` retrieves an engine instance's parent instance. + */ + function getEngineParent(engine: EngineInstance): EngineInstance; + /** + * Display a deprecation warning with the provided message and a stack trace + * (Chrome and Firefox only). + */ + function deprecate( + message: string, + test: boolean, + options: { id: string; until: string } + ): any; + /** + * @deprecated Missing deprecation options: https://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options + */ + function deprecate( + message: string, + test: boolean, + options?: { id?: string; until?: string } + ): any; + /** + * Define an assertion that will throw an exception if the condition is not met. + */ + function assert(desc: string, test?: boolean): void | never; + /** + * Display a debug notice. + */ + function debug(message: string): void; + /** + * NOTE: This is a low-level method used by other parts of the API. + * You almost never want to call this method directly. Instead you + * should use Ember.mixin() to define new properties. + */ + function defineProperty( + obj: object, + keyName: string, + desc?: PropertyDescriptor | ComputedProperty, + data?: any, + meta?: any + ): void; + /** + * Alias an old, deprecated method with its new counterpart. + */ + function deprecateFunc any)>( + message: string, + options: { id: string; until: string }, + func: Func + ): Func; + /** + * @deprecated Missing deprecation options: https://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options + */ + function deprecateFunc any)>( + message: string, + func: Func + ): Func; + /** + * Run a function meant for debugging. + */ + function runInDebug(func: () => void): any; + /** + * Display a warning with the provided message. + */ + function warn(message: string, test: boolean, options: { id: string }): any; + function warn(message: string, options: { id: string }): any; + /** + * @deprecated Missing deprecation options: https://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options + */ + function warn(message: string, test: boolean, options?: { id?: string }): any; + /** + * @deprecated Missing deprecation options: https://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options + */ + function warn(message: string, options?: { id?: string }): any; + /** + * Global helper method to create a new binding. Just pass the root object + * along with a `to` and `from` path to create and connect the binding. + * @deprecated https://emberjs.com/deprecations/v2.x#toc_ember-binding + */ + function bind(obj: {}, to: string, from: string): Binding; + /** + * Returns the cached value for a property, if one exists. + * This can be useful for peeking at the value of a computed + * property that is generated lazily, without accidentally causing + * it to be created. + */ + function cacheFor( + obj: ComputedPropertyGetters, + key: K + ): T[K] | undefined; + /** + * Add an event listener + */ + function addListener( + obj: Context, + key: keyof Context, + target: Target, + method: ObserverMethod, + once?: boolean + ): void; + function addListener( + obj: Context, + key: keyof Context, + method: ObserverMethod + ): void; + /** + * Remove an event listener + */ + function removeListener( + obj: Context, + key: keyof Context, + target: Target, + method: ObserverMethod + ): any; + function removeListener( + obj: Context, + key: keyof Context, + method: ObserverMethod + ): any; + /** + * Send an event. The execution of suspended listeners + * is skipped, and once listeners are removed. A listener without + * a target is executed on the passed object. If an array of actions + * is not passed, the actions stored on the passed object are invoked. + */ + function sendEvent(obj: any, eventName: string, params?: any[], actions?: any[]): boolean; + /** + * Define a property as a function that should be executed when + * a specified event or events are triggered. + */ + function on(eventNames: string, func: (...args: any[]) => void): (...args: any[]) => void; + /** + * To get multiple properties at once, call `Ember.getProperties` + * with an object followed by a list of strings or an array: + */ + function getProperties( + obj: ComputedPropertyGetters, + list: K[] + ): Pick; + function getProperties(obj: T, list: K[]): Pick; // for dynamic K + function getProperties( + obj: ComputedPropertyGetters, + ...list: K[] + ): Pick; + function getProperties(obj: T, ...list: K[]): Pick; // for dynamic K + /** + * A value is blank if it is empty or a whitespace string. + */ + function isBlank(obj: any): boolean; + /** + * Verifies that a value is `null` or an empty string, empty array, + * or empty function. + */ + function isEmpty(obj: any): boolean; + /** + * Returns true if the passed value is null or undefined. This avoids errors + * from JSLint complaining about use of ==, which can be technically + * confusing. + */ + function isNone(obj: any): obj is null | undefined; + /** + * A value is present if it not `isBlank`. + */ + function isPresent(obj: any): boolean; + /** + * Merge the contents of two objects together into the first object. + * @deprecated Use Object.assign + */ + function merge(original: T, updates: U): T & U; + /** + * Makes a method available via an additional name. + */ + function aliasMethod(methodName: string): ComputedProperty; + /** + * Specify a method that observes property changes. + */ + function observer(key1: string, func: (target: any, key: string) => void): void; + function observer( + key1: string, + key2: string, + func: (target: any, key: string) => void + ): void; + function observer( + key1: string, + key2: string, + key3: string, + func: (target: any, key: string) => void + ): void; + function observer( + key1: string, + key2: string, + key3: string, + key4: string, + func: (target: any, key: string) => void + ): void; + function observer( + key1: string, + key2: string, + key3: string, + key4: string, + key5: string, + func: (target: any, key: string) => void + ): void; + /** + * Adds an observer on a property. + */ + function addObserver( + obj: Context, + key: keyof Context, + target: Target, + method: ObserverMethod + ): void; + function addObserver( + obj: Context, + key: keyof Context, + method: ObserverMethod + ): void; + /** + * Remove an observer you have previously registered on this object. Pass + * the same key, target, and method you passed to `addObserver()` and your + * target will no longer receive notifications. + */ + function removeObserver( + obj: Context, + key: keyof Context, + target: Target, + method: ObserverMethod + ): any; + function removeObserver( + obj: Context, + key: keyof Context, + method: ObserverMethod + ): any; + /** + * Gets the value of a property on an object. If the property is computed, + * the function will be invoked. If the property is not defined but the + * object implements the `unknownProperty` method then that will be invoked. + */ + function get(obj: ComputedPropertyGetters, key: K): T[K]; + function get(obj: T, key: K): T[K]; // for dynamic K + /** + * Retrieves the value of a property from an Object, or a default value in the + * case that the property returns `undefined`. + */ + function getWithDefault( + obj: ComputedPropertyGetters, + key: K, + defaultValue: T[K] + ): T[K]; + function getWithDefault(obj: T, key: K, defaultValue: T[K]): T[K]; // for dynamic K + /** + * Sets the value of a property on an object, respecting computed properties + * and notifying observers and other listeners of the change. If the + * property is not defined but the object implements the `setUnknownProperty` + * method then that will be invoked as well. + */ + function set( + obj: ComputedPropertySetters, + key: K, + value: V + ): V; + function set(obj: T, key: K, value: V): V; // for dynamic K + /** + * Error-tolerant form of `Ember.set`. Will not blow up if any part of the + * chain is `undefined`, `null`, or destroyed. + */ + function trySet(root: object, path: string, value: any): any; + /** + * Set a list of properties on an object. These properties are set inside + * a single `beginPropertyChanges` and `endPropertyChanges` batch, so + * observers will be buffered. + */ + function setProperties( + obj: ComputedPropertySetters, + hash: Pick + ): Pick; + function setProperties(obj: T, hash: Pick): Pick; // for dynamic K + /** + * Detects when a specific package of Ember (e.g. 'Ember.Application') + * has fully loaded and is available for extension. + */ + function onLoad(name: string, callback: Function): any; + /** + * Called when an Ember.js package (e.g Ember.Application) has finished + * loading. Triggers any callbacks registered for this event. + */ + function runLoadHooks(name: string, object?: {}): any; + /** + * Creates an `Ember.NativeArray` from an Array like object. + * Does not modify the original object's contents. Ember.A is not needed if + * `EmberENV.EXTEND_PROTOTYPES` is `true` (the default value). However, + * it is recommended that you use Ember.A when creating addons for + * ember or when you can not guarantee that `EmberENV.EXTEND_PROTOTYPES` + * will be `true`. + */ + function A(arr?: T[]): NativeArray; + /** + * Compares two javascript values and returns: + */ + function compare(v: any, w: any): number; + /** + * Creates a shallow copy of the passed object. A deep copy of the object is + * returned if the optional `deep` argument is `true`. + */ + function copy(obj: any, deep?: boolean): any; + /** + * Compares two objects, returning true if they are equal. + */ + function isEqual(a: any, b: any): boolean; + /** + * Returns true if the passed object is an array or Array-like. + */ + function isArray(obj: any): obj is ArrayLike; + /** + * Returns a consistent type for the passed object. + */ + function typeOf(item: any): string; + /** + * Copy properties from a source object to a target object. + * @deprecated Use Object.assign + */ + function assign(target: T, source: U): T & U; + function assign(target: T, source1: U, source2: V): T & U & V; + function assign(target: T, source1: U, source2: V, source3: W): T & U & V & W; + /** + * Polyfill for Object.create + * @deprecated Use Object.create + */ + function create(o: object | null): any; + /** + * Polyfill for Object.keys + * @deprecated Use Object.keys + */ + function keys(o: any): string[]; + /** + * Returns a unique id for the object. If the object does not yet have a guid, + * one will be assigned to it. You can call this on any object, + * `Ember.Object`-based or not, but be aware that it will add a `_guid` + * property. + */ + function guidFor(obj: any): string; + /** + * Convenience method to inspect an object. This method will attempt to + * convert the object into a useful string description. + */ + function inspect(obj: any): string; + /** + * Checks to see if the `methodName` exists on the `obj`, + * and if it does, invokes it with the arguments passed. + */ + function tryInvoke(obj: any, methodName: string, args?: any[]): any; + /** + * Forces the passed object to be part of an array. If the object is already + * an array, it will return the object. Otherwise, it will add the object to + * an array. If obj is `null` or `undefined`, it will return an empty array. + */ + function makeArray(obj?: T[] | T | null): T[]; + /** + * Framework objects in an Ember application (components, services, routes, etc.) + * are created via a factory and dependency injection system. Each of these + * objects is the responsibility of an "owner", which handled its + * instantiation and manages its lifetime. + */ + function getOwner(object: any): any; + /** + * `setOwner` forces a new owner on a given object instance. This is primarily + * useful in some testing cases. + */ + function setOwner(object: any, owner: any): void; + /** + * A function may be assigned to `Ember.onerror` to be called when Ember + * internals encounter an error. This is useful for specialized error handling + * and reporting code. + */ + function onerror(error: Error): void; + /** + * An empty function useful for some operations. Always returns `this`. + * @deprecated https://emberjs.com/deprecations/v2.x/#toc_code-ember-k-code + */ + function K(this: This): This; + /** + * The semantic version + */ + const VERSION: string; + /** + * Alias for jQuery + */ + const $: JQueryStatic; + /** + * This property indicates whether or not this application is currently in + * testing mode. This is set when `setupForTesting` is called on the current + * application. + */ + const testing: boolean; + + const instrument: typeof Instrumentation.instrument; + + const reset: typeof Instrumentation.reset; + + const subscribe: typeof Instrumentation.subscribe; + + const unsubscribe: typeof Instrumentation.unsubscribe; + /** + * Expands `pattern`, invoking `callback` for each expansion. + */ + function expandProperties(pattern: string, callback: (expanded: string) => void): void; + } + + type RouteModel = object | string | number; + // https://emberjs.com/api/ember/2.18/classes/RouterService + /** + * The Router service is the public API that provides component/view layer access to the router. + */ + export class RouterService extends Ember.Service { + // + /** + Name of the current route. + This property represent the logical name of the route, + which is comma separated. + For the following router: + ```app/router.js + Router.map(function() { + this.route('about'); + this.route('blog', function () { + this.route('post', { path: ':post_id' }); + }); + }); + ``` + It will return: + * `index` when you visit `/` + * `about` when you visit `/about` + * `blog.index` when you visit `/blog` + * `blog.post` when you visit `/blog/some-post-id` + */ + readonly currentRouteName: string; + // + /** + Current URL for the application. + This property represent the URL path for this route. + For the following router: + ```app/router.js + Router.map(function() { + this.route('about'); + this.route('blog', function () { + this.route('post', { path: ':post_id' }); + }); + }); + ``` + It will return: + * `/` when you visit `/` + * `/about` when you visit `/about` + * `/blog` when you visit `/blog` + * `/blog/some-post-id` when you visit `/blog/some-post-id` + */ + readonly currentURL: string; + // + /** + * Determines whether a route is active. + * + * @param routeName the name of the route + * @param models the model(s) or identifier(s) to be used while + * transitioning to the route + * @param options optional hash with a queryParams property containing a + * mapping of query parameters + */ + isActive(routeName: string, options?: { queryParams: object }): boolean; + isActive(routeName: string, models: RouteModel, options?: { queryParams: object }): boolean; + isActive(routeName: string, modelsA: RouteModel, modelsB: RouteModel, options?: { queryParams: object }): boolean; + isActive(routeName: string, modelsA: RouteModel, modelsB: RouteModel, modelsC: RouteModel, options?: { queryParams: object }): boolean; + isActive(routeName: string, modelsA: RouteModel, modelsB: RouteModel, modelsC: RouteModel, modelsD: RouteModel, options?: { queryParams: object }): boolean; + + // https://emberjs.com/api/ember/2.18/classes/RouterService/methods/isActive?anchor=replaceWith + /** + * Transition into another route while replacing the current URL, if + * possible. The route may be either a single route or route path. + * + * @param routeNameOrUrl the name of the route or a URL + * @param models the model(s) or identifier(s) to be used while + * transitioning to the route. + * @param options optional hash with a queryParams property + * containing a mapping of query parameters + * @returns the Transition object associated with this attempted transition + */ + replaceWith(routeNameOrUrl: string, options?: { queryParams: object }): Ember.Transition; + replaceWith(routeNameOrUrl: string, models: RouteModel, options?: { queryParams: object }): Ember.Transition; + replaceWith(routeNameOrUrl: string, modelsA: RouteModel, modelsB: RouteModel, options?: { queryParams: object }): Ember.Transition; + replaceWith(routeNameOrUrl: string, modelsA: RouteModel, modelsB: RouteModel, modelsC: RouteModel, options?: { queryParams: object }): Ember.Transition; + replaceWith(routeNameOrUrl: string, modelsA: RouteModel, modelsB: RouteModel, modelsC: RouteModel, modelsD: RouteModel, options?: { queryParams: object }): Ember.Transition; + + // https://emberjs.com/api/ember/2.18/classes/RouterService/methods/isActive?anchor=transitionTo + /** + * Transition the application into another route. The route may be + * either a single route or route path + * + * @param routeNameOrUrl the name of the route or a URL + * @param models the model(s) or identifier(s) to be used while + * transitioning to the route. + * @param options optional hash with a queryParams property + * containing a mapping of query parameters + * @returns the Transition object associated with this attempted transition + */ + transitionTo(routeNameOrUrl: string, options?: { queryParam: object }): Ember.Transition; + transitionTo(routeNameOrUrl: string, models: RouteModel, options?: { queryParams: object }): Ember.Transition; + transitionTo(routeNameOrUrl: string, modelsA: RouteModel, modelsB: RouteModel, options?: { queryParams: object }): Ember.Transition; + transitionTo(routeNameOrUrl: string, modelsA: RouteModel, modelsB: RouteModel, modelsC: RouteModel, options?: { queryParams: object }): Ember.Transition; + transitionTo(routeNameOrUrl: string, modelsA: RouteModel, modelsB: RouteModel, modelsC: RouteModel, modelsD: RouteModel, options?: { queryParams: object }): Ember.Transition; + + // https://emberjs.com/api/ember/2.18/classes/RouterService/methods/isActive?anchor=urlFor + /** + * Generate a URL based on the supplied route name. + * + * @param routeName the name of the route or a URL + * @param models the model(s) or identifier(s) to be used while + * transitioning to the route. + * @param options optional hash with a queryParams property containing + * a mapping of query parameters + * @returns the string representing the generated URL + */ + urlFor(routeName: string, options?: { queryParams: object }): string; + urlFor(routeName: string, models: RouteModel, options?: { queryParams: object }): string; + urlFor(routeName: string, modelsA: RouteModel, modelsB: RouteModel, options?: { queryParams: object }): string; + urlFor(routeName: string, modelsA: RouteModel, modelsB: RouteModel, modelsC: RouteModel, options?: { queryParams: object }): string; + urlFor(routeName: string, modelsA: RouteModel, modelsB: RouteModel, modelsC: RouteModel, modelsD: RouteModel, options?: { queryParams: object }): string; + } + + module '@ember/service' { + interface Registry { + 'router': RouterService; + } + } + + export default Ember; +} + +declare module '@ember/application' { + import Ember from 'ember'; + export default class Application extends Ember.Application { } + export const getOwner: typeof Ember.getOwner; + export const onLoad: typeof Ember.onLoad; + export const runLoadHooks: typeof Ember.runLoadHooks; + export const setOwner: typeof Ember.setOwner; +} + +declare module '@ember/application/deprecations' { + import Ember from 'ember'; + export const deprecate: typeof Ember.deprecate; + export const deprecateFunc: typeof Ember.deprecateFunc; +} + +declare module '@ember/application/globals-resolver' { + import Ember from 'ember'; + export default class GlobalsResolver extends Ember.DefaultResolver { } +} + +declare module '@ember/application/instance' { + import Ember from 'ember'; + export default class ApplicationInstance extends Ember.ApplicationInstance { } +} + +declare module '@ember/application/resolver' { + import Ember from 'ember'; + export default class Resolver extends Ember.Resolver { } +} + +declare module '@ember/array' { + import Ember from 'ember'; + type EmberArray = Ember.Array; + const EmberArray: typeof Ember.Array; + export default EmberArray; + export const A: typeof Ember.A; + export const isArray: typeof Ember.isArray; + export const makeArray: typeof Ember.makeArray; +} + +declare module '@ember/array/mutable' { + import Ember from 'ember'; + type MutableArray = Ember.MutableArray; + const MutableArray: typeof Ember.MutableArray; + export default MutableArray; +} + +declare module '@ember/array/proxy' { + import Ember from 'ember'; + export default class ArrayProxy extends Ember.ArrayProxy { } +} + +declare module '@ember/component' { + import Ember from 'ember'; + export default class Component extends Ember.Component { } +} + +declare module '@ember/component/checkbox' { + import Ember from 'ember'; + export default class Checkbox extends Ember.Checkbox { } +} + +declare module '@ember/component/helper' { + import Ember from 'ember'; + export default class Helper extends Ember.Helper { } + /** + * In many cases, the ceremony of a full `Helper` class is not required. + * The `helper` method create pure-function helpers without instances. For + * example: + * ```app/helpers/format-currency.js + * import { helper } from '@ember/component/helper'; + * export default helper(function(params, hash) { + * let cents = params[0]; + * let currency = hash.currency; + * return `${currency}${cents * 0.01}`; + * }); + * ``` + */ + export function helper(helperFn: (params: any[], hash?: any) => any): any; +} + +declare module '@ember/component/text-area' { + import Ember from 'ember'; + export default class TextArea extends Ember.TextArea { } +} + +declare module '@ember/component/text-field' { + import Ember from 'ember'; + export default class TextField extends Ember.TextField { } +} + +declare module '@ember/controller' { + import Ember from 'ember'; + export default class Controller extends Ember.Controller { } + export const inject: typeof Ember.inject.controller; + + // A type registry for Ember `Controller`s. Meant to be declaration-merged + // so string lookups resolve to the correct type. + export interface Registry {} +} + +declare module '@ember/debug' { + import Ember from 'ember'; + export const assert: typeof Ember.assert; + export const debug: typeof Ember.debug; + export const inspect: typeof Ember.inspect; + export const registerDeprecationHandler: typeof Ember.Debug.registerDeprecationHandler; + export const registerWarnHandler: typeof Ember.Debug.registerWarnHandler; + export const runInDebug: typeof Ember.runInDebug; + export const warn: typeof Ember.warn; +} + +declare module '@ember/debug/container-debug-adapter' { + import Ember from 'ember'; + export default class ContainerDebugAdapter extends Ember.ContainerDebugAdapter { } +} + +declare module '@ember/debug/data-adapter' { + import Ember from 'ember'; + export default class DataAdapter extends Ember.DataAdapter { } +} + +declare module '@ember/engine' { + import Ember from 'ember'; + export default class Engine extends Ember.Engine { } + export const getEngineParent: typeof Ember.getEngineParent; +} + +declare module '@ember/engine/instance' { + import Ember from 'ember'; + export default class EngineInstance extends Ember.EngineInstance { } +} + +declare module '@ember/enumerable' { + import Ember from 'ember'; + type Enumerable = Ember.Enumerable; + const Enumerable: typeof Ember.Enumerable; + export default Enumerable; +} + +declare module '@ember/error' { + import Ember from 'ember'; + const Error: typeof Ember.Error; + export default Error; +} + +declare module '@ember/instrumentation' { + import Ember from 'ember'; + export const instrument: typeof Ember.instrument; + export const reset: typeof Ember.reset; + export const subscribe: typeof Ember.subscribe; + export const unsubscribe: typeof Ember.unsubscribe; +} + +declare module '@ember/map' { + import Ember from 'ember'; + export default class EmberMap extends Ember.Map { } +} + +declare module '@ember/map/with-default' { + import Ember from 'ember'; + export default class MapWithDefault extends Ember.MapWithDefault { } +} + +declare module '@ember/object' { + import Ember from 'ember'; + export default class EmberObject extends Ember.Object { } + export const aliasMethod: typeof Ember.aliasMethod; + export const computed: typeof Ember.computed; + export const defineProperty: typeof Ember.defineProperty; + export const get: typeof Ember.get; + export const getProperties: typeof Ember.getProperties; + export const getWithDefault: typeof Ember.getWithDefault; + export const observer: typeof Ember.observer; + export const set: typeof Ember.set; + export const setProperties: typeof Ember.setProperties; + export const trySet: typeof Ember.trySet; +} + +declare module '@ember/object/computed' { + import Ember from 'ember'; + export default class ComputedProperty extends Ember.ComputedProperty { } + export const alias: typeof Ember.computed.alias; + export const and: typeof Ember.computed.and; + export const bool: typeof Ember.computed.bool; + export const collect: typeof Ember.computed.collect; + export const deprecatingAlias: typeof Ember.computed.deprecatingAlias; + export const empty: typeof Ember.computed.empty; + export const equal: typeof Ember.computed.equal; + export const expandProperties: typeof Ember.expandProperties; + export const filter: typeof Ember.computed.filter; + export const filterBy: typeof Ember.computed.filterBy; + export const gt: typeof Ember.computed.gt; + export const gte: typeof Ember.computed.gte; + export const intersect: typeof Ember.computed.intersect; + export const lt: typeof Ember.computed.lt; + export const lte: typeof Ember.computed.lte; + export const map: typeof Ember.computed.map; + export const mapBy: typeof Ember.computed.mapBy; + export const match: typeof Ember.computed.match; + export const max: typeof Ember.computed.max; + export const min: typeof Ember.computed.min; + export const none: typeof Ember.computed.none; + export const not: typeof Ember.computed.not; + export const notEmpty: typeof Ember.computed.notEmpty; + export const oneWay: typeof Ember.computed.oneWay; + export const or: typeof Ember.computed.or; + export const readOnly: typeof Ember.computed.readOnly; + export const reads: typeof Ember.computed.reads; + export const setDiff: typeof Ember.computed.setDiff; + export const sort: typeof Ember.computed.sort; + export const sum: typeof Ember.computed.sum; + export const union: typeof Ember.computed.union; + export const uniq: typeof Ember.computed.uniq; + export const uniqBy: typeof Ember.computed.uniqBy; +} + +declare module '@ember/object/core' { + import Ember from 'ember'; + export default class CoreObject extends Ember.CoreObject { } +} + +declare module '@ember/object/evented' { + import Ember from 'ember'; + type Evented = Ember.Evented; + const Evented: typeof Ember.Evented; + export default Evented; + export const on: typeof Ember.on; +} + +declare module '@ember/object/events' { + import Ember from 'ember'; + export const addListener: typeof Ember.addListener; + export const removeListener: typeof Ember.removeListener; + export const sendEvent: typeof Ember.sendEvent; +} + +declare module '@ember/object/internals' { + import Ember from 'ember'; + export const cacheFor: typeof Ember.cacheFor; + export const copy: typeof Ember.copy; + export const guidFor: typeof Ember.guidFor; +} + +declare module '@ember/object/mixin' { + import Ember from 'ember'; + export default class Mixin extends Ember.Mixin {} +} + +declare module '@ember/object/observable' { + import Ember from 'ember'; + type Observable = Ember.Observable; + const Observable: typeof Ember.Observable; + export default Observable; +} + +declare module '@ember/object/observers' { + import Ember from 'ember'; + export const addObserver: typeof Ember.addObserver; + export const removeObserver: typeof Ember.removeObserver; +} + +declare module '@ember/object/promise-proxy-mixin' { + import Ember from 'ember'; + type PromiseProxyMixin = Ember.PromiseProxyMixin; + const PromiseProxyMixin: typeof Ember.PromiseProxyMixin; + export default PromiseProxyMixin; +} + +declare module '@ember/object/proxy' { + import Ember from 'ember'; + export default class ObjectProxy extends Ember.ObjectProxy { } +} + +declare module '@ember/polyfills' { + import Ember from 'ember'; + export const assign: typeof Ember.assign; + export const create: typeof Ember.create; + export const hasPropertyAccessors: typeof Ember.platform.hasPropertyAccessors; + export const keys: typeof Ember.keys; + export const merge: typeof Ember.merge; +} + +declare module '@ember/routing/auto-location' { + import Ember from 'ember'; + export default class AutoLocation extends Ember.AutoLocation { } +} + +declare module '@ember/routing/hash-location' { + import Ember from 'ember'; + export default class HashLocation extends Ember.HashLocation { } +} + +declare module '@ember/routing/history-location' { + import Ember from 'ember'; + export default class HistoryLocation extends Ember.HistoryLocation { } +} + +declare module '@ember/routing/link-component' { + import Ember from 'ember'; + export default class LinkComponent extends Ember.LinkComponent { } +} + +declare module '@ember/routing/location' { + import Ember from 'ember'; + const Location: typeof Ember.Location; + export default Location; +} + +declare module '@ember/routing/none-location' { + import Ember from 'ember'; + export default class NoneLocation extends Ember.NoneLocation { } +} + +declare module '@ember/routing/route' { + import Ember from 'ember'; + export default class Route extends Ember.Route { } +} + +declare module '@ember/routing/router' { + import Ember from 'ember'; + export default class EmberRouter extends Ember.Router { } +} + +declare module '@ember/routing/router-service' { + import { RouterService } from 'ember'; + export default class extends RouterService { } +} + +declare module '@ember/runloop' { + import Ember from 'ember'; + export const begin: typeof Ember.run.begin; + export const bind: typeof Ember.run.bind; + export const cancel: typeof Ember.run.cancel; + export const debounce: typeof Ember.run.debounce; + export const end: typeof Ember.run.end; + export const join: typeof Ember.run.join; + export const later: typeof Ember.run.later; + export const next: typeof Ember.run.next; + export const once: typeof Ember.run.once; + export const run: typeof Ember.run; + export const schedule: typeof Ember.run.schedule; + export const scheduleOnce: typeof Ember.run.scheduleOnce; + export const throttle: typeof Ember.run.throttle; +} + +declare module '@ember/service' { + import Ember from 'ember'; + export default class Service extends Ember.Service { } + export const inject: typeof Ember.inject.service; + + // A type registry for Ember `Service`s. Meant to be declaration-merged so + // string lookups resolve to the correct type. + interface Registry {} +} + +declare module '@ember/string' { + import Ember from 'ember'; + export const camelize: typeof Ember.String.camelize; + export const capitalize: typeof Ember.String.capitalize; + export const classify: typeof Ember.String.classify; + export const dasherize: typeof Ember.String.dasherize; + export const decamelize: typeof Ember.String.decamelize; + export const fmt: typeof Ember.String.fmt; + export const htmlSafe: typeof Ember.String.htmlSafe; + export const isHTMLSafe: typeof Ember.String.isHTMLSafe; + export const loc: typeof Ember.String.loc; + export const underscore: typeof Ember.String.underscore; + export const w: typeof Ember.String.w; +} + +declare module '@ember/test' { + import Ember from 'ember'; + export const registerAsyncHelper: typeof Ember.Test.registerAsyncHelper; + export const registerHelper: typeof Ember.Test.registerHelper; + export const registerWaiter: typeof Ember.Test.registerWaiter; + export const unregisterHelper: typeof Ember.Test.unregisterHelper; + export const unregisterWaiter: typeof Ember.Test.unregisterWaiter; +} + +declare module '@ember/test/adapter' { + import Ember from 'ember'; + export default class TestAdapter extends Ember.Test.Adapter { } +} + +declare module '@ember/utils' { + import Ember from 'ember'; + export const compare: typeof Ember.compare; + export const isBlank: typeof Ember.isBlank; + export const isEmpty: typeof Ember.isEmpty; + export const isEqual: typeof Ember.isEqual; + export const isNone: typeof Ember.isNone; + export const isPresent: typeof Ember.isPresent; + export const tryInvoke: typeof Ember.tryInvoke; + export const typeOf: typeof Ember.typeOf; +} + +declare module 'htmlbars-inline-precompile' { + interface TemplateFactory { + __htmlbars_inline_precompile_template_factory: any; + } + export default function hbs(tagged: TemplateStringsArray): TemplateFactory; +} diff --git a/types/ember/v2/test/application-instance.ts b/types/ember/v2/test/application-instance.ts new file mode 100644 index 0000000000..9ae22e5f26 --- /dev/null +++ b/types/ember/v2/test/application-instance.ts @@ -0,0 +1,29 @@ +import ApplicationInstance from '@ember/application/instance'; +import hbs from 'htmlbars-inline-precompile'; + +const appInstance = ApplicationInstance.create(); +appInstance.register('some:injection', class Foo {}); + +appInstance.register('some:injection', class Foo {}, { + singleton: true, +}); + +appInstance.register('some:injection', class Foo {}, { + instantiate: false, +}); + +appInstance.register('templates:foo/bar', hbs`

Hello World

`); + +appInstance.register('some:injection', class Foo {}, { + singleton: false, + instantiate: true, +}); + +appInstance.factoryFor('router:main'); +appInstance.lookup('route:basic'); + +appInstance.boot(); + +(async function() { + await appInstance.boot(); +}()); diff --git a/types/ember/v2/test/application.ts b/types/ember/v2/test/application.ts new file mode 100755 index 0000000000..d0fc2e9c44 --- /dev/null +++ b/types/ember/v2/test/application.ts @@ -0,0 +1,35 @@ +import Ember from 'ember'; +import { assertType } from "./lib/assert"; + +let BaseApp = Ember.Application.extend({ + modulePrefix: 'my-app' +}); + +BaseApp.initializer({ + name: 'my-initializer', + initialize(app) { + app.register('foo:bar', Ember.Object.extend({ foo: 'bar' })); + } +}); + +BaseApp.instanceInitializer({ + name: 'my-instance-initializer', + initialize(app) { + app.lookup('foo:bar').get('foo'); + } +}); + +let App1 = BaseApp.create({ + rootElement: '#app-one', + customEvents: { + paste: 'paste' + } +}); + +let App2 = BaseApp.create({ + rootElement: '#app-two', + customEvents: { + mouseenter: null, + mouseleave: null + } +}); diff --git a/types/ember/v2/test/array-ext.ts b/types/ember/v2/test/array-ext.ts new file mode 100755 index 0000000000..059d60c00c --- /dev/null +++ b/types/ember/v2/test/array-ext.ts @@ -0,0 +1,21 @@ +import Ember from 'ember'; +import { assertType } from './lib/assert'; + +declare global { + interface Array extends Ember.ArrayPrototypeExtensions {} +} + +class Person extends Ember.Object { + name: string; +} + +const person = Person.create({ name: 'Joe' }); +const array = [person]; + +assertType(array.get('length')); +assertType(array.get('firstObject')); +assertType(array.mapBy('name')); +assertType(array.map(p => p.get('name'))); +assertType(array.sortBy('name')); +assertType(array.uniq()); +assertType(array.uniqBy('name')); diff --git a/types/ember/v2/test/array-proxy.ts b/types/ember/v2/test/array-proxy.ts new file mode 100644 index 0000000000..dceea7b847 --- /dev/null +++ b/types/ember/v2/test/array-proxy.ts @@ -0,0 +1,26 @@ +import Ember from 'ember'; +import { assertType } from './lib/assert'; + +const pets = ['dog', 'cat', 'fish']; +const proxy = Ember.ArrayProxy.create({ content: Ember.A(pets) }); + +proxy.get('firstObject'); // 'dog' +proxy.set('content', Ember.A(['amoeba', 'paramecium'])); +proxy.get('firstObject'); // 'amoeba' + +const overridden = Ember.ArrayProxy.create({ + content: Ember.A(pets), + objectAtContent(idx: number): string { + return this.get('content').objectAt(idx)!.toUpperCase(); + } +}); + +overridden.get('firstObject'); // 'DOG' + +class MyNewProxy extends Ember.ArrayProxy { + isNew = true; +} + +let x = MyNewProxy.create({ content: Ember.A([1, 2, 3]) }) as MyNewProxy; +assertType(x.get('firstObject')); +assertType(x.isNew); diff --git a/types/ember/v2/test/array.ts b/types/ember/v2/test/array.ts new file mode 100755 index 0000000000..8416a4a9ec --- /dev/null +++ b/types/ember/v2/test/array.ts @@ -0,0 +1,48 @@ +import Ember from 'ember'; +import { assertType } from './lib/assert'; + +type Person = typeof Person.prototype; +const Person = Ember.Object.extend({ + name: '', + isHappy: false +}); + +const people = Ember.A([ + Person.create({ name: 'Yehuda', isHappy: true }), + Person.create({ name: 'Majd', isHappy: false }), +]); + +assertType(people.get('length')); +assertType(people.get('lastObject')); +assertType(people.isAny('isHappy')); +assertType(people.isAny('isHappy', 'false')); +assertType>(people.filterBy('isHappy')); +assertType>(people.rejectBy('isHappy')); +assertType>(people.filter((person) => person.get('name') === 'Yehuda')); +assertType(people.get('[]')); +assertType(people.get('[]').get('firstObject')); + +assertType>(people.mapBy('isHappy')); +assertType(people.mapBy('name.length')); + +const last = people.get('lastObject'); +if (last) { + assertType(last.get('name')); +} + +const first = people.get('lastObject'); +if (first) { + assertType(first.get('isHappy')); +} + +const letters: Ember.Enumerable = Ember.A(['a', 'b', 'c']); +const codes: number[] = letters.map((item, index, enumerable) => { + assertType(item); + assertType(index); + return item.charCodeAt(0); +}); + +let value = '1,2,3'; +let filters = Ember.A(value.split(',')); +filters.push('4'); +filters.sort(); diff --git a/types/ember/v2/test/component.ts b/types/ember/v2/test/component.ts new file mode 100755 index 0000000000..bcc314300d --- /dev/null +++ b/types/ember/v2/test/component.ts @@ -0,0 +1,124 @@ +import Ember from 'ember'; +import Component from '@ember/component'; +import Object, { computed } from '@ember/object'; +import hbs from 'htmlbars-inline-precompile'; +import { assertType } from "./lib/assert"; + +Component.extend({ + layout: hbs` +
+ {{yield}} +
+ `, +}); + +Component.extend({ + layout: 'my-layout', +}); + +const MyComponent = Component.extend(); +assertType(Ember.get(MyComponent, 'positionalParams')); + +const component1 = Component.extend({ + actions: { + hello(name: string) { + console.log('Hello', name); + }, + }, +}); + +Component.extend({ + name: '', + hello(name: string) { + this.set('name', name); + }, +}); + +Component.extend({ + tagName: 'em', +}); + +Component.extend({ + classNames: ['my-class', 'my-other-class'], +}); + +Component.extend({ + classNameBindings: ['propertyA', 'propertyB'], + propertyA: 'from-a', + propertyB: computed(function() { + if (!this.get('propertyA')) { + return 'from-b'; + } + }), +}); + +Component.extend({ + classNameBindings: ['hovered'], + hovered: true, +}); + +Component.extend({ + classNameBindings: ['messages.empty'], + messages: Object.create({ + empty: true, + }), +}); + +Component.extend({ + classNameBindings: ['isEnabled:enabled:disabled'], + isEnabled: true, +}); + +Component.extend({ + classNameBindings: ['isEnabled::disabled'], + isEnabled: true, +}); + +Component.extend({ + tagName: 'a', + attributeBindings: ['href'], + href: 'http://google.com', +}); + +Component.extend({ + tagName: 'a', + attributeBindings: ['url:href'], + url: 'http://google.com', +}); + +Component.extend({ + tagName: 'use', + attributeBindings: ['xlinkHref:xlink:href'], + xlinkHref: '#triangle', +}); + +Component.extend({ + tagName: 'input', + attributeBindings: ['disabled'], + disabled: false, +}); + +Component.extend({ + tagName: 'input', + attributeBindings: ['disabled'], + disabled: computed(() => { + if ('someLogic') { + return true; + } else { + return false; + } + }), +}); + +Component.extend({ + tagName: 'form', + attributeBindings: ['novalidate'], + novalidate: null, +}); + +Component.extend({ + click(event: object) { + // will be called when an instance's + // rendered element is clicked + }, +}); diff --git a/types/ember/v2/test/computed.ts b/types/ember/v2/test/computed.ts new file mode 100755 index 0000000000..f93b07a0f5 --- /dev/null +++ b/types/ember/v2/test/computed.ts @@ -0,0 +1,166 @@ +import Ember from 'ember'; +import Component from '@ember/component'; +import Computed, { alias, or } from '@ember/object/computed'; +import { assertType } from './lib/assert'; + +const Person = Ember.Object.extend({ + firstName: '', + lastName: '', + age: 0, + + noArgs: Ember.computed(() => 'test'), + + fullName: Ember.computed('firstName', 'lastName', function() { + return `${this.get('firstName')} ${this.get('lastName')}`; + }), + + fullNameReadonly: Ember.computed('fullName', function() { + return this.get('fullName'); + }).readOnly(), + + fullNameWritable: Ember.computed('firstName', 'lastName', { + get() { + return this.get('fullName'); + }, + set(key, value) { + let [first, last] = value.split(' '); + this.set('firstName', first); + this.set('lastName', last); + return value; + } + }), + + fullNameGetOnly: Ember.computed('fullName', { + get() { + return this.get('fullName'); + } + }), + + fullNameSetOnly: Ember.computed('firstName', 'lastName', { + set(key, value) { + let [first, last] = value.split(' '); + this.set('firstName', first); + this.set('lastName', last); + return value; + } + }), + + combinators: Ember.computed(function() { + return this.get('firstName'); + }).property('firstName') + .meta({ foo: 'bar' }) + .volatile() + .readOnly(), + + explicitlyDeclared: alias('fullName') as Computed, +}); + +const person = Person.create({ + firstName: 'Fred', + lastName: 'Smith', + age: 29, +}); + +assertType(person.firstName); +assertType(person.age); +assertType>(person.noArgs); +assertType>(person.fullName); +assertType>(person.fullNameReadonly); +assertType>(person.fullNameWritable); +assertType>(person.fullNameGetOnly); +assertType>(person.fullNameSetOnly); +assertType>(person.combinators); +assertType>(person.explicitlyDeclared); + +assertType(person.get('firstName')); +assertType(person.get('age')); +assertType(person.get('noArgs')); +assertType(person.get('fullName')); +assertType(person.get('fullNameReadonly')); +assertType(person.get('fullNameWritable')); +assertType(person.get('fullNameGetOnly')); +assertType(person.get('fullNameSetOnly')); +assertType(person.get('combinators')); +assertType(person.get('explicitlyDeclared')); + +assertType<{ firstName: string, fullName: string, age: number }>(person.getProperties('firstName', 'fullName', 'age')); + +const person2 = Person.create({ + fullName: 'Fred Smith' +}); + +assertType(person2.get('firstName')); +assertType(person2.get('fullName')); + +const person3 = Person.extend({ + firstName: 'Fred', + fullName: 'Fred Smith' +}).create(); + +assertType(person3.get('firstName')); +assertType(person3.get('fullName')); + +const person4 = Person.extend({ + firstName: Ember.computed(() => 'Fred'), + fullName: Ember.computed(() => 'Fred Smith') +}).create(); + +assertType(person4.get('firstName')); +assertType(person4.get('fullName')); + +// computed property macros +const objectWithComputedProperties = Ember.Object.extend({ + alias: Ember.computed.alias('foo'), + and: Ember.computed.and('foo', 'bar', 'baz', 'qux'), + bool: Ember.computed.bool('foo'), + collect: Ember.computed.collect('foo', 'bar', 'baz', 'qux'), + deprecatingAlias: Ember.computed.deprecatingAlias('foo', { + id: 'hamster.deprecate-banana', + until: '3.0.0' + }), + empty: Ember.computed.empty('foo'), + equalNumber: Ember.computed.equal('foo', 1), + equalString: Ember.computed.equal('foo', 'bar'), + equalObject: Ember.computed.equal('foo', {}), + filter: Ember.computed.filter('foo', (item) => item === 'bar'), + filterBy1: Ember.computed.filterBy('foo', 'bar'), + filterBy2: Ember.computed.filterBy('foo', 'bar', false), + gt: Ember.computed.gt('foo', 3), + gte: Ember.computed.gte('foo', 3), + intersect: Ember.computed.intersect('foo', 'bar', 'baz', 'qux'), + lt: Ember.computed.lt('foo', 3), + lte: Ember.computed.lte('foo', 3), + map: Ember.computed.map('foo', (item, index) => item.bar), + mapBy: Ember.computed.mapBy('foo', 'bar'), + match: Ember.computed.match('foo', /^tom.ter$/), + max: Ember.computed.max('foo'), + min: Ember.computed.min('foo'), + none: Ember.computed.none('foo'), + not: Ember.computed.not('foo'), + notEmpty: Ember.computed.notEmpty('foo'), + oneWay: Ember.computed.oneWay('foo'), + or: Ember.computed.or('foo', 'bar', 'baz', 'qux'), + readOnly: Ember.computed.readOnly('foo'), + reads: Ember.computed.reads('foo'), + setDiff: Ember.computed.setDiff('foo', 'bar'), + sort1: Ember.computed.sort('foo', 'bar'), + sort2: Ember.computed.sort('foo', (itemA, itemB) => { + if (itemA < itemB) { + return -1; + } else if (itemA > itemB) { + return 1; + } else { + return 0; + } + }), + sum: Ember.computed.sum('foo'), + union: Ember.computed.union('foo', 'bar', 'baz', 'qux'), + uniq: Ember.computed.uniq('foo'), + uniqBy: Ember.computed.uniqBy('foo', 'bar') +}); + +const component2 = Component.extend({ + isAnimal: or('isDog', 'isCat') +}).create(); + +assertType(component2.get('isAnimal')); diff --git a/types/ember/v2/test/controller.ts b/types/ember/v2/test/controller.ts new file mode 100755 index 0000000000..02307f447c --- /dev/null +++ b/types/ember/v2/test/controller.ts @@ -0,0 +1,11 @@ +import Controller from '@ember/controller'; + +Controller.extend ({ + queryParams: ['category'], + category: null, + isExpanded: false, + + toggleBody() { + this.toggleProperty('isExpanded'); + } +}); diff --git a/types/ember/v2/test/create.ts b/types/ember/v2/test/create.ts new file mode 100755 index 0000000000..6dc61b80f6 --- /dev/null +++ b/types/ember/v2/test/create.ts @@ -0,0 +1,7 @@ +import Ember from 'ember'; +import { assertType } from './lib/assert'; + +const obj = Ember.Object.create({ a: 1 }, { b: 2 }, { c: 3 }); +assertType(obj.a); +assertType(obj.b); +assertType(obj.c); diff --git a/types/ember/v2/test/detect-instance.ts b/types/ember/v2/test/detect-instance.ts new file mode 100755 index 0000000000..1b25beb244 --- /dev/null +++ b/types/ember/v2/test/detect-instance.ts @@ -0,0 +1,20 @@ +import Ember from 'ember'; +import { assertType } from './lib/assert'; + +const ExtendClass = Ember.Object.extend({ + foo: 'hello' +}); + +class ES6Class extends Ember.Object { + bar: string; +} + +let testObject = null; + +if (ExtendClass.detectInstance(testObject)) { + assertType(testObject.foo); +} + +if (ES6Class.detectInstance(testObject)) { + assertType(testObject.bar); +} diff --git a/types/ember/v2/test/detect.ts b/types/ember/v2/test/detect.ts new file mode 100755 index 0000000000..cd54880f9f --- /dev/null +++ b/types/ember/v2/test/detect.ts @@ -0,0 +1,20 @@ +import Ember from 'ember'; +import { assertType } from './lib/assert'; + +const ExtendClass = Ember.Object.extend({ + foo: 'hello' +}); + +class ES6Class extends Ember.Object { + bar: string; +} + +let TestClass = Ember.Object; + +if (ExtendClass.detect(TestClass)) { + assertType(TestClass.create().foo); +} + +if (ES6Class.detect(TestClass)) { + assertType(TestClass.create().bar); +} diff --git a/types/ember/v2/test/ember-tests.ts b/types/ember/v2/test/ember-tests.ts new file mode 100755 index 0000000000..c049512eb0 --- /dev/null +++ b/types/ember/v2/test/ember-tests.ts @@ -0,0 +1,170 @@ +import Ember from 'ember'; + +let App: any; + +App = Ember.Application.create(); +App.president = Ember.Object.create({ + name: 'Barack Obama', +}); +App.country = Ember.Object.create({ + presidentNameBinding: 'MyApp.president.name', +}); +App.country.get('presidentName'); +App.president = Ember.Object.create({ + firstName: 'Barack', + lastName: 'Obama', + fullName: Ember.computed(function() { + return `${this.get('firstName')} ${this.get('lastName')}`; + }), +}); +App.president.get('fullName'); + +declare class MyPerson extends Ember.Object { + static createMan(): MyPerson; +} +MyPerson.createMan(); + +const Person1 = Ember.Object.extend({ + say: (thing: string) => { + alert(thing); + }, +}); + +declare class MyPerson2 extends Ember.Object { + helloWorld(): void; +} +MyPerson2.create().helloWorld(); + +const tom = Person1.create({ + name: 'Tom Dale', + helloWorld() { + this.say('Hi my name is ' + this.get('name')); + }, +}); +tom.helloWorld(); + +const PersonReopened = Person1.reopen({ isPerson: true }); +PersonReopened.create().get('isPerson'); + +App.todosController = Ember.Object.create({ + todos: [Ember.Object.create({ isDone: false })], + remaining: Ember.computed('todos.@each.isDone', function() { + const todos = this.get('todos'); + return todos.filterProperty('isDone', false).get('length'); + }), +}); + +const todos = App.todosController.get('todos'); +let todo = todos.objectAt(0); +todo.set('isDone', true); +App.todosController.get('remaining'); +todo = Ember.Object.create({ isDone: false }); +todos.pushObject(todo); +App.todosController.get('remaining'); + +App.wife = Ember.Object.create({ + householdIncome: 80000, +}); +App.husband = Ember.Object.create({ + householdIncomeBinding: 'App.wife.householdIncome', +}); +App.husband.get('householdIncome'); +App.husband.set('householdIncome', 90000); +App.wife.get('householdIncome'); + +App.user = Ember.Object.create({ + fullName: 'Kara Gates', +}); +App.user.set('fullName', 'Krang Gates'); +App.userView.set('userName', 'Truckasaurus Gates'); +App.user.get('fullName'); + +App = Ember.Application.create({ + rootElement: '#sidebar', +}); + +App.userController = Ember.Object.create({ + content: Ember.Object.create({ + firstName: 'Albert', + lastName: 'Hofmann', + posts: 25, + hobbies: 'Riding bicycles', + }), +}); + +Handlebars.registerHelper( + 'highlight', + (property: string, options: any) => + new Handlebars.SafeString('' + 'some value' + '') +); + +const coolView = App.CoolView.create(); + +const Person2 = Ember.Object.extend({ + name: '', + sayHello() { + console.log('Hello from ' + this.get('name')); + }, +}); +const people = Ember.A([ + Person2.create({ name: 'Juan' }), + Person2.create({ name: 'Charles' }), + Person2.create({ name: 'Majd' }), +]); +people.invoke('sayHello'); + +const arr = Ember.A([Ember.Object.create(), Ember.Object.create()]); +arr.setEach('name', 'unknown'); +arr.getEach('name'); + +const Person3 = Ember.Object.extend({ + name: '', + isHappy: false, +}); +const people2 = Ember.A([ + Person3.create({ name: 'Yehuda', isHappy: true }), + Person3.create({ name: 'Majd', isHappy: false }), +]); +const isHappy = (person: typeof Person3.prototype): boolean => { + return !!person.get('isHappy'); +}; +people2.every(isHappy); +people2.any(isHappy); +people2.isEvery('isHappy'); +people2.isEvery('isHappy', true); +people2.isAny('isHappy', 'true'); +people2.isAny('isHappy'); + +// Examples taken from http://emberjs.com/api/classes/Em.RSVP.Promise.html +const promise = new Ember.RSVP.Promise((resolve: Function, reject: Function) => { + // on success + resolve('ok!'); + + // on failure + reject('no-k!'); +}); + +promise.then( + (value: any) => { + // on fulfillment + }, + (reason: any) => { + // on rejection + } +); + +// make sure Ember.RSVP.Promise can be reference as a type +declare function promiseReturningFunction(urn: string): Ember.RSVP.Promise; + +const mix1 = Ember.Mixin.create({ + foo: 1, +}); + +const mix2 = Ember.Mixin.create({ + bar: 2, +}); + +const component1 = Ember.Component.extend(mix1, mix2, { + lyft: Ember.inject.service(), + cars: Ember.computed.readOnly('lyft.cars'), +}); diff --git a/types/ember/v2/test/engine-instance.ts b/types/ember/v2/test/engine-instance.ts new file mode 100644 index 0000000000..c74914dea5 --- /dev/null +++ b/types/ember/v2/test/engine-instance.ts @@ -0,0 +1,26 @@ +import EngineInstance from '@ember/engine/instance'; + +const engineInstance = EngineInstance.create(); +engineInstance.register('some:injection', class Foo {}); + +engineInstance.register('some:injection', class Foo {}, { + singleton: true, +}); + +engineInstance.register('some:injection', class Foo {}, { + instantiate: false, +}); + +engineInstance.register('some:injection', class Foo {}, { + singleton: false, + instantiate: true, +}); + +engineInstance.factoryFor('router:main'); +engineInstance.lookup('route:basic'); + +engineInstance.boot(); + +(async function() { + await engineInstance.boot(); +}()); diff --git a/types/ember/v2/test/error.ts b/types/ember/v2/test/error.ts new file mode 100644 index 0000000000..ad3c2ee8c3 --- /dev/null +++ b/types/ember/v2/test/error.ts @@ -0,0 +1,6 @@ +import { assertType } from "./lib/assert"; + +import Ember from "ember"; +import EmberError from "@ember/error"; + +assertType(EmberError); diff --git a/types/ember/v2/test/event.ts b/types/ember/v2/test/event.ts new file mode 100755 index 0000000000..c934072440 --- /dev/null +++ b/types/ember/v2/test/event.ts @@ -0,0 +1,58 @@ +import Ember from 'ember'; + +function testOn() { + let Job = Ember.Object.extend({ + logCompleted: Ember.on('completed', function() { + console.log('Job completed!'); + }) + }); + + let job = Job.create(); + + Ember.sendEvent(job, 'completed'); // Logs 'Job completed!' +} + +function testEvented() { + let Person = Ember.Object.extend(Ember.Evented, { + greet() { + this.trigger('greet'); + } + }); + + let person = Person.create(); + + person.on('greet', function() { + console.log('Our person has greeted'); + }); + + person.on('greet', function() { + console.log('Our person has greeted'); + }).one('greet', function() { + console.log('Offer one-time special'); + }).off('event', {}, function() {}); + + person.greet(); +} + +function testObserver() { + Ember.Object.extend({ + valueObserver: Ember.observer('value', function() { + // Executes whenever the "value" property changes + }) + }); +} + +function testListener() { + Ember.Component.extend({ + init() { + Ember.addListener(this, 'willDestroyElement', this, 'willDestroyListener'); + Ember.addListener(this, 'willDestroyElement', this, 'willDestroyListener', true); + Ember.addListener(this, 'willDestroyElement', this, this.willDestroyListener); + Ember.addListener(this, 'willDestroyElement', this, this.willDestroyListener, true); + Ember.removeListener(this, 'willDestroyElement', this, 'willDestroyListener'); + Ember.removeListener(this, 'willDestroyElement', this, this.willDestroyListener); + }, + willDestroyListener() { + } + }); +} diff --git a/types/ember/v2/test/extend.ts b/types/ember/v2/test/extend.ts new file mode 100755 index 0000000000..a54f81a600 --- /dev/null +++ b/types/ember/v2/test/extend.ts @@ -0,0 +1,61 @@ +import Ember from 'ember'; +import { assertType } from './lib/assert'; + +const Person = Ember.Object.extend({ + firstName: '', + lastName: '', + + getFullName() { + return `${this.firstName} ${this.lastName}`; + }, + getFullName2(): string { + return `${this.get('firstName')} ${this.get('lastName')}`; + } +}); + +assertType(Person.prototype.firstName); +assertType<() => string>(Person.prototype.getFullName); + +const person = Person.create({ + firstName: 'Joe', + lastName: 'Blow', + extra: 42 +}); + +assertType(person.getFullName()); +assertType(person.extra); + +class ES6Person extends Ember.Object { + firstName: string; + lastName: string; + + get fullName() { + return `${this.firstName} ${this.lastName}`; + } + get fullName2(): string { + return `${this.get('firstName')} ${this.get('lastName')}`; + } +} + +assertType(ES6Person.prototype.firstName); +assertType(ES6Person.prototype.fullName); + +const es6Person = ES6Person.create({ + firstName: 'Joe', + lastName: 'Blow', + extra: 42 +}); + +assertType(es6Person.fullName); +assertType(es6Person.extra); + +class PersonWithStatics extends Ember.Object { + static isPerson = true; +} +const PersonWithStatics2 = PersonWithStatics.extend({}); +class PersonWithStatics3 extends PersonWithStatics {} +class PersonWithStatics4 extends PersonWithStatics2 {} +assertType(PersonWithStatics.isPerson); +assertType(PersonWithStatics2.isPerson); +assertType(PersonWithStatics3.isPerson); +assertType(PersonWithStatics4.isPerson); diff --git a/types/ember/v2/test/function-ext.ts b/types/ember/v2/test/function-ext.ts new file mode 100755 index 0000000000..37d831d49a --- /dev/null +++ b/types/ember/v2/test/function-ext.ts @@ -0,0 +1,21 @@ +import Ember from 'ember'; + +declare global { + interface Function extends Ember.FunctionPrototypeExtensions {} +} + +Ember.Object.extend({ + foo: '', + + arr: function() { + return []; + }.property(), + + alias: function(this: any) { + return this.get('foo'); + }.property('foo', 'bar.@each.baz'), + + observer: function() {}.observes('foo', 'bar'), + + on: function() {}.on('foo', 'bar'), +}); diff --git a/types/ember/v2/test/helper.ts b/types/ember/v2/test/helper.ts new file mode 100755 index 0000000000..2aa79a5ba1 --- /dev/null +++ b/types/ember/v2/test/helper.ts @@ -0,0 +1,41 @@ +import Ember from 'ember'; + +const FormatCurrencyHelper = Ember.Helper.helper(function(params, hash: { currency: string }) { + let cents = params[0]; + let currency = hash.currency; + return `${currency}${cents * 0.01}`; +}); + +class User extends Ember.Object { + email: string; +} + +class SessionService extends Ember.Service { + currentUser: User; +} + +const CurrentUserEmailHelper = Ember.Helper.extend({ + session: Ember.inject.service() as Ember.ComputedProperty, + onNewUser: Ember.observer('session.currentUser', function(this: Ember.Helper) { + this.recompute(); + }), + compute(): string { + return this.get('session') + .get('currentUser') + .get('email'); + }, +}); + +import { helper } from '@ember/component/helper'; + +function typedHelp(/*params, hash*/) { + return 'my type of help'; +} + +export default helper(typedHelp); + +function arrayNumHelp(/*params, hash*/) { + return [1, 2, 3]; +} + +helper(arrayNumHelp); diff --git a/types/ember/v2/test/inject.ts b/types/ember/v2/test/inject.ts new file mode 100755 index 0000000000..3ea0176ea6 --- /dev/null +++ b/types/ember/v2/test/inject.ts @@ -0,0 +1,59 @@ +import Ember from 'ember'; + +class AuthService extends Ember.Service { + isAuthenticated: boolean; +} + +class ApplicationController extends Ember.Controller { + model: {}; + string: string; + transitionToLogin() {} +} + +declare module '@ember/service' { + interface Registry { + 'auth': AuthService; + } +} + +declare module '@ember/controller' { + interface Registry { + 'application': ApplicationController; + } +} + +class LoginRoute extends Ember.Route { + auth = Ember.inject.service('auth'); + application = Ember.inject.controller('application'); + + didTransition() { + if (!this.get('auth').get('isAuthenticated')) { + this.get('application').transitionToLogin(); + } + } + + anyOldMethod() { + this.controllerFor('application').set('string', 'must be a string'); + } +} + +// New module injection style. +import Controller, { inject as controller } from '@ember/controller'; +import Service, { inject as service } from '@ember/service'; +import { assertType } from './lib/assert'; + +class ComponentInjection extends Ember.Component { + applicationController = controller('application'); + auth = service('auth'); + router = service('router'); + misc = service(); + + testem() { + assertType(this.get('misc')); + const url = this.get('router').urlFor('some-route', 1, 2, 3, { queryParams: { seriously: 'yes' } }); + assertType(url); + if (!this.get('auth').isAuthenticated) { + this.get('applicationController').transitionToLogin(); + } + } +} diff --git a/types/ember/v2/test/lib/assert.ts b/types/ember/v2/test/lib/assert.ts new file mode 100755 index 0000000000..d6748cd5bc --- /dev/null +++ b/types/ember/v2/test/lib/assert.ts @@ -0,0 +1,5 @@ +/** Static assertion that `value` has type `T` */ +// Disable tslint here b/c the generic is used to let us do a type coercion and +// validate that coercion works for the type value "passed into" the function. +// tslint:disable-next-line:no-unnecessary-generics +export declare function assertType(value: T): void; diff --git a/types/ember/v2/test/mixin.ts b/types/ember/v2/test/mixin.ts new file mode 100755 index 0000000000..a89f490a11 --- /dev/null +++ b/types/ember/v2/test/mixin.ts @@ -0,0 +1,57 @@ +import Ember from 'ember'; +import { assertType } from "./lib/assert"; + +interface EditableMixin { + edit(): void; + isEditing: boolean; +} + +const EditableMixin: Ember.Mixin = Ember.Mixin.create({ + edit() { + this.get('controller'); + console.log('starting to edit'); + this.set('isEditing', true); + }, + isEditing: false +}); + +const EditableComment = Ember.Route.extend(EditableMixin, { + postId: 0, + + canEdit() { + return !this.isEditing; + }, + + tryEdit() { + if (this.canEdit()) { + this.edit(); + } + } +}); + +const comment = EditableComment.create({ + postId: 42 +}); + +comment.edit(); +comment.canEdit(); +comment.tryEdit(); +assertType(comment.isEditing); +assertType(comment.postId); + +const LiteralMixins = Ember.Object.extend({ a: 1 }, { b: 2 }, { c: 3 }); +const obj = LiteralMixins.create(); +assertType(obj.a); +assertType(obj.b); +assertType(obj.c); + +/* Test composition of mixins */ +const EditableAndCancelableMixin = Ember.Mixin.create(EditableMixin, { + cancelled: false, +}); + +const EditableAndCancelableComment = Ember.Route.extend(EditableAndCancelableMixin); + +const editableAndCancelable = EditableAndCancelableComment.create(); +assertType(editableAndCancelable.isEditing); +assertType(editableAndCancelable.cancelled); diff --git a/types/ember/v2/test/object.ts b/types/ember/v2/test/object.ts new file mode 100755 index 0000000000..e1eefb75e9 --- /dev/null +++ b/types/ember/v2/test/object.ts @@ -0,0 +1,27 @@ +import Ember from 'ember'; + +const LifetimeHooks = Ember.Object.extend({ + resource: null as {} | null, + + init() { + this._super(); + this.resource = {}; + }, + + willDestroy() { + delete this.resource; + this._super(); + } +}); + +class MyObject30 extends Ember.Object { + constructor() { + super(); + } +} + +class MyObject31 extends Ember.Object { + constructor(properties: object) { + super(properties); + } +} diff --git a/types/ember/v2/test/observable.ts b/types/ember/v2/test/observable.ts new file mode 100755 index 0000000000..a642da271f --- /dev/null +++ b/types/ember/v2/test/observable.ts @@ -0,0 +1,113 @@ +import Ember from 'ember'; +import { assertType } from './lib/assert'; + +class MyComponent extends Ember.Component { + foo = 'bar'; + + init() { + this._super.apply(this, arguments); + this.addObserver('foo', this, 'fooDidChange'); + this.addObserver('foo', this, this.fooDidChange); + Ember.addObserver(this, 'foo', this, 'fooDidChange'); + Ember.addObserver(this, 'foo', this, this.fooDidChange); + this.removeObserver('foo', this, 'fooDidChange'); + this.removeObserver('foo', this, this.fooDidChange); + Ember.removeObserver(this, 'foo', this, 'fooDidChange'); + Ember.removeObserver(this, 'foo', this, this.fooDidChange); + const lambda = () => { + this.fooDidChange(this, 'foo'); + }; + this.addObserver('foo', lambda); + this.removeObserver('foo', lambda); + Ember.addObserver(this, 'foo', lambda); + Ember.removeObserver(this, 'foo', lambda); + } + + fooDidChange(sender: MyComponent, key: 'foo') { + // your code + } +} + +const myComponent = MyComponent.create(); +myComponent.addObserver('foo', null, () => {}); +myComponent.set('foo', 'baz'); + +const person = Ember.Object.create({ + name: 'Fred', + age: 29, + capitalized: Ember.computed(function() { + return this.get('name').toUpperCase(); + }) +}); + +const pojo = { name: 'Fred', age: 29 }; + +function testGet() { + assertType(Ember.get(person, 'name')); + assertType(Ember.get(person, 'age')); + assertType(Ember.get(person, 'capitalized')); + assertType(person.get('name')); + assertType(person.get('age')); + assertType(person.get('capitalized')); + assertType(Ember.get(pojo, 'name')); +} + +function testGetProperties() { + assertType<{ name: string }>(Ember.getProperties(person, 'name')); + assertType<{ name: string, age: number }>(Ember.getProperties(person, 'name', 'age')); + assertType<{ name: string, age: number }>(Ember.getProperties(person, [ 'name', 'age' ])); + assertType<{ name: string, age: number, capitalized: string }>(Ember.getProperties(person, 'name', 'age', 'capitalized')); + assertType<{ name: string }>(person.getProperties('name')); + assertType<{ name: string, age: number }>(person.getProperties('name', 'age')); + assertType<{ name: string, age: number }>(person.getProperties([ 'name', 'age' ])); + assertType<{ name: string, age: number, capitalized: string }>(person.getProperties('name', 'age', 'capitalized')); + assertType<{ name: string, age: number }>(Ember.getProperties(pojo, 'name', 'age')); +} + +function testGetWithDefault() { + assertType(Ember.getWithDefault(person, 'name', 'Joe')); + assertType(Ember.getWithDefault(person, 'age', 20)); + assertType(Ember.getWithDefault(person, 'capitalized', 'JOE')); + assertType(person.getWithDefault('name', 'Joe')); + assertType(person.getWithDefault('age', 20)); + assertType(person.getWithDefault('capitalized', 'JOE')); + assertType(Ember.getWithDefault(pojo, 'name', 'JOE')); +} + +function testSet() { + assertType(Ember.set(person, 'name', 'Joe')); + assertType(Ember.set(person, 'age', 35)); + assertType(Ember.set(person, 'capitalized', 'JOE')); + assertType(person.set('name', 'Joe')); + assertType(person.set('age', 35)); + assertType(person.set('capitalized', 'JOE')); + assertType(Ember.set(pojo, 'name', 'Joe')); +} + +function testSetProperties() { + assertType<{ name: string }>(Ember.setProperties(person, { name: 'Joe' })); + assertType<{ name: string, age: number }>(Ember.setProperties(person, { name: 'Joe', age: 35 })); + assertType<{ name: string, capitalized: string }>(Ember.setProperties(person, { name: 'Joe', capitalized: 'JOE' })); + assertType<{ name: string }>(person.setProperties({ name: 'Joe' })); + assertType<{ name: string, age: number }>(person.setProperties({ name: 'Joe', age: 35 })); + assertType<{ name: string, capitalized: string }>(person.setProperties({ name: 'Joe', capitalized: 'JOE' })); + assertType<{ name: string, age: number }>(Ember.setProperties(pojo, { name: 'Joe', age: 35 })); +} + +function testDynamic() { + const obj: any = {}; + const dynamicKey: string = 'dummy'; // tslint:disable-line:no-inferrable-types + + assertType(Ember.get(obj, 'dummy')); + assertType(Ember.get(obj, dynamicKey)); + assertType(Ember.getWithDefault(obj, 'dummy', 'default')); + assertType(Ember.getWithDefault(obj, dynamicKey, 'default')); + assertType<{ dummy: any }>(Ember.getProperties(obj, 'dummy')); + assertType<{ dummy: any }>(Ember.getProperties(obj, [ 'dummy' ])); + assertType(Ember.getProperties(obj, dynamicKey)); + assertType(Ember.getProperties(obj, [ dynamicKey ])); + assertType(Ember.set(obj, 'dummy', 'value')); + assertType(Ember.set(obj, dynamicKey, 'value')); + assertType<{ dummy: string }>(Ember.setProperties(obj, { dummy: 'value '})); + assertType(Ember.setProperties(obj, { [dynamicKey]: 'value' })); +} diff --git a/types/ember/v2/test/reopen.ts b/types/ember/v2/test/reopen.ts new file mode 100755 index 0000000000..6c13ca4155 --- /dev/null +++ b/types/ember/v2/test/reopen.ts @@ -0,0 +1,65 @@ +import Ember from 'ember'; +import { assertType } from "./lib/assert"; + +type Person = typeof Person.prototype; +const Person = Ember.Object.extend({ + name: '', + sayHello() { + alert(`Hello. My name is ${this.get('name')}`); + } +}); + +assertType(Person.reopen()); + +assertType(Person.create().name); +assertType(Person.create().sayHello()); + +const Person2 = Person.reopenClass({ + species: 'Homo sapiens', + + createPerson(name: string): Person { + return Person.create({ name }); + } +}); + +assertType(Person2.create().name); +assertType(Person2.create().sayHello()); +assertType(Person2.species); + +let tom = Person2.create({ + name: 'Tom Dale' +}); +let yehuda = Person2.createPerson('Yehuda Katz'); + +tom.sayHello(); // "Hello. My name is Tom Dale" +yehuda.sayHello(); // "Hello. My name is Yehuda Katz" +alert(Person2.species); // "Homo sapiens" + +const Person3 = Person2.reopen({ + goodbyeMessage: 'goodbye', + + sayGoodbye() { + alert(`${this.get('goodbyeMessage')}, ${this.get('name')}`); + } +}); + +const person3 = Person3.create(); +person3.get('name'); +person3.get('goodbyeMessage'); +person3.sayHello(); +person3.sayGoodbye(); + +interface AutoResizeMixin { resizable: true; } +declare const AutoResizeMixin: Ember.Mixin; + +const ResizableTextArea = Ember.TextArea.reopen(AutoResizeMixin, { + scaling: 1.0 +}); +const text = ResizableTextArea.create(); +assertType(text.resizable); +assertType(text.scaling); + +const Reopened = Ember.Object.reopenClass({ a: 1 }, { b: 2 }, { c: 3 }); +assertType(Reopened.a); +assertType(Reopened.b); +assertType(Reopened.c); diff --git a/types/ember/v2/test/route.ts b/types/ember/v2/test/route.ts new file mode 100755 index 0000000000..84e432dbd3 --- /dev/null +++ b/types/ember/v2/test/route.ts @@ -0,0 +1,104 @@ +import Route from '@ember/routing/route'; +import Object from '@ember/object'; +import Array from '@ember/array'; +import Ember from 'ember'; // currently needed for Transition + +interface Post extends Ember.Object {} + +interface Posts extends Array {} + +Route.extend({ + beforeModel(transition: Ember.Transition) { + this.transitionTo('someOtherRoute'); + }, +}); + +Route.extend({ + afterModel(posts: Posts, transition: Ember.Transition) { + if (posts.length === 1) { + this.transitionTo('post.show', posts.firstObject); + } + }, +}); + +Route.extend({ + actions: { + showModal(evt: { modalName: string }) { + this.render(evt.modalName, { + outlet: 'modal', + into: 'application', + }); + }, + hideModal(evt: { modalName: string }) { + this.disconnectOutlet({ + outlet: 'modal', + parentView: 'application', + }); + }, + }, +}); + +Ember.Route.extend({ + model() { + return this.modelFor('post'); + }, +}); + +Route.extend({ + queryParams: { + memberQp: { refreshModel: true }, + }, +}); + +Route.extend({ + renderTemplate() { + this.render('photos', { + into: 'application', + outlet: 'anOutletName', + }); + }, +}); + +Route.extend({ + renderTemplate(controller: Ember.Controller, model: {}) { + this.render('posts', { + view: 'someView', // the template to render, referenced by name + into: 'application', // the template to render into, referenced by name + outlet: 'anOutletName', // the outlet inside `options.into` to render into. + controller: 'someControllerName', // the controller to use for this template, referenced by name + model, // the model to set on `options.controller`. + }); + }, +}); + +Route.extend({ + resetController(controller: Ember.Controller, isExiting: boolean, transition: boolean) { + if (isExiting) { + // controller.set('page', 1); + } + }, +}); + +Route.extend({ + setupController(controller: Ember.Controller, model: {}) { + this._super(controller, model); + this.controllerFor('application').set('model', model); + }, +}); + +class RouteUsingClass extends Route.extend({ + randomProperty: 'the .extend + extends bit type-checks properly', +}) { + beforeModel(this: RouteUsingClass) { + return 'beforeModel can return anything, not just promises'; + } + intermediateTransitionWithoutModel() { + this.intermediateTransitionTo('some-route'); + } + intermediateTransitionWithModel() { + this.intermediateTransitionTo('some.other.route', { }); + } + intermediateTransitionWithMultiModel() { + this.intermediateTransitionTo('some.other.route', 1, 2, { }); + } +} diff --git a/types/ember/v2/test/router.ts b/types/ember/v2/test/router.ts new file mode 100755 index 0000000000..760e9ed5bc --- /dev/null +++ b/types/ember/v2/test/router.ts @@ -0,0 +1,54 @@ +import Ember from 'ember'; +import { assertType } from './lib/assert'; + +const AppRouter = Ember.Router.extend({ +}); + +AppRouter.map(function() { + this.route('index', { path: '/' }); + this.route('about'); + this.route('favorites', { path: '/favs' }); + this.route('posts', function() { + this.route('index', { path: '/' }); + this.route('new'); + this.route('post', { path: '/post/:post_id', resetNamespace: true }); + this.route('comments', { resetNamespace: true }, function() { + this.route('new'); + }); + }); + this.route('photo', { path: '/photo/:id' }, function() { + this.route('comment', { path: '/comment/:id' }); + }); + this.route('not-found', { path: '/*path' }); + this.mount('my-engine'); + this.mount('my-engine', { as: 'some-other-engine', path: '/some-other-engine'}); +}); + +const RouterServiceConsumer = Ember.Service.extend({ + router: Ember.inject.service('router'), + currentRouteName() { + const x: string = Ember.get(this, 'router').currentRouteName; + }, + currentURL() { + const x: string = Ember.get(this, 'router').currentURL; + }, + transitionWithoutModel() { + Ember.get(this, 'router') + .transitionTo('some-route'); + }, + transitionWithModel() { + const model = Ember.Object.create(); + Ember.get(this, 'router') + .transitionTo('some.other.route', model); + }, + transitionWithMultiModel() { + const model = Ember.Object.create(); + Ember.get(this, 'router') + .transitionTo('some.other.route', model, model); + }, + transitionWithModelAndOptions() { + const model = Ember.Object.create(); + Ember.get(this, 'router') + .transitionTo('index', model, { queryParams: { search: 'ember' }}); + } +}); diff --git a/types/ember/v2/test/run.ts b/types/ember/v2/test/run.ts new file mode 100755 index 0000000000..8d1c82e6e3 --- /dev/null +++ b/types/ember/v2/test/run.ts @@ -0,0 +1,204 @@ +import Ember from 'ember'; +import RSVP from 'rsvp'; +import { run } from '@ember/runloop'; +import { assertType } from "./lib/assert"; + +assertType(Ember.run.queues); + +function testRun() { + let r = run(function() { + // code to be executed within a RunLoop + return 123; + }); + assertType(r); + + function destroyApp(application: Ember.Application) { + Ember.run(application, 'destroy'); + run(application, function() { + this.destroy(); + }); + } +} + +function testBind() { + Ember.Component.extend({ + init() { + const bound = Ember.run.bind(this, this.setupEditor); + bound(); + }, + + editor: null as string | null, + + setupEditor(editor: string) { + this.set('editor', editor); + } + }); +} + +function testCancel() { + const myContext = {}; + + let runNext = run.next(myContext, function() { + // will not be executed + }); + + run.cancel(runNext); + + let runLater = run.later(myContext, function() { + // will not be executed + }, 500); + + run.cancel(runLater); + + let runScheduleOnce = run.scheduleOnce('afterRender', myContext, function() { + // will not be executed + }); + + run.cancel(runScheduleOnce); + + let runOnce = run.once(myContext, function() { + // will not be executed + }); + + run.cancel(runOnce); + + let throttle = run.throttle(myContext, function() { + // will not be executed + }, 1, false); + + run.cancel(throttle); + + let debounce = run.debounce(myContext, function() { + // will not be executed + }, 1); + + run.cancel(debounce); + + let debounceImmediate = run.debounce(myContext, function() { + // will be executed since we passed in true (immediate) + }, 100, true); + + // the 100ms delay until this method can be called again will be canceled + run.cancel(debounceImmediate); +} + +function testDebounce() { + function runIt() { + } + + let myContext = { name: 'debounce' }; + + run.debounce(runIt, 150); + run.debounce(myContext, runIt, 150); + run.debounce(myContext, runIt, 150, true); + + Ember.Component.extend({ + searchValue: 'test', + fetchResults(value: string) {}, + + actions: { + handleTyping() { + // the fetchResults function is passed into the component from its parent + Ember.run.debounce(this, this.get('fetchResults'), this.get('searchValue'), 250); + } + } + }); +} + +function testBegin() { + run.begin(); + // code to be executed within a RunLoop + run.end(); +} + +function testJoin() { + run.join(function() { + // creates a new run-loop + }); + + run(function() { + // creates a new run-loop + run.join(function() { + // joins with the existing run-loop, and queues for invocation on + // the existing run-loops action queue. + }); + }); + + new RSVP.Promise(function(resolve) { + Ember.run.later(function() { + resolve({ msg: 'Hold Your Horses' }); + }, 3000); + }); +} + +function testLater() { + const myContext = {}; + run.later(myContext, function() { + // code here will execute within a RunLoop in about 500ms with this == myContext + }, 500); +} + +function testNext() { + const myContext = {}; + run.next(myContext, function() { + // code to be executed in the next run loop, + // which will be scheduled after the current one + }); +} + +function testOnce() { + Ember.Component.extend({ + init() { + Ember.run.once(this, 'processFullName'); + }, + + processFullName() { + } + }); +} + +function testSchedule() { + Ember.Component.extend({ + init() { + run.schedule('sync', this, function() { + // this will be executed in the first RunLoop queue, when bindings are synced + console.log('scheduled on sync queue'); + }); + + run.schedule('actions', this, function() { + // this will be executed in the 'actions' queue, after bindings have synced. + console.log('scheduled on actions queue'); + }); + } + }); + + Ember.run.schedule('actions', () => { + // Do more things + }); +} + +function testScheduleOnce() { + function sayHi() { + console.log('hi'); + } + + const myContext = {}; + run(function() { + run.scheduleOnce('afterRender', myContext, sayHi); + run.scheduleOnce('afterRender', myContext, sayHi); + // sayHi will only be executed once, in the afterRender queue of the RunLoop + }); + run.scheduleOnce('actions', myContext, function() { + console.log('Closure'); + }); +} + +function testThrottle() { + function runIt() { + } + + let myContext = { name: 'throttle' }; + + run.throttle(runIt, 150); + run.throttle(myContext, runIt, 150); +} diff --git a/types/ember/v2/test/test.ts b/types/ember/v2/test/test.ts new file mode 100755 index 0000000000..6cd1b2b908 --- /dev/null +++ b/types/ember/v2/test/test.ts @@ -0,0 +1,32 @@ +import Ember from 'ember'; + +let pending = 0; +Ember.Test.registerWaiter(() => pending !== 0); + +declare const MyDb: { + hasPendingTransactions(): boolean; +}; +Ember.Test.registerWaiter(MyDb, MyDb.hasPendingTransactions); + +Ember.Test.promise(function(resolve) { + window.setTimeout(resolve, 500); +}); + +Ember.Test.registerHelper('boot', function(app) { + Ember.run(app, app.advanceReadiness); +}); + +Ember.Test.registerAsyncHelper('boot', function(app) { + Ember.run(app, app.advanceReadiness); +}); + +Ember.Test.registerAsyncHelper('waitForPromise', (app, promise) => { + return new Ember.Test.Promise((resolve) => { + Ember.Test.adapter.asyncStart(); + + promise.then(() => { + Ember.run.schedule('afterRender', null, resolve); + Ember.Test.adapter.asyncEnd(); + }); + }); +}); diff --git a/types/ember/v2/test/transition.ts b/types/ember/v2/test/transition.ts new file mode 100755 index 0000000000..3a64675c24 --- /dev/null +++ b/types/ember/v2/test/transition.ts @@ -0,0 +1,28 @@ +import Ember from 'ember'; + +Ember.Route.extend({ + beforeModel(transition: Ember.Transition) { + if (new Date() > new Date('January 1, 1980')) { + alert('Sorry, you need a time machine to enter this route.'); + transition.abort(); + } + } +}); + +Ember.Controller.extend({ + previousTransition: null, + + actions: { + login() { + // Log the user in, then reattempt previous transition if it exists. + let previousTransition = this.get('previousTransition'); + if (previousTransition) { + this.set('previousTransition', null); + previousTransition.retry(); + } else { + // Default back to homepage + this.transitionToRoute('index'); + } + } + } +}); diff --git a/types/ember/v2/test/utils.ts b/types/ember/v2/test/utils.ts new file mode 100755 index 0000000000..d729d472b8 --- /dev/null +++ b/types/ember/v2/test/utils.ts @@ -0,0 +1,71 @@ +import Ember from 'ember'; +import * as utils from '@ember/utils'; +import { assertType } from "./lib/assert"; + +function testIsNoneType() { + const maybeUndefined: string | undefined = 'not actually undefined'; + if (utils.isNone(maybeUndefined)) { + return; + } + + const anotherString = maybeUndefined + 'another string'; +} + +function testMerge() { + assertType<{ first: string, last: string }>( + Ember.merge({ first: 'Tom' }, { last: 'Dale' }) + ); +} + +function testAssign() { + assertType<{ first: string, middle: string, last: string }>( + Ember.assign({ first: 'Tom' }, { middle: 'M' }, { last: 'Dale' }) + ); +} + +function testOnError() { + Ember.onerror = function(error) { + Ember.$.post('/report-error', { + stack: error.stack, + otherInformation: 'whatever app state you want to provide' + }); + }; +} + +function testMakeArray() { + assertType(Ember.makeArray()); + assertType(Ember.makeArray(null)); + assertType(Ember.makeArray(undefined)); + assertType(Ember.makeArray('lindsay')); + assertType(Ember.makeArray([1, 2, 42])); +} + +function testDeprecateFunc() { + function newMethod(first: string, second: number): string { + return ''; + } + + let oldMethod = Ember.deprecateFunc('Please use the new method', { id: 'deprecated.id', until: '6.0' }, newMethod); + assertType(newMethod('first', 123)); + assertType(oldMethod('first', 123)); +} + +function testDefineProperty() { + const contact = {}; + + // ES5 compatible mode + Ember.defineProperty(contact, 'firstName', { + writable: true, + configurable: false, + enumerable: true, + value: 'Charles' + }); + + // define a simple property + Ember.defineProperty(contact, 'lastName', undefined, 'Jolley'); + + // define a computed property + Ember.defineProperty(contact, 'fullName', Ember.computed('firstName', 'lastName', function() { + return `${this.firstName} ${this.lastName}`; + })); +} diff --git a/types/ember/v2/test/view-utils.ts b/types/ember/v2/test/view-utils.ts new file mode 100644 index 0000000000..a3613064eb --- /dev/null +++ b/types/ember/v2/test/view-utils.ts @@ -0,0 +1,5 @@ +import Ember from 'ember'; +import { assertType } from './lib/assert'; + +const { ViewUtils: { isSimpleClick } } = Ember; +assertType(isSimpleClick(new Event('wat'))); diff --git a/types/ember/v2/tsconfig.json b/types/ember/v2/tsconfig.json new file mode 100755 index 0000000000..28f9bddb67 --- /dev/null +++ b/types/ember/v2/tsconfig.json @@ -0,0 +1,58 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "lib": [ + "es6", + "dom" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": false, + "baseUrl": "../../", + "typeRoots": [ + "../../" + ], + "paths": { + "ember": ["ember/v2"] + }, + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "test/lib/assert.ts", + "test/application.ts", + "test/application-instance.ts", + "test/engine-instance.ts", + "test/ember-tests.ts", + "test/error.ts", + "test/event.ts", + "test/extend.ts", + "test/create.ts", + "test/object.ts", + "test/observable.ts", + "test/mixin.ts", + "test/reopen.ts", + "test/detect.ts", + "test/detect-instance.ts", + "test/array.ts", + "test/array-ext.ts", + "test/array-proxy.ts", + "test/helper.ts", + "test/computed.ts", + "test/component.ts", + "test/function-ext.ts", + "test/inject.ts", + "test/utils.ts", + "test/transition.ts", + "test/router.ts", + "test/run.ts", + "test/test.ts", + "test/controller.ts", + "test/route.ts", + "test/view-utils.ts" + ] +} diff --git a/types/ember/v2/tslint.json b/types/ember/v2/tslint.json new file mode 100755 index 0000000000..f77f8d2ed8 --- /dev/null +++ b/types/ember/v2/tslint.json @@ -0,0 +1,30 @@ +{ + "extends": "dtslint/dt.json", + "rules": { + // Heavy use of Function type in this older package. + "ban-types": false, + "jsdoc-format": false, + "no-misused-new": false, + + // these are disabled because of rfc176 module exports + "strict-export-declare-modifiers": false, + "no-single-declare-module": false, + "no-declare-current-package": false, + "no-self-import": false, + + // We use interfaces in a number of places to express things (including + // mixins in particular, but also including extending a global + // interface) which TS currently can't express correctly. + "no-empty-interface": false, + + "no-duplicate-imports": false, + "no-unnecessary-qualifier": false, + "prefer-const": false, + "no-void-expression": false, + "only-arrow-functions": false, + "no-submodule-imports": false, + + // false positives + "unified-signatures": false + } +}