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

[NodeJS Templating] Enable host parameters #7199

Merged
merged 16 commits into from
Apr 13, 2022
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion source/nodejs/adaptivecards-designer-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"dependencies": {
"adaptivecards": "^3.0.0-beta.1",
"adaptivecards-designer": "^2.4.0-alpha.0",
"adaptivecards-templating": "^2.3.0-alpha.0",
"adaptivecards-templating": "^2.4.0-alpha.0",
"monaco-editor": "^0.29.1"
}
}
2 changes: 1 addition & 1 deletion source/nodejs/adaptivecards-designer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"devDependencies": {
"adaptive-expressions": "^4.11.0",
"adaptivecards": "^3.0.0-beta.1",
"adaptivecards-templating": "^2.3.0-alpha.0",
"adaptivecards-templating": "^2.4.0-alpha.0",
"cpy-cli": "^3.1.1",
"dotenv-webpack": "^7.0.3",
"monaco-editor": "^0.29.1",
Expand Down
2 changes: 1 addition & 1 deletion source/nodejs/adaptivecards-site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"adaptive-expressions": "^4.11.0",
"adaptivecards": "^3.0.0-beta.1",
"adaptivecards-designer": "^2.4.0-alpha.0",
"adaptivecards-templating": "^2.3.0-alpha.0",
"adaptivecards-templating": "^2.4.0-alpha.0",
"change-case": "^3.0.1",
"cheerio": "^1.0.0-rc.3",
"glob": "^7.1.6",
Expand Down
2 changes: 1 addition & 1 deletion source/nodejs/adaptivecards-templating/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "adaptivecards-templating",
"version": "2.3.0-alpha.0",
"version": "2.4.0-alpha.0",
"description": "Adaptive Card data binding and templating engine for JavaScript",
"author": "AdaptiveCards",
"license": "MIT",
Expand Down
57 changes: 33 additions & 24 deletions source/nodejs/adaptivecards-templating/src/template-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@
import * as AEL from "adaptive-expressions";

class EvaluationContext {
private static readonly _reservedFields = ["$data", "$when", "$root", "$index"];
private static readonly _reservedFields = ["$data", "$when", "$root", "$index", "$host"];

private _stateStack: Array<{ $data: any, $index: any }> = [];
private _$data: any;

$root: any;
$host: any;
$index: number;

constructor(context?: IEvaluationContext) {
if (context !== undefined) {
this.$root = context.$root;
this.$host = context.$host;
}
}

Expand Down Expand Up @@ -55,6 +57,7 @@ class TemplateObjectMemory implements AEL.MemoryInterface {
$root: any;
$data: any;
$index: any;
$host: any;

constructor() {
this._memory = new AEL.SimpleObjectMemory(this);
Expand Down Expand Up @@ -84,24 +87,24 @@ export class GlobalSettings {
* and that field is undefined or null. By default, expression evaluation will substitute an undefined
* field with its binding expression (e.g. `${field}`). This callback makes it possible to customize that
* behavior.
*
*
* **Example**
* Given this data object:
*
*
* ```json
* {
* firstName: "David"
* }
* ```
*
*
* The expression `${firstName} ${lastName}` will evaluate to "David ${lastName}" because the `lastName`
* field is undefined.
*
*
* Now let's set the callback:
* ```typescript
* GlobalSettings.getUndefinedFieldValueSubstitutionString = (path: string) => { return "<undefined value>"; }
* ```
*
*
* With that, the above expression will evaluate to "David &lt;undefined value&gt;"
*/
static getUndefinedFieldValueSubstitutionString?: (path: string) => string | undefined = undefined;
Expand All @@ -115,7 +118,12 @@ export interface IEvaluationContext {
* The root data object the template will bind to. Expressions that refer to $root in the template payload
* map to this field. Initially, $data also maps to $root.
*/
$root: any
$root?: any;
/**
* The host data object the template will bind to. Expressions that refer to $host in the template payload
* map to this field. This allows a host process to supply additional context to the template.
*/
$host?: any;
}

/**
Expand Down Expand Up @@ -157,6 +165,7 @@ export class Template {
memory.$root = context.$root;
memory.$data = context.$data;
memory.$index = context.$index;
memory.$host = context.$host;

let options: AEL.Options | undefined = undefined;

Expand All @@ -166,9 +175,9 @@ export class Template {
let substitutionValue: string | undefined = undefined;

if (GlobalSettings.getUndefinedFieldValueSubstitutionString) {
substitutionValue = GlobalSettings.getUndefinedFieldValueSubstitutionString(path);
substitutionValue = GlobalSettings.getUndefinedFieldValueSubstitutionString(path);
}

return substitutionValue ? substitutionValue : "${" + path + "}";
}
}
Expand All @@ -182,7 +191,7 @@ export class Template {

for (let childExpression of expression.children) {
let evaluationResult: { value: any; error: string };

try {
evaluationResult = childExpression.tryEvaluate(memory, options);
}
Expand All @@ -203,13 +212,13 @@ export class Template {

return { value: result, error: undefined };
}

return expression.tryEvaluate(memory, options);
}

/**
* Parses an interpolated string into an Expression object ready to evaluate.
*
*
* @param interpolatedString The interpolated string to parse. Example: "Hello ${name}"
* @returns An Expression object if the provided interpolated string contained at least one expression (e.g. "${expression}"); the original string otherwise.
*/
Expand Down Expand Up @@ -262,7 +271,7 @@ export class Template {

/**
* Tries to evaluate the provided expression using the provided context.
*
*
* @param expression The expression to evaluate.
* @param context The context (data) used to evaluate the expression.
* @param allowSubstitutions Indicates if the expression evaluator should substitute undefined value with a default
Expand Down Expand Up @@ -374,7 +383,7 @@ export class Template {
if (when instanceof AEL.Expression) {
let evaluationResult = Template.internalTryEvaluateExpression(when, this._context, false);
let whenValue: boolean = false;

// If $when fails to evaluate or evaluates to anything but a boolean, consider it is false
if (!evaluationResult.error) {
whenValue = typeof evaluationResult.value === "boolean" && evaluationResult.value;
Expand Down Expand Up @@ -412,8 +421,8 @@ export class Template {
* Initializes a new Template instance based on the provided payload.
* Once created, the instance can be bound to different data objects
* in a loop.
*
* @param payload The template payload.
*
* @param payload The template payload.
*/
constructor(payload: any) {
this._preparedPayload = Template.prepare(payload);
Expand All @@ -423,9 +432,9 @@ export class Template {
* Expands the template using the provided context. Template expansion involves
* evaluating the expressions used in the original template payload, as well as
* repeating (expanding) parts of that payload that are bound to arrays.
*
*
* Example:
*
*
* ```typescript
* let context = {
* $root: {
Expand All @@ -437,7 +446,7 @@ export class Template {
* ]
* }
* }
*
*
* let templatePayload = {
* type: "AdaptiveCard",
* version: "1.2",
Expand All @@ -453,14 +462,14 @@ export class Template {
* }
* ]
* }
*
*
* let template = new Template(templatePayload);
*
*
* let expandedTemplate = template.expand(context);
* ```
*
*
* With the above code, the value of `expandedTemplate` will be
*
*
* ```json
* {
* type: "AdaptiveCard",
Expand All @@ -481,7 +490,7 @@ export class Template {
* ]
* }
* ```
*
*
* @param context The context to bind the template to.
* @returns A value representing the expanded template. The type of that value
* is dependent on the type of the original template payload passed to the constructor.
Expand Down
2 changes: 1 addition & 1 deletion source/nodejs/adaptivecards-ui-testapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@
"adaptive-expressions": "^4.11.0",
"adaptivecards": "^3.0.0-beta.1",
"adaptivecards-controls": "^0.9.0",
"adaptivecards-templating": "^2.3.0-alpha.0"
"adaptivecards-templating": "^2.4.0-alpha.0"
}
}
3 changes: 2 additions & 1 deletion source/nodejs/lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"adaptivecards*/**",
"marked-schema/**",
"spec-generator/**",
"ac-typed-schema/**"
"ac-typed-schema/**",
"tests/unit-tests/**"
],
"command": {
"publish": {
Expand Down
3 changes: 2 additions & 1 deletion source/nodejs/tests/unit-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"devDependencies": {
"adaptivecards": "^2.10.0",
"monaco-editor": "^0.29.1",
"vkbeautify": "^0.99.3"
"vkbeautify": "^0.99.3",
"adaptivecards-templating": "^2.4.0-alpha.0"
}
}
Loading