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
Refactor #19
base: master
Are you sure you want to change the base?
Refactor #19
Conversation
Signed-off-by: Charlike Mike Reagent <mameto2011@gmail.com>
Signed-off-by: Charlike Mike Reagent <mameto2011@gmail.com>
Signed-off-by: Charlike Mike Reagent <mameto2011@gmail.com>
Signed-off-by: Charlike Mike Reagent <mameto2011@gmail.com>
'lower(upper): {{lower (upper name)}}', | ||
'spacer(upper, lower): {{spacer (upper name) (lower "X")}}', | ||
'block: {{#block}}{{upper name}}{{/block}}', | ||
'ifConditional1: {{#if (equals "foo" foo)}}{{upper name}}{{/if}}', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretty strange. I understand why it goes into the if. Because equals
returns boolean false which is passed to the callback, but in reality, this means that it will get converted to string 'false'
, and that's why it goes inside.
Not sure how to handle this. You can see that the added ifConditional3
is working correctly and does to go inside the if.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should handle such cases in the implementation, because it may break other cases such as lodash tests.
I think that in the equals
helper we can check if it is falsey value then pass empty string or just call cb()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason this happens is because of the 2 steps that are taken... the template is rendered into a string with async ids, then the ids are resolved. Since the if
helper isn't wrapped, the async id is passed directly to the if
logic so it looks like a truthy value.
This is the same reason why in engines like lodash
, you can't directly use if
statements with async helpers.
It's something that we've talked about and think that it would take another pass at the "engine" level to possible detect built-in helpers (like {{#if}}
in handlebars
or control flow statements like if
in lodash
. I don't think it should be handled in async-helpers
since this is intended to be template engine agnostic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aaaah. Yea, equals
is async function so the return is again an id. ;d
I don't think it should be handled in async-helpers since this is intended to be template engine agnostic.
Agree.
But how then it is working in the current master (v0.3)? If it's not a problem, we can continue.
Signed-off-by: Charlike Mike Reagent <mameto2011@gmail.com>
test/handlebars.js
Outdated
@@ -23,6 +23,8 @@ var tmpl = [ | |||
'ifConditional1: {{#if (equals "foo" foo)}}{{upper name}}{{/if}}', | |||
'ifConditional2: {{#if (equals "baz" bar)}}{{upper name}}{{/if}}', | |||
'ifConditional3: {{#if foo}}{{upper name}}{{/if}}', | |||
'ifConditional4: {{#if false}}{{upper name}}{{/if}}', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get why when equals
returns boolean false
it does not work when this passes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the comment above, I explain how the async helper equals
will actually return a string (the async id) during the rendering pass, then the id is resolved. Since false
here is a literal value that handlebars
handles, this works fine.
Signed-off-by: Charlike Mike Reagent <mameto2011@gmail.com>
Signed-off-by: Charlike Mike Reagent <mameto2011@gmail.com>
Signed-off-by: Charlike Mike Reagent <mameto2011@gmail.com>
Signed-off-by: Charlike Mike Reagent <mameto2011@gmail.com>
Everything below Node < 8 fails. |
test/test.js
Outdated
// We just care and handle only async helpers here. | ||
// The sync helpers are processed even on engine rendering, | ||
// even before the `.resolve()` calling. | ||
it.skip('should handle errors in sync helpers', function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The errors are caught and handled to add additional information to the error object. This is because not all template engines provide enough information about the error (like which helper the error occurred in).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kinda make sense, yea. But the only thing that is a need that I can see is to wrap the sync helper in try/catch add meta info and rethrow.
@tunnckoCore thanks for this PR! There are a few things that aren't handled now that were before (like resolving ids passed to sync helpers). I think this is because Jon and I had discussions about why that is necessary that probably didn't make it into comments. I'd like to get some input from @jonschlinkert when he has a chance because we had talked about handling async helpers differently. Thanks again for doing this and I'll try to give more feedback soon. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about this yet. I recently spent quite a bit of time on async helpers and took a different approach, you can see that here: https://github.com/jonschlinkert/templates/blob/refactor/lib/resolve.js. It seemed like there were a few things that weren't being handled in this lib, I would just want to make sure that we are handling partials, inline partials, and other edge cases that made this brittle before.
index.js
Outdated
function appendPrefix(prefix, counter) { | ||
return prefix + counter + '$'; | ||
} | ||
const argz = args.map(function func(arg) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we use fat arrow here and this
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm using a regular one because later we map
over the item.args
, so to be recursive. And the context should be item.context
.
index.js
Outdated
var keys = Object.keys(helpers).filter(function(name) { | ||
return ['async', 'sync', 'displayName'].indexOf(name) === -1; | ||
function promisify(fn) { | ||
return function func(...args) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should use util.promisify
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, thought about that, but if someone wants to use it in the browser this way may save a lot.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's the reason i didn't used the assert
too.
Like @jonschlinkert, agree. But I like that separation of |
Yeah! Reimplemented it :D Works with sync, async and callbacks. One question: do we need to support Btw, preserved the API (mostly) ;p
|
Couple of things to note:
I have probably kidna weird work process :D It's definitely not TDD, probably BDD, but for sure it's weird. Or not. Maybe RDD. |
Signed-off-by: Charlike Mike Reagent <mameto2011@gmail.com>
this.ids[id].value = await fn.call(context, ...(await Promise.all(argz))); | ||
return id; | ||
}; | ||
this.wrappedHelpers[name].wrapped = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need defineProperty
/ Reflect
?
const escapeRegex = require('escape-string-regexp'); | ||
const isAsyncFunction = require('is-async-function'); | ||
const util = require('util'); | ||
const isAsyncWithCb = require('is-async-function'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to support callbacks. Users will be able to just pass the result of util.promisify(fn)
as helper function ... Why add dependencies when we can't?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And if we switch to custom promisify
we guaranteed friendly browser usage.
Signed-off-by: Charlike Mike Reagent <mameto2011@gmail.com>
Okey, Lodash is passing again. Handlebars fails in the Is that |
Signed-off-by: Charlike Mike Reagent <mameto2011@gmail.com>
Yeah, the goal was to move the logic I did in templates over to this lib. But if you refactor works, that's fine too. |
Is this API okey? So I can continue to the normal tests. :P I think that one method that does both "set", "get" and "getAll" functionalities may be a bit confusing, but is also smaller code and kinda intuitive. Or making plural aliases too would make it less confusing? |
lol, this had me laughing. I'm probably the same.
If it's not too much trouble, can you look through the helper tests in the templates refactor and see if everything is covered here?
That was the plan. I was going to move the async helper logic from templates to this lib before we released. I don't need that code to be used though, I appreciate you doing this! |
Signed-off-by: Charlike Mike Reagent <mameto2011@gmail.com>
index.js
Outdated
// } | ||
if (isObject(arg) && isObject(arg.hash)) { | ||
for (const key of Object.keys(arg.hash)) { | ||
arg.hash[key] = await func(arg.hash[key]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely intentionally using a recursive call to func()
instead to the this.resolveId
or this.resolveIds
, because when the passed value is actual value and not an async id, then it (resolveId method) will throw.
Signed-off-by: Charlike Mike Reagent <mameto2011@gmail.com>
Okey, with the latest commit everything is a lot better. :D
Still think we can merge this one after porting the Haha, now I see why we can add |
Signed-off-by: Charlike Mike Reagent <mameto2011@gmail.com>
Signed-off-by: Charlike Mike Reagent <mameto2011@gmail.com>
Signed-off-by: Charlike Mike Reagent <mameto2011@gmail.com>
Signed-off-by: Charlike Mike Reagent <mameto2011@gmail.com>
@@ -179,6 +179,24 @@ describe('async-helpers', function() { | |||
assert.deepEqual(val, 'doowb'); | |||
}); | |||
}); | |||
|
|||
it('should support sync and async value items in argument arrays', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might not be pretty clear what it does from the title...
But basically tests if array argument passed to helper, can have both actual values and asyncIds which will be resolved to actual values.
|
||
# Install scripts. (runs after repo cloning) | ||
install: | ||
# Get the latest stable version of Node.js or io.js | ||
- ps: Install-Product node $env:nodejs_version | ||
# install modules | ||
- npm install | ||
- appveyor-retry npm install |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
appveyor-retry
is to ensure it install everything properly. Because pretty weirdly some times it fails. Or at least it was that way before year or more.
It will run the command more than once ONLY if it fails (I believe).
Sweeet 🎉 I don't see what more. I think it is pretty enough and stable. Please try to integrate it that way first. And if something is not as expected, then throw it in the garbage and do whatever you want. But I have strong confidence in it. I soon may add the tests from The |
Quite simplified.
Lodash and Handlebars (except for one specific case, need help) tests are working.
Sending the PR for now, but will continue work.
Also, do we need all the 0.3 methods? I think we can only rename
resolve
toresolveIds
and make one moreresolveId
for single id.Also, removed the devDeps (gulp) and updated to eslint config to latest found on
engine
refactor. All this was needed, because the config was pretty old and was throwing errors for async/await. But in anyway, you haveupdate
so you can update everything. I just did it to be able to start develop without frustrations and errors.