diff --git a/ember-resources/package.json b/ember-resources/package.json index 0dbacfaec..aef9cc157 100644 --- a/ember-resources/package.json +++ b/ember-resources/package.json @@ -10,9 +10,7 @@ "exports": { ".": "./dist/index.js", "./core": "./dist/core/index.js", - "./core/class-based": "./dist/core/class-based/index.js", "./core/function-based": "./dist/core/function-based/index.js", - "./link": "./dist/link.js", "./modifier": "./dist/modifier/index.js", "./addon-main.js": "./addon-main.cjs" }, @@ -24,12 +22,6 @@ "core": [ "dist/core/index.d.ts" ], - "link": [ - "dist/link.d.ts" - ], - "service": [ - "dist/service.d.ts" - ], "modifier": [ "dist/modifier/index.d.ts" ] diff --git a/ember-resources/src/link.ts b/ember-resources/src/link.ts deleted file mode 100644 index 46c40f9cd..000000000 --- a/ember-resources/src/link.ts +++ /dev/null @@ -1,208 +0,0 @@ -import { getOwner, setOwner } from '@ember/application'; -import { deprecate } from '@ember/debug'; -import { assert } from '@ember/debug'; -import { associateDestroyableChild } from '@ember/destroyable'; - -import type { Class, Stage1Decorator, Stage1DecoratorDescriptor } from '[core-types]'; - -deprecate( - `importing from 'ember-resources/link' is deprecated and will be removed in ember-resources@v7. ` + - `The exact same code and support is available at https://github.com/universal-ember/reactiveweb. ` + - `\`pnpm add reactiveweb\` and then \` import { link } from 'reactiveweb/link';\`. ` + - `See also: https://github.com/NullVoxPopuli/ember-resources/issues/1061`, - false, - { - id: `ember-resources.link`, - until: `7.0.0`, - for: `ember-resources`, - url: `https://reactive.nullvoxpopuli.com/functions/link.link.html`, - since: { - available: '6.4.4', - enabled: '6.4.4', - }, - }, -); - -type NonKey = K extends string ? never : K extends symbol ? never : K; - -/** - *
- * - * This is not a core part of ember-resources, but is a useful utility when working with Resources. This utility is still under the broader library's SemVer policy. - * - * A consuming app will not pay for the bytes of this utility unless imported. - * - *
- * - * A util to abstract away the boilerplate of linking of "things" with an owner - * and making them destroyable. - * - * ```js - * import Component from '@glimmer/component'; - * import { link } from 'ember-resources/link'; - * - * class MyClass { ... } - * - * export default class Demo extends Component { - * @link(MyClass) myInstance; - * } - * ``` - */ -export function link(child: Class): Stage1Decorator; -/** - * @note This is not a core part of ember-resources, but is a useful utility when working with Resources. This utility is still under the broader library's SemVer policy. - * A consuming app will not pay for the bytes of this utility unless imported. - * - * A util to abstract away the boilerplate of linking of "things" with an owner - * and making them destroyable. - * - * ```js - * import Component from '@glimmer/component'; - * import { cached } from '@glimmer/tracking'; - * import { link } from 'ember-resources/link'; - * - * export default class Demo extends Component { - * @cached - * get myFunction() { - * let instance = new MyClass(this.args.foo); - * - * return link(instance, this); - * } - * } - * ``` - * - * NOTE: If args change, as in this example, memory pressure will increase, - * as the linked instance will be held on to until the host object is destroyed. - */ -export function link(child: Child, parent: NonKey): Child; - -/** - * @note This is not a core part of ember-resources, but is a useful utility when working with Resources. This utility is still under the broader library's SemVer policy. - * A consuming app will not pay for the bytes of this utility unless imported. - * - * A util to abstract away the boilerplate of linking of "things" with an owner - * and making them destroyable. - * - * ```js - * import Component from '@glimmer/component'; - * import { link } from 'ember-resources/link'; - * - * class MyClass { ... } - * - * export default class Demo extends Component { - * @link myInstance = new MyClass(); - * } - * ``` - * - * NOTE: reactive args may not be passed to `MyClass` directly if you wish updates to be observed. - * A way to use reactive args is this: - * - * ```js - * import Component from '@glimmer/component'; - * import { tracked } from '@glimmer/tracking'; - * import { link } from 'ember-resources/link'; - * - * class MyClass { ... } - * - * export default class Demo extends Component { - * @tracked foo = 'bar'; - * - * @link myInstance = new MyClass({ - * foo: () => this.args.foo, - * bar: () => this.bar, - * }); - * } - * ``` - * - * This way, whenever foo() or bar() is invoked within `MyClass`, - * only the thing that does that invocation will become entangled with the tracked data - * referenced within those functions. - */ -export function link(...args: Parameters): void; - -export function link(...args: any[]) { - if (args.length === 3) { - /** - * Uses initializer to get the child - */ - return linkDecorator(...(args as Parameters)); - } - - if (args.length === 1) { - return linkDecoratorFactory(...(args as unknown as [any])); - } - - // Because TS types assume property decorators might not have a descriptor, - // we have to cast.... - return directLink(...(args as unknown as [object, object])); -} - -function directLink(child: object, parent: object) { - associateDestroyableChild(parent, child); - - let owner = getOwner(parent); - - if (owner) { - setOwner(child, owner); - } - - return child; -} - -function linkDecoratorFactory(child: Class) { - return function decoratorPrep(...args: Parameters) { - return linkDecorator(...args, child); - }; -} - -function linkDecorator( - _prototype: object, - key: string | Symbol, - descriptor: Stage1DecoratorDescriptor | undefined, - explicitChild?: Class, -): void { - assert(`@link is a stage 1 decorator, and requires a descriptor`, descriptor); - assert(`@link can only be used with string-keys`, typeof key === 'string'); - - let { initializer } = descriptor; - - assert( - `@link requires an initializer or be used as a decorator factory (\`@link(...))\`). For example, ` + - `\`@link foo = new MyClass();\` or \`@link(MyClass) foo;\``, - initializer || explicitChild, - ); - - let caches = new WeakMap(); - - return { - get(this: object) { - let child = caches.get(this); - - if (!child) { - if (initializer) { - child = initializer.call(this); - } - - if (explicitChild) { - // How do you narrow this to a constructor? - child = new explicitChild(); - } - - assert(`Failed to create child instance.`, child); - - associateDestroyableChild(this, child); - - let owner = getOwner(this); - - assert(`Owner was not present on parent. Is instance of ${this.constructor.name}`, owner); - - setOwner(child, owner); - - caches.set(this, child); - assert(`Failed to create cache for internal resource configuration object`, child); - } - - return child; - }, - } as unknown as void /* Thanks TS. */; -} diff --git a/ember-resources/type-tests/link.test.ts b/ember-resources/type-tests/link.test.ts deleted file mode 100644 index d4067cc5f..000000000 --- a/ember-resources/type-tests/link.test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { expectTypeOf } from 'expect-type'; - -import { link } from '../src/link'; - -class Demo { - foo = 2; -} - -class A { - @link demo = new Demo(); -} - -expectTypeOf(new A().demo).toMatchTypeOf; - -class B { - @link(Demo) declare demo: Demo; -} - -expectTypeOf(new B().demo).toMatchTypeOf; - -let c = link(new Demo(), new Demo()); - -expectTypeOf(c).toMatchTypeOf; diff --git a/test-app/tests/link-test.ts b/test-app/tests/link-test.ts deleted file mode 100644 index d1649ebb5..000000000 --- a/test-app/tests/link-test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { setOwner } from '@ember/application'; -import Service, { inject as service } from '@ember/service'; -import { module, test } from 'qunit'; -import { setupTest } from 'ember-qunit'; - -import { link } from 'ember-resources/link'; - -module('@link', function (hooks) { - setupTest(hooks); - - class FooService extends Service { - bar = 2; - } - - test('works with no initializer', async function (assert) { - this.owner.register('service:foo', FooService); - - class Demo { - @service declare foo: FooService; - } - - class TestDemo { - @link(Demo) declare demo: Demo; - } - - let testDemo = new TestDemo(); - - setOwner(testDemo, this.owner); - - assert.strictEqual(testDemo.demo.foo.bar, 2); - }); - - test('works with initializer', async function (assert) { - this.owner.register('service:foo', FooService); - - class Demo { - @service declare foo: FooService; - } - - class TestDemo { - @link demo = new Demo(); - } - - let testDemo = new TestDemo(); - - setOwner(testDemo, this.owner); - - assert.strictEqual(testDemo.demo.foo.bar, 2); - }); -}); - -module('link', function (hooks) { - setupTest(hooks); - - class FooService extends Service { - foo = 2; - } - - test('it works', async function (assert) { - this.owner.register('service:foo', FooService); - - class Demo { - @service declare foo: FooService; - } - - let demo = new Demo(); - - link(demo, this); - - assert.strictEqual(demo.foo.foo, 2); - }); -});