Skip to content

Commit bdef85e

Browse files
committed
Merge remote-tracking branch 'origin/main' into publish-v2-addon
2 parents 30b9b0a + 988dd79 commit bdef85e

File tree

60 files changed

+2680
-1297
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+2680
-1297
lines changed

package.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,30 @@
294294
"@ember/runloop/index.js": "ember-source/@ember/runloop/index.js",
295295
"@ember/service/index.js": "ember-source/@ember/service/index.js",
296296
"@ember/template-compilation/index.js": "ember-source/@ember/template-compilation/index.js",
297+
"@ember/template-compiler/-internal-primitives.js": "ember-source/@ember/template-compiler/-internal-primitives.js",
298+
"@ember/template-compiler/-internal-utils.js": "ember-source/@ember/template-compiler/-internal-utils.js",
299+
"@ember/template-compiler/index.js": "ember-source/@ember/template-compiler/index.js",
300+
"@ember/template-compiler/lib/-internal/primitives.js": "ember-source/@ember/template-compiler/lib/-internal/primitives.js",
301+
"@ember/template-compiler/lib/compile-options.js": "ember-source/@ember/template-compiler/lib/compile-options.js",
302+
"@ember/template-compiler/lib/dasherize-component-name.js": "ember-source/@ember/template-compiler/lib/dasherize-component-name.js",
303+
"@ember/template-compiler/lib/plugins/assert-against-attrs.js": "ember-source/@ember/template-compiler/lib/plugins/assert-against-attrs.js",
304+
"@ember/template-compiler/lib/plugins/assert-against-named-outlets.js": "ember-source/@ember/template-compiler/lib/plugins/assert-against-named-outlets.js",
305+
"@ember/template-compiler/lib/plugins/assert-input-helper-without-block.js": "ember-source/@ember/template-compiler/lib/plugins/assert-input-helper-without-block.js",
306+
"@ember/template-compiler/lib/plugins/assert-reserved-named-arguments.js": "ember-source/@ember/template-compiler/lib/plugins/assert-reserved-named-arguments.js",
307+
"@ember/template-compiler/lib/plugins/index.js": "ember-source/@ember/template-compiler/lib/plugins/index.js",
308+
"@ember/template-compiler/lib/plugins/transform-action-syntax.js": "ember-source/@ember/template-compiler/lib/plugins/transform-action-syntax.js",
309+
"@ember/template-compiler/lib/plugins/transform-each-in-into-each.js": "ember-source/@ember/template-compiler/lib/plugins/transform-each-in-into-each.js",
310+
"@ember/template-compiler/lib/plugins/transform-each-track-array.js": "ember-source/@ember/template-compiler/lib/plugins/transform-each-track-array.js",
311+
"@ember/template-compiler/lib/plugins/transform-in-element.js": "ember-source/@ember/template-compiler/lib/plugins/transform-in-element.js",
312+
"@ember/template-compiler/lib/plugins/transform-quoted-bindings-into-just-bindings.js": "ember-source/@ember/template-compiler/lib/plugins/transform-quoted-bindings-into-just-bindings.js",
313+
"@ember/template-compiler/lib/plugins/transform-resolutions.js": "ember-source/@ember/template-compiler/lib/plugins/transform-resolutions.js",
314+
"@ember/template-compiler/lib/plugins/transform-wrap-mount-and-outlet.js": "ember-source/@ember/template-compiler/lib/plugins/transform-wrap-mount-and-outlet.js",
315+
"@ember/template-compiler/lib/plugins/utils.js": "ember-source/@ember/template-compiler/lib/plugins/utils.js",
316+
"@ember/template-compiler/lib/public-api.js": "ember-source/@ember/template-compiler/lib/public-api.js",
317+
"@ember/template-compiler/lib/runtime.js": "ember-source/@ember/template-compiler/lib/runtime.js",
318+
"@ember/template-compiler/lib/system/calculate-location-display.js": "ember-source/@ember/template-compiler/lib/system/calculate-location-display.js",
319+
"@ember/template-compiler/lib/template.js": "ember-source/@ember/template-compiler/lib/template.js",
320+
"@ember/template-compiler/runtime.js": "ember-source/@ember/template-compiler/runtime.js",
297321
"@ember/template-factory/index.js": "ember-source/@ember/template-factory/index.js",
298322
"@ember/template/index.js": "ember-source/@ember/template/index.js",
299323
"@ember/test/adapter.js": "ember-source/@ember/test/adapter.js",
Lines changed: 338 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
import { template } from '@ember/template-compiler/runtime';
2+
import { RenderingTestCase, defineSimpleModifier, moduleFor } from 'internal-test-helpers';
3+
import GlimmerishComponent from '../../utils/glimmerish-component';
4+
import { on } from '@ember/modifier/on';
5+
import { fn } from '@ember/helper';
6+
7+
moduleFor(
8+
'Strict Mode - Runtime Template Compiler (explicit)',
9+
class extends RenderingTestCase {
10+
async '@test Can use a component in scope'() {
11+
await this.renderComponentModule(() => {
12+
let Foo = template('Hello, world!');
13+
14+
return template('<Foo />', {
15+
scope: () => ({ Foo }),
16+
});
17+
});
18+
19+
this.assertHTML('Hello, world!');
20+
this.assertStableRerender();
21+
}
22+
23+
async '@test Can use a custom helper in scope (in append position)'() {
24+
await this.renderComponentModule(() => {
25+
let foo = () => 'Hello, world!';
26+
27+
return template('{{foo}}', {
28+
scope: () => ({ foo }),
29+
});
30+
});
31+
32+
this.assertHTML('Hello, world!');
33+
this.assertStableRerender();
34+
}
35+
36+
async '@test Can use a custom modifier in scope'() {
37+
await this.renderComponentModule(() => {
38+
let foo = defineSimpleModifier((element: Element) => (element.innerHTML = 'Hello, world!'));
39+
return template('<div {{foo}}></div>', {
40+
scope: () => ({ foo }),
41+
});
42+
});
43+
44+
this.assertHTML('<div>Hello, world!</div>');
45+
this.assertStableRerender();
46+
}
47+
48+
async '@test Can shadow keywords'() {
49+
await this.renderComponentModule(() => {
50+
let each = template(`{{yield}}`);
51+
52+
return template(`{{#each}}Hello, world!{{/each}}`, {
53+
scope: () => ({ each }),
54+
});
55+
});
56+
57+
this.assertHTML('Hello, world!');
58+
this.assertStableRerender();
59+
}
60+
61+
async '@test Can use constant values in ambiguous helper/component position'() {
62+
await this.renderComponentModule(() => {
63+
let value = 'Hello, world!';
64+
65+
return template(`{{value}}`, {
66+
scope: () => ({ value }),
67+
});
68+
});
69+
70+
this.assertHTML('Hello, world!');
71+
this.assertStableRerender();
72+
}
73+
74+
async '@test Can use inline if and unless in strict mode templates'() {
75+
await this.renderComponentModule(() => {
76+
return template('{{if true "foo" "bar"}}{{unless true "foo" "bar"}}');
77+
});
78+
79+
this.assertHTML('foobar');
80+
this.assertStableRerender();
81+
}
82+
83+
async '@test Can use a dynamic component definition'() {
84+
await this.renderComponentModule(() => {
85+
let Foo = template('Hello, world!');
86+
87+
return class extends GlimmerishComponent {
88+
static {
89+
template('<this.Foo />', {
90+
component: this,
91+
});
92+
}
93+
94+
Foo = Foo;
95+
};
96+
});
97+
98+
this.assertHTML('Hello, world!');
99+
this.assertStableRerender();
100+
}
101+
102+
async '@test Can use a dynamic component definition (curly)'() {
103+
await this.renderComponentModule(() => {
104+
let Foo = template('Hello, world!');
105+
106+
return class extends GlimmerishComponent {
107+
static {
108+
template('{{this.Foo}}', {
109+
component: this,
110+
});
111+
}
112+
113+
Foo = Foo;
114+
};
115+
});
116+
117+
this.assertHTML('Hello, world!');
118+
this.assertStableRerender();
119+
}
120+
121+
async '@test Can use a dynamic helper definition'() {
122+
await this.renderComponentModule(() => {
123+
let foo = () => 'Hello, world!';
124+
125+
return class extends GlimmerishComponent {
126+
static {
127+
template('{{this.foo}}', {
128+
component: this,
129+
});
130+
}
131+
132+
foo = foo;
133+
};
134+
});
135+
136+
this.assertHTML('Hello, world!');
137+
this.assertStableRerender();
138+
}
139+
140+
async '@test Can use a curried dynamic helper'() {
141+
await this.renderComponentModule(() => {
142+
let foo = (v: string) => v;
143+
144+
let Foo = template('{{@value}}');
145+
146+
return template('<Foo @value={{helper foo "Hello, world!"}}/>', {
147+
scope: () => ({ foo, Foo }),
148+
});
149+
});
150+
this.assertHTML('Hello, world!');
151+
this.assertStableRerender();
152+
}
153+
154+
async '@test Can use a curried dynamic modifier'() {
155+
await this.renderComponentModule(() => {
156+
let foo = defineSimpleModifier(
157+
(element: Element, [text]: [string]) => (element.innerHTML = text)
158+
);
159+
160+
let Foo = template('<div {{@value}}></div>');
161+
162+
return template('<Foo @value={{modifier foo "Hello, world!"}}/>', {
163+
scope: () => ({ foo, Foo }),
164+
});
165+
});
166+
this.assertHTML('<div>Hello, world!</div>');
167+
this.assertStableRerender();
168+
}
169+
}
170+
);
171+
172+
moduleFor(
173+
'Strict Mode - Runtime Template Compiler (explicit) - built ins',
174+
class extends RenderingTestCase {
175+
async '@test Can use Input'() {
176+
const { Input } = await import('@ember/component');
177+
178+
await this.renderComponentModule(() => {
179+
return template('<Input/>', {
180+
scope: () => ({
181+
Input,
182+
}),
183+
});
184+
});
185+
186+
this.assertComponentElement(this.firstChild, {
187+
tagName: 'input',
188+
attrs: {
189+
type: 'text',
190+
class: 'ember-text-field ember-view',
191+
},
192+
});
193+
this.assertStableRerender();
194+
}
195+
196+
async '@test Can use Textarea'() {
197+
const { Textarea } = await import('@ember/component');
198+
199+
await this.renderComponentModule(() => {
200+
return template('<Textarea/>', {
201+
scope: () => ({
202+
Textarea,
203+
}),
204+
});
205+
});
206+
207+
this.assertComponentElement(this.firstChild, {
208+
tagName: 'textarea',
209+
attrs: {
210+
class: 'ember-text-area ember-view',
211+
},
212+
});
213+
this.assertStableRerender();
214+
}
215+
216+
async '@test Can use hash'() {
217+
const { hash } = await import('@glimmer/runtime');
218+
219+
await this.renderComponentModule(() => {
220+
return template('{{#let (hash value="Hello, world!") as |hash|}}{{hash.value}}{{/let}}', {
221+
scope: () => ({ hash }),
222+
});
223+
});
224+
225+
this.assertHTML('Hello, world!');
226+
this.assertStableRerender();
227+
}
228+
229+
async '@test Can use array'() {
230+
const { array } = await import('@glimmer/runtime');
231+
232+
await this.renderComponentModule(() => {
233+
return template('{{#each (array "Hello, world!") as |value|}}{{value}}{{/each}}', {
234+
scope: () => ({ array }),
235+
});
236+
});
237+
this.assertHTML('Hello, world!');
238+
this.assertStableRerender();
239+
}
240+
241+
async '@test Can use concat'() {
242+
const { concat } = await import('@glimmer/runtime');
243+
244+
await this.renderComponentModule(() => {
245+
return template('{{(concat "Hello" ", " "world!")}}', {
246+
scope: () => ({ concat }),
247+
});
248+
});
249+
250+
this.assertHTML('Hello, world!');
251+
this.assertStableRerender();
252+
}
253+
254+
async '@test Can use get'() {
255+
const { hash, get } = await import('@glimmer/runtime');
256+
257+
await this.renderComponentModule(() => {
258+
return template(
259+
'{{#let (hash value="Hello, world!") as |hash|}}{{(get hash "value")}}{{/let}}',
260+
{
261+
scope: () => ({ hash, get }),
262+
}
263+
);
264+
});
265+
266+
this.assertHTML('Hello, world!');
267+
this.assertStableRerender();
268+
}
269+
270+
async '@test Can use on and fn'(assert: QUnit['assert']) {
271+
assert.expect(1);
272+
273+
await this.renderComponentModule(() => {
274+
let handleClick = (value: unknown) => {
275+
assert.equal(value, 123);
276+
};
277+
278+
return template('<button {{on "click" (fn handleClick 123)}}>Click</button>', {
279+
scope: () => ({ handleClick, on, fn }),
280+
});
281+
});
282+
283+
this.click('button');
284+
}
285+
286+
// Test some of the additional keywords not built-in to glimmer-vm (those
287+
// we specifically enable them when calling `precompile`)
288+
289+
// Ember currently uses AST plugins to implement certain features that
290+
// glimmer-vm does not natively provide, such as {{#each-in}}, {{outlet}}
291+
// {{mount}} and some features in {{#in-element}}. These rewrites the AST
292+
// and insert private keywords e.g. `{{#each (-each-in)}}`. These tests
293+
// ensures we have _some_ basic coverage for those features in strict mode.
294+
//
295+
// Ultimately, our test coverage for strict mode is quite inadequate. This
296+
// is particularly important as we expect more apps to start adopting the
297+
// feature. Ideally we would run our entire/most of our test suite against
298+
// both strict and resolution modes, and these things would be implicitly
299+
// covered elsewhere, but until then, these coverage are essential.
300+
301+
async '@test Can use each-in'() {
302+
let obj = {
303+
foo: 'FOO',
304+
bar: 'BAR',
305+
};
306+
307+
await this.renderComponentModule(() => {
308+
return template('{{#each-in obj as |k v|}}[{{k}}:{{v}}]{{/each-in}}', {
309+
scope: () => ({ obj }),
310+
});
311+
});
312+
313+
this.assertHTML('[foo:FOO][bar:BAR]');
314+
this.assertStableRerender();
315+
}
316+
317+
async '@test Can use in-element'() {
318+
const fixture = document.querySelector('#qunit-fixture')!;
319+
const element: HTMLTemplateElement = document.createElement('template');
320+
element.innerHTML = '[<div id="in-element-test"></div>]';
321+
fixture.appendChild(element.content);
322+
323+
const getElement = (id: string) => document.querySelector(`#${id}`)!;
324+
325+
await this.renderComponentModule(() => {
326+
return template(
327+
'{{#in-element (getElement "in-element-test")}}before{{/in-element}}after',
328+
{
329+
scope: () => ({ getElement }),
330+
}
331+
);
332+
});
333+
334+
this.assertText('[before]after');
335+
this.assertStableRerender();
336+
}
337+
}
338+
);

0 commit comments

Comments
 (0)