diff --git a/.eslintignore b/.eslintignore index 2a54281cf..76a71708b 100644 --- a/.eslintignore +++ b/.eslintignore @@ -23,3 +23,4 @@ addon-test-support/**/*.js addon-test-support/**/*.d.ts +public-types diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 5e91bbefb..c0c28d80c 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -71,3 +71,27 @@ jobs: run: yarn install --frozen-lockfile - name: test run: node_modules/.bin/ember try:one ${{ matrix.ember-try-scenario }} --skip-cleanup + + types: + runs-on: ubuntu-latest + + needs: test + + strategy: + fail-fast: false + matrix: + ts-version: + - 4.7 + - next + + steps: + - uses: actions/checkout@v2 + - uses: volta-cli/action@v1 + with: + node-version: 12.x + - name: install dependencies + run: yarn install --frozen-lockfile + - name: install TS version + run: yarn install --dev typescript@${{matrix.ts-version}} + - name: test types + run: yarn lint:ts diff --git a/.gitignore b/.gitignore index 6978e3523..f6a13b6ea 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ # tyescript related output files addon-test-support/**/*.js addon-test-support/**/*.d.ts +public-types diff --git a/API.md b/API.md index bd1c47c0a..55941b20c 100644 --- a/API.md +++ b/API.md @@ -934,7 +934,7 @@ a new test metadata object if one does not exist. * `context` **BaseContext** the context to use -Returns **ITestMetadata** the test metadata for the provided context +Returns **TestMetadata** the test metadata for the provided context ## getDeprecations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dd9412f62..6ecf99d99 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,6 +11,10 @@ * `yarn lint` * `yarn lint:fix` +## Types + +When updating the API, you will need to update the type tests (in `tests/api.ts`) as well. The kinds of changes required will make it clear whether the change is backwards compatible or not! + ## Running tests * `ember test` – Runs the test suite on the current Ember version diff --git a/README.md b/README.md index 537f84adc..2b5589d10 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,9 @@ Compatibility - Ember 3.8 or above - Ember CLI 3.8 or above - Node.js 10 or above +- TypeScript 4.7 + - SemVer policy: [simple majors](https://www.semver-ts.org/#simple-majors) + - the public API is defined by [API.md](./API.md). Installation diff --git a/addon-test-support/@ember/test-helpers/-internal/build-registry.ts b/addon-test-support/@ember/test-helpers/-internal/build-registry.ts index ccad02a6c..45777ccfe 100644 --- a/addon-test-support/@ember/test-helpers/-internal/build-registry.ts +++ b/addon-test-support/@ember/test-helpers/-internal/build-registry.ts @@ -1,4 +1,4 @@ -import type Resolver from '@ember/application/resolver'; +import type Resolver from 'ember-resolver'; import ApplicationInstance from '@ember/application/instance'; import Application from '@ember/application'; import EmberObject from '@ember/object'; @@ -29,11 +29,12 @@ function exposeRegistryMethodsWithoutDeprecations(container: any) { ]; for (let i = 0, l = methods.length; i < l; i++) { - let method = methods[i]; + let methodName = methods[i]; - if (method in container) { - container[method] = function (...args: unknown[]) { - return container._registry[method](...args); + if (methodName && methodName in container) { + const knownMethod = methodName; + container[knownMethod] = function (...args: unknown[]) { + return container._registry[knownMethod](...args); }; } } @@ -57,10 +58,10 @@ const Owner = EmberObject.extend(RegistryProxyMixin, ContainerProxyMixin, { * @see {@link https://github.com/emberjs/ember.js/blob/v4.5.0-alpha.5/packages/%40ember/engine/instance.ts#L152-L167} */ unregister(fullName: string) { - this.__container__.reset(fullName); + this['__container__'].reset(fullName); // We overwrote this method from RegistryProxyMixin. - this.__registry__.unregister(fullName); + this['__registry__'].unregister(fullName); }, }); diff --git a/addon-test-support/@ember/test-helpers/-internal/debug-info.ts b/addon-test-support/@ember/test-helpers/-internal/debug-info.ts index 7756edd75..7875582f5 100644 --- a/addon-test-support/@ember/test-helpers/-internal/debug-info.ts +++ b/addon-test-support/@ember/test-helpers/-internal/debug-info.ts @@ -1,15 +1,10 @@ +import { _backburner } from '@ember/runloop'; import { - _backburner, DebugInfo as BackburnerDebugInfo, QueueItem, - DeferredActionQueues, -} from '@ember/runloop'; +} from '@ember/runloop/-private/backburner'; import { DebugInfoHelper, debugInfoHelpers } from './debug-info-helpers'; -import { - getPendingWaiterState, - PendingWaiterState, - TestWaiterDebugInfo, -} from '@ember/test-waiters'; +import { getPendingWaiterState, PendingWaiterState } from '@ember/test-waiters'; const PENDING_AJAX_REQUESTS = 'Pending AJAX requests'; const PENDING_TEST_WAITERS = 'Pending test waiters'; @@ -17,7 +12,6 @@ const SCHEDULED_ASYNC = 'Scheduled async'; const SCHEDULED_AUTORUN = 'Scheduled autorun'; type MaybeDebugInfo = BackburnerDebugInfo | null; -type WaiterDebugInfo = true | unknown[]; interface SettledState { hasPendingTimers: boolean; @@ -37,18 +31,22 @@ interface SummaryInfo { pendingTimersCount: number; hasPendingTimers: boolean; pendingTimersStackTraces: (string | undefined)[]; - pendingScheduledQueueItemCount: Number; + pendingScheduledQueueItemCount: number; pendingScheduledQueueItemStackTraces: (string | undefined)[]; hasRunLoop: boolean; isRenderPending: boolean; } +/** + * The base functionality which may be present on the `SettledState` interface + * in the `settled` module (**not** the one in this module). + */ export default interface DebugInfo { toConsole: () => void; } /** - * Determins if the `getDebugInfo` method is available in the + * Determines if the `getDebugInfo` method is available in the * running verison of backburner. * * @returns {boolean} True if `getDebugInfo` is present in backburner, otherwise false. @@ -112,9 +110,12 @@ export class TestDebugInfo implements DebugInfo { this._summaryInfo.pendingScheduledQueueItemCount = this._debugInfo.instanceStack .filter((q) => q) - .reduce((total: Number, item) => { - Object.keys(item).forEach((queueName: string) => { - total += item[queueName].length; + .reduce((total, item) => { + Object.keys(item).forEach((queueName) => { + // SAFETY: this cast is *not* safe, but the underlying type is + // not currently able to be safer than this because it was + // built as a bag-of-queues *and* a structured item originally. + total += (item[queueName] as QueueItem[]).length; }); return total; @@ -122,21 +123,17 @@ export class TestDebugInfo implements DebugInfo { this._summaryInfo.pendingScheduledQueueItemStackTraces = this._debugInfo.instanceStack .filter((q) => q) - .reduce( - ( - stacks: string[], - deferredActionQueues: DeferredActionQueues - ) => { - Object.keys(deferredActionQueues).forEach((queue) => { - deferredActionQueues[queue].forEach( - (queueItem: QueueItem) => - queueItem.stack && stacks.push(queueItem.stack) - ); - }); - return stacks; - }, - [] - ); + .reduce((stacks, deferredActionQueues) => { + Object.keys(deferredActionQueues).forEach((queue) => { + // SAFETY: this cast is *not* safe, but the underlying type is + // not currently able to be safer than this because it was + // built as a bag-of-queues *and* a structured item originally. + (deferredActionQueues[queue] as QueueItem[]).forEach( + (queueItem) => queueItem.stack && stacks.push(queueItem.stack) + ); + }); + return stacks; + }, [] as string[]); } if (this._summaryInfo.hasPendingTestWaiters) { @@ -165,12 +162,12 @@ export class TestDebugInfo implements DebugInfo { Object.keys(summary.pendingTestWaiterInfo.waiters).forEach( (waiterName) => { - let waiterDebugInfo: WaiterDebugInfo = + let waiterDebugInfo = summary.pendingTestWaiterInfo.waiters[waiterName]; if (Array.isArray(waiterDebugInfo)) { _console.group(waiterName); - waiterDebugInfo.forEach((debugInfo: TestWaiterDebugInfo) => { + waiterDebugInfo.forEach((debugInfo) => { _console.log( `${debugInfo.label ? debugInfo.label : 'stack'}: ${ debugInfo.stack @@ -221,7 +218,7 @@ export class TestDebugInfo implements DebugInfo { }); } - _formatCount(title: string, count: Number): string { + _formatCount(title: string, count: number): string { return `${title}: ${count}`; } } diff --git a/addon-test-support/@ember/test-helpers/-internal/deprecations.ts b/addon-test-support/@ember/test-helpers/-internal/deprecations.ts index 54d4b5274..3d96acee9 100644 --- a/addon-test-support/@ember/test-helpers/-internal/deprecations.ts +++ b/addon-test-support/@ember/test-helpers/-internal/deprecations.ts @@ -13,7 +13,7 @@ export interface DeprecationOptions { export interface DeprecationFailure { message: string; - options: DeprecationOptions; + options?: DeprecationOptions; } const DEPRECATIONS = new WeakMap>(); @@ -53,12 +53,12 @@ export function getDeprecationsForContext( * * @private * @param {BaseContext} [context] the test context - * @param {CallableFunction} [callback] The callback that when executed will have its DeprecationFailure recorded + * @param {Function} [callback] The callback that when executed will have its DeprecationFailure recorded * @return {Array} The Deprecation Failures associated with the corresponding baseContext which occured while the CallbackFunction was executed */ export function getDeprecationsDuringCallbackForContext( context: BaseContext, - callback: CallableFunction + callback: () => void ): Array | Promise> { if (!context) { throw new TypeError( @@ -92,7 +92,7 @@ if (typeof URLSearchParams !== 'undefined') { // those deprecations will be squelched if (disabledDeprecations) { registerDeprecationHandler((message, options, next) => { - if (!disabledDeprecations.includes(options.id)) { + if (!options || !disabledDeprecations.includes(options.id)) { next.apply(null, [message, options]); } }); @@ -102,7 +102,7 @@ if (typeof URLSearchParams !== 'undefined') { // `some-other-thing` deprecation is triggered, this `debugger` will be hit` if (debugDeprecations) { registerDeprecationHandler((message, options, next) => { - if (debugDeprecations.includes(options.id)) { + if (options && debugDeprecations.includes(options.id)) { debugger; // eslint-disable-line no-debugger } diff --git a/addon-test-support/@ember/test-helpers/-internal/warnings.ts b/addon-test-support/@ember/test-helpers/-internal/warnings.ts index 78b3cbbd6..c69ce5206 100644 --- a/addon-test-support/@ember/test-helpers/-internal/warnings.ts +++ b/addon-test-support/@ember/test-helpers/-internal/warnings.ts @@ -48,12 +48,12 @@ export function getWarningsForContext(context: BaseContext): Array { * * @private * @param {BaseContext} [context] the test context - * @param {CallableFunction} [callback] The callback that when executed will have its warnings recorded + * @param {Function} [callback] The callback that when executed will have its warnings recorded * @return {Array} The warnings associated with the corresponding baseContext which occured while the CallbackFunction was executed */ export function getWarningsDuringCallbackForContext( context: BaseContext, - callback: CallableFunction + callback: () => void ): Array | Promise> { if (!context) { throw new TypeError( @@ -89,7 +89,7 @@ if (typeof URLSearchParams !== 'undefined') { // those warnings will be squelched if (disabledWarnings) { registerWarnHandler((message, options, next) => { - if (!disabledWarnings.includes(options.id)) { + if (!options || !disabledWarnings.includes(options.id)) { next.apply(null, [message, options]); } }); @@ -99,7 +99,7 @@ if (typeof URLSearchParams !== 'undefined') { // `some-other-thing` warning is triggered, this `debugger` will be hit` if (debugWarnings) { registerWarnHandler((message, options, next) => { - if (debugWarnings.includes(options.id)) { + if (options && debugWarnings.includes(options.id)) { debugger; // eslint-disable-line no-debugger } diff --git a/addon-test-support/@ember/test-helpers/build-owner.ts b/addon-test-support/@ember/test-helpers/build-owner.ts index 7a75712d2..3edb1ff8d 100644 --- a/addon-test-support/@ember/test-helpers/build-owner.ts +++ b/addon-test-support/@ember/test-helpers/build-owner.ts @@ -1,5 +1,5 @@ import Application from '@ember/application'; -import type Resolver from '@ember/application/resolver'; +import type Resolver from 'ember-resolver'; import { Promise } from './-utils'; @@ -13,6 +13,7 @@ export interface Owner ContainerProxyMixin, RegistryProxyMixin { _emberTestHelpersMockOwner?: boolean; + rootElement?: string | Element; _lookupFactory?(key: string): any; diff --git a/addon-test-support/@ember/test-helpers/dom/-target.ts b/addon-test-support/@ember/test-helpers/dom/-target.ts index 90be41b7d..9683664fe 100644 --- a/addon-test-support/@ember/test-helpers/dom/-target.ts +++ b/addon-test-support/@ember/test-helpers/dom/-target.ts @@ -7,8 +7,12 @@ export interface HTMLElementContentEditable extends HTMLElement { } // eslint-disable-next-line require-jsdoc -export function isElement(target: any): target is Element { - return target.nodeType === Node.ELEMENT_NODE; +export function isElement(target: unknown): target is Element { + return ( + target !== null && + typeof target === 'object' && + Reflect.get(target, 'nodeType') === Node.ELEMENT_NODE + ); } // eslint-disable-next-line require-jsdoc @@ -17,8 +21,12 @@ export function isWindow(target: Target): target is Window { } // eslint-disable-next-line require-jsdoc -export function isDocument(target: any): target is Document { - return target.nodeType === Node.DOCUMENT_NODE; +export function isDocument(target: unknown): target is Document { + return ( + target !== null && + typeof target === 'object' && + Reflect.get(target, 'nodeType') === Node.DOCUMENT_NODE + ); } // eslint-disable-next-line require-jsdoc diff --git a/addon-test-support/@ember/test-helpers/dom/get-root-element.ts b/addon-test-support/@ember/test-helpers/dom/get-root-element.ts index 3b016adc6..b677a5992 100644 --- a/addon-test-support/@ember/test-helpers/dom/get-root-element.ts +++ b/addon-test-support/@ember/test-helpers/dom/get-root-element.ts @@ -1,4 +1,4 @@ -import { getContext } from '../setup-context'; +import { getContext, isTestContext } from '../setup-context'; import { isDocument, isElement } from './-target'; /** @@ -9,14 +9,15 @@ import { isDocument, isElement } from './-target'; */ export default function getRootElement(): Element | Document { let context = getContext(); - let owner = context && context.owner; - if (!owner) { + if (!context || !isTestContext(context) || !context.owner) { throw new Error( 'Must setup rendering context before attempting to interact with elements.' ); } + let owner = context.owner; + let rootElement; // When the host app uses `setApplication` (instead of `setResolver`) the owner has // a `rootElement` set on it with the element or id to be used diff --git a/addon-test-support/@ember/test-helpers/dom/tab.ts b/addon-test-support/@ember/test-helpers/dom/tab.ts index 97231f138..35fa7accc 100644 --- a/addon-test-support/@ember/test-helpers/dom/tab.ts +++ b/addon-test-support/@ember/test-helpers/dom/tab.ts @@ -87,8 +87,7 @@ function compileFocusAreas(root: Element = document.body) { ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP; }, - }, - false + } ); let node: Node | null; diff --git a/addon-test-support/@ember/test-helpers/dom/tap.ts b/addon-test-support/@ember/test-helpers/dom/tap.ts index e651e628f..20be8c671 100644 --- a/addon-test-support/@ember/test-helpers/dom/tap.ts +++ b/addon-test-support/@ember/test-helpers/dom/tap.ts @@ -56,7 +56,7 @@ registerHook('tap', 'start', (target: Target) => { */ export default function tap( target: Target, - options: object = {} + options: TouchEventInit = {} ): Promise { return Promise.resolve() .then(() => { @@ -79,7 +79,7 @@ export default function tap( return fireEvent(element, 'touchstart', options) .then((touchstartEv) => fireEvent(element as Element, 'touchend', options).then( - (touchendEv) => [touchstartEv, touchendEv] + (touchendEv) => [touchstartEv, touchendEv] as const ) ) .then(([touchstartEv, touchendEv]) => diff --git a/addon-test-support/@ember/test-helpers/dom/trigger-key-event.ts b/addon-test-support/@ember/test-helpers/dom/trigger-key-event.ts index 56cc8eae5..259a7efcc 100644 --- a/addon-test-support/@ember/test-helpers/dom/trigger-key-event.ts +++ b/addon-test-support/@ember/test-helpers/dom/trigger-key-event.ts @@ -159,7 +159,7 @@ export function __triggerKeyEvent__( }; } else if (typeof key === 'string' && key.length !== 0) { let firstCharacter = key[0]; - if (firstCharacter !== firstCharacter.toUpperCase()) { + if (!firstCharacter || firstCharacter !== firstCharacter.toUpperCase()) { throw new Error( `Must provide a \`key\` to \`triggerKeyEvent\` that starts with an uppercase character but you passed \`${key}\`.` ); diff --git a/addon-test-support/@ember/test-helpers/dom/type-in.ts b/addon-test-support/@ember/test-helpers/dom/type-in.ts index 26873436e..2368845de 100644 --- a/addon-test-support/@ember/test-helpers/dom/type-in.ts +++ b/addon-test-support/@ember/test-helpers/dom/type-in.ts @@ -112,7 +112,7 @@ function fillOut( .map((character) => keyEntry(element, character)); return inputFunctions.reduce((currentPromise, func) => { return currentPromise.then(() => delayedExecute(delay)).then(func); - }, Promise.resolve(undefined)); + }, Promise.resolve()); } // eslint-disable-next-line require-jsdoc diff --git a/addon-test-support/@ember/test-helpers/has-ember-version.ts b/addon-test-support/@ember/test-helpers/has-ember-version.ts index 661dab798..bb5fb3a3f 100644 --- a/addon-test-support/@ember/test-helpers/has-ember-version.ts +++ b/addon-test-support/@ember/test-helpers/has-ember-version.ts @@ -10,7 +10,12 @@ import Ember from 'ember'; @returns {boolean} true if the Ember version is >= MAJOR.MINOR specified, false otherwise */ export default function hasEmberVersion(major: number, minor: number): boolean { - let numbers = Ember.VERSION.split('-')[0].split('.'); + let numbers = Ember.VERSION.split('-')[0]?.split('.'); + + if (!numbers || !numbers[0] || !numbers[1]) { + throw new Error('`Ember.VERSION` is not set.'); + } + let actualMajor = parseInt(numbers[0], 10); let actualMinor = parseInt(numbers[1], 10); return actualMajor > major || (actualMajor === major && actualMinor >= minor); diff --git a/addon-test-support/@ember/test-helpers/index.ts b/addon-test-support/@ember/test-helpers/index.ts index 7b3ba77e5..06b19ae1b 100644 --- a/addon-test-support/@ember/test-helpers/index.ts +++ b/addon-test-support/@ember/test-helpers/index.ts @@ -1,3 +1,8 @@ +import { + Backburner, + DeferredActionQueues, +} from '@ember/runloop/-private/backburner'; + export { setResolver, getResolver } from './resolver'; export { getApplication, setApplication } from './application'; export { @@ -9,8 +14,12 @@ export { resumeTest, getDeprecations, getDeprecationsDuringCallback, + DeprecationFailure, getWarnings, getWarningsDuringCallback, + Warning, + BaseContext, + TestContext, } from './setup-context'; export { default as teardownContext } from './teardown-context'; export { @@ -29,9 +38,9 @@ export { default as settled, isSettled, getSettledState } from './settled'; export { default as waitUntil } from './wait-until'; export { default as validateErrorHandler } from './validate-error-handler'; export { default as setupOnerror, resetOnerror } from './setup-onerror'; -export { getDebugInfo } from './-internal/debug-info'; +export { getDebugInfo, default as DebugInfo } from './-internal/debug-info'; export { default as registerDebugInfoHelper } from './-internal/debug-info-helpers'; -export { default as getTestMetadata } from './test-metadata'; +export { default as getTestMetadata, TestMetadata } from './test-metadata'; export { registerHook as _registerHook, runHooks as _runHooks, @@ -54,3 +63,13 @@ export { default as find } from './dom/find'; export { default as findAll } from './dom/find-all'; export { default as typeIn } from './dom/type-in'; export { default as scrollTo } from './dom/scroll-to'; + +// Declaration-merge for our internal purposes. +declare module '@ember/runloop' { + interface PrivateBackburner extends Backburner { + hasTimers(): boolean; + currentInstance: DeferredActionQueues | null; + } + + export const _backburner: PrivateBackburner; +} diff --git a/addon-test-support/@ember/test-helpers/resolver.ts b/addon-test-support/@ember/test-helpers/resolver.ts index 1716e91c9..4b57c9176 100644 --- a/addon-test-support/@ember/test-helpers/resolver.ts +++ b/addon-test-support/@ember/test-helpers/resolver.ts @@ -1,4 +1,4 @@ -import type Resolver from '@ember/application/resolver'; +import type Resolver from 'ember-resolver'; let __resolver__: Resolver | undefined; diff --git a/addon-test-support/@ember/test-helpers/setup-application-context.ts b/addon-test-support/@ember/test-helpers/setup-application-context.ts index 93a8bdb1a..35ac29756 100644 --- a/addon-test-support/@ember/test-helpers/setup-application-context.ts +++ b/addon-test-support/@ember/test-helpers/setup-application-context.ts @@ -9,8 +9,11 @@ import { import global from './global'; import hasEmberVersion from './has-ember-version'; import settled from './settled'; -import getTestMetadata, { ITestMetadata } from './test-metadata'; +import getTestMetadata from './test-metadata'; import { runHooks } from './-internal/helper-hooks'; +import type { Router } from '@ember/routing'; +import type RouterService from '@ember/routing/router-service'; +import { assert } from '@ember/debug'; export interface ApplicationTestContext extends TestContext { element?: Element | null; @@ -74,7 +77,7 @@ export function hasPendingTransitions(): boolean | null { */ export function setupRouterSettlednessTracking() { const context = getContext(); - if (context === undefined) { + if (context === undefined || !isTestContext(context)) { throw new Error( 'Cannot setupRouterSettlednessTracking outside of a test context' ); @@ -87,9 +90,15 @@ export function setupRouterSettlednessTracking() { HAS_SETUP_ROUTER.set(context, true); let { owner } = context; - let router; + let router: Router | RouterService; if (CAN_USE_ROUTER_EVENTS) { - router = owner.lookup('service:router'); + // SAFETY: unfortunately we cannot `assert` here at present because the + // class is not exported, only the type, since it is not designed to be + // sub-classed. The most we can do at present is assert that it at least + // *exists* and assume that if it does exist, it is bound correctly. + let routerService = owner.lookup('service:router'); + assert('router service is not set up correctly', !!routerService); + router = routerService as RouterService; // track pending transitions via the public routeWillChange / routeDidChange APIs // routeWillChange can fire many times and is only useful to know when we have _started_ @@ -97,7 +106,11 @@ export function setupRouterSettlednessTracking() { router.on('routeWillChange', () => (routerTransitionsPending = true)); router.on('routeDidChange', () => (routerTransitionsPending = false)); } else { - router = owner.lookup('router:main'); + // SAFETY: similarly, this cast cannot be made safer because on the versions + // where we fall into this path, this is *also* not an exported class. + let mainRouter = owner.lookup('router:main'); + assert('router:main is not available', !!mainRouter); + router = mainRouter as Router; ROUTER.set(context, router); } @@ -120,7 +133,7 @@ export function setupRouterSettlednessTracking() { */ export function visit( url: string, - options?: { [key: string]: any } + options?: Record ): Promise { const context = getContext(); if (!context || !isApplicationTestContext(context)) { @@ -172,8 +185,12 @@ export function currentRouteName(): string { } let router = context.owner.lookup('router:main'); - - return get(router, 'currentRouteName'); + let currentRouteName = get(router, 'currentRouteName'); + assert( + 'currentRouteName shoudl be a string', + typeof currentRouteName === 'string' + ); + return currentRouteName; } const HAS_CURRENT_URL_ON_ROUTER = hasEmberVersion(2, 13); @@ -193,9 +210,27 @@ export function currentURL(): string { let router = context.owner.lookup('router:main'); if (HAS_CURRENT_URL_ON_ROUTER) { - return get(router, 'currentURL'); + let routerCurrentURL = get(router, 'currentURL'); + + // SAFETY: this path is a lie for the sake of the public-facing types. The + // framework itself sees this path, but users never do. A user who calls the + // API without calling `visit()` will see an `UnrecognizedURLError`, rather + // than getting back `null`. + if (routerCurrentURL === null) { + return routerCurrentURL as never as string; + } + + assert( + `currentUrl should be a string, but was ${typeof routerCurrentURL}`, + typeof routerCurrentURL === 'string' + ); + + return routerCurrentURL; } else { - return get(router, 'location').getURL(); + // SAFETY: this is *positively ancient* and should probably be removed at + // some point; old routers which don't have `currentURL` *should* have a + // `location` with `getURL()` per the docs for 2.12. + return (get(router, 'location') as any).getURL(); } } @@ -210,12 +245,12 @@ export function currentURL(): string { @public @param {Object} context the context to setup - @returns {Promise} resolves with the context that was setup + @returns {Promise} resolves when the context is set up */ export default function setupApplicationContext( context: TestContext ): Promise { - let testMetadata: ITestMetadata = getTestMetadata(context); + let testMetadata = getTestMetadata(context); testMetadata.setupTypes.push('setupApplicationContext'); return Promise.resolve(); diff --git a/addon-test-support/@ember/test-helpers/setup-context.ts b/addon-test-support/@ember/test-helpers/setup-context.ts index b85e9663c..cdcdf26a3 100644 --- a/addon-test-support/@ember/test-helpers/setup-context.ts +++ b/addon-test-support/@ember/test-helpers/setup-context.ts @@ -1,6 +1,6 @@ import { _backburner, run } from '@ember/runloop'; import { set, setProperties, get, getProperties } from '@ember/object'; -import type Resolver from '@ember/application/resolver'; +import type Resolver from 'ember-resolver'; import { setOwner } from '@ember/application'; import buildOwner, { Owner } from './build-owner'; @@ -16,7 +16,7 @@ import global from './global'; import { getResolver } from './resolver'; import { getApplication } from './application'; import { Promise } from './-utils'; -import getTestMetadata, { ITestMetadata } from './test-metadata'; +import getTestMetadata from './test-metadata'; import { registerDestructor, associateDestroyableChild, @@ -61,15 +61,22 @@ registerWarnHandler((message, options, next) => { }); export interface BaseContext { - [key: string]: any; + [key: string]: unknown; } +/** + * The public API for the test context, which test authors can depend on being + * available. + * + * Note: this is *not* user-constructible; it becomes available by calling + * `setupContext()` with a `BaseContext`. + */ export interface TestContext extends BaseContext { owner: Owner; - set(key: string, value: any): any; - setProperties(hash: { [key: string]: any }): { [key: string]: any }; - get(key: string): any; + set(key: string, value: T): T; + setProperties>(hash: T): T; + get(key: string): unknown; getProperties(...args: string[]): Pick; pauseTest(): Promise; @@ -79,8 +86,8 @@ export interface TestContext extends BaseContext { // eslint-disable-next-line require-jsdoc export function isTestContext(context: BaseContext): context is TestContext { return ( - typeof context.pauseTest === 'function' && - typeof context.resumeTest === 'function' + typeof context['pauseTest'] === 'function' && + typeof context['resumeTest'] === 'function' ); } @@ -189,13 +196,16 @@ export function resumeTest(): void { function cleanup(context: BaseContext) { _teardownAJAXHooks(); + // SAFETY: this is intimate API *designed* for us to override. (Ember as any).testing = false; unsetContext(); - // this should not be required, but until https://github.com/emberjs/ember.js/pull/19106 - // lands in a 3.20 patch release - context.owner.destroy(); + if (isTestContext(context)) { + // this should not be required, but until https://github.com/emberjs/ember.js/pull/19106 + // lands in a 3.20 patch release + context.owner.destroy(); + } } /** @@ -227,11 +237,13 @@ export function getDeprecations(): Array { return getDeprecationsForContext(context); } +export type { DeprecationFailure }; + /** * Returns deprecations which have occured so far for a the current test context * * @public - * @param {CallableFunction} [callback] The callback that when executed will have its DeprecationFailure recorded + * @param {Function} [callback] The callback that when executed will have its DeprecationFailure recorded * @returns {Array | Promise>} An array of deprecation messages * @example Usage via ember-qunit * @@ -256,7 +268,7 @@ export function getDeprecations(): Array { * }); */ export function getDeprecationsDuringCallback( - callback: CallableFunction + callback: () => void ): Array | Promise> { const context = getContext(); @@ -298,11 +310,13 @@ export function getWarnings(): Array { return getWarningsForContext(context); } +export type { Warning }; + /** * Returns warnings which have occured so far for a the current test context * * @public - * @param {CallableFunction} [callback] The callback that when executed will have its warnings recorded + * @param {Function} [callback] The callback that when executed will have its warnings recorded * @returns {Array | Promise>} An array of warnings information * @example Usage via ember-qunit * @@ -329,7 +343,7 @@ export function getWarnings(): Array { * }); */ export function getWarningsDuringCallback( - callback: CallableFunction + callback: () => void ): Array | Promise> { const context = getContext(); @@ -368,10 +382,11 @@ export default function setupContext( context: BaseContext, options: { resolver?: Resolver } = {} ): Promise { + // SAFETY: this is intimate API *designed* for us to override. (Ember as any).testing = true; setContext(context); - let testMetadata: ITestMetadata = getTestMetadata(context); + let testMetadata = getTestMetadata(context); testMetadata.setupTypes.push('setupContext'); _backburner.DEBUG = true; @@ -417,7 +432,7 @@ export default function setupContext( Object.defineProperty(context, 'set', { configurable: true, enumerable: true, - value(key: string, value: any): any { + value(key: string, value: unknown): unknown { let ret = run(function () { if (ComponentRenderMap.has(context)) { assert( @@ -487,17 +502,17 @@ export default function setupContext( writable: false, }); - let resume: Function | undefined; - context.resumeTest = function resumeTest() { + let resume: ((value?: unknown) => void) | undefined; + context['resumeTest'] = function resumeTest() { assert( 'Testing has not been paused. There is nothing to resume.', - Boolean(resume) + !!resume ); - (resume as Function)(); + resume(); global.resumeTest = resume = undefined; }; - context.pauseTest = function pauseTest() { + context['pauseTest'] = function pauseTest() { console.info('Testing paused. Use `resumeTest()` to continue.'); // eslint-disable-line no-console return new Promise((resolve) => { diff --git a/addon-test-support/@ember/test-helpers/setup-rendering-context.ts b/addon-test-support/@ember/test-helpers/setup-rendering-context.ts index 7caba3837..b570ef685 100644 --- a/addon-test-support/@ember/test-helpers/setup-rendering-context.ts +++ b/addon-test-support/@ember/test-helpers/setup-rendering-context.ts @@ -13,7 +13,7 @@ import settled from './settled'; import { hbs, TemplateFactory } from 'ember-cli-htmlbars'; import getRootElement from './dom/get-root-element'; import { Owner } from './build-owner'; -import getTestMetadata, { ITestMetadata } from './test-metadata'; +import getTestMetadata, { TestMetadata } from './test-metadata'; import { assert, deprecate } from '@ember/debug'; import { runHooks } from './-internal/helper-hooks'; import hasEmberVersion from './has-ember-version'; @@ -22,6 +22,7 @@ import { macroCondition, dependencySatisfies } from '@embroider/macros'; import { ComponentRenderMap, SetUsage } from './setup-context'; import { ensureSafeComponent } from '@embroider/util'; import type { ComponentInstance } from '@glimmer/interfaces'; +import ViewMixin from '@ember/component/-private/view-mixin'; const OUTLET_TEMPLATE = hbs`{{outlet}}`; const EMPTY_TEMPLATE = hbs``; @@ -42,8 +43,8 @@ export function isRenderingTestContext( ): context is RenderingTestContext { return ( isTestContext(context) && - typeof context.render === 'function' && - typeof context.clearRender === 'function' + typeof context['render'] === 'function' && + typeof context['clearRender'] === 'function' ); } @@ -117,7 +118,10 @@ export function render( let testMetadata = getTestMetadata(context); testMetadata.usedHelpers.push('render'); - let toplevelView = owner.lookup('-top-level-view:main'); + // SAFETY: this is all wildly unsafe, because it is all using private API. + // At some point we should define a path forward for this kind of internal + // API. For now, just flagging it as *NOT* being safe! + let toplevelView = owner.lookup('-top-level-view:main') as any; let OutletTemplate = lookupOutletTemplate(owner); let ownerToRenderFrom = options?.owner || owner; @@ -213,7 +217,11 @@ export function render( // setting outletState should ensureInstance, since we know we need to // render), but on Ember < 3.23 that is not guaranteed. if (!hasEmberVersion(3, 23)) { - run.backburner.ensureInstance(); + // SAFETY: this was correct and type checked on the Ember v3 types, but + // since the `run` namespace does not exist in Ember v4, this no longer + // can be type checked. When (eventually) dropping support for Ember v3, + // and therefore for versions before 3.23, this can be removed entirely. + (run as any).backburner.ensureInstance(); } // returning settled here because the actual rendering does not happen until @@ -269,7 +277,7 @@ export function clearRender(): Promise { export default function setupRenderingContext( context: TestContext ): Promise { - let testMetadata: ITestMetadata = getTestMetadata(context); + let testMetadata = getTestMetadata(context); testMetadata.setupTypes.push('setupRenderingContext'); return Promise.resolve() @@ -286,8 +294,9 @@ export default function setupRenderingContext( for: '@ember/test-helpers', since: { enabled: '2.0.0', + available: '2.0.0', }, - } as any // @types/ember is missing since + for + } ); return render(template); @@ -303,8 +312,9 @@ export default function setupRenderingContext( for: '@ember/test-helpers', since: { enabled: '2.0.0', + available: '2.0.0', }, - } as any // @types/ember is missing since + for + } ); return clearRender(); diff --git a/addon-test-support/@ember/test-helpers/test-metadata.ts b/addon-test-support/@ember/test-helpers/test-metadata.ts index 2ee839dc3..009d06bd7 100644 --- a/addon-test-support/@ember/test-helpers/test-metadata.ts +++ b/addon-test-support/@ember/test-helpers/test-metadata.ts @@ -1,16 +1,6 @@ import { BaseContext } from './setup-context'; -export interface ITestMetadata { - testName?: string; - setupTypes: string[]; - usedHelpers: string[]; - [key: string]: any; - - readonly isRendering: boolean; - readonly isApplication: boolean; -} - -export class TestMetadata implements ITestMetadata { +class TestMetadata { [key: string]: any; testName?: string; setupTypes: string[]; @@ -33,16 +23,31 @@ export class TestMetadata implements ITestMetadata { } } -const TEST_METADATA = new WeakMap(); +export { + // Exported only for testing purposes. + TestMetadata as __TestMetadata, +}; + +// Only export the type side of the item: this way the only way (it is legal) to +// construct it is here, but users can still reference the type. +export type { + /** + * A non-user-constructible interface representing the metadata associated + * with a test, designed for test frameworks to use e.g. with their reporters. + */ + TestMetadata, +}; + +const TEST_METADATA = new WeakMap(); /** * Gets the test metadata associated with the provided test context. Will create * a new test metadata object if one does not exist. * * @param {BaseContext} context the context to use - * @returns {ITestMetadata} the test metadata for the provided context + * @returns {TestMetadata} the test metadata for the provided context */ -export default function getTestMetadata(context: BaseContext): ITestMetadata { +export default function getTestMetadata(context: BaseContext): TestMetadata { if (!TEST_METADATA.has(context)) { TEST_METADATA.set(context, new TestMetadata()); } diff --git a/addon-test-support/@ember/test-helpers/validate-error-handler.ts b/addon-test-support/@ember/test-helpers/validate-error-handler.ts index 887ef9c17..c158af07f 100644 --- a/addon-test-support/@ember/test-helpers/validate-error-handler.ts +++ b/addon-test-support/@ember/test-helpers/validate-error-handler.ts @@ -1,4 +1,9 @@ import Ember from 'ember'; + +type ErrorHandlerValidation = + | Readonly<{ isValid: true; message: null }> + | Readonly<{ isValid: false; message: string }>; + const VALID = Object.freeze({ isValid: true, message: null }); const INVALID = Object.freeze({ isValid: false, @@ -28,7 +33,9 @@ const INVALID = Object.freeze({ * assert.ok(result.isValid, result.message); * }); */ -export default function validateErrorHandler(callback = Ember.onerror) { +export default function validateErrorHandler( + callback = Ember.onerror +): ErrorHandlerValidation { if (callback === undefined || callback === null) { return VALID; } diff --git a/addon-test-support/@ember/test-helpers/wait-until.ts b/addon-test-support/@ember/test-helpers/wait-until.ts index 269039b34..dbe235bb0 100644 --- a/addon-test-support/@ember/test-helpers/wait-until.ts +++ b/addon-test-support/@ember/test-helpers/wait-until.ts @@ -49,10 +49,8 @@ export default function waitUntil( // eslint-disable-next-line require-jsdoc function scheduleCheck(timeoutsIndex: number) { - let interval = TIMEOUTS[timeoutsIndex]; - if (interval === undefined) { - interval = MAX_TIMEOUT; - } + let knownTimeout = TIMEOUTS[timeoutsIndex]; + let interval = knownTimeout === undefined ? MAX_TIMEOUT : knownTimeout; futureTick(function () { time += interval; diff --git a/package.json b/package.json index bc91196f1..f37ce3365 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,10 @@ "test": "tests" }, "scripts": { - "prepack": "yarn babel --extensions '.ts' --presets @babel/preset-typescript addon-test-support --out-dir addon-test-support/ --ignore '**/*.d.ts'", + "build:types": "tsc --project types.tsconfig.json", + "build:js": "yarn babel --extensions '.ts' --presets @babel/preset-typescript addon-test-support --out-dir addon-test-support/ --ignore '**/*.d.ts'", + "build": "npm-run-all --parallel build:*", + "prepack": "yarn build", "postpack": "rimraf addon-test-support/**/*.js", "clean": "git clean -x -f", "docs": "documentation build --document-exported \"addon-test-support/@ember/test-helpers/index.js\" --config documentation.yml --markdown-toc-max-depth 3 -f md -o API.md", @@ -56,7 +59,19 @@ "@glimmer/component": "^1.0.4", "@glimmer/interfaces": "^0.84.1", "@glimmer/reference": "^0.84.1", - "@types/ember": "^3.16.5", + "@tsconfig/ember": "^1.0.1", + "@types/ember": "~4.0.0", + "@types/ember__application": "~4.0.0", + "@types/ember__component": "~4.0.8", + "@types/ember__debug": "~4.0.1", + "@types/ember__destroyable": "~4.0.0", + "@types/ember__engine": "~4.0.0", + "@types/ember__object": "~4.0.2", + "@types/ember__routing": "~4.0.7", + "@types/ember__polyfills": "~4.0.0", + "@types/ember__runloop": "~4.0.1", + "@types/ember__service": "~4.0.0", + "@types/ember__test": "~4.0.0", "@types/ember-testing-helpers": "^0.0.4", "@types/rsvp": "^4.0.4", "@typescript-eslint/eslint-plugin": "^4.29.0", @@ -83,6 +98,7 @@ "eslint-plugin-disable-features": "^0.1.3", "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^4.0.0", + "expect-type": "^0.13.0", "fs-extra": "^10.0.0", "latest-version": "^5.0.0", "loader.js": "^4.7.0", @@ -93,7 +109,7 @@ "release-it": "~14.11.6", "release-it-lerna-changelog": "^3.1.0", "rimraf": "^3.0.2", - "typescript": "^4.3.5", + "typescript": "^4.7.4", "webpack": "^5.57.1" }, "engines": { @@ -140,5 +156,12 @@ "volta": { "node": "12.22.4", "yarn": "1.22.4" + }, + "typesVersions": { + "*": { + "*": [ + "public-types/*" + ] + } } } diff --git a/tests/api.ts b/tests/api.ts new file mode 100644 index 000000000..a2c51db97 --- /dev/null +++ b/tests/api.ts @@ -0,0 +1,246 @@ +import { expectTypeOf } from 'expect-type'; + +import { + // DOM Interaction Helpers + blur, + click, + doubleClick, + fillIn, + focus, + scrollTo, + select, + tap, + triggerEvent, + triggerKeyEvent, + typeIn, + // DOM Query Helpers + find, + findAll, + getRootElement, + // Routing Helpers + visit, + currentRouteName, + currentURL, + // Rendering Helpers + render, + clearRender, + // Wait Helpers + waitFor, + waitUntil, + settled, + isSettled, + getSettledState, + // Pause Helpers + pauseTest, + resumeTest, + // Debug Helpers + getDebugInfo, + registerDebugInfoHelper, + // Test Framework APIs + setResolver, + getResolver, + setupContext, + getContext, + setContext, + unsetContext, + teardownContext, + setupRenderingContext, + getApplication, + setApplication, + setupApplicationContext, + validateErrorHandler, + setupOnerror, + resetOnerror, + getTestMetadata, + // deprecation and warning APIs + getDeprecations, + getDeprecationsDuringCallback, + getWarnings, + getWarningsDuringCallback, + BaseContext, + TestContext, + TestMetadata, + DebugInfo as InternalDebugInfo, + DeprecationFailure, + Warning, +} from '@ember/test-helpers'; +import { ComponentInstance } from '@glimmer/interfaces'; +import { Owner } from '@ember/test-helpers/build-owner'; +import { DebugInfo as BackburnerDebugInfo } from '@ember/runloop/-private/backburner'; +import EmberResolver from 'ember-resolver'; +import Application from '@ember/application'; +import { TemplateFactory } from 'ember-cli-htmlbars'; + +type Target = string | Element | Document | Window; + +// DOM Interaction Helpers +expectTypeOf(blur).toEqualTypeOf<(target?: Target) => Promise>(); +expectTypeOf(click).toEqualTypeOf< + (target: Target, options?: MouseEventInit) => Promise +>(); +expectTypeOf(doubleClick).toEqualTypeOf< + (target: Target, options?: MouseEventInit) => Promise +>(); +expectTypeOf(fillIn).toEqualTypeOf< + (target: Target, text: string) => Promise +>(); +expectTypeOf(focus).toEqualTypeOf<(target: Target) => Promise>(); +expectTypeOf(scrollTo).toEqualTypeOf< + (target: string | HTMLElement, x: number, y: number) => Promise +>(); +expectTypeOf(select).toEqualTypeOf< + ( + target: Target, + options: string | string[], + keepPreviouslySelected?: boolean + ) => Promise +>(); +expectTypeOf(tap).toEqualTypeOf< + (target: Target, options?: TouchEventInit) => Promise +>(); +expectTypeOf(triggerEvent).toEqualTypeOf< + (target: Target, eventType: string, options?: object) => Promise +>(); +expectTypeOf(triggerKeyEvent).toEqualTypeOf< + ( + target: Target, + eventType: 'keydown' | 'keyup' | 'keypress', + key: number | string, + modifiers?: { + ctrlKey?: boolean; + altKey?: boolean; + shiftKey?: boolean; + metaKey?: boolean; + } + ) => Promise +>(); +expectTypeOf(typeIn).toEqualTypeOf< + ( + target: Target, + text: string, + options?: { + delay?: number; + } + ) => Promise +>(); + +// DOM Query Helpers +expectTypeOf(find).toEqualTypeOf<(selector: string) => Element | null>(); +expectTypeOf(findAll).toEqualTypeOf<(selector: string) => Array>(); +expectTypeOf(getRootElement).toEqualTypeOf<() => Element | Document>(); + +// Routing Helpers +expectTypeOf(visit).toEqualTypeOf< + (url: string, options?: Record) => Promise +>(); +expectTypeOf(currentRouteName).toEqualTypeOf<() => string>(); +expectTypeOf(currentURL).toEqualTypeOf<() => string>(); + +// Rendering Helpers +expectTypeOf(render).toMatchTypeOf< + ( + templateOrComponent: TemplateFactory | ComponentInstance, + options?: { owner?: Owner } + ) => Promise +>(); +expectTypeOf(clearRender).toEqualTypeOf<() => Promise>(); + +// Wait Helpers +expectTypeOf(waitFor).toEqualTypeOf< + ( + selector: string, + options?: { + timeout?: number; + count?: number | null; + timeoutMessage?: string; + } + ) => Promise> +>(); +expectTypeOf(waitUntil).toEqualTypeOf< + ( + callback: () => T | void | false | 0 | '' | null | undefined, + options?: { + timeout?: number; + timeoutMessage?: string; + } + ) => Promise +>(); +expectTypeOf(settled).toEqualTypeOf<() => Promise>(); +expectTypeOf(isSettled).toEqualTypeOf<() => boolean>(); +expectTypeOf(getSettledState).toEqualTypeOf< + () => { + hasRunLoop: boolean; + hasPendingTimers: boolean; + hasPendingWaiters: boolean; + hasPendingRequests: boolean; + hasPendingTransitions: boolean | null; + isRenderPending: boolean; + pendingRequestCount: number; + debugInfo?: InternalDebugInfo; + } +>(); + +// Pause Helpers +expectTypeOf(pauseTest).toEqualTypeOf<() => Promise>(); +expectTypeOf(resumeTest).toEqualTypeOf<() => void>(); + +// Debug Helpers +expectTypeOf(getDebugInfo).toEqualTypeOf<() => BackburnerDebugInfo | null>(); +expectTypeOf(registerDebugInfoHelper).toEqualTypeOf< + (debugInfoHelper: { name: string; log: () => void }) => void +>(); + +// Test Framework APIs +expectTypeOf(setResolver).toEqualTypeOf<(resolver: EmberResolver) => void>(); +expectTypeOf(getResolver).toEqualTypeOf<() => EmberResolver | undefined>(); +expectTypeOf(setupContext).toEqualTypeOf< + ( + context: BaseContext, + options?: { resolver?: EmberResolver } + ) => Promise +>(); +expectTypeOf(getContext).toEqualTypeOf<() => BaseContext | undefined>(); +expectTypeOf(setContext).toEqualTypeOf<(context: BaseContext) => void>(); +expectTypeOf(unsetContext).toEqualTypeOf<() => void>(); +expectTypeOf(teardownContext).toEqualTypeOf< + ( + context: TestContext, + options?: { waitForSettled?: boolean } + ) => Promise +>(); +expectTypeOf(setupRenderingContext).toEqualTypeOf< + (context: TestContext) => Promise +>(); +expectTypeOf(getApplication).toEqualTypeOf<() => Application | undefined>(); +expectTypeOf(setApplication).toEqualTypeOf< + (application: Application) => void +>(); +expectTypeOf(setupApplicationContext).toEqualTypeOf< + (context: TestContext) => Promise +>(); +expectTypeOf(validateErrorHandler).toMatchTypeOf< + ( + callback?: (error: Error) => void + ) => + | Readonly<{ isValid: true; message: null }> + | Readonly<{ isValid: false; message: string }> +>(); +expectTypeOf(setupOnerror).toEqualTypeOf< + (onError?: (error: Error) => void) => void +>(); +expectTypeOf(resetOnerror).toEqualTypeOf<() => void>(); +expectTypeOf(getTestMetadata).toEqualTypeOf< + (context: BaseContext) => TestMetadata +>(); + +// deprecation and warning APIs +expectTypeOf(getDeprecations).toEqualTypeOf<() => Array>(); +expectTypeOf(getDeprecationsDuringCallback).toEqualTypeOf< + ( + callback: () => void + ) => Array | Promise> +>(); +expectTypeOf(getWarnings).toEqualTypeOf<() => Array>(); +expectTypeOf(getWarningsDuringCallback).toEqualTypeOf< + (callback: () => void) => Array | Promise> +>(); diff --git a/tests/unit/test-metadata-test.js b/tests/unit/test-metadata-test.js index d4837a8bc..5d5622bab 100644 --- a/tests/unit/test-metadata-test.js +++ b/tests/unit/test-metadata-test.js @@ -1,13 +1,13 @@ import QUnit, { module, test } from 'qunit'; import { getTestMetadata } from '@ember/test-helpers'; -import { TestMetadata } from '@ember/test-helpers/test-metadata'; +import { __TestMetadata } from '@ember/test-helpers/test-metadata'; module('Test Metadata', function () { test('getTestMetadata returns default test metadata', function (assert) { let test = QUnit.config.current; let testMetadata = getTestMetadata(test); - assert.ok(testMetadata instanceof TestMetadata); + assert.ok(testMetadata instanceof __TestMetadata); assert.deepEqual(testMetadata.setupTypes, []); }); diff --git a/tsconfig.json b/tsconfig.json index 26310d93b..27ab413da 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,49 +1,13 @@ { + "extends": "@tsconfig/ember/tsconfig.json", "compilerOptions": { - "target": "es2019", - "allowJs": false, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "noImplicitAny": true, - "noImplicitThis": true, - "alwaysStrict": true, - "strictNullChecks": true, - "strictPropertyInitialization": true, - "noFallthroughCasesInSwitch": true, - "noUnusedLocals": true, - "noUnusedParameters": false, - "noImplicitReturns": true, - "noEmitOnError": false, - "noEmit": true, - "declaration": true, - "inlineSourceMap": true, - "inlineSources": true, - "module": "ES2015", "paths": { - "dummy/tests/*": [ - "./tests/*" - ], - "dummy/*": [ - "./tests/dummy/app/*", - "./app/*" - ], - "@ember/test-helpers": [ - "./addon-test-support/@ember/test-helpers" - ], - "@ember/test-helpers/*": [ - "./addon-test-support/@ember/test-helpers/*" - ], - "@ember/destroyable": ["./node_modules/ember-destroyable-polyfill"], - "*": [ - "./types/*", - "./node_modules/@types/*" - ] + "dummy/tests/*": ["./tests/*"], + "dummy/*": ["./tests/dummy/app/*", "./app/*"], + "@ember/test-helpers": ["./addon-test-support/@ember/test-helpers"], + "@ember/test-helpers/*": ["./addon-test-support/@ember/test-helpers/*"], + "*": ["./types/*"] } }, - "exclude": [ - "node_modules" - ], - "include": [ - "./addon-test-support/**/*.ts" - ] + "include": ["./addon-test-support/**/*.ts", "tests/**/*.ts"] } diff --git a/types.tsconfig.json b/types.tsconfig.json new file mode 100644 index 000000000..074a04244 --- /dev/null +++ b/types.tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + // Use TS to emit declarations + "noEmit": false, + "emitDeclarationOnly": true, + "outDir": "public-types" + } +} diff --git a/types/@ember/runloop.d.ts b/types/@ember/runloop.d.ts deleted file mode 100644 index d3b6cb069..000000000 --- a/types/@ember/runloop.d.ts +++ /dev/null @@ -1,374 +0,0 @@ -/** - * Temporarily copying these types into @ember/test-helpers until - * https://github.com/DefinitelyTyped/DefinitelyTyped/pull/32970 lands. - */ -import { RunMethod, EmberRunQueues } from '@ember/runloop/-private/types'; -import { EmberRunTimer } from '@ember/runloop/types'; - -export interface QueueItem { - method: string; - target: object; - args: object[]; - stack: string | undefined; -} - -export interface DeferredActionQueues { - [index: string]: any; - queues: object; - schedule( - queueName: string, - target: any, - method: any, - args: any, - onceFlag: boolean, - stack: any - ): any; - flush(fromAutorun: boolean): any; -} - -export interface DebugInfo { - autorun: Error | undefined | null; - counters: object; - timers: QueueItem[]; - instanceStack: DeferredActionQueues[]; -} - -export interface Backburner { - currentInstance: DeferredActionQueues | null; - hasTimers(): boolean; - join(...args: any[]): void; - on(...args: any[]): void; - scheduleOnce(...args: any[]): void; - schedule( - queueName: string, - target: object | null, - method: () => void | string - ): void; - ensureInstance(): void; - DEBUG: boolean; - getDebugInfo(): DebugInfo; -} - -export interface RunNamespace { - /** - * 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[]; - - backburner: Backburner; -} - -export const _backburner: Backburner; -export const run: RunNamespace; -export const begin: typeof run.begin; -export const bind: typeof run.bind; -export const cancel: typeof run.cancel; -export const debounce: typeof run.debounce; -export const end: typeof run.end; -export const join: typeof run.join; -export const later: typeof run.later; -export const next: typeof run.next; -export const once: typeof run.once; -export const schedule: typeof run.schedule; -export const scheduleOnce: typeof run.scheduleOnce; -export const throttle: typeof run.throttle; diff --git a/yarn.lock b/yarn.lock index a913c62a9..8aa60c807 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2168,6 +2168,11 @@ dependencies: defer-to-connect "^2.0.0" +"@tsconfig/ember@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@tsconfig/ember/-/ember-1.0.1.tgz#d7556d81f108438c17e4030acb4e1be6b2974e88" + integrity sha512-aPzLw5BfQxsFPrh5fNDOK4SbSkp2q5fMlrKVeniVjMz1lAcyOh2eH5THkKKcBi1YN1/fbMdAWN/dKGW6lg2+8g== + "@types/acorn@^4.0.3": version "4.0.6" resolved "https://registry.yarnpkg.com/@types/acorn/-/acorn-4.0.6.tgz#d61ca5480300ac41a7d973dd5b84d0a591154a22" @@ -2227,6 +2232,13 @@ resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== +"@types/ember-resolver@*": + version "5.0.11" + resolved "https://registry.yarnpkg.com/@types/ember-resolver/-/ember-resolver-5.0.11.tgz#db931fb5c2d6bda4e29adea132fb48c7ed17aa62" + integrity sha512-2BL9d8kBdNUO9Je6KBF7Q34BSwbQG6vzCzTeSopt8FAmLDfaDU9xDDdyZobpfy9GR36mCSeG9b9wr4bgYh/MYw== + dependencies: + "@types/ember__object" "*" + "@types/ember-testing-helpers@^0.0.4": version "0.0.4" resolved "https://registry.yarnpkg.com/@types/ember-testing-helpers/-/ember-testing-helpers-0.0.4.tgz#d305b418d477c6f84fcd4dcb851a3efadbc4a2bd" @@ -2235,17 +2247,16 @@ "@types/jquery" "*" "@types/rsvp" "*" -"@types/ember@^3.16.5": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@types/ember/-/ember-3.16.5.tgz#c2d6b0f178761c0c2fbc6fc39b4b6958c256d0ac" - integrity sha512-8BzT1g8r7xQsN2p7qIUZ0AXWEVpJ5LmaRWP3iT79PLyIQfTAYvHSueUl14lrB8renETjwr4+ZvVPKurn9TKxNA== +"@types/ember@*", "@types/ember@~4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/ember/-/ember-4.0.0.tgz#0c29294fa0e5aa07ba6090f60243707dde8fc411" + integrity sha512-IR4o8OkFgoiRKVLRI8URvyNhEBSkjO5DXp2900/TptxOl0Retu8/tKtFaRTwkqteg2a0/6zXAA1rpFb3BbxNpA== dependencies: "@types/ember__application" "*" "@types/ember__array" "*" "@types/ember__component" "*" "@types/ember__controller" "*" "@types/ember__debug" "*" - "@types/ember__destroyable" "*" "@types/ember__engine" "*" "@types/ember__error" "*" "@types/ember__object" "*" @@ -2258,131 +2269,136 @@ "@types/ember__test" "*" "@types/ember__utils" "*" "@types/htmlbars-inline-precompile" "*" - "@types/jquery" "*" "@types/rsvp" "*" -"@types/ember__application@*": - version "3.16.3" - resolved "https://registry.yarnpkg.com/@types/ember__application/-/ember__application-3.16.3.tgz#f16e852b3200d5601b6f073be5a030cfadebb778" - integrity sha512-kx7euIQ+zy7EjyBMoWTOMPxkbGmLitwKp7Cxga2xeKnpMPrZCIaLcFM50XnbnbjzmlSMmJEn5EDIEYwlqnfzvg== +"@types/ember__application@*", "@types/ember__application@~4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/ember__application/-/ember__application-4.0.0.tgz#a4d2fead37845550dad83bb1fd8afd52052563a7" + integrity sha512-1Atwevfyu1/vjiezPPdP4s96BxWGelEQlCJRU5ZQV9WlzVuMTuCDPumZ1lQdS4/EYycFZeod030FjE3CT9mZFA== dependencies: + "@types/ember" "*" + "@types/ember-resolver" "*" "@types/ember__application" "*" "@types/ember__engine" "*" "@types/ember__object" "*" "@types/ember__routing" "*" "@types/ember__array@*": - version "3.16.4" - resolved "https://registry.yarnpkg.com/@types/ember__array/-/ember__array-3.16.4.tgz#d61b5b876e4976de03aa027ea89cb48cd640d49d" - integrity sha512-K21LKDNDW3ug0fLsFUTHZPyaFnzUUZEOtsmzmmeXKI6apJcoaz/yF3V0fvM2FUWNLs6rXB3PXegtzik6lq44Yw== + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/ember__array/-/ember__array-4.0.1.tgz#b62126ed080b29351a5633bd28e595a5cfee27ce" + integrity sha512-fwrYcYmFbsEnu77Xn9z3WSAp6tqpwn8Wksx8RzGg5pib6VmFD/dkT5jefwoKtlcImsxUNEoP1VgWKrdrpGaQcg== dependencies: + "@types/ember" "*" "@types/ember__array" "*" "@types/ember__object" "*" -"@types/ember__component@*": - version "3.16.6" - resolved "https://registry.yarnpkg.com/@types/ember__component/-/ember__component-3.16.6.tgz#affc4798ee97f58747f5d173b8f739ddab26e551" - integrity sha512-Zi82wppu0wtijXKAsyn75KBauJKIIHoYk5cbk7OmOKE2zmV1qzCfsxjM8x9iTJpu97T1P0vXWZ91aXM7KeQFMw== +"@types/ember__component@*", "@types/ember__component@~4.0.8": + version "4.0.8" + resolved "https://registry.yarnpkg.com/@types/ember__component/-/ember__component-4.0.8.tgz#09a5f954f734fcbe6c988a173f4de4fa09084470" + integrity sha512-YVGn/kpWtpZAu6I2XtS9fsZV+78/sON5NyKzK5EOUyMiCwwpbUr5XL8dTSdkHehYrsfzJikcYvqpmwbNZSJxGQ== dependencies: + "@types/ember" "*" "@types/ember__component" "*" "@types/ember__object" "*" - "@types/jquery" "*" "@types/ember__controller@*": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@types/ember__controller/-/ember__controller-3.16.5.tgz#29a7b9fb11bc940097964d84d11945b89f713226" - integrity sha512-T+MJI6HMJ/HOf91Eq/nhESNPLHeUwIacidTiLZiLysMWzbrcT9Opih8+vf7V6CNTxaWfMiSWn5iSB2WblhzLyw== + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/ember__controller/-/ember__controller-4.0.0.tgz#f8891840ebb84cb54eba82385e3b2dbe805d692a" + integrity sha512-rxJt8McWaaIZFsu2z+IB7TvgSjglAPb07Pj0F7OGvZQ3j9NV7kreqqics/cHQIEBG3GgVAewBE+xI5D6PNq/vg== dependencies: "@types/ember__object" "*" -"@types/ember__debug@*": - version "3.16.4" - resolved "https://registry.yarnpkg.com/@types/ember__debug/-/ember__debug-3.16.4.tgz#b5fca2a568505f7e0a39b5ab5f489f8d32990caf" - integrity sha512-Tlz6TB2nRbRczGa+v2+nGPvF8Cw0WRp29t3uT6Ryog6W2Alocqclsqc57EsGgLi1g4jEPP53NUI3dIJGa3AUig== +"@types/ember__debug@*", "@types/ember__debug@~4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/ember__debug/-/ember__debug-4.0.1.tgz#1e4a8a1045484295dddc7bd4356d0b3014b0d509" + integrity sha512-qrKk6Ujh6oev7TSB0eB7AEmQWKCt5t84k/K3hDvJXUiLU3YueN0kyt7aPoIAkVjC111A9FqDugl9n60+N5yeEw== dependencies: + "@types/ember-resolver" "*" "@types/ember__debug" "*" - "@types/ember__engine" "*" "@types/ember__object" "*" -"@types/ember__destroyable@*": - version "3.22.0" - resolved "https://registry.yarnpkg.com/@types/ember__destroyable/-/ember__destroyable-3.22.0.tgz#2af2c27f5d8996694c3f0fe906e2536b2e4c5aca" - integrity sha512-T5wZGK1MwEelNIv1bbAvRQZPo9zvfjpGyyFPwjz+sakjImKVcQzb/yq1SgGyT0QTAQAT7l0L+kFru9+fSVVo5A== +"@types/ember__destroyable@~4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/ember__destroyable/-/ember__destroyable-4.0.0.tgz#997af44863323979796fbd153e9ad76498defb33" + integrity sha512-QxyRhCOlQmc056tbWvHOQZ7vIjlFOFYMOU82P3pcCFfxyi55+NRhj4ySruymcBCfrzKQmVQLCbbOGhyFMLqq0Q== -"@types/ember__engine@*": - version "3.16.3" - resolved "https://registry.yarnpkg.com/@types/ember__engine/-/ember__engine-3.16.3.tgz#f61114922ed7d1a65f468bfd3e9dd5b128f32822" - integrity sha512-D9cLOlkQjT+b+9vszgAfxnTelx1H/GiL9FNmPcYQbLd+Ta8+FdKssb2Vt4DbHZrc5MsBJ8LMRs5/xPhkHuCDMA== +"@types/ember__engine@*", "@types/ember__engine@~4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/ember__engine/-/ember__engine-4.0.0.tgz#e39c06d98c7a085912508e8257c48a70196c1a87" + integrity sha512-AfJHIWaBeZ+TZWJbSoUz7LK+z8uNPjMqmucz8C5u+EV2NDiaq02oGPTB4SeKInLNBMga8c5xvz0gVefZJnTBnQ== dependencies: + "@types/ember-resolver" "*" "@types/ember__engine" "*" "@types/ember__object" "*" "@types/ember__error@*": - version "3.16.1" - resolved "https://registry.yarnpkg.com/@types/ember__error/-/ember__error-3.16.1.tgz#752d977f4ee35d4fa66bcfeebae6e85240fc62a6" - integrity sha512-bnB58krc18B8qgSMsRBbrVbNb4msyb8pMzS9Yo3brw/bRjuPb1ONUrjieAVHeespXlXNJOusvvX/pji641iCPQ== + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/ember__error/-/ember__error-4.0.0.tgz#c73037e65c1c3d7060b97f98135ba73c712972b1" + integrity sha512-1WVMR65/QTqPzMWafK2vKEwGafILxRxItbWJng6eEJyKDHRvvHFCl3XzJ4dQjdFcfOlozsn0mmEYCpjKoyzMqA== -"@types/ember__object@*": - version "3.12.6" - resolved "https://registry.yarnpkg.com/@types/ember__object/-/ember__object-3.12.6.tgz#5f77662881e3c6f877d63e08b46861c52a36714a" - integrity sha512-LAGldyJmFpErWLCm1HOAGd3G4E7Sem+AzQycKH+zSiYSwKVxNSpzUIU1yewlScHn5WvKwLEVE2H6mPvwvkQ+yA== +"@types/ember__object@*", "@types/ember__object@~4.0.2": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/ember__object/-/ember__object-4.0.2.tgz#070f1a36961f7df777e1fceed2551a648db0fd23" + integrity sha512-m3xjqjs7bGVT0+QXlgIoDMsp/oqePobnf4IiVoFdXLBpGCICiOAEi7HuUtCLi57WTvx0lYsS9hE1vgGyZn9qnw== dependencies: + "@types/ember" "*" "@types/ember__object" "*" "@types/rsvp" "*" -"@types/ember__polyfills@*": - version "3.12.1" - resolved "https://registry.yarnpkg.com/@types/ember__polyfills/-/ember__polyfills-3.12.1.tgz#aed838e35a3e8670d247333d4c7ea2c2f7b3c43e" - integrity sha512-Xw9RxFizB8guT6YGg3VNi5tjbzAjqk+bLtAJ1oVl2I1FylKrRFh0bwobxT2K0BF/i0QFEYlqckHpN/OoCpkvkA== +"@types/ember__polyfills@*", "@types/ember__polyfills@~4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/ember__polyfills/-/ember__polyfills-4.0.0.tgz#d83ae94ff2890ad47798315426d9916f39ff4ae6" + integrity sha512-Yk85J18y1Ys6agoIBLdJWu6ZkWe68oaC9JPyW7BhOINVNKm89PXrR/yxdOJ1/vN1Hj7ZZQKq+4X6fz3sxebavA== -"@types/ember__routing@*": - version "3.16.15" - resolved "https://registry.yarnpkg.com/@types/ember__routing/-/ember__routing-3.16.15.tgz#14e7e98ae331d05b19aacc29c9759c9f3dc222ec" - integrity sha512-M+QujBvUQZJgcLo/vj1aYVdEZaQWxuD+GM2CLp2jmkb4RYGhdYPuNYK7KkDMhJH5vMICOeK7KVVKrmN1KhAQHg== +"@types/ember__routing@*", "@types/ember__routing@~4.0.7": + version "4.0.7" + resolved "https://registry.yarnpkg.com/@types/ember__routing/-/ember__routing-4.0.7.tgz#16cc442fcee2dda06dc79bb3d7fd5002f154ad07" + integrity sha512-iWsk8C0WIqqK6dgK1UdJisyQLs6rVq/+A2f7fXjdLJHA+SAHK8aqfCHHFkTuiy4sXkM/PBINmP9qHpk4KrScbw== dependencies: - "@types/ember__component" "*" + "@types/ember" "*" "@types/ember__controller" "*" "@types/ember__object" "*" "@types/ember__routing" "*" "@types/ember__service" "*" -"@types/ember__runloop@*": - version "3.16.3" - resolved "https://registry.yarnpkg.com/@types/ember__runloop/-/ember__runloop-3.16.3.tgz#c37ed507aed0f642ef19cbc4b5d0b3a167e3ada6" - integrity sha512-iYT7+9z6lVOi4RSyM9tBwIOidRI0Y5nyaRtIMP1DhP8n2UZjvVG6ao4PkpFnpFWR4R8Ajj2p13SaPGxpEV62jg== +"@types/ember__runloop@*", "@types/ember__runloop@~4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/ember__runloop/-/ember__runloop-4.0.1.tgz#7f6e45af7dbf1158655ef3ad852852b0bf87065f" + integrity sha512-3HrsavVrdgxUkYptQUv/e9RwJG02cV9WbnJxKSvwl9ZYpeX4JbuDVucjTWk5BAvJUVtbiQLPGzLEHZ6daoCbbg== dependencies: + "@types/ember" "*" "@types/ember__runloop" "*" -"@types/ember__service@*": - version "3.16.1" - resolved "https://registry.yarnpkg.com/@types/ember__service/-/ember__service-3.16.1.tgz#e8f941ec50ff4a7531487dc60830b4e6c7da6a47" - integrity sha512-XYl75IZGE+ZqRiCr9tBLXNYBVM9WX18AQHw/73QSQP/7sfyv5QFP/C/KvJrwP9wJmqh0BS2lVAXP3Nx4/BRNTw== +"@types/ember__service@*", "@types/ember__service@~4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/ember__service/-/ember__service-4.0.0.tgz#ae6164e3b5d927fe17513b49867b52dc0222490d" + integrity sha512-FbN2y6tRb6NIV+kmzQcxRAoB17vH7qHCfzcKlxsmt2EI7fboLTcdeKpZKPBEromRXg83fx67QX1b95WcwSGtaw== dependencies: "@types/ember__object" "*" "@types/ember__string@*": - version "3.16.3" - resolved "https://registry.yarnpkg.com/@types/ember__string/-/ember__string-3.16.3.tgz#6c474d422dfae5c382a3c52bd3c994048d04b72e" - integrity sha512-0T9ofzm9LL/bSG5u1SxKx/j2h/bHKkl5NKjGCNbFQxEKBw4f2cs6+AMDgWke9z+qrRRIz9vGEtMXnA3yJrO2xA== - dependencies: - "@types/ember__template" "*" + version "3.0.9" + resolved "https://registry.yarnpkg.com/@types/ember__string/-/ember__string-3.0.9.tgz#669188ccea5a61777a36bf88a05ba6875dc9b7d7" + integrity sha512-v9QwhhfTTgJH6PCviWlz3JgcraYdSWQoTg2XN5Z7bPgXMJYXczxB/N22L9FnuFgDYdN87yXdTJv6E9rw2YGEhw== "@types/ember__template@*": - version "3.16.1" - resolved "https://registry.yarnpkg.com/@types/ember__template/-/ember__template-3.16.1.tgz#30d7f50a49b190934db0f5a56dd76ad86c21efc6" - integrity sha512-APQINizzizl2LHWGMFBCanRjKZQsdzqn7b+us17zbNhnx/R0IZAJq901x/i7eozCRwxsDKmGzNABSCIu6uc1Tg== + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/ember__template/-/ember__template-4.0.0.tgz#3423b6ddc3a6cf0b13a1e0fd5f1a84eec664a095" + integrity sha512-51bAEQecMKpDYRXMmVVfU7excrtxDJixRU7huUsAm4acBCqL2+TmMgTqZEkOQSNy6qnKUc2ktSzX28a9//C6pA== -"@types/ember__test@*": - version "3.16.1" - resolved "https://registry.yarnpkg.com/@types/ember__test/-/ember__test-3.16.1.tgz#8407e42b9835a13ef0c6ef7a7ce3aa3d7ebcb7ed" - integrity sha512-0ICnkM4BDwOKhqmLQRpfvNuZlb6QOqE+FhP5fPaWXWy7bgcL9CY7kMRc7N+wZQbTvbSKqgEdfbvjd0bJsIrz5w== +"@types/ember__test@*", "@types/ember__test@~4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/ember__test/-/ember__test-4.0.0.tgz#1a7dcbe24fedfc34fa60547b03f130a14397c4b6" + integrity sha512-vI/qhZkexJLN25lp1UAfjJv4R6pPtrQlAmPDXkKd8PNjwRk3KANFVRzdghN7HWhXgQ+s91PbvxEnZ3eZiRPdcQ== dependencies: "@types/ember__application" "*" "@types/ember__utils@*": - version "3.16.2" - resolved "https://registry.yarnpkg.com/@types/ember__utils/-/ember__utils-3.16.2.tgz#3fa9a0666a3e8204262e2a2960289aaf01f29467" - integrity sha512-tBbqewgegiKSpGZvGh3pbcoXwLCMvKVdLRE97vys75nAEz/vBzkGJm+PDz1HVaTkRukWbRhlDiTm2qFH8qRnSw== + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/ember__utils/-/ember__utils-4.0.0.tgz#a7e9e11334b5e203324e6155ff74c2b33ec21567" + integrity sha512-gwSFUm+6t6StkQxSllbn9lqRms/dXMCQDieRfaTGN8IRatnKjJoEPME3A0T6O9afsU6viBQyqlPyFxsOWknYkg== + dependencies: + "@types/ember" "*" "@types/eslint-scope@^3.7.0": version "3.7.1" @@ -7148,6 +7164,11 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2: dependencies: homedir-polyfill "^1.0.1" +expect-type@^0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/expect-type/-/expect-type-0.13.0.tgz#916646a7a73f3ee77039a634ee9035efe1876eb2" + integrity sha512-CclevazQfrqo8EvbLPmP7osnb1SZXkw47XPPvUUpeMz4HuGzDltE7CaIt3RLyT9UQrwVK/LDn+KVcC0hcgjgDg== + express@^4.10.7, express@^4.17.1: version "4.17.1" resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" @@ -13786,10 +13807,10 @@ typescript-memoize@^1.0.1: resolved "https://registry.yarnpkg.com/typescript-memoize/-/typescript-memoize-1.1.0.tgz#4a8f512d06fc995167c703a3592219901db8bc79" integrity sha512-LQPKVXK8QrBBkL/zclE6YgSWn0I8ew5m0Lf+XL00IwMhlotqRLlzHV+BRrljVQIc+NohUAuQP7mg4HQwrx5Xbg== -typescript@^4.3.5: - version "4.3.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" - integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== +typescript@^4.7.4: + version "4.7.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" + integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6"