/**
@module ember
*/
import { assert } from '@ember/debug';
import { symbol } from 'ember-utils';
import { INVOKE, UPDATE } from '../utils/references';
/**
The `mut` helper lets you __clearly specify__ that a child `Component` can update the
(mutable) value passed to it, which will __change the value of the parent component__.
To specify that a parameter is mutable, when invoking the child `Component`:
```handlebars
{{my-child childClickCount=(mut totalClicks)}}
```
The child `Component` can then modify the parent's value just by modifying its own
property:
```javascript
// my-child.js
export default Component.extend({
click() {
this.incrementProperty('childClickCount');
}
});
```
Note that for curly components (`{{my-component}}`) the bindings are already mutable,
making the `mut` unnecessary.
Additionally, the `mut` helper can be combined with the `action` helper to
mutate a value. For example:
```handlebars
{{my-child childClickCount=totalClicks click-count-change=(action (mut totalClicks))}}
```
The child `Component` would invoke the action with the new click value:
```javascript
// my-child.js
export default Component.extend({
click() {
this.get('click-count-change')(this.get('childClickCount') + 1);
}
});
```
The `mut` helper changes the `totalClicks` value to what was provided as the action argument.
The `mut` helper, when used with `action`, will return a function that
sets the value passed to `mut` to its first argument. This works like any other
closure action and interacts with the other features `action` provides.
As an example, we can create a button that increments a value passing the value
directly to the `action`:
```handlebars
{{! inc helper is not provided by Ember }}
```
You can also use the `value` option:
```handlebars
```
@method mut
@param {Object} [attr] the "two-way" attribute that can be modified.
@for Ember.Templates.helpers
@public
*/
const MUT_REFERENCE = symbol('MUT');
const SOURCE = symbol('SOURCE');
export function isMut(ref) {
return ref && ref[MUT_REFERENCE];
}
export function unMut(ref) {
return ref[SOURCE] || ref;
}
export default function (_vm, args) {
let rawRef = args.positional.at(0);
if (isMut(rawRef)) {
return rawRef;
}
// TODO: Improve this error message. This covers at least two distinct
// cases:
//
// 1. (mut "not a path") – passing a literal, result from a helper
// invocation, etc
//
// 2. (mut receivedValue) – passing a value received from the caller
// that was originally derived from a literal, result from a helper
// invocation, etc
//
// This message is alright for the first case, but could be quite
// confusing for the second case.
assert('You can only pass a path to mut', rawRef[UPDATE]);
let wrappedRef = Object.create(rawRef);
wrappedRef[SOURCE] = rawRef;
wrappedRef[INVOKE] = rawRef[UPDATE];
wrappedRef[MUT_REFERENCE] = true;
return wrappedRef;
}