Skip to content

Fix ember-component and ember-helper reexports #71

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions packages/environment-ember-loose/ember-component/helper.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import type { Invoke, Invokable } from '@glint/template/-private/resolution';
import type { EmptyObject } from '@glint/template/-private/signature';

const EmberHelper = window.require('ember').Helper;
declare const Ember: { Helper: EmberHelperConstructor };

type EmberHelper = import('@ember/component/helper').default;
type EmberHelperConstructor = typeof import('@ember/component/helper').default;

const emberHelper = window.require('ember').Helper.helper;
const EmberHelper = Ember.Helper;
const emberHelper = Ember.Helper.helper;

type Get<T, Key, Otherwise = EmptyObject> = Key extends keyof T
? Exclude<T[Key], undefined>
Expand All @@ -15,7 +17,7 @@ type HelperFactory = <Positional extends unknown[] = [], Named = EmptyObject, Re
fn: (params: Positional, hash: Named) => Return
) => new () => Invokable<(named: Named, ...positional: Positional) => Return>;

export const helper = emberHelper as HelperFactory;
export const helper = (emberHelper as unknown) as HelperFactory;

export interface HelperSignature {
NamedArgs?: Record<string, unknown>;
Expand All @@ -26,7 +28,7 @@ export interface HelperSignature {
// Overriding `compute` directly is impossible because the base class has such
// wide parameter types, so we explicitly exclude that from the interface we're
// extending here so our override can "take" without an error.
const Helper = EmberHelper as new <T extends HelperSignature>(
const Helper = (EmberHelper as unknown) as new <T extends HelperSignature>(
...args: ConstructorParameters<EmberHelperConstructor>
) => Helper<T>;

Expand Down
6 changes: 4 additions & 2 deletions packages/environment-ember-loose/ember-component/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { ContextType, Invoke, TemplateContext } from '@glint/template/-private';
import type { AcceptsBlocks, EmptyObject } from '@glint/template/-private/signature';

const EmberComponent = window.require('ember').EmberComponent;
declare const Ember: { Component: EmberComponentConstructor };

const EmberComponent = Ember.Component;
type EmberComponent = import('@ember/component').default;
type EmberComponentConstructor = typeof import('@ember/component').default;

Expand All @@ -16,7 +18,7 @@ export interface ComponentSignature {
Yields?: Partial<Record<string, Array<unknown>>>;
}

const Component = EmberComponent as new <T extends ComponentSignature = {}>(
const Component = (EmberComponent as unknown) as new <T extends ComponentSignature = {}>(
...args: ConstructorParameters<EmberComponentConstructor>
) => Component<T>;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import Component, { ArgsFor } from '@glint/environment-ember-loose/ember-component';

export interface EmberSignature {
export interface EmberComponentSignature {
Args: {
required: string;
hasDefault?: string;
optional?: number;
};
}

export default interface Ember extends ArgsFor<EmberSignature> {}
export default class Ember extends Component<EmberSignature> {
export default interface EmberComponent extends ArgsFor<EmberComponentSignature> {}
export default class EmberComponent extends Component<EmberComponentSignature> {
public hasDefault = 'defaultValue';

public checkTypes(): unknown {
Expand All @@ -23,6 +23,6 @@ export default class Ember extends Component<EmberSignature> {

declare module '@glint/environment-ember-loose/types/registry' {
export default interface Registry {
Ember: typeof Ember;
EmberComponent: typeof EmberComponent;
}
}
20 changes: 20 additions & 0 deletions test-packages/demo-ember-app/app/components/foo.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,23 @@
<Baz />

<Qux />

<EmberComponent />

<EmberComponent @required="req" />

<EmberComponent @required={{1}} />

<EmberComponent @required="req" @optional={{1}} />

<EmberComponent @required="req" @optional="opt" />

<EmberComponent @required="req" @hasDefault="override" />

<EmberComponent @required="req" @hasDefault={{false}} />

{{repeat "foo" 3}}

{{repeat "foo"}}

{{repeat "foo" "bar"}}
15 changes: 15 additions & 0 deletions test-packages/demo-ember-app/app/helpers/repeat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { helper } from '@glint/environment-ember-loose/ember-component/helper';

function repeat(params: [string, number]/*, hash*/) {
return params[0].repeat(params[1]);
}

const repeatHelper = helper(repeat);

export default repeatHelper;

declare module '@glint/environment-ember-loose/types/registry' {
export default interface Registry {
'repeat': typeof repeatHelper;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';

module('Integration | Component | ember', function(hooks) {
setupRenderingTest(hooks);

test('it renders', async function(assert) {
await render(hbs`<EmberComponent @required="foo" />`);

if (!this.element.textContent) {
throw new Error('No text content!');
}

assert.deepEqual(
this.element.textContent.trim().split(/\s+/),
['foo','defaultValue','foo']
);
});

test('it renders with incorrect arg type', async function(assert) {
await render(hbs`<EmberComponent @required=1 />`);

if (!this.element.textContent) {
throw new Error('No text content!');
}

assert.deepEqual(
this.element.textContent.trim().split(/\s+/),
['1','defaultValue','1']
);
});

test('it renders with missing args', async function(assert) {
await render(hbs`<EmberComponent />`);

if (!this.element.textContent) {
throw new Error('No text content!');
}

assert.equal(this.element.textContent.trim(), 'defaultValue');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,41 @@ module('Integration | Component | foo', function(hooks) {

assert.deepEqual(
this.element.textContent.trim().split(/\s+/),
['FOO','BAR-0','BAR-A','BAR-','BAR-','BAZ','QUX']
[
'FOO',
'BAR-0',
'BAR-A',
'BAR-',
'BAR-',
'BAZ',
'QUX',
'defaultValue',
'req',
'defaultValue',
'req',
'1',
'defaultValue',
'1',
'req',
'1',
'defaultValue',
'req',
'1',
'req',
'opt',
'defaultValue',
'req',
'opt',
'req',
'override',
'req',
'override',
'req',
'false',
'req',
'false',
'foofoofoo',
]
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';

module('Integration | Helper | repeat', function(hooks) {
setupRenderingTest(hooks);

test('it repeats', async function(assert) {
await render(hbs`{{repeat "foo" 3}}`);

assert.equal(this.element.textContent?.trim(), 'foofoofoo');
});
});