diff --git a/packages/@ember/-internals/glimmer/lib/resolver.ts b/packages/@ember/-internals/glimmer/lib/resolver.ts index 384154ef9b5..fc8b7e9ce8a 100644 --- a/packages/@ember/-internals/glimmer/lib/resolver.ts +++ b/packages/@ember/-internals/glimmer/lib/resolver.ts @@ -3,6 +3,7 @@ import { ENV } from '@ember/-internals/environment'; import { LookupOptions, Owner, setOwner } from '@ember/-internals/owner'; import { lookupComponent, lookupPartial, OwnedTemplateMeta } from '@ember/-internals/views'; import { + EMBER_GLIMMER_ARRAY_HELPER, EMBER_MODULE_UNIFICATION, GLIMMER_CUSTOM_COMPONENT_MANAGER, GLIMMER_MODIFIER_MANAGER, @@ -66,7 +67,6 @@ const BUILTINS_HELPERS = { concat, get, hash, - array, log, mut, 'query-params': queryParams, @@ -84,6 +84,10 @@ const BUILTINS_HELPERS = { '-assert-implicit-component-helper-argument': componentAssertionHelper, }; +if (EMBER_GLIMMER_ARRAY_HELPER) { + BUILTINS_HELPERS['array'] = array; +} + const BUILTIN_MODIFIERS = { action: { manager: new ActionModifierManager(), state: null }, }; diff --git a/packages/@ember/-internals/glimmer/tests/integration/helpers/array-test.js b/packages/@ember/-internals/glimmer/tests/integration/helpers/array-test.js index 6e33a842953..5144a429fb2 100644 --- a/packages/@ember/-internals/glimmer/tests/integration/helpers/array-test.js +++ b/packages/@ember/-internals/glimmer/tests/integration/helpers/array-test.js @@ -2,95 +2,97 @@ import { RenderingTest, moduleFor } from '../../utils/test-case'; import { strip } from '../../utils/abstract-test-case'; import { Component } from '../../utils/helpers'; import { set } from '@ember/-internals/metal'; - -moduleFor( - 'Helpers test: {{array}}', - class extends RenderingTest { - ['@test returns an array']() { - this.render(strip` +import { EMBER_GLIMMER_ARRAY_HELPER } from '@ember/canary-features'; + +if (EMBER_GLIMMER_ARRAY_HELPER) { + moduleFor( + 'Helpers test: {{array}}', + class extends RenderingTest { + ['@test returns an array']() { + this.render(strip` {{#with (array "Sergio") as |people|}} {{#each people as |personName|}} {{personName}} {{/each}} {{/with}}`); - this.assertText('Sergio'); + this.assertText('Sergio'); - this.assertStableRerender(); - } + this.assertStableRerender(); + } - ['@test can have more than one value']() { - this.render(strip` + ['@test can have more than one value']() { + this.render(strip` {{#with (array "Sergio" "Robert") as |people|}} {{#each people as |personName|}} {{personName}}, {{/each}} {{/with}}`); - this.assertText('Sergio,Robert,'); + this.assertText('Sergio,Robert,'); - this.assertStableRerender(); - } + this.assertStableRerender(); + } - ['@test binds values when variables are used']() { - this.render( - strip`{{#with (array personOne) as |people|}} + ['@test binds values when variables are used']() { + this.render( + strip`{{#with (array personOne) as |people|}} {{#each people as |personName|}} {{personName}} {{/each}} {{/with}}`, - { - personOne: 'Tom', - } - ); + { + personOne: 'Tom', + } + ); - this.assertText('Tom'); + this.assertText('Tom'); - this.assertStableRerender(); + this.assertStableRerender(); - this.runTask(() => set(this.context, 'personOne', 'Yehuda')); - this.assertText('Yehuda'); + this.runTask(() => set(this.context, 'personOne', 'Yehuda')); + this.assertText('Yehuda'); - this.runTask(() => set(this.context, 'personOne', 'Tom')); - this.assertText('Tom'); - } + this.runTask(() => set(this.context, 'personOne', 'Tom')); + this.assertText('Tom'); + } - ['@test binds multiple values when variables are used']() { - this.render( - strip`{{#with (array personOne personTwo) as |people|}} + ['@test binds multiple values when variables are used']() { + this.render( + strip`{{#with (array personOne personTwo) as |people|}} {{#each people as |personName|}} {{personName}}, {{/each}} {{/with}}`, - { - personOne: 'Tom', - personTwo: 'Yehuda', - } - ); + { + personOne: 'Tom', + personTwo: 'Yehuda', + } + ); - this.assertText('Tom,Yehuda,'); + this.assertText('Tom,Yehuda,'); - this.assertStableRerender(); + this.assertStableRerender(); - this.runTask(() => set(this.context, 'personOne', 'Sergio')); + this.runTask(() => set(this.context, 'personOne', 'Sergio')); - this.assertText('Sergio,Yehuda,'); + this.assertText('Sergio,Yehuda,'); - this.runTask(() => set(this.context, 'personTwo', 'Tom')); + this.runTask(() => set(this.context, 'personTwo', 'Tom')); - this.assertText('Sergio,Tom,'); + this.assertText('Sergio,Tom,'); - this.runTask(() => { - set(this.context, 'personOne', 'Tom'); - set(this.context, 'personTwo', 'Yehuda'); - }); + this.runTask(() => { + set(this.context, 'personOne', 'Tom'); + set(this.context, 'personTwo', 'Yehuda'); + }); - this.assertText('Tom,Yehuda,'); - } + this.assertText('Tom,Yehuda,'); + } - ['@test array helpers can be nested']() { - this.render( - strip`{{#with (array (array personOne personTwo)) as |listOfPeople|}} + ['@test array helpers can be nested']() { + this.render( + strip`{{#with (array (array personOne personTwo)) as |listOfPeople|}} {{#each listOfPeople as |people|}} List: {{#each people as |personName|}} @@ -98,190 +100,191 @@ moduleFor( {{/each}} {{/each}} {{/with}}`, - { - personOne: 'Tom', - personTwo: 'Yehuda', - } - ); + { + personOne: 'Tom', + personTwo: 'Yehuda', + } + ); - this.assertText('List:Tom,Yehuda,'); + this.assertText('List:Tom,Yehuda,'); - this.assertStableRerender(); + this.assertStableRerender(); - this.runTask(() => set(this.context, 'personOne', 'Chad')); + this.runTask(() => set(this.context, 'personOne', 'Chad')); - this.assertText('List:Chad,Yehuda,'); + this.assertText('List:Chad,Yehuda,'); - this.runTask(() => set(this.context, 'personTwo', 'Balint')); + this.runTask(() => set(this.context, 'personTwo', 'Balint')); - this.assertText('List:Chad,Balint,'); + this.assertText('List:Chad,Balint,'); - this.runTask(() => { - set(this.context, 'personOne', 'Tom'); - set(this.context, 'personTwo', 'Yehuda'); - }); + this.runTask(() => { + set(this.context, 'personOne', 'Tom'); + set(this.context, 'personTwo', 'Yehuda'); + }); - this.assertText('List:Tom,Yehuda,'); - } + this.assertText('List:Tom,Yehuda,'); + } + + ['@test should yield hash of an array of internal properties']() { + let fooBarInstance; + let FooBarComponent = Component.extend({ + init() { + this._super(); + fooBarInstance = this; + this.model = { personOne: 'Chad' }; + }, + }); + + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: `{{yield (hash people=(array model.personOne))}}`, + }); - ['@test should yield hash of an array of internal properties']() { - let fooBarInstance; - let FooBarComponent = Component.extend({ - init() { - this._super(); - fooBarInstance = this; - this.model = { personOne: 'Chad' }; - }, - }); - - this.registerComponent('foo-bar', { - ComponentClass: FooBarComponent, - template: `{{yield (hash people=(array model.personOne))}}`, - }); - - this.render(strip` + this.render(strip` {{#foo-bar as |values|}} {{#each values.people as |personName|}} {{personName}} {{/each}} {{/foo-bar}}`); - this.assertText('Chad'); + this.assertText('Chad'); - this.assertStableRerender(); + this.assertStableRerender(); - this.runTask(() => set(fooBarInstance, 'model.personOne', 'Godfrey')); + this.runTask(() => set(fooBarInstance, 'model.personOne', 'Godfrey')); - this.assertText('Godfrey'); + this.assertText('Godfrey'); - this.runTask(() => set(fooBarInstance, 'model', { personOne: 'Chad' })); + this.runTask(() => set(fooBarInstance, 'model', { personOne: 'Chad' })); - this.assertText('Chad'); + this.assertText('Chad'); - this.runTask(() => set(fooBarInstance, 'model.personOne', 'Godfrey')); + this.runTask(() => set(fooBarInstance, 'model.personOne', 'Godfrey')); - this.assertText('Godfrey'); - } + this.assertText('Godfrey'); + } + + ['@test should yield hash of an array of internal and external properties']() { + let fooBarInstance; + let FooBarComponent = Component.extend({ + init() { + this._super(); + fooBarInstance = this; + this.model = { personOne: 'Chad' }; + }, + }); - ['@test should yield hash of an array of internal and external properties']() { - let fooBarInstance; - let FooBarComponent = Component.extend({ - init() { - this._super(); - fooBarInstance = this; - this.model = { personOne: 'Chad' }; - }, - }); - - this.registerComponent('foo-bar', { - ComponentClass: FooBarComponent, - template: `{{yield (hash people=(array model.personOne personTwo))}}`, - }); - - this.render( - strip`{{#foo-bar personTwo=model.personTwo as |values|}} + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: `{{yield (hash people=(array model.personOne personTwo))}}`, + }); + + this.render( + strip`{{#foo-bar personTwo=model.personTwo as |values|}} {{#each values.people as |personName|}} {{personName}}, {{/each}} {{/foo-bar}}`, - { - model: { personTwo: 'Tom' }, - } - ); + { + model: { personTwo: 'Tom' }, + } + ); - this.assertText('Chad,Tom,'); + this.assertText('Chad,Tom,'); - this.assertStableRerender(); + this.assertStableRerender(); - this.runTask(() => { - set(fooBarInstance, 'model.personOne', 'Godfrey'); - set(this.context, 'model.personTwo', 'Yehuda'); - }); + this.runTask(() => { + set(fooBarInstance, 'model.personOne', 'Godfrey'); + set(this.context, 'model.personTwo', 'Yehuda'); + }); - this.assertText('Godfrey,Yehuda,'); + this.assertText('Godfrey,Yehuda,'); - this.runTask(() => { - set(fooBarInstance, 'model', { personOne: 'Chad' }); - set(this.context, 'model', { personTwo: 'Tom' }); - }); + this.runTask(() => { + set(fooBarInstance, 'model', { personOne: 'Chad' }); + set(this.context, 'model', { personTwo: 'Tom' }); + }); - this.assertText('Chad,Tom,'); - } + this.assertText('Chad,Tom,'); + } - ['@test should render when passing as argument to a component invocation']() { - let FooBarComponent = Component.extend({}); + ['@test should render when passing as argument to a component invocation']() { + let FooBarComponent = Component.extend({}); - this.registerComponent('foo-bar', { - ComponentClass: FooBarComponent, - template: strip` + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: strip` {{#each people as |personName|}} {{personName}}, {{/each}}`, - }); + }); - this.render(strip`{{foo-bar people=(array "Tom" personTwo)}}`, { personTwo: 'Chad' }); + this.render(strip`{{foo-bar people=(array "Tom" personTwo)}}`, { personTwo: 'Chad' }); - this.assertText('Tom,Chad,'); + this.assertText('Tom,Chad,'); - this.assertStableRerender(); + this.assertStableRerender(); - this.runTask(() => set(this.context, 'personTwo', 'Godfrey')); + this.runTask(() => set(this.context, 'personTwo', 'Godfrey')); - this.assertText('Tom,Godfrey,'); + this.assertText('Tom,Godfrey,'); - this.runTask(() => set(this.context, 'personTwo', 'Chad')); + this.runTask(() => set(this.context, 'personTwo', 'Chad')); - this.assertText('Tom,Chad,'); - } + this.assertText('Tom,Chad,'); + } + + ['@test should return an entirely new array when any argument change']() { + let fooBarInstance; + let FooBarComponent = Component.extend({ + init() { + this._super(); + fooBarInstance = this; + }, + }); - ['@test should return an entirely new array when any argument change']() { - let fooBarInstance; - let FooBarComponent = Component.extend({ - init() { - this._super(); - fooBarInstance = this; - }, - }); - - this.registerComponent('foo-bar', { - ComponentClass: FooBarComponent, - template: strip` + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: strip` {{#each people as |personName|}} {{personName}}, {{/each}}`, - }); + }); - this.render(strip`{{foo-bar people=(array "Tom" personTwo)}}`, { personTwo: 'Chad' }); + this.render(strip`{{foo-bar people=(array "Tom" personTwo)}}`, { personTwo: 'Chad' }); - let firstArray = fooBarInstance.people; + let firstArray = fooBarInstance.people; - this.runTask(() => set(this.context, 'personTwo', 'Godfrey')); + this.runTask(() => set(this.context, 'personTwo', 'Godfrey')); - this.assert.ok( - firstArray !== fooBarInstance.people, - 'should have created an entirely new array' - ); - } + this.assert.ok( + firstArray !== fooBarInstance.people, + 'should have created an entirely new array' + ); + } - ['@test capture array values in JS to assert deep equal']() { - let captured; + ['@test capture array values in JS to assert deep equal']() { + let captured; - this.registerHelper('capture', function([array]) { - captured = array; - return 'captured'; - }); + this.registerHelper('capture', function([array]) { + captured = array; + return 'captured'; + }); - this.render(`{{capture (array 'Tom' personTwo)}}`, { personTwo: 'Godfrey' }); + this.render(`{{capture (array 'Tom' personTwo)}}`, { personTwo: 'Godfrey' }); - this.assert.deepEqual(captured, ['Tom', 'Godfrey']); + this.assert.deepEqual(captured, ['Tom', 'Godfrey']); - this.runTask(() => set(this.context, 'personTwo', 'Robert')); + this.runTask(() => set(this.context, 'personTwo', 'Robert')); - this.assert.deepEqual(captured, ['Tom', 'Robert']); + this.assert.deepEqual(captured, ['Tom', 'Robert']); - this.runTask(() => set(this.context, 'personTwo', 'Godfrey')); + this.runTask(() => set(this.context, 'personTwo', 'Godfrey')); - this.assert.deepEqual(captured, ['Tom', 'Godfrey']); + this.assert.deepEqual(captured, ['Tom', 'Godfrey']); + } } - } -); + ); +} diff --git a/packages/@ember/canary-features/index.ts b/packages/@ember/canary-features/index.ts index 34093de2d2f..43127afa07b 100644 --- a/packages/@ember/canary-features/index.ts +++ b/packages/@ember/canary-features/index.ts @@ -23,6 +23,7 @@ export const DEFAULT_FEATURES = { GLIMMER_MODIFIER_MANAGER: null, EMBER_METAL_TRACKED_PROPERTIES: null, EMBER_GLIMMER_ANGLE_BRACKET_INVOCATION: true, + EMBER_GLIMMER_ARRAY_HELPER: null, }; /** @@ -85,3 +86,4 @@ export const EMBER_GLIMMER_ANGLE_BRACKET_INVOCATION = featureValue( FEATURES.EMBER_GLIMMER_ANGLE_BRACKET_INVOCATION ); export const GLIMMER_MODIFIER_MANAGER = featureValue(FEATURES.GLIMMER_MODIFIER_MANAGER); +export const EMBER_GLIMMER_ARRAY_HELPER = featureValue(FEATURES.EMBER_GLIMMER_ARRAY_HELPER);