Skip to content

Commit

Permalink
[@kbn/handlebars] Refactor internal context handling (elastic#148029)
Browse files Browse the repository at this point in the history
  • Loading branch information
Thomas Watson authored Dec 22, 2022
1 parent 251bdce commit 0d2e815
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 15 deletions.
2 changes: 1 addition & 1 deletion packages/kbn-handlebars/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ To instruct the `Visitor` code to traverse any child nodes of a given node, our

We keep state internally in the `ElasticHandlebarsVisitor` object using the following private properties:

- `scopes`: An array (stack) of `context` objects. In a simple template this array will always only contain a single element: The main `context` object. In more complicated scenarios, new `context` objects will be pushed and popped to and from the `scopes` stack as needed.
- `contexts`: An array (stack) of `context` objects. In a simple template this array will always only contain a single element: The main `context` object. In more complicated scenarios, new `context` objects will be pushed and popped to and from the `contexts` stack as needed.
- `output`: An array containing the "rendered" output of each node (normally just one element per node). In the most simple template, this is simply joined together into a the final output string after the AST has been traversed. In more complicated templates, we use this array temporarily to collect parameters to give to helper functions (see the `getParams` function).

## Testing
Expand Down
30 changes: 16 additions & 14 deletions packages/kbn-handlebars/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ interface Container {
}

class ElasticHandlebarsVisitor extends Handlebars.Visitor {
private scopes: any[] = [];
private contexts: any[] = [];
private output: any[] = [];
private template?: string;
private compileOptions: ExtendedCompileOptions;
Expand Down Expand Up @@ -288,7 +288,7 @@ class ElasticHandlebarsVisitor extends Handlebars.Visitor {
}

render(context: any, options: ExtendedRuntimeOptions = {}): string {
this.scopes = [context];
this.contexts = [context];
this.output = [];
this.runtimeOptions = options;
this.container.helpers = Object.assign(this.initialHelpers, options.helpers);
Expand Down Expand Up @@ -364,7 +364,7 @@ class ElasticHandlebarsVisitor extends Handlebars.Visitor {
} else if (path.data) {
result = this.lookupData(this.runtimeOptions!.data, path);
} else {
result = this.resolvePath(this.scopes[path.depth], path);
result = this.resolvePath(this.contexts[path.depth], path);
}

this.output.push(result);
Expand Down Expand Up @@ -514,7 +514,7 @@ class ElasticHandlebarsVisitor extends Handlebars.Visitor {
// @ts-expect-error strict is not a valid property on PathExpression, but we used in the same way it's also used in the original handlebars
path.strict = true;
const result = this.resolveNodes(path)[0];
const lambdaResult = this.container.lambda(result, this.scopes[0]);
const lambdaResult = this.container.lambda(result, this.context);

if (isBlock(node)) {
this.blockValue(node, lambdaResult);
Expand All @@ -531,8 +531,7 @@ class ElasticHandlebarsVisitor extends Handlebars.Visitor {
const name = node.path.original;
const options = this.setupParams(node, name);

const context = this.scopes[0];
const result = this.container.hooks.blockHelperMissing!.call(context, value, options);
const result = this.container.hooks.blockHelperMissing!.call(this.context, value, options);

this.output.push(result);
}
Expand Down Expand Up @@ -647,8 +646,7 @@ class ElasticHandlebarsVisitor extends Handlebars.Visitor {
const helper = this.setupHelper(block, name);

if (!helper.fn) {
const context = this.scopes[0];
value = this.container.hooks.blockHelperMissing!.call(context, value, helper.options);
value = this.container.hooks.blockHelperMissing!.call(this.context, value, helper.options);
}

return value;
Expand All @@ -665,7 +663,7 @@ class ElasticHandlebarsVisitor extends Handlebars.Visitor {
} {
return {
fn: this.container.lookupProperty(this.container.helpers, helperName),
context: this.scopes[0],
context: this.context,
params: this.resolveNodes(node.params),
options: this.setupParams(node, helperName),
};
Expand All @@ -679,9 +677,9 @@ class ElasticHandlebarsVisitor extends Handlebars.Visitor {
if (decorator.params.length > 0) {
if (!this.processedRootDecorators) {
// When processing the root decorators, temporarily remove the root context so it's not accessible to the decorator
const context = this.scopes.shift();
const context = this.contexts.shift();
options.args = this.resolveNodes(decorator.params);
this.scopes.unshift(context);
this.contexts.unshift(context);
} else {
options.args = this.resolveNodes(decorator.params);
}
Expand Down Expand Up @@ -735,16 +733,16 @@ class ElasticHandlebarsVisitor extends Handlebars.Visitor {
// stash parent program data
const tmpRuntimeOptions = this.runtimeOptions;
this.runtimeOptions = runtimeOptions;
const shiftContext = nextContext !== this.scopes[0];
if (shiftContext) this.scopes.unshift(nextContext);
const shiftContext = nextContext !== this.context;
if (shiftContext) this.contexts.unshift(nextContext);
this.blockParamValues.unshift(runtimeOptions.blockParams || []);

// execute child program
const result = this.resolveNodes(program).join('');

// unstash parent program data
this.blockParamValues.shift();
if (shiftContext) this.scopes.shift();
if (shiftContext) this.contexts.shift();
this.runtimeOptions = tmpRuntimeOptions;

// return result of child program
Expand Down Expand Up @@ -809,6 +807,10 @@ class ElasticHandlebarsVisitor extends Handlebars.Visitor {

return result;
}

private get context() {
return this.contexts[0];
}
}

// ********************************************** //
Expand Down

0 comments on commit 0d2e815

Please sign in to comment.