diff --git a/.vscode/settings.json b/.vscode/settings.json index 25fa6215..95fbfac4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "typescript.tsdk": "node_modules/typescript/lib" -} + "typescript.tsdk": "node_modules/typescript/lib", + "glint.libraryPath": "./ember-async-data" +} \ No newline at end of file diff --git a/ember-async-data/.prettierrc.js b/ember-async-data/.prettierrc.js index df5c6e8f..3fd864db 100644 --- a/ember-async-data/.prettierrc.js +++ b/ember-async-data/.prettierrc.js @@ -9,4 +9,5 @@ module.exports = { }, }, ], + plugins: ['prettier-plugin-ember-template-tag'], }; diff --git a/ember-async-data/babel.config.json b/ember-async-data/babel.config.json index cd53605c..57f48dc7 100644 --- a/ember-async-data/babel.config.json +++ b/ember-async-data/babel.config.json @@ -1,9 +1,14 @@ { - "presets": [["@babel/preset-typescript"]], + "presets": [ + [ + "@babel/preset-typescript" + ] + ], "plugins": [ + "ember-template-imports/src/babel-plugin", "@embroider/addon-dev/template-colocation-plugin", ["@babel/plugin-transform-typescript", { "allowDeclareFields": true }], ["@babel/plugin-proposal-decorators", { "version": "legacy" }], "@babel/plugin-proposal-class-properties" ] -} +} \ No newline at end of file diff --git a/ember-async-data/package.json b/ember-async-data/package.json index d354af0e..ad0e98fd 100644 --- a/ember-async-data/package.json +++ b/ember-async-data/package.json @@ -47,16 +47,17 @@ "@embroider/addon-dev": "^4.1.0", "@glimmer/component": "^1.1.2", "@glimmer/tracking": "^1.1.2", - "@glint/core": "^1.0.2", - "@glint/environment-ember-loose": "^1.0.2", - "@glint/template": "^1.0.2", + "@glint/core": "^1.1.0", + "@glint/environment-ember-loose": "^1.1.0", + "@glint/environment-ember-template-imports": "^1.1.0", + "@glint/template": "^1.1.0", "@rollup/plugin-babel": "^6.0.3", "@rollup/plugin-node-resolve": "^15.1.0", "@tsconfig/ember": "^2.0.0", "@typescript-eslint/eslint-plugin": "^6.2.1", "@typescript-eslint/parser": "^6.2.1", "concurrently": "^8.2.0", - "ember-source": "^4.12.3", + "ember-source": "^5.2.0", "ember-template-lint": "^5.11.2", "eslint": "^8.46.0", "eslint-config-prettier": "^8.8.0", diff --git a/ember-async-data/rollup-plugin-template-tag.mjs b/ember-async-data/rollup-plugin-template-tag.mjs new file mode 100644 index 00000000..530ec3e5 --- /dev/null +++ b/ember-async-data/rollup-plugin-template-tag.mjs @@ -0,0 +1,75 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import { preprocessEmbeddedTemplates } from "ember-template-imports/lib/preprocess-embedded-templates.js"; +import { + TEMPLATE_TAG_NAME, + TEMPLATE_TAG_PLACEHOLDER, +} from "ember-template-imports/lib/util.js"; + +export default function firstClassComponentTemplates() { + return { + name: "preprocess-fccts", + async resolveId(source, importer, options) { + if (source.endsWith(".hbs")) return; + + for (let ext of ["", ".gjs", ".gts"]) { + let result = await this.resolve(source + ext, importer, { + ...options, + skipSelf: true, + }); + + if (result?.external) { + return; + } + + if (FCCT_EXTENSION.test(result?.id)) { + return resolutionFor(result.id); + } + } + }, + + async load(id) { + let originalId = this.getModuleInfo(id)?.meta?.fccts?.originalId ?? id; + + if (originalId !== id) { + this.addWatchFile(originalId); + } + + if (FCCT_EXTENSION.test(originalId)) { + return await preprocessTemplates(originalId); + } + }, + }; +} + +const FCCT_EXTENSION = /\.g([jt]s)$/; + +function resolutionFor(originalId) { + return { + id: originalId.replace(FCCT_EXTENSION, ".$1"), + meta: { + fccts: { originalId }, + }, + }; +} + +async function preprocessTemplates(id) { + let ember = (await import("ember-source")).default; + let contents = await fs.readFile(id, "utf-8"); + + // This is basically taken directly from `ember-template-imports` + let result = preprocessEmbeddedTemplates(contents, { + relativePath: path.relative(".", id), + + getTemplateLocalsRequirePath: ember.absolutePaths.templateCompiler, + getTemplateLocalsExportPath: "_GlimmerSyntax.getTemplateLocals", + + templateTag: TEMPLATE_TAG_NAME, + templateTagReplacement: TEMPLATE_TAG_PLACEHOLDER, + + includeSourceMaps: true, + includeTemplateTokens: true, + }); + + return result.output; +} diff --git a/ember-async-data/rollup.config.mjs b/ember-async-data/rollup.config.mjs index b30b8cfd..319df228 100644 --- a/ember-async-data/rollup.config.mjs +++ b/ember-async-data/rollup.config.mjs @@ -1,14 +1,15 @@ import { babel } from '@rollup/plugin-babel'; import { nodeResolve } from '@rollup/plugin-node-resolve'; import { Addon } from '@embroider/addon-dev/rollup'; +import templateTag from './rollup-plugin-template-tag.mjs'; const addon = new Addon({ - srcDir: 'src', - destDir: 'dist', + srcDir: "src", + destDir: "dist", }); // Add extensions here, such as ts, gjs, etc that you may import -const extensions = ['.js', '.ts']; +const extensions = ['.js', '.ts', '.gjs', '.gts']; export default { // This provides defaults that work well alongside `publicEntrypoints` below. @@ -28,7 +29,9 @@ export default { // These are the modules that should get reexported into the traditional // "app" tree. Things in here should also be in publicEntrypoints above, but // not everything in publicEntrypoints necessarily needs to go here. - addon.appReexports(['helpers/**/*.js']), + addon.appReexports(["helpers/**/*.js"]), + + templateTag(), // Follow the V2 Addon rules about dependencies. Your code can import from // `dependencies` and `peerDependencies` as well as standard Ember-provided @@ -54,7 +57,7 @@ export default { // addons are allowed to contain imports of .css files, which we want rollup // to leave alone and keep in the published output. - addon.keepAssets(['**/*.css']), + addon.keepAssets(["**/*.css"]), // Remove leftover build artifacts when starting a new build. addon.clean(), diff --git a/ember-async-data/src/components/async.gts b/ember-async-data/src/components/async.gts new file mode 100644 index 00000000..eded8942 --- /dev/null +++ b/ember-async-data/src/components/async.gts @@ -0,0 +1,81 @@ +import Component from '@glimmer/component'; +import { cached } from '@glimmer/tracking'; +import TrackedAsyncData from '../tracked-async-data'; + +export interface AsyncSignature { + Args: { + /** The `TrackedAsyncData` to render. */ + data: T | Promise; + }; + Blocks: { + /** To render while waiting on the promise */ + pending: []; + /** To render once the promise has resolved, with the resolved value. */ + resolved: [value: T]; + /** To render if the promise has rejected, with the associated reason. */ + rejected: [reason: unknown]; + }; +} + +/** + Render a `TrackedAsyncData` in a template, with named blocks for each of the + states the value may be in. This is somewhat nicer than doing the same with + an `if`/`else if` chain, and composes nicely with other template primitives. + + It is also less error prone, in that you *cannot* access the value of the data + in the `pending` or `rejected` blocks: it is only yielded by the `resolved` + named block. + + ```ts + import { Async } from 'ember-async-data' + import LoadingSpinner from './loading-spinner'; + + function dumpError(error: unknown) { + return JSON.stringify(error); + } + + let example = new TrackedAsyncData("hello"); + + + ``` + */ +// IMPLEMENTATION NOTE: yes, future maintainer, this *does* have to be a class, +// not a template-only component. This is because it must be generic over the +// type passed in so that the yielded type can preserve that ("parametricity"). +// That is: if we pass in a `TrackedAsyncData`, the value yielded from +// the `resolved` named block should be a string. The only things which can +// preserve the type parameter that way are functions and classes, and we do not +// presently have a function-based way to define components, so we have to use +// a class instead to preserve the type! +export default class Async extends Component> { + @cached get data() { + return new TrackedAsyncData(this.args.data); + } + + +} diff --git a/ember-async-data/src/index.ts b/ember-async-data/src/index.ts index 4d16a81a..ef42a283 100644 --- a/ember-async-data/src/index.ts +++ b/ember-async-data/src/index.ts @@ -1,2 +1,3 @@ export { default as TrackedAsyncData } from './tracked-async-data'; export { load } from './helpers/load'; +export { default as Async } from './components/async'; diff --git a/ember-async-data/src/template-registry.ts b/ember-async-data/src/template-registry.ts index 49984c1c..8100b879 100644 --- a/ember-async-data/src/template-registry.ts +++ b/ember-async-data/src/template-registry.ts @@ -3,7 +3,9 @@ // See https://typed-ember.gitbook.io/glint/using-glint/ember/authoring-addons import type Load from './helpers/load'; +import type Async from './components/async'; export default interface Registry { load: typeof Load; + Async: typeof Async; } diff --git a/ember-async-data/src/tracked-async-data.ts b/ember-async-data/src/tracked-async-data.ts index cfeb4be9..a4c47dd9 100644 --- a/ember-async-data/src/tracked-async-data.ts +++ b/ember-async-data/src/tracked-async-data.ts @@ -182,6 +182,21 @@ class _TrackedAsyncData { toString(): string { return JSON.stringify(this.toJSON(), null, 2); } + + match(matcher: { + pending: () => V; + resolved: (value: T) => V; + rejected: (reason: unknown) => V; + }) { + switch (this.#state.data[0]) { + case 'PENDING': + return matcher.pending(); + case 'RESOLVED': + return matcher.resolved(this.#state.data[1]); + case 'REJECTED': + return matcher.rejected(this.#state.data[1]); + } + } } /** @@ -223,30 +238,38 @@ export type JSONRepr = // shared implementations (i.e. `.toJSON()` and `.toString()`) are shared // automatically. -interface Pending extends _TrackedAsyncData { +/** + A `TrackedAsyncData` whose wrapped promise is still pending, and which + therefore does not have a `value` or an `error` property. + */ +interface Pending extends Omit<_TrackedAsyncData, 'value' | 'error'> { state: 'PENDING'; isPending: true; isResolved: false; isRejected: false; - value: null; - error: null; } -interface Resolved extends _TrackedAsyncData { +/** + A `TrackedAsyncData` whose wrapped promise has resolved, and which therefore + has a `value` property with the value the promise resolved to. + */ +interface Resolved extends Omit<_TrackedAsyncData, 'error'> { state: 'RESOLVED'; isPending: false; isResolved: true; isRejected: false; value: T; - error: null; } -interface Rejected extends _TrackedAsyncData { +/** + A `TrackedAsyncData` whose wrapped promise has rejected, and which therefore + has an `error` property with the rejection value of the promise (if any). + */ +interface Rejected extends Omit<_TrackedAsyncData, 'value'> { state: 'REJECTED'; isPending: false; isResolved: false; isRejected: true; - value: null; error: unknown; } @@ -268,32 +291,39 @@ interface Rejected extends _TrackedAsyncData { import Component from '@glimmer/component'; import { cached } from '@glimmer/tracking'; import { inject as service } from '@ember/service'; - import TrackedAsyncData from 'ember-async-data/tracked-async-data'; + import type Store from '@ember-data/store'; + import { TrackedAsyncData, Match } from 'ember-async-data'; + import LoadingSpinner from './loading-spinner'; + import PresentTheData from './present-the-data'; + + interface ProfileSignature { + Args: { + id: number; + }; + } - export default class SmartProfile extends Component<{ id: number }> { - @service store; + export default class SmartProfile extends Component { + @service declare store: Store; - @cached - get someData() { + @cached get someData() { let recordPromise = this.store.findRecord('user', this.args.id); return new TrackedAsyncData(recordPromise); } - } - ``` - And a corresponding template: - - ```hbs - {{#if this.someData.isResolved}} - - {{else if this.someData.isPending}} - - {{else if this.someData.isRejected}} -

- Whoops! Looks like something went wrong! - {{this.someData.error.message}} -

- {{/if}} + + } ``` */ type TrackedAsyncData = Pending | Resolved | Rejected; diff --git a/ember-async-data/tsconfig.json b/ember-async-data/tsconfig.json index 2198eb8f..a406fa8a 100644 --- a/ember-async-data/tsconfig.json +++ b/ember-async-data/tsconfig.json @@ -1,11 +1,14 @@ { - "extends": "@tsconfig/ember/tsconfig.json", + "extends": "../tsconfig.json", "include": [ "src/**/*", "unpublished-development-types/**/*" ], "glint": { - "environment": "ember-loose" + "environment": [ + "ember-loose", + "ember-template-imports" + ] }, "compilerOptions": { "declarationDir": "declarations" diff --git a/package.json b/package.json index 76db645b..4409a5dd 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "prepare": "yarn build", "release": "release-it", "start": "concurrently 'npm:start:*' --restart-after 5000 --prefix-colors cyan,white,yellow", - "start:addon": "yarn workspace ember-async-data1 run start", + "start:addon": "yarn workspace ember-async-data run start", "start:test-app": "yarn workspace test-app run start", "test": "yarn workspaces run test" }, diff --git a/test-app/.eslintrc.js b/test-app/.eslintrc.js index 99e56414..87a7bc7a 100644 --- a/test-app/.eslintrc.js +++ b/test-app/.eslintrc.js @@ -10,7 +10,6 @@ module.exports = { extends: [ 'eslint:recommended', 'plugin:ember/recommended', - 'plugin:prettier/recommended', ], env: { browser: true, diff --git a/test-app/.prettierrc.js b/test-app/.prettierrc.js index e5f7b6d1..a84e4dbc 100644 --- a/test-app/.prettierrc.js +++ b/test-app/.prettierrc.js @@ -3,7 +3,7 @@ module.exports = { overrides: [ { - files: '*.{js,ts}', + files: '*.{js,ts,gjs,gts}', options: { singleQuote: true, }, diff --git a/test-app/package.json b/test-app/package.json index 74f961d6..3c008001 100644 --- a/test-app/package.json +++ b/test-app/package.json @@ -33,8 +33,10 @@ "@embroider/test-setup": "^3.0.1", "@glimmer/component": "^1.1.2", "@glimmer/tracking": "^1.1.2", - "@glint/environment-ember-loose": "^1.0.2", - "@glint/template": "^1.0.2", + "@glint/core": "^1.1.0", + "@glint/environment-ember-loose": "^1.1.0", + "@glint/environment-ember-template-imports": "^1.1.0", + "@glint/template": "^1.1.0", "@tsconfig/ember": "^2.0.0", "@types/qunit": "^2.19.6", "@types/rsvp": "^4.0.4", @@ -58,8 +60,9 @@ "ember-page-title": "^7.0.0", "ember-qunit": "^7.0.0", "ember-resolver": "^11.0.1", - "ember-source": "^4.12.3", + "ember-source": "^5.2.0", "ember-source-channel-url": "^3.0.0", + "ember-template-imports": "^3.4.2", "ember-template-lint": "^5.11.2", "ember-try": "^3.0.0", "eslint": "^8.46.0", diff --git a/test-app/tests/defer.ts b/test-app/tests/defer.ts index 2680e830..1ea319fa 100644 --- a/test-app/tests/defer.ts +++ b/test-app/tests/defer.ts @@ -1,20 +1,20 @@ -interface Deferred { - resolve: (value?: unknown) => void; +interface Deferred { + resolve: (value: T) => void; reject: (value?: unknown) => void; - promise: Promise; + promise: Promise; } -export function defer(): Deferred { +export function defer(): Deferred { const deferred = { resolve: undefined, reject: undefined, promise: undefined, - } as Partial; + } as Partial>; deferred.promise = new Promise((resolve, reject) => { deferred.resolve = resolve; deferred.reject = reject; }); - return deferred as Deferred; + return deferred as Deferred; } diff --git a/test-app/tests/integration/components/async-test.gts b/test-app/tests/integration/components/async-test.gts new file mode 100644 index 00000000..cb276329 --- /dev/null +++ b/test-app/tests/integration/components/async-test.gts @@ -0,0 +1,300 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, waitFor } from '@ember/test-helpers'; +import { defer } from '../../defer'; +import { Async } from 'ember-async-data'; +import { tracked } from '@glimmer/tracking'; + +class State { + @tracked promise: Promise; + constructor(promise: Promise) { + this.promise = promise; + } +} + +module('Integration | Component | Async', function (hooks) { + setupRenderingTest(hooks); + + test('it renders loading state', async function (assert) { + assert.expect(1); + + const { promise, resolve } = defer(); + + const renderPromise = render(); + + await waitFor('[data-test-async-component]'); + + assert.dom('[data-test-async-component]').hasText('PENDING'); + + resolve('hello'); + await renderPromise; + }); + + test('it renders loaded state', async function (assert) { + assert.expect(2); + + const deferred = defer(); + deferred.resolve('foobar'); + await deferred.promise; + + const renderPromise = render(); + + await waitFor('[data-test-async-component]'); + assert.dom('[data-test-async-component]').containsText('RESOLVED'); + assert.dom('[data-test-async-component]').containsText('foobar'); + + await renderPromise; + }); + + test('it renders error state', async function (assert) { + assert.expect(3); + + const { promise, reject } = defer(); + + // This handles the error throw from rendering a rejected promise + promise.catch((error: Error) => { + assert.ok(error instanceof Error); + assert.strictEqual(error.message, 'foobar'); + }); + + reject(new Error('foobar')); + + const renderPromise = render(); + + await waitFor('[data-test-async-component]'); + assert.dom('[data-test-async-component]').hasText('REJECTED'); + + await renderPromise; + }); + + test('it renders loading state and then loaded state', async function (assert) { + assert.expect(2); + + const { promise, resolve } = defer(); + + const renderPromise = render(); + + await waitFor('[data-test-async-component]'); + assert.dom('[data-test-async-component]').hasText('PENDING'); + + resolve('goodbye'); + + await waitFor('[data-test-state="RESOLVED"]'); + assert.dom('[data-test-async-component]').hasText('RESOLVED goodbye'); + + await renderPromise; + }); + + test('it renders loading state and then error state', async function (assert) { + assert.expect(3); + + const { promise, reject } = defer(); + + const renderPromise = render(); + + await waitFor('[data-test-async-component]'); + assert.dom('[data-test-async-component]').hasText('PENDING'); + + reject(new Error('foobar')); + + // This handles the error thrown at the top level + await promise.catch(() => { + assert.ok(true, 'things are neat!'); + }); + + await waitFor('[data-test-state="REJECTED"]'); + assert.dom('[data-test-async-component]').hasText('REJECTED', 'rejected'); + + await renderPromise; + }); + + test('it renders the state for the new promise if a new promise is sent and resolves before the old promise is done loading', async function (assert) { + assert.expect(4); + + const { promise: oldPromise, reject: rejectOld } = defer(); + const state = new State(oldPromise); + + // This handles the error throw from rendering a rejected promise + oldPromise.catch((error) => { + assert.ok(error instanceof Error); + assert.strictEqual(error.message, 'foobar'); + }); + + const renderPromise = render(); + + await waitFor('[data-test-async-component]'); + assert.dom('[data-test-async-component]').hasText('PENDING'); + + const { promise: newPromise, resolve: resolveNew } = defer(); + state.promise = newPromise; + + resolveNew('ahoy'); + await newPromise; + rejectOld(new Error('foobar')); + + await waitFor('[data-test-state="RESOLVED"]'); + assert.dom('[data-test-async-component]').hasText('RESOLVED ahoy'); + + await renderPromise; + }); + + test('it renders the state and value for the new promise if a new promise with a different value is sent before the old promise is done loading', async function (assert) { + assert.expect(3); + + const { promise: oldPromise, resolve: resolveOld } = defer(); + const state = new State(oldPromise); + + const renderPromise = render(); + + await waitFor('[data-test-async-component]'); + assert.dom('[data-test-async-component]').hasText('PENDING'); + + const { promise: newPromise, resolve: resolveNew } = defer(); + state.promise = newPromise; + + resolveNew('New'); + await newPromise; + resolveOld('Old'); + await oldPromise; + + await waitFor('[data-test-state="RESOLVED"]'); + assert.dom('[data-test-async-component]').containsText('RESOLVED'); + assert.dom('[data-test-async-component]').containsText('New'); + + await renderPromise; + }); + + test('it renders error state and then loading state for a retried promise', async function (assert) { + assert.expect(4); + + const deferred = defer(); + const state = new State(deferred.promise); + + // This handles the error throw from rendering a rejected promise + deferred.promise.catch((error: Error) => { + assert.ok(error instanceof Error); + assert.strictEqual(error.message, 'foobar'); + }); + + // eslint-disable-next-line ember/no-array-prototype-extensions + deferred.reject(new Error('foobar')); + + const renderPromise = render(); + + await waitFor('[data-test-async-component]'); + assert.dom('[data-test-async-component]').hasText('REJECTED'); + + const retryDeferred = defer(); + state.promise = retryDeferred.promise; + + await waitFor('[data-test-state="PENDING"]'); + assert.dom('[data-test-async-component]').hasText('PENDING'); + + retryDeferred.resolve('hello'); + await retryDeferred.promise; + await renderPromise; + }); +}); diff --git a/test-app/tests/integration/helpers/load-test.ts b/test-app/tests/integration/helpers/load-test.gts similarity index 56% rename from test-app/tests/integration/helpers/load-test.ts rename to test-app/tests/integration/helpers/load-test.gts index 4f6d08d8..1efd00e1 100644 --- a/test-app/tests/integration/helpers/load-test.ts +++ b/test-app/tests/integration/helpers/load-test.gts @@ -1,25 +1,29 @@ import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; -import { render, waitFor, type TestContext } from '@ember/test-helpers'; -import { hbs } from 'ember-cli-htmlbars'; +import { render, waitFor } from '@ember/test-helpers'; import { defer } from '../../defer'; - -interface LocalTestContext extends TestContext { - promise: Promise; +import { load } from 'ember-async-data'; +import { tracked } from '@glimmer/tracking'; + +class State { + @tracked promise: Promise; + constructor(promise: Promise) { + this.promise = promise; + } } module('Integration | Helper | load', function (hooks) { setupRenderingTest(hooks); - test('it renders loading state', async function (this: LocalTestContext, assert) { - const { promise, resolve } = defer(); - this.set('promise', promise); + test('it renders loading state', async function (assert) { + const { promise, resolve } = defer(); - const renderPromise = render(hbs` + const renderPromise = render(); await waitFor('[data-test-load-helper]'); assert.dom('[data-test-load-helper]').hasText('PENDING'); - resolve(); + resolve('hello'); await renderPromise; }); - test('it renders loaded state', async function (this: LocalTestContext, assert) { - const deferred = defer(); + test('it renders loaded state', async function (assert) { + const deferred = defer(); deferred.resolve('foobar'); await deferred.promise; - this.set('promise', deferred.promise); - const renderPromise = render(hbs` + const renderPromise = render(); await waitFor('[data-test-load-helper]'); assert.dom('[data-test-load-helper]').containsText('RESOLVED'); @@ -64,10 +68,10 @@ module('Integration | Helper | load', function (hooks) { await renderPromise; }); - test('it renders error state', async function (this: LocalTestContext, assert) { + test('it renders error state', async function (assert) { assert.expect(3); - const { promise, reject } = defer(); + const { promise, reject } = defer(); // This handles the error throw from rendering a rejected promise promise.catch((error: Error) => { @@ -76,13 +80,13 @@ module('Integration | Helper | load', function (hooks) { }); reject(new Error('foobar')); - this.set('promise', promise); - const renderPromise = render(hbs` + const renderPromise = render(); await waitFor('[data-test-load-helper]'); assert.dom('[data-test-load-helper]').hasText('REJECTED'); @@ -98,13 +102,12 @@ module('Integration | Helper | load', function (hooks) { await renderPromise; }); - test('it renders loading state and then loaded state', async function (this: LocalTestContext, assert) { - const { promise, resolve } = defer(); - this.set('promise', promise); + test('it renders loading state and then loaded state', async function (assert) { + const { promise, resolve } = defer(); - const renderPromise = render(hbs` + const renderPromise = render(); await waitFor('[data-test-load-helper]'); assert.dom('[data-test-load-helper]').hasText('PENDING'); - resolve(); + resolve('goodbye'); await waitFor('[data-test-state="RESOLVED"]'); - assert.dom('[data-test-load-helper]').hasText('RESOLVED'); + assert.dom('[data-test-load-helper]').hasText('RESOLVED goodbye'); await renderPromise; }); - test('it renders loading state and then error state', async function (this: LocalTestContext, assert) { + test('it renders loading state and then error state', async function (assert) { assert.expect(3); - const { promise, reject } = defer(); - this.set('promise', promise); + const { promise, reject } = defer(); - const renderPromise = render(hbs` + const renderPromise = render(); await waitFor('[data-test-load-helper]'); assert.dom('[data-test-load-helper]').hasText('PENDING'); @@ -163,11 +165,11 @@ module('Integration | Helper | load', function (hooks) { await renderPromise; }); - test('it renders the state for the new promise if a new promise is sent and resolves before the old promise is done loading', async function (this: LocalTestContext, assert) { - assert.expect(4); + test('it renders the state for the new promise if a new promise is sent and resolves before the old promise is done loading', async function (assert) { + assert.expect(5); - const { promise: oldPromise, reject: rejectOld } = defer(); - this.set('promise', oldPromise); + const { promise: oldPromise, reject: rejectOld } = defer(); + const state = new State(oldPromise); // This handles the error throw from rendering a rejected promise oldPromise.catch((error) => { @@ -175,59 +177,60 @@ module('Integration | Helper | load', function (hooks) { assert.strictEqual(error.message, 'foobar'); }); - const renderPromise = render(hbs` + const renderPromise = render(); await waitFor('[data-test-load-helper]'); assert.dom('[data-test-load-helper]').hasText('PENDING'); - const { promise: newPromise, resolve: resolveNew } = defer(); - this.set('promise', newPromise); + const { promise: newPromise, resolve: resolveNew } = defer(); + state.promise = newPromise; - resolveNew(); + resolveNew('ahoy'); await newPromise; rejectOld(new Error('foobar')); await waitFor('[data-test-state="RESOLVED"]'); - assert.dom('[data-test-load-helper]').hasText('RESOLVED'); + assert.dom('[data-test-load-helper]').containsText('RESOLVED'); + assert.dom('[data-test-load-helper]').containsText('ahoy'); await renderPromise; }); - test('it renders the state and value for the new promise if a new promise with a different value is sent before the old promise is done loading', async function (this: LocalTestContext, assert) { - const { promise: oldPromise, resolve: resolveOld } = defer(); - this.set('promise', oldPromise); - - const renderPromise = render(hbs` -
- {{#let (load this.promise) as |result|}} - {{#if result.isResolved}} -
RESOLVED {{result.value}}
- {{else if result.isPending}} -
PENDING
- {{else if result.isRejected}} -
REJECTED
- {{/if}} - {{/let}} -
- `); + test('it renders the state and value for the new promise if a new promise with a different value is sent before the old promise is done loading', async function (assert) { + const { promise: oldPromise, resolve: resolveOld } = defer(); + let state = new State(oldPromise); + + const renderPromise = render(); await waitFor('[data-test-load-helper]'); assert.dom('[data-test-load-helper]').hasText('PENDING'); - const { promise: newPromise, resolve: resolveNew } = defer(); - this.set('promise', newPromise); + const { promise: newPromise, resolve: resolveNew } = defer(); + state.promise = newPromise; resolveNew('New'); await newPromise; @@ -241,11 +244,11 @@ module('Integration | Helper | load', function (hooks) { await renderPromise; }); - test('it renders error state and then loading state for a retried promise', async function (this: LocalTestContext, assert) { + test('it renders error state and then loading state for a retried promise', async function (assert) { assert.expect(4); - const deferred = defer(); - this.set('promise', deferred.promise); + const deferred = defer(); + const state = new State(deferred.promise); // This handles the error throw from rendering a rejected promise deferred.promise.catch((error: Error) => { @@ -256,30 +259,30 @@ module('Integration | Helper | load', function (hooks) { // eslint-disable-next-line ember/no-array-prototype-extensions deferred.reject(new Error('foobar')); - const renderPromise = render(hbs` -
- {{#let (load this.promise) as |result|}} - {{#if result.isResolved}} -
RESOLVED {{result.value}}
- {{else if result.isPending}} -
PENDING
- {{else if result.isRejected}} -
REJECTED
- {{/if}} - {{/let}} -
- `); + const renderPromise = render(); await waitFor('[data-test-load-helper]'); assert.dom('[data-test-load-helper]').hasText('REJECTED'); - const retryDeferred = defer(); - this.set('promise', retryDeferred.promise); + const retryDeferred = defer(); + state.promise = retryDeferred.promise; await waitFor('[data-test-state="PENDING"]'); assert.dom('[data-test-load-helper]').hasText('PENDING'); - retryDeferred.resolve(); + retryDeferred.resolve('hello'); await retryDeferred.promise; await renderPromise; }); diff --git a/test-app/tests/unit/tracked-async-data-test.ts b/test-app/tests/unit/tracked-async-data-test.ts index 9f301e28..6602fc32 100644 --- a/test-app/tests/unit/tracked-async-data-test.ts +++ b/test-app/tests/unit/tracked-async-data-test.ts @@ -20,8 +20,6 @@ module('Unit | TrackedAsyncData', function () { assert.true(result.isPending); assert.false(result.isResolved); assert.false(result.isRejected); - assert.strictEqual(result.value, null); - assert.strictEqual(result.error, null); deferred.resolve(); await deferred.promise; diff --git a/test-app/tsconfig.json b/test-app/tsconfig.json index 6e6f1f71..96ff3f8c 100644 --- a/test-app/tsconfig.json +++ b/test-app/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "@tsconfig/ember/tsconfig.json", + "extends": "../tsconfig.json", "compilerOptions": { // The combination of `baseUrl` with `paths` allows Ember's classic package // layout, which is not resolvable with the Node resolution algorithm, to @@ -10,5 +10,11 @@ "test-app/*": ["app/*"], "*": ["types/*"] } + }, + "glint": { + "environment": [ + "ember-loose", + "ember-template-imports" + ] } } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..7c32de90 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@tsconfig/ember/tsconfig.json", + "glint": { + "environment": [ + "ember-loose", + "ember-template-imports" + ] + } +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 19ab8f58..2f0290d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -654,13 +654,20 @@ dependencies: "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-block-scoping@^7.19.4", "@babel/plugin-transform-block-scoping@^7.20.5": +"@babel/plugin-transform-block-scoping@^7.19.4": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.21.0.tgz#e737b91037e5186ee16b76e7ae093358a5634f02" integrity sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ== dependencies: "@babel/helper-plugin-utils" "^7.20.2" +"@babel/plugin-transform-block-scoping@^7.21.0": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.15.tgz#494eb82b87b5f8b1d8f6f28ea74078ec0a10a841" + integrity sha512-G1czpdJBZCtngoK1sJgloLiOHUnkb/bLZwqVZD8kXmq0ZnVfTTWUcs9OWtp0mBtYJ+4LQY1fllqBkOIPhXmFmw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-transform-classes@^7.19.0": version "7.19.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz#0e61ec257fba409c41372175e7c1e606dc79bb20" @@ -1347,6 +1354,17 @@ resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== +"@glimmer/compiler@0.84.2": + version "0.84.2" + resolved "https://registry.yarnpkg.com/@glimmer/compiler/-/compiler-0.84.2.tgz#ff4ef4fb244afa254189a579fa4453b2783ae7ab" + integrity sha512-rU8qpqbqxIPwrEQH82yDDFi1hgv6ud1agYexmnmCXlaLS5uCVATJAqKsVozc7aHOgmmF4Ukd/LoF4NYfGr8X3w== + dependencies: + "@glimmer/interfaces" "0.84.2" + "@glimmer/syntax" "0.84.2" + "@glimmer/util" "0.84.2" + "@glimmer/wire-format" "0.84.2" + "@simple-dom/interface" "^1.4.0" + "@glimmer/component@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@glimmer/component/-/component-1.1.2.tgz#892ec0c9f0b6b3e41c112be502fde073cf24d17c" @@ -1367,16 +1385,42 @@ ember-cli-version-checker "^3.1.3" ember-compatibility-helpers "^1.1.2" +"@glimmer/destroyable@0.84.2": + version "0.84.2" + resolved "https://registry.yarnpkg.com/@glimmer/destroyable/-/destroyable-0.84.2.tgz#67009d931346f4988a6dd329cd8b95141726a453" + integrity sha512-74L4+jlGUhzhUe87lTxjFdYEEfcDWcza+jqLXoyIb/p4cS0hWsTGlyF+OcuUbHO4yqJd4bXchGOVocoajmSp6w== + dependencies: + "@glimmer/env" "0.1.7" + "@glimmer/global-context" "0.84.2" + "@glimmer/interfaces" "0.84.2" + "@glimmer/util" "0.84.2" + "@glimmer/di@^0.1.9": version "0.1.11" resolved "https://registry.yarnpkg.com/@glimmer/di/-/di-0.1.11.tgz#a6878c07a13a2c2c76fcde598a5c97637bfc4280" integrity sha512-moRwafNDwHTnTHzyyZC9D+mUSvYrs1Ak0tRPjjmCghdoHHIvMshVbEnwKb/1WmW5CUlKc2eL9rlAV32n3GiItg== +"@glimmer/encoder@0.84.2": + version "0.84.2" + resolved "https://registry.yarnpkg.com/@glimmer/encoder/-/encoder-0.84.2.tgz#3e6038f4115cde40a1252f13ae33774341325d40" + integrity sha512-599TMDNDHiw+PhNXy5/AnMjh83NBKy+tl2YmwSRY9qktx4DDOZenzgwZ5haLlzPaceejJ6ZNAoGyV5bBrDY5+w== + dependencies: + "@glimmer/env" "0.1.7" + "@glimmer/interfaces" "0.84.2" + "@glimmer/vm" "0.84.2" + "@glimmer/env@0.1.7", "@glimmer/env@^0.1.7": version "0.1.7" resolved "https://registry.yarnpkg.com/@glimmer/env/-/env-0.1.7.tgz#fd2d2b55a9029c6b37a6c935e8c8871ae70dfa07" integrity sha512-JKF/a9I9jw6fGoz8kA7LEQslrwJ5jms5CXhu/aqkBWk+PmZ6pTl8mlb/eJ/5ujBGTiQzBhy5AIWF712iA+4/mw== +"@glimmer/global-context@0.84.2": + version "0.84.2" + resolved "https://registry.yarnpkg.com/@glimmer/global-context/-/global-context-0.84.2.tgz#cd4612925dbd68787b9270e91b213691150c307f" + integrity sha512-6FycLh/Eq0P3LA94bJL6WHPJyOTKeQD4KBWhowZ9TbeO3p4/WUr+POKPVEyfIx6YHybhpL9MGj45Y2r0hqVigw== + dependencies: + "@glimmer/env" "^0.1.7" + "@glimmer/global-context@0.84.3": version "0.84.3" resolved "https://registry.yarnpkg.com/@glimmer/global-context/-/global-context-0.84.3.tgz#f8bf2cda9562716f2ddf3f96837e7559600635c4" @@ -1384,6 +1428,13 @@ dependencies: "@glimmer/env" "^0.1.7" +"@glimmer/interfaces@0.84.2": + version "0.84.2" + resolved "https://registry.yarnpkg.com/@glimmer/interfaces/-/interfaces-0.84.2.tgz#764cf92c954adcd1a851e5dc68ec1f6b654dc3bd" + integrity sha512-tMZxQpOddUVmHEOuripkNqVR7ba0K4doiYnFd4WyswqoHPlxqpBujbIamQ+bWCWEF0U4yxsXKa31ekS/JHkiBQ== + dependencies: + "@simple-dom/interface" "^1.4.0" + "@glimmer/interfaces@0.84.3": version "0.84.3" resolved "https://registry.yarnpkg.com/@glimmer/interfaces/-/interfaces-0.84.3.tgz#629777a4abe373b0785656f6c8d08989f5784805" @@ -1391,6 +1442,78 @@ dependencies: "@simple-dom/interface" "^1.4.0" +"@glimmer/low-level@0.78.2": + version "0.78.2" + resolved "https://registry.yarnpkg.com/@glimmer/low-level/-/low-level-0.78.2.tgz#bca5f666760ce98345e87c5b3e37096e772cb2de" + integrity sha512-0S6TWOOd0fzLLysw1pWZN0TgasaHmYs1Sjz9Til1mTByIXU1S+1rhdyr2veSQPO/aRjPuEQyKXZQHvx23Zax6w== + +"@glimmer/manager@0.84.2": + version "0.84.2" + resolved "https://registry.yarnpkg.com/@glimmer/manager/-/manager-0.84.2.tgz#a96730388994a57517c45cbacf6ac481bdf1cd47" + integrity sha512-cXOnRTH9nwAe/un8hK0x6z1m67Cv5ywAuK7KRxAFTWHgGX/i6BvoZCStr6zJD/U6Frna2c7RJK8JpleP94opEA== + dependencies: + "@glimmer/destroyable" "0.84.2" + "@glimmer/env" "0.1.7" + "@glimmer/global-context" "0.84.2" + "@glimmer/interfaces" "0.84.2" + "@glimmer/reference" "0.84.2" + "@glimmer/util" "0.84.2" + "@glimmer/validator" "0.84.2" + +"@glimmer/node@0.84.2": + version "0.84.2" + resolved "https://registry.yarnpkg.com/@glimmer/node/-/node-0.84.2.tgz#74d4eb8fc58dbf5ed2b57af39a1f350548cf0469" + integrity sha512-kefGxH+0N0xNyb6QovdPzmIBefZwu8TID45qsASgVbFx7mfFiXjQiyaxbRUyam4MAEb8Nzzx1Byxn1FQCYyLdA== + dependencies: + "@glimmer/interfaces" "0.84.2" + "@glimmer/runtime" "0.84.2" + "@glimmer/util" "0.84.2" + "@simple-dom/document" "^1.4.0" + "@simple-dom/interface" "^1.4.0" + +"@glimmer/opcode-compiler@0.84.2": + version "0.84.2" + resolved "https://registry.yarnpkg.com/@glimmer/opcode-compiler/-/opcode-compiler-0.84.2.tgz#df0fb70e2fdacb7c6f6ec3edd1c66a5639f2e2c9" + integrity sha512-KwTH9cWEW4Neu3jmD9ANMIQYBiEqPsLx+h55G+wYp5djyjiYwSJ7KhgMAB+wEHuvB6izp3XdSO6jDMgp3pp49A== + dependencies: + "@glimmer/encoder" "0.84.2" + "@glimmer/env" "0.1.7" + "@glimmer/interfaces" "0.84.2" + "@glimmer/reference" "0.84.2" + "@glimmer/util" "0.84.2" + "@glimmer/vm" "0.84.2" + "@glimmer/wire-format" "0.84.2" + +"@glimmer/owner@0.84.2": + version "0.84.2" + resolved "https://registry.yarnpkg.com/@glimmer/owner/-/owner-0.84.2.tgz#423fd5b43fa49e95558456999be3ec0150742474" + integrity sha512-maZn642eXRImp/hOSa4nQmzMLEIywXwgahS/ZMuzD4HTTsA2SlEdjXSrVbRQYarYF8LkiJ7fpcKHkyNCe8SHrQ== + dependencies: + "@glimmer/util" "0.84.2" + +"@glimmer/program@0.84.2": + version "0.84.2" + resolved "https://registry.yarnpkg.com/@glimmer/program/-/program-0.84.2.tgz#4cfb5bb3a31a221671f35817f31ad175ebf4fad7" + integrity sha512-Ohx+7H3+CSVHbC08trUK7fXC6ti9x0SQDC2Lwd7BMXmMyoOZHxdaKNrTJ+CsQ8nV1JkLfXhnvRDG08TqD5VHJw== + dependencies: + "@glimmer/encoder" "0.84.2" + "@glimmer/env" "0.1.7" + "@glimmer/interfaces" "0.84.2" + "@glimmer/manager" "0.84.2" + "@glimmer/opcode-compiler" "0.84.2" + "@glimmer/util" "0.84.2" + +"@glimmer/reference@0.84.2": + version "0.84.2" + resolved "https://registry.yarnpkg.com/@glimmer/reference/-/reference-0.84.2.tgz#c8d91a3ba0b92a9430b6023d7b6f39dd56c79af1" + integrity sha512-hH0VD76OXMsGSHbqaqD64u1aBEqy//jhZtIaHGwAHNpTEX+zDtW3ka298KbAn2CZyDDrNAnuc2U1Vy4COR3zlA== + dependencies: + "@glimmer/env" "^0.1.7" + "@glimmer/global-context" "0.84.2" + "@glimmer/interfaces" "0.84.2" + "@glimmer/util" "0.84.2" + "@glimmer/validator" "0.84.2" + "@glimmer/reference@^0.84.3": version "0.84.3" resolved "https://registry.yarnpkg.com/@glimmer/reference/-/reference-0.84.3.tgz#6420ad9c102633ac83939fd1b2457269d21fb632" @@ -1402,6 +1525,35 @@ "@glimmer/util" "0.84.3" "@glimmer/validator" "0.84.3" +"@glimmer/runtime@0.84.2": + version "0.84.2" + resolved "https://registry.yarnpkg.com/@glimmer/runtime/-/runtime-0.84.2.tgz#3d4a565cf72762b0aab06982e5151f7e3c1ccdd8" + integrity sha512-mUefYwq8l4df61iWYsRKVYQUqAeCgeZ3fuYNRNbvKDudnT9bQXayJLqr6ZxwTVaDoeKjg+7lMjkDSDSvqoxfsA== + dependencies: + "@glimmer/destroyable" "0.84.2" + "@glimmer/env" "0.1.7" + "@glimmer/global-context" "0.84.2" + "@glimmer/interfaces" "0.84.2" + "@glimmer/low-level" "0.78.2" + "@glimmer/owner" "0.84.2" + "@glimmer/program" "0.84.2" + "@glimmer/reference" "0.84.2" + "@glimmer/util" "0.84.2" + "@glimmer/validator" "0.84.2" + "@glimmer/vm" "0.84.2" + "@glimmer/wire-format" "0.84.2" + "@simple-dom/interface" "^1.4.0" + +"@glimmer/syntax@0.84.2": + version "0.84.2" + resolved "https://registry.yarnpkg.com/@glimmer/syntax/-/syntax-0.84.2.tgz#a3f65e51eec20f6adb79c6159d1ad1166fa5bccd" + integrity sha512-SPBd1tpIR9XeaXsXsMRCnKz63eLnIZ0d5G9QC4zIBFBC3pQdtG0F5kWeuRVCdfTIFuR+5WBMfk5jvg+3gbQhjg== + dependencies: + "@glimmer/interfaces" "0.84.2" + "@glimmer/util" "0.84.2" + "@handlebars/parser" "~2.0.0" + simple-html-tokenizer "^0.5.11" + "@glimmer/syntax@^0.84.2", "@glimmer/syntax@^0.84.3": version "0.84.3" resolved "https://registry.yarnpkg.com/@glimmer/syntax/-/syntax-0.84.3.tgz#4045a1708cef7fd810cff42fe6deeba40c7286d0" @@ -1420,6 +1572,15 @@ "@glimmer/env" "^0.1.7" "@glimmer/validator" "^0.44.0" +"@glimmer/util@0.84.2": + version "0.84.2" + resolved "https://registry.yarnpkg.com/@glimmer/util/-/util-0.84.2.tgz#2711ba40f25f44b2ea309cad49f5c2622c6211bc" + integrity sha512-VbhzE2s4rmU+qJF3gGBTL1IDjq+/G2Th51XErS8MQVMCmE4CU2pdwSzec8PyOowqCGUOrVIWuMzEI6VoPM4L4w== + dependencies: + "@glimmer/env" "0.1.7" + "@glimmer/interfaces" "0.84.2" + "@simple-dom/interface" "^1.4.0" + "@glimmer/util@0.84.3": version "0.84.3" resolved "https://registry.yarnpkg.com/@glimmer/util/-/util-0.84.3.tgz#9ae0166982c0b48aa94b02d6ba8c2c81976ade4b" @@ -1434,6 +1595,14 @@ resolved "https://registry.yarnpkg.com/@glimmer/util/-/util-0.44.0.tgz#45df98d73812440206ae7bda87cfe04aaae21ed9" integrity sha512-duAsm30uVK9jSysElCbLyU6QQYO2X9iLDLBIBUcCqck9qN1o3tK2qWiHbGK5d6g8E2AJ4H88UrfElkyaJlGrwg== +"@glimmer/validator@0.84.2": + version "0.84.2" + resolved "https://registry.yarnpkg.com/@glimmer/validator/-/validator-0.84.2.tgz#29394d262cf8373fe20f4e225c1adc9857a4164b" + integrity sha512-9tpSmwiktsJDqriNEiFfyP+9prMSdk08THA6Ik71xS/sudBKxoDpul678uvyEYST/+Z23F8MxwKccC+QxCMXNA== + dependencies: + "@glimmer/env" "^0.1.7" + "@glimmer/global-context" "0.84.2" + "@glimmer/validator@0.84.3", "@glimmer/validator@^0.84.3": version "0.84.3" resolved "https://registry.yarnpkg.com/@glimmer/validator/-/validator-0.84.3.tgz#cd83b7f9ab78953f23cc11a32d83d7f729c54df2" @@ -1454,14 +1623,30 @@ dependencies: babel-plugin-debug-macros "^0.3.4" -"@glint/core@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@glint/core/-/core-1.0.2.tgz#eb684b6b7c830b8e0a8e3ddda550bc269d1cbb5e" - integrity sha512-0bVt/lT/NurpD8nBG9RTPKYlcpg51UDGCKgLoBEFOiTXv3aCSxAVKPud1IYaitGBKE0C+s5pl2PHkgptotVS+w== +"@glimmer/vm@0.84.2": + version "0.84.2" + resolved "https://registry.yarnpkg.com/@glimmer/vm/-/vm-0.84.2.tgz#ade992d1e4baea3e88d320ec06f3d3e173c236e9" + integrity sha512-IuQeDlh+AUOOX8QXc+ehPv5uFnqstQVZGplqqvPQRcKvsEalog88RC34dAEwFdB756SKjgRSw+N+nT3ZDNVlvA== + dependencies: + "@glimmer/interfaces" "0.84.2" + "@glimmer/util" "0.84.2" + +"@glimmer/wire-format@0.84.2": + version "0.84.2" + resolved "https://registry.yarnpkg.com/@glimmer/wire-format/-/wire-format-0.84.2.tgz#fa90d93b2f7c5baa1ef24d82d649892e6a1d8671" + integrity sha512-/FmbXSPFJAoIZ6qu28xVXpAdy2Ln++Ewe6mRHFpnudV1lUrBN+Q09A4j/RN/hpAkyz/8ai5W+5rHKuaWxoi4Dg== + dependencies: + "@glimmer/interfaces" "0.84.2" + "@glimmer/util" "0.84.2" + +"@glint/core@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@glint/core/-/core-1.1.0.tgz#b89600b59fcfac7a112615510ea05c08f985d3d9" + integrity sha512-SeAdKrQF65NRDzzmkwUC0VRZjBDysQXeIKXhyCUtXaatFDeyC0zdESJRcUykMdQoI5R6MKcts2X3gthLRuEGKA== dependencies: "@glimmer/syntax" "^0.84.2" escape-string-regexp "^4.0.0" - semver "^7.3.8" + semver "^7.5.2" silent-error "^1.1.1" uuid "^8.3.2" vscode-languageserver "^8.0.1" @@ -1469,15 +1654,20 @@ vscode-uri "^3.0.2" yargs "^17.5.1" -"@glint/environment-ember-loose@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@glint/environment-ember-loose/-/environment-ember-loose-1.0.2.tgz#701d084625707e9ba9ca2cf5269bbea443b15d62" - integrity sha512-tVLYzAx6c/4vcSaijiAubwR27/+K2tujuozArxeNud58MTwncGxhUkCHSM9xl+wn4VJjsjkzI6+nmzjEdkszSg== +"@glint/environment-ember-loose@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@glint/environment-ember-loose/-/environment-ember-loose-1.1.0.tgz#b0e3a321376924cd74c9bb741fdfd99a04d9f363" + integrity sha512-Qwr3OAptRZ8zqxaPvpVBdbSiiImYMRNu+0IPQGaDutqOV80GzWYeiMuEyPC0Nwy4mQ3991YxE24Q+a5/FTfTNw== -"@glint/template@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@glint/template/-/template-1.0.2.tgz#dcb96f048df52e7d0e78cf194fa07b3c42f15278" - integrity sha512-kFWfJrS7XM0NjC5YSN0CWA9FiN0mhUvWVlQ2O7YRz/uhrO8+TVYNLst0WKELRbfCXbdI7wyYQkazNgz6FoL9CA== +"@glint/environment-ember-template-imports@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@glint/environment-ember-template-imports/-/environment-ember-template-imports-1.1.0.tgz#908ec8b38a5837f4c28b12e4a3fe6c547366d37a" + integrity sha512-duNk2NzDilNctzz+XHecICfMMt8LjLEhaWPiBvFfFeLW35gqZo2XQpeBQI/pq2gH0ZbWOP7rr9Kde12v7ossZg== + +"@glint/template@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@glint/template/-/template-1.1.0.tgz#5734f8f4d9f425676c97bb701c9af03dd2e783ab" + integrity sha512-gK4tifrw7mIMYECzGeG5jrez2lY0TlwE584cnoYOFhzxXKrsuungdiebd7LDwjvfQpImQd1JUSQr3u/uF/XYJg== "@handlebars/parser@~2.0.0": version "2.0.0" @@ -1826,6 +2016,13 @@ estree-walker "^2.0.2" picomatch "^2.3.1" +"@simple-dom/document@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@simple-dom/document/-/document-1.4.0.tgz#af60855f957f284d436983798ef1006cca1a1678" + integrity sha512-/RUeVH4kuD3rzo5/91+h4Z1meLSLP66eXqpVAw/4aZmYozkeqUkMprq0znL4psX/adEed5cBgiNJcfMz/eKZLg== + dependencies: + "@simple-dom/interface" "^1.4.0" + "@simple-dom/interface@^1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@simple-dom/interface/-/interface-1.4.0.tgz#e8feea579232017f89b0138e2726facda6fbb71f" @@ -2914,6 +3111,11 @@ backbone@^1.1.2: dependencies: underscore ">=1.8.3" +backburner.js@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/backburner.js/-/backburner.js-2.7.0.tgz#36a5b8a8bfceb7efc8ad56e006a238924acfd67e" + integrity sha512-eBZC6r7wT+YYAOKeru8IqgzOimz3VgyspXiZ1k6MI8i10zUdU8cnNII56rlnItQ89cHgQO3C/nPuFW3V9di+zg== + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -4755,7 +4957,7 @@ electron-to-chromium@^1.4.431: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.470.tgz#0e932816be8d5f2b491ad2aa449ea47db4785398" integrity sha512-zZM48Lmy2FKWgqyvsX9XK+J6FfP7aCDUFLmgooLJzA7v1agCs/sxSoBpTIwDLhmbhpx9yJIxj2INig/ncjJRqg== -ember-auto-import@^2.5.0, ember-auto-import@^2.6.0: +ember-auto-import@^2.6.0: version "2.6.2" resolved "https://registry.yarnpkg.com/ember-auto-import/-/ember-auto-import-2.6.2.tgz#ea0bfccb79c0601d2857764ebe04a67559a57b48" integrity sha512-h0bdE1atVqEXkE+9OTkEi2wRHBpJilKn6iXlbrOS2nI4HGpWlqmUjWmQk/iMFad+1XEDBvNJnikxgtKb/GFL5A== @@ -5272,25 +5474,41 @@ ember-source-channel-url@^3.0.0: dependencies: node-fetch "^2.6.0" -ember-source@^4.12.3: - version "4.12.3" - resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-4.12.3.tgz#6c401f6a856bb2f7f2871f56d46e7496f97e936a" - integrity sha512-UuFpMWf931pEWBPuujkaMYhsoPvFyZc+tMYjlUn7um20uL+hWs+k2n/TxMVuxydSzJLnxrXz81nTwbYIlgRWdw== +ember-source@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-5.2.0.tgz#9cfa89b8b32b658fa70dc59c11264daf77e765f5" + integrity sha512-rr8qLnyW6QV5N4ItwFluTH/SZ5W7uGsYL5GP0tYA2z9zFqD0g2TTJRBsaUPYFlHqcuUhWHiGg+xOyLcHZJOrig== dependencies: "@babel/helper-module-imports" "^7.16.7" - "@babel/plugin-transform-block-scoping" "^7.20.5" + "@babel/plugin-transform-block-scoping" "^7.21.0" "@ember/edition-utils" "^1.2.0" + "@glimmer/compiler" "0.84.2" + "@glimmer/component" "^1.1.2" + "@glimmer/destroyable" "0.84.2" + "@glimmer/env" "^0.1.7" + "@glimmer/global-context" "0.84.3" + "@glimmer/interfaces" "0.84.2" + "@glimmer/manager" "0.84.2" + "@glimmer/node" "0.84.2" + "@glimmer/opcode-compiler" "0.84.2" + "@glimmer/owner" "0.84.2" + "@glimmer/program" "0.84.2" + "@glimmer/reference" "0.84.2" + "@glimmer/runtime" "0.84.2" + "@glimmer/syntax" "0.84.2" + "@glimmer/validator" "0.84.2" "@glimmer/vm-babel-plugins" "0.84.2" "@simple-dom/interface" "^1.4.0" babel-plugin-debug-macros "^0.3.4" babel-plugin-filter-imports "^4.0.0" + backburner.js "^2.7.0" broccoli-concat "^4.2.5" broccoli-debug "^0.6.4" broccoli-file-creator "^2.1.1" broccoli-funnel "^3.0.8" broccoli-merge-trees "^4.2.0" chalk "^4.0.0" - ember-auto-import "^2.5.0" + ember-auto-import "^2.6.3" ember-cli-babel "^7.26.11" ember-cli-get-component-path-option "^1.0.0" ember-cli-is-package-missing "^1.0.0" @@ -5302,6 +5520,8 @@ ember-source@^4.12.3: ember-router-generator "^2.0.0" inflection "^1.13.2" resolve "^1.22.0" + route-recognizer "^0.3.4" + router_js "^8.0.3" semver "^7.3.8" silent-error "^1.1.1" @@ -10870,6 +11090,18 @@ rollup@^3.28.0: optionalDependencies: fsevents "~2.3.2" +route-recognizer@^0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.3.4.tgz#39ab1ffbce1c59e6d2bdca416f0932611e4f3ca3" + integrity sha512-2+MhsfPhvauN1O8KaXpXAOfR/fwe8dnUXVM+xw7yt40lJRfPVQxV6yryZm0cgRvAj5fMF/mdRZbL2ptwbs5i2g== + +router_js@^8.0.3: + version "8.0.3" + resolved "https://registry.yarnpkg.com/router_js/-/router_js-8.0.3.tgz#c00912925839bd2a427c8e12b6cec6bc0f496947" + integrity sha512-lSgNMksk/wp8nspLX3Pn6QD499FUjwYMkgP99RxqKEScil4DKC/59YezpEZ318zGtkq8WR01VBhH+/u3InlLgg== + dependencies: + "@glimmer/env" "^0.1.7" + rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0: version "3.6.2" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" @@ -11059,7 +11291,7 @@ semver-diff@^4.0.0: dependencies: semver "^7.3.5" -semver@7.5.4, semver@^7.0.0, semver@^7.1.3, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: +semver@7.5.4, semver@^7.0.0, semver@^7.1.3, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==