Skip to content
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

can-stache 4.0 #289

Closed
phillipskevin opened this Issue Sep 6, 2017 · 10 comments

Comments

Projects
None yet
5 participants
@phillipskevin
Copy link
Contributor

phillipskevin commented Sep 6, 2017

TLDR

To make stache easier to lean and understand, we should:

  • Remove implicit scope walking
  • Remove automatic function calling
  • Remove %special keywords
  • Remove @
  • Use can-parse for parsing Expressions

This was discussed at a contributors meeting (28:44)

Steps

3.0 Issues:

4.0 issues:

5.0 issues:

Possible other steps:

Details

The first version of can-stache shipped with CanJS 2.1 nearly 3½ years ago. In that time many new features have been added and countless bugs have been fixed. We've also taught stache to countless meetup attendees and client developers and found many hard edges that make it difficult for new users to learn and difficult for even seasoned CanJS developers to maintain in large apps.

Here are the major changes that we'd like to make in a can-stache 5.0 release:

Remove implicit scope walking

Currently in can-stache, any variables you use within magic tags or bindings are looked up in a hierarchy of scopes.

This means that if you render a stache template like

{{#each children}}
    <li>{{name}} is {{age}} years old</li>
{{/each}}

with some data like

{
    name: 'Justin',
    age: 33,
    children: [{
        name: 'Ramiya',
        age: 2
    }, {
        name: 'Joffrey'
    }]
}

You will get an output that looks like

    <li>Ramiya is 2 years old</li>
    <li>Joffrey is 33 years old</li>

It might be obvious what is happening in this simple example, but when this happens in larger apps it is often very difficult to identify.

There are many ways to prevent this from happening; You can use ./ and ../ to explicitly specify the scope you want to read from.

{{#each children}}
    <li>{{./name}} is {{./age}} years old</li>
{{/each}}

We are also adding the ability to use hash expressions to explicitly name the variables used in {{#each}} and {{#with}} statements, so you can do something like:

{{#each children child=value}}
    <li>{{child.name}} is {{child.age}} years old</li>
{{/each}}

These things make it possible to do the right thing, so we should remove the current default thing which is almost always not what you want.

If you want to explicitly walk up the scope, you can still do that with ../.

Remove automatic function calling

The default behavior in Stache lookups is to execute functions to get their return values.

This confuses people because they expect to have to call a function in order to get its return value. For example, people get confused that both of the following will call myFunction and set the value of the input to whatever myFunction returns.

<input value:from="myFunction" type="text">
<input value:from="myFunction()" type="text">

This also means that in order to actually pass the function through bindings, you need to use @ which people sometimes also find confusing.

In 5.0, we should remove this behavior so that functions are not automatically called and you have to call them yourself in order to get the return value.

Remove %special keywords

This is detailed in depth in this issue.

Remove @

Since we will no longer call functions by default, we do not need @ to prevent that behavior. Also discussed in this issue.

Use can-parse for parsing Expressions

This is #290. This isn't a breaking change, but would rewrite all of the code that is used for parsing expressions in can-stache so could be done along with 5.0 in order to reduce the risk of regressions in a patch/minor release.

The purpose of this is to increase the consistency of the behavior of stache expressions by using a structured parser instead of the while loop and if/else statements that are used today.

This will reduce the number of issues where certain Expressions do not work in every scenario someone expects and would allow us to more clearly specify when you can use each type of Expression.

For example, here are some issues related to Bracket Expressions not working in different places:

These were all related to Bracket Expressions simply because this was the Expression that was added most recently. Similar problems have existed with other types of Expressions that people wanted to use in places that weren't originally anticipated.

Using a structured parser with an actual grammar will make it much easier to avoid issues like this and will allow us to add new features much more quickly.

@phillipskevin phillipskevin added the Epic label Sep 6, 2017

@matthewp

This comment has been minimized.

Copy link
Contributor

matthewp commented Sep 6, 2017

If special keywords are removed how would you reference, for example, the index within an array?

@phillipskevin

This comment has been minimized.

Copy link
Contributor Author

phillipskevin commented Sep 6, 2017

One idea is to use a reserved scope keyword. #287 describes that.

I've also though about making our helpers look more like arrow functions (instead of using as), so you would do something like:

{{#each(todos => (todo, index))}}
    <li>todo {{index}}: {{todo.name}}</li>
{{/each}}

edit: this syntax doesn't exactly make sense... not sure exactly what it should look like.

@andrejewski

This comment has been minimized.

Copy link
Contributor

andrejewski commented Sep 6, 2017

Ember does as |value index| to expose the index of an array. Example:

{{#each model as |item index|}}
  <li>
    Index: {{index}} Content: {{item}}
  </li>
{{/each}}
@matthewp

This comment has been minimized.

Copy link
Contributor

matthewp commented Sep 6, 2017

Cool, we have an as as well: https://canjs.com/doc/can-stache.helpers.each.html#___eachEXPRESSIONasKEY__FN__else__INVERSE___each__

Maybe this could be made to support some type of destructing syntax...

@justinbmeyer

This comment has been minimized.

Copy link
Contributor

justinbmeyer commented Sep 28, 2017

Do we want to enable people to call functions like:

{{myFunc}} vs {{myFunc}}

{{#each thing}}

{{foo}}

  1. check if on current context
    2.check helpers
  2. walk up scope

Instead

  1. check on current scope
  2. check global helpers? (can we remove options scope?)
  3. break
@justinbmeyer

This comment has been minimized.

Copy link
Contributor

justinbmeyer commented Sep 28, 2017

zed: "string"

can-stache-key

can.hasOwnProperty(obj,"zed") //-> true

don't warn

@justinbmeyer

This comment has been minimized.

Copy link
Contributor

justinbmeyer commented Sep 28, 2017

{{getThingFrom id}} getThingFrom must be a helper

@justinbmeyer

This comment has been minimized.

Copy link
Contributor

justinbmeyer commented Sep 28, 2017

{{#each( items, item=boo) }}

@phillipskevin phillipskevin changed the title can-stache 4.0 can-stache 5.0 Oct 16, 2017

@phillipskevin

This comment has been minimized.

Copy link
Contributor Author

phillipskevin commented Oct 27, 2017

can we remove this weird lookup?

// If the expression looks like a helper, try to get a helper right away.
if (looksLikeAHelper) {
// Try to find a registered helper.
helper = mustacheHelpers.getHelper(methodKey, helperOptions);

@phillipskevin phillipskevin changed the title can-stache 5.0 can-stache 4.0 Jan 29, 2018

@frank-dspeed

This comment has been minimized.

Copy link
Contributor

frank-dspeed commented Feb 12, 2018

@phillipskevin i think this issue needs to get reduced to 5.0 related parts as can stache is already 4 ?

@justinbmeyer justinbmeyer changed the title can-stache 4.0 can-stache 5.0 Mar 7, 2018

@justinbmeyer justinbmeyer changed the title can-stache 5.0 can-stache 4.0 Mar 7, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.