From 5dc54928ef79498d730ef634fbd89a114027f910 Mon Sep 17 00:00:00 2001 From: Mike North Date: Fri, 14 Sep 2018 09:06:43 -0700 Subject: [PATCH] [ember] refactor @ember/debug types into their own package (#28817) * [ember] fix: runInDebug should return void fixes https://github.com/typed-ember/ember-cli-typescript/issues/284 * [ember] tests for DataAdapter and ContainerDebugAdapter * [ember] more specific observable handlers in tests * [ember] refactor @ember/debug types into their own package --- types/ember/index.d.ts | 54 +++++++++++++------ types/ember/test/data-adapter.ts | 53 ++++++++++++++++++ types/ember/test/debug.ts | 53 ++++++++++++++++++ types/ember/test/private/observable-tests.ts | 4 +- types/ember/tsconfig.json | 4 +- .../ember__debug/container-debug-adapter.d.ts | 2 + types/ember__debug/data-adapter.d.ts | 3 ++ types/ember__debug/ember__debug-tests.ts | 45 ++++++++++++++++ types/ember__debug/index.d.ts | 14 +++++ types/ember__debug/tsconfig.json | 31 +++++++++++ types/ember__debug/tslint.json | 4 ++ 11 files changed, 248 insertions(+), 19 deletions(-) create mode 100644 types/ember/test/data-adapter.ts create mode 100644 types/ember/test/debug.ts create mode 100644 types/ember__debug/container-debug-adapter.d.ts create mode 100644 types/ember__debug/data-adapter.d.ts create mode 100644 types/ember__debug/ember__debug-tests.ts create mode 100644 types/ember__debug/index.d.ts create mode 100644 types/ember__debug/tsconfig.json create mode 100644 types/ember__debug/tslint.json diff --git a/types/ember/index.d.ts b/types/ember/index.d.ts index 6d79e1df8b..5b059a0ee4 100755 --- a/types/ember/index.d.ts +++ b/types/ember/index.d.ts @@ -739,7 +739,7 @@ declare module 'ember' { class ContainerDebugAdapter extends Object { resolver: Resolver; canCatalogEntriesByType(type: string): boolean; - catalogEntriesByType(type: string): any[]; + catalogEntriesByType(type: string): string[]; } /** * Additional methods for the Controller. @@ -1004,32 +1004,54 @@ declare module 'ember' { * The container-debug-adapter which is used * to list all models. */ - containerDebugAdapter: any; + containerDebugAdapter: ContainerDebugAdapter; /** * Ember Data > v1.0.0-beta.18 * requires string model names to be passed * around instead of the actual factories. */ - acceptsModelName: any; + acceptsModelName: boolean; /** * 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[]; + getFilters(): DataAdapter.Column[]; /** * Fetch the model types and observe them for changes. */ - watchModelTypes(typesAdded: Function, typesUpdated: Function): Function; + watchModelTypes( + typesAdded: (types: DataAdapter.WrappedType[]) => void, + typesUpdated: (types: DataAdapter.WrappedType[]) => void + ): () => void; /** * Fetch the records of a given type and observe them for changes. */ watchRecords( modelName: string, - recordsAdded: Function, - recordsUpdated: Function, - recordsRemoved: Function - ): Function; + recordsAdded: (records: DataAdapter.WrappedRecord[]) => void, + recordsUpdated: (records: DataAdapter.WrappedRecord[]) => void, + recordsRemoved: (idx: number, count: number) => void + ): () => void; + } + namespace DataAdapter { + interface Column { + name: string; + desc: string; + } + interface WrappedRecord { + columnValues: object; + object: object; + } + interface WrappedType { + type: { + name: string; + count: number; + columns: Column[]; + object: typeof Object; + }; + release: () => void; + } } const Debug: { /** @@ -1038,14 +1060,14 @@ declare module 'ember' { * 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; + registerDeprecationHandler(handler: (message: string, options: { id: string, until: string }, next: () => void) => void): void; /** * 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; + registerWarnHandler(handler: (message: string, options: { id: string }, next: () => void) => void): void; }; /** * The DefaultResolver defines the default lookup rules to resolve @@ -3017,20 +3039,20 @@ declare module 'ember' { /** * Run a function meant for debugging. */ - function runInDebug(func: () => void): any; + function runInDebug(func: () => any): void; /** * 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; + function warn(message: string, test: boolean, options: { id: string }): void; + function warn(message: string, options: { id: string }): void; /** * @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; + function warn(message: string, test: boolean, options?: { id?: string }): void; /** * @deprecated Missing deprecation options: https://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options */ - function warn(message: string, options?: { id?: string }): any; + function warn(message: string, options?: { id?: string }): void; /** * 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. diff --git a/types/ember/test/data-adapter.ts b/types/ember/test/data-adapter.ts new file mode 100644 index 0000000000..ea77b27e70 --- /dev/null +++ b/types/ember/test/data-adapter.ts @@ -0,0 +1,53 @@ +import Ember from 'ember'; + +const da = Ember.DataAdapter.create(); + +const filters = da.getFilters(); +filters.includes({ name: 'foo', desc: 'bar'}); // $ExpectType boolean +filters.includes({}); // $ExpectError + +filters[0].name; // $ExpectType string +filters[0].desc; // $ExpectType string + +da.watchModelTypes(// $ExpectType () => void + function added(wrappedTypes) { + wrappedTypes; + wrappedTypes[0].release; // $ExpectType () => void + wrappedTypes[0].type.columns[0].desc; // $ExpectType string + wrappedTypes[0].type.columns[0].name; // $ExpectType string + wrappedTypes[0].type.count; // $ExpectType number + wrappedTypes[0].type.name; // $ExpectType string + }, + function updated(wrappedTypes) { + wrappedTypes; + wrappedTypes[0].release; // $ExpectType () => void + wrappedTypes[0].type.columns[0].desc; // $ExpectType string + wrappedTypes[0].type.columns[0].name; // $ExpectType string + wrappedTypes[0].type.count; // $ExpectType number + wrappedTypes[0].type.name; // $ExpectType string + } +); +da.watchModelTypes(() => void); // $ExpectError + +da.watchRecords('house', // $ExpectType () => void + function added(records) { + records[0].object; // $ExpectType object + records[0].columnValues; // $ExpectType object + }, + function updated(records) { + records[0].object; // $ExpectType object + records[0].columnValues; // $ExpectType object + }, + function removed(idx, count) { + idx; // $ExpectType number + count; // $ExpectType number + } +); +da.watchRecords(() => void); // $ExpectError + +da.acceptsModelName; // $ExpectType boolean +da.containerDebugAdapter; // $ExpectType ContainerDebugAdapter + +const ca: Ember.ContainerDebugAdapter = da.containerDebugAdapter; +ca.canCatalogEntriesByType('controller'); // $ExpectType boolean +ca.catalogEntriesByType('controller'); // $ExpectType string[] diff --git a/types/ember/test/debug.ts b/types/ember/test/debug.ts new file mode 100644 index 0000000000..b3f4bb5f17 --- /dev/null +++ b/types/ember/test/debug.ts @@ -0,0 +1,53 @@ +import Ember from 'ember'; + +const { + runInDebug, + warn, + debug, + assert, + Debug: { registerDeprecationHandler, registerWarnHandler } +} = Ember; + +/** + * @ember/debug tests + */ +runInDebug(); // $ExpectError +let x = runInDebug(() => console.log('Should not show up in prod')); // $ExpectType void + +// Log a warning if we have more than 3 tomsters +const tomsterCount = 2; +warn('Too many tomsters!'); // $ExpectType void +warn('Too many tomsters!', tomsterCount <= 3); // $ExpectType void +warn('Too many tomsters!', tomsterCount <= 3, { // $ExpectType void + id: 'ember-debug.too-many-tomsters' +}); + +debug(); // $ExpectError +debug('Too many tomsters!'); // $ExpectType void +debug('Too many tomsters!', 'foo'); // $ExpectError + +// Test for truthiness +const str = 'hello'; +assert('Must pass a string', typeof str === 'string'); // $ExpectType void + +// Fail unconditionally +assert('This code path should never be run'); // $ExpectType void + +// next is not called, so no warnings get the default behavior +registerWarnHandler(); // $ExpectError +registerWarnHandler(() => {}); // $ExpectType void +registerWarnHandler((message, { id }, next) => { // $ExpectType void + message; // $ExpectType string + id; // $ExpectType string + next; // $ExpectType () => void +}); + +// next is not called, so no warnings get the default behavior +registerDeprecationHandler(); // $ExpectError +registerDeprecationHandler(() => {}); // $ExpectType void +registerDeprecationHandler((message, { id, until }, next) => { // $ExpectType void + message; // $ExpectType string + id; // $ExpectType string + until; // $ExpectType string + next; // $ExpectType () => void +}); diff --git a/types/ember/test/private/observable-tests.ts b/types/ember/test/private/observable-tests.ts index 015be1057b..be3d4bd69f 100644 --- a/types/ember/test/private/observable-tests.ts +++ b/types/ember/test/private/observable-tests.ts @@ -69,12 +69,12 @@ class DemoObservable implements Observable { notifyPropertyChange(keyName: string): this { throw new Error("Method not implemented."); } - addObserver(key: keyof this, target: Target, method: keyof Target | ((this: Target, sender: this, key: keyof this, value: any, rev: number) => void)): void; + addObserver(key: keyof this, target: Target, method: keyof Target | ((this: Target, sender: this, key: string, value: any, rev: number) => void)): void; addObserver(key: K, method: keyof this | ((this: this, sender: this, key: K, value: this[K], rev: number) => void)): void; addObserver(key: any, target: any, method?: any) { throw new Error("Method not implemented."); } - removeObserver(key: keyof this, target: Target, method: keyof Target | ((this: Target, sender: this, key: keyof this, value: any, rev: number) => void)): void; + removeObserver(key: keyof this, target: Target, method: keyof Target | ((this: Target, sender: this, key: string, value: any, rev: number) => void)): void; removeObserver(key: keyof this, method: keyof this | ((this: this, sender: this, key: string, value: any, rev: number) => void)): void; removeObserver(key: any, target: any, method?: any): void { throw new Error("Method not implemented."); diff --git a/types/ember/tsconfig.json b/types/ember/tsconfig.json index 6619ea0e47..a267c26dd5 100755 --- a/types/ember/tsconfig.json +++ b/types/ember/tsconfig.json @@ -40,6 +40,8 @@ "test/core-object.ts", "test/create-negative.ts", "test/create.ts", + "test/data-adapter.ts", + "test/debug.ts", "test/detect-instance.ts", "test/detect.ts", "test/ember-tests.ts", @@ -58,8 +60,8 @@ "test/route.ts", "test/router.ts", "test/run.ts", - "test/string.ts", "test/string-ext.ts", + "test/string.ts", "test/test.ts", "test/transition.ts", "test/utils.ts", diff --git a/types/ember__debug/container-debug-adapter.d.ts b/types/ember__debug/container-debug-adapter.d.ts new file mode 100644 index 0000000000..4bd24103a4 --- /dev/null +++ b/types/ember__debug/container-debug-adapter.d.ts @@ -0,0 +1,2 @@ +import Ember from 'ember'; +export default class ContainerDebugAdapter extends Ember.ContainerDebugAdapter { } diff --git a/types/ember__debug/data-adapter.d.ts b/types/ember__debug/data-adapter.d.ts new file mode 100644 index 0000000000..bc86573991 --- /dev/null +++ b/types/ember__debug/data-adapter.d.ts @@ -0,0 +1,3 @@ +import Ember from 'ember'; + +export default class DataAdapter extends Ember.DataAdapter {} diff --git a/types/ember__debug/ember__debug-tests.ts b/types/ember__debug/ember__debug-tests.ts new file mode 100644 index 0000000000..0fbdcbc174 --- /dev/null +++ b/types/ember__debug/ember__debug-tests.ts @@ -0,0 +1,45 @@ +import { runInDebug, warn, debug, assert, registerWarnHandler, registerDeprecationHandler } from "@ember/debug"; + +/** + * @ember/debug tests + */ +runInDebug(); // $ExpectError +runInDebug(() => console.log('Should not show up in prod')); // $ExpectType void + +// Log a warning if we have more than 3 tomsters +const tomsterCount = 2; +warn('Too many tomsters!'); // $ExpectType void +warn('Too many tomsters!', tomsterCount <= 3); // $ExpectType void +warn('Too many tomsters!', tomsterCount <= 3, { // $ExpectType void + id: 'ember-debug.too-many-tomsters' +}); + +debug(); // $ExpectError +debug('Too many tomsters!'); // $ExpectType void +debug('Too many tomsters!', 'foo'); // $ExpectError + +// Test for truthiness +const str = 'hello'; +assert('Must pass a string', typeof str === 'string'); // $ExpectType void + +// Fail unconditionally +assert('This code path should never be run'); // $ExpectType void + +// next is not called, so no warnings get the default behavior +registerWarnHandler(); // $ExpectError +registerWarnHandler(() => {}); // $ExpectType void +registerWarnHandler((message, { id }, next) => { // $ExpectType void + message; // $ExpectType string + id; // $ExpectType string + next; // $ExpectType () => void +}); + +// next is not called, so no warnings get the default behavior +registerDeprecationHandler(); // $ExpectError +registerDeprecationHandler(() => {}); // $ExpectType void +registerDeprecationHandler((message, { id, until }, next) => { // $ExpectType void + message; // $ExpectType string + id; // $ExpectType string + until; // $ExpectType string + next; // $ExpectType () => void +}); diff --git a/types/ember__debug/index.d.ts b/types/ember__debug/index.d.ts new file mode 100644 index 0000000000..8f1352baff --- /dev/null +++ b/types/ember__debug/index.d.ts @@ -0,0 +1,14 @@ +// Type definitions for @ember/debug 3.0 +// Project: http://emberjs.com/ +// Definitions by: Mike North +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.8 + +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; diff --git a/types/ember__debug/tsconfig.json b/types/ember__debug/tsconfig.json new file mode 100644 index 0000000000..c7688e6861 --- /dev/null +++ b/types/ember__debug/tsconfig.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "lib": [ + "es6", + "dom" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "paths": { + "@ember/debug": ["ember__debug"], + "@ember/debug/*": ["ember__debug/*"] + }, + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "data-adapter.d.ts", + "container-debug-adapter.d.ts", + "ember__debug-tests.ts" + ] +} diff --git a/types/ember__debug/tslint.json b/types/ember__debug/tslint.json new file mode 100644 index 0000000000..1a60b8a5dd --- /dev/null +++ b/types/ember__debug/tslint.json @@ -0,0 +1,4 @@ +{ + "extends": "dtslint/dt.json", + "rules": { } +}