Comments (4)
Something similar to this issue has been causing me headaches. I took a stab at revising getPath to handle cases like this. Code is below. It needs some review from those more familiar with the innards of dust than I am so far plus throwing it against a battery of tests lest it break something. It seems to cure your cases and fix my headaches so I'm hopeful. Code adds two functions and modifies existing getPath. Note: find method is a near duplicate of get but returns pointer to location rather than value in location. I debated. I didn't consolidate them but one could have get call find to reduce code bulk.
// Find parent stack level with this key. Returns pointer or undefined if not found.
Stack.prototype.find = function(key) {
var stk = this, value;
while(stk) {
if (stk.isObject) {
value = stk.head[key];
if (!(value === undefined)) {
return stk.head;
}
}
stk = stk.tail;
}
return undefined;
};
Context.prototype.getPath = function(cur, down) {
var stk = this.stack,
len = down.length,
ostk = stk;
if (cur && len === 0) return stk.head;
if (!stk.isObject) return undefined;
stk = stk.head;
// See if path can be found from current position
stk = getSubPath(stk, down, len);
if (!stk) {
// See if there is a match to first path elt up-stack
stk = ostk.find(down[0]);
if (stk) {
// if found up-stack, see if whole path matches
return getSubPath(stk, down, len);
}
}
return undefined;
};
// Match a subpath in "down" from current position. Returns final match or undefined.
function getSubPath(obj, down, len) {
var i = 0;
while(obj && i < len) {
obj = obj[down[i]];
i++;
}
return obj;
}
from dustjs.
From what I understand,
get ( walks up the tree, so it is bottom up traversing of the context stack he creates )
Context.prototype.get = function(key) {
var ctx = this.stack, value;
while(ctx) {
if (ctx.isObject) {
value = ctx.head[key];
if (!(value === undefined)) {
return value;
}
}
ctx = ctx.tail;
}
return this.global ? this.global[key] : undefined;
};
getPath ( is walking down the tree from the "current stack head" )
{#person}
{name}, {age}
{#another.in} // the this.stack.head or the current stack head is now pointing to { "name" :Larry, "age" : "45"}
{name}
{age}
{/another.in}
{/person}
Hence it fails to find the another inside of the current stack head : { "name" :Larry, "age" : "45"}
Instead if it was a block, it would do a "get" and walk up the tree.
But the real confusing part is that, using the block # does not make it a new block at that point ( and use the the get )
It is the combination of # and . ( that is not spec'ed out clearly, as to what needs to happen )
so I am open to fixing this abd basically using the solution you propose.
from dustjs.
I'm not sure I agree. I took your example and changed it slightly by adding a simple value as a peer of "person" and "another".
var json = {
"person": {
"name": "Larry",
"age": 45,
},
"another": {
in : {
"name": "Tommy",
"age": 44
},
},
"simpleAnother": "simpleValue"
}
{#person}
{name}, {age}
{#another}
{#in}
{name}-{age}
{/in}
{/another}
{/person}
{#person}
{simpleAnother}
{/person}
Then if I reference {simpleAnother} in the {#person} context, the get will go up the stack and find "simpleAnother".
However, if I happen to need simpleAnother to be a more complex object like name + age, I can no longer reference the parts of it -- this seems wrong.
Handlebars has a mechanism to allow accessing structured values from ancestors of the current context. https://github.com/wycats/handlebars.js
I'm not a big fan of Handlebars ../ notation but just letting paths find the path root "up" the tree and descend to a matched value feels natural to me.
The original docs for dust say
"To avoid brittle and confusing references, paths never backtrack up the context stack. If you need to drill into a key available within the parent context, pass the key as a parameter."
This seems very clear that using a path only goes down from the current context. I'm not sure why such references are brittle and confusing unless at the time he wrote this it was in light of handlebars use of .. to access parent contexts. I could see that being brittle and confusing. I find that {another} finding a simple value but {another.in.name} not finding the element of a basic structure up the tree is confusing to me. Finding path references "up" the tree seems as natural as finding a simple element up the tree -- certainly no more brittle.
As an alternative, he suggests passing the key as a parameter (e.g.
{#person name=another.in.name age=another.in.age}
++{name}, {age}
{/person}
This works but for any but the simplest substructure or with many values it quickly becomes onerous.
I keep hitting up against this issue when I do things that add a layer to the context stack because what was a current path ceases to be current and getPath won't find it.
Things I'm exploring that might hit this include
{@Local var="name"}valueForLocalVar{/local}
Though I was proposing allowing globals {+name} to be passed, the more I look a them the less I like them as a model for variables. They turn out to be just like the JS global var with all the problems of people stepping on your global name. I'd much rather have something like:
{@Local p1="2" p2="{b}"}
stuff that can ref the locals
{/local}
and avoid global name issues. However, adding the local names to the stack causes previous pathed "current context" references to break. If pathed references would just look "up" the tree, this and other scoping helpers would work fine.
Cheers, Rich
From: Veena Basavaraj [[email protected]]
Sent: Monday, May 28, 2012 7:25 PM
To: Ragan, Richard
Subject: Re: [dustjs] Fix inconsistency in resolving dust reference (#47)
I was a little irritated with the inconsistency, but digging deeper, I think agree with his implementation now.
From what I understand,
get ( walks up the tree, so it is bottom up traversing of the context stack he created ),
Context.prototype.get = function(key) {
var ctx = this.stack, value;
while(ctx) {
if (ctx.isObject) {
value = ctx.head[key];
if (!(value === undefined)) {
return value;
}
}
ctx = ctx.tail;
}
return this.global ? this.global[key] : undefined;
};
getPath ( is walking down the tree from the "current stack head" )
{#person}
{name}, {age}
{#another.in} // the this.stack.head or the current stack head is now pointing to { "name" :Larry, "age" : "45"}
{name}
{age}
{/another.in}
{/person}
Hence it fails to find the another inside of the current stack head : { "name" :Larry, "age" : "45"}
Instead if it was a block, it would do a "get" and walk up the tree
Reply to this email directly or view it on GitHub:
#47 (comment)
from dustjs.
thanks for your detailed response.
We both seem to agree that the implementation is legit and is according to what he explains:)
the difference is basically between when it uses get and when it uses getPath ( a dot operator forces it to be local, walking down the tree )
(function(){dust.register(null,body_0);function body_0(chk,ctx){return chk.section(ctx.getPath(false,["person","in"]),ctx,{"block":body_1},null).write("------------------------");}function body_1(chk,ctx){return chk.reference(ctx.get("simpleAnother"),ctx,"h").reference(ctx.get("name"),ctx,"h").write(", ").reference(ctx.get("age"),ctx,"h").section(ctx.getPath(false,["another","in"]),ctx,{"block":body_2},null);}function body_2(chk,ctx){return chk.write(" // bloc inside the top level person block").reference(ctx.get("name"),ctx,"h").reference(ctx.get("age"),ctx,"h");}return body_0;})();
I am not a big fan of ../ either.
But I see your pain, some of us as well have felt the same, where "." has confused us ( since we most often overlook the current stack head )
Our solution : avoid the path and avoid inline params if possible, instead use blocks ( this uses the get( ) method and allows us to access the values upto to the root )
So our resort has been to use the block context whenever we need to walk into or access the data of other nodes in the JSON
https://github.com/linkedin/dustjs/wiki/Dust.js-little-less-know-language-constructs
For instance, one of the example under traversing the JSON tree in dust
If we want to access the projects -> name inside the comments block, all we need to do is create the team->projects block
Down side : we have to be careful in making sure that some typos in the JSON or missing data in some cases, does not let dust walk way more than we intended to.
Another topic you bring up is the helper : local
We do want to create a local scope at times,
for creating local contexts ( we create a new context, copy only the required context.get("somekey"), copy the inline params to it ans do a dust.makeBase( newlocalcontext) )
is this what you intended?
from dustjs.
Related Issues (20)
- dust-full js looks for ./parser ./dust js files inside dist folder
- "Try it out" UI components not working in latest chrome HOT 2
- Upgrade chokidar to 2.0+ to resolve security problem in dependency? HOT 2
- The website is showing blank black boxes HOT 8
- Dependencies with vulnerabilities HOT 1
- Dust js does not stream (show html) when using helmet
- [Question] Can we add a default filter without actually adding | "filtername" in template.
- Security Issue: Upgrade to higher version of Chokidar HOT 2
- Unexpected HTML encoding over string
- Page reloads and loses focus on text everytime a character is entered
- Dustjs output limited to 65536 characters HOT 2
- Non-string types are handled inconsistently between javascript and html escaping
- use of https
- Security bug about prototype pollution HOT 1
- Vulnerability Issue (High) - Please, Upgrade to chokidar 3.5.2 to Fix HOT 1
- why is v3 a breaking change? HOT 2
- Dustjs.com website is down HOT 5
- Input Text Removes \n from the string HOT 5
- vulnerable undefined property lookup that escalating prototype pollution to reflected XSS
- dustjs.com is down
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from dustjs.