diff --git a/libraries/adaptive-expressions/src/expressionFunctions.ts b/libraries/adaptive-expressions/src/expressionFunctions.ts index 3e30f4cc3d..f2e7d61d5b 100644 --- a/libraries/adaptive-expressions/src/expressionFunctions.ts +++ b/libraries/adaptive-expressions/src/expressionFunctions.ts @@ -817,7 +817,7 @@ export class ExpressionFunctions { * @param expression * @param state */ - private static tryAccumulatePath(expression: Expression, state: MemoryInterface): {path: string; left: Expression; error: string} { + public static tryAccumulatePath(expression: Expression, state: MemoryInterface): {path: string; left: Expression; error: string} { let path = ''; let left = expression; while (left !== undefined) { @@ -833,11 +833,14 @@ export class ExpressionFunctions { return {path: undefined, left: undefined, error}; } - if (isNaN(parseInt(value)) && typeof value !== 'string') { + if (ExpressionFunctions.isNumber(parseInt(value))) { + path = `[${ value }].${ path }`; + } else if (typeof value === 'string'){ + path = `['${ value }'].${ path }`; + } else { return {path: undefined, left: undefined, error:`${ left.children[1].toString() } dones't return a int or string`}; } - path = `[${ value }].${ path }`; left = left.children[0]; } else { break; diff --git a/libraries/adaptive-expressions/src/memory/simpleObjectMemory.ts b/libraries/adaptive-expressions/src/memory/simpleObjectMemory.ts index 4d9ab9df12..d25106fe85 100644 --- a/libraries/adaptive-expressions/src/memory/simpleObjectMemory.ts +++ b/libraries/adaptive-expressions/src/memory/simpleObjectMemory.ts @@ -1,5 +1,6 @@ import { MemoryInterface } from './memoryInterface'; import { Extensions } from '../extensions'; +import { Util } from '../parser/util'; /** * @module adaptive-expressions @@ -39,7 +40,15 @@ export class SimpleObjectMemory implements MemoryInterface { return undefined; } - const parts: string[] = path.split(/[.\[\]]+/).filter((u: string): boolean => u !== undefined && u !== ''); + const parts: string[] = path.split(/[.\[\]]+/) + .filter((u: string): boolean => u !== undefined && u !== '') + .map((u: string): string => { + if ((u.startsWith('"') && u.endsWith('"')) || (u.startsWith('\'') && u.endsWith('\''))) { + return u.substr(1, u.length - 2); + } else { + return u; + } + }); let value: any; let curScope = this.memory; @@ -74,7 +83,15 @@ export class SimpleObjectMemory implements MemoryInterface { return;; } - const parts: string[] = path.split(/[.\[\]]+/).filter((u: string): boolean => u !== undefined && u !== ''); + const parts: string[] = path.split(/[.\[\]]+/) + .filter((u: string): boolean => u !== undefined && u !== '') + .map((u: string): string => { + if ((u.startsWith('"') && u.endsWith('"')) || (u.startsWith('\'') && u.endsWith('\''))) { + return u.substr(1, u.length - 2); + } else { + return u; + } + }); let curScope: any = this.memory; let curPath = ''; let error: string = undefined; diff --git a/libraries/adaptive-expressions/tests/expression.test.js b/libraries/adaptive-expressions/tests/expression.test.js index f0c66a643c..b6af289f7f 100644 --- a/libraries/adaptive-expressions/tests/expression.test.js +++ b/libraries/adaptive-expressions/tests/expression.test.js @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-use-before-define */ /* eslint-disable @typescript-eslint/no-var-requires */ -const { ExpressionEngine, Extensions } = require('../'); +const { ExpressionEngine, Extensions, SimpleObjectMemory, ExpressionFunctions } = require('../'); const assert = require('assert'); const moment = require('moment'); @@ -645,6 +645,43 @@ describe('expression functional test', () => { } } }); + + it('Test AccumulatePath', () => { + const scope = { + f: 'foo', + b: 'bar', + z: { + z: 'zar' + }, + n: 2 + }; + const memory = new SimpleObjectMemory(scope); + let parser = new ExpressionEngine(); + + // normal case, note, we doesn't append a " yet + let exp = parser.parse('a[f].b[n].z'); + let path = undefined; + let left = undefined; + let error = undefined; + ({path, left, error} = ExpressionFunctions.tryAccumulatePath(exp, memory)); + assert.strictEqual(path, 'a[\'foo\'].b[2].z'); + + // normal case + exp = parser.parse('a[z.z][z.z].y'); + ({path, left, error} = ExpressionFunctions.tryAccumulatePath(exp, memory)); + assert.strictEqual(path, 'a[\'zar\'][\'zar\'].y'); + + // normal case + exp = parser.parse('a.b[z.z]'); + ({path, left, error} = ExpressionFunctions.tryAccumulatePath(exp, memory)); + assert.strictEqual(path, 'a.b[\'zar\']'); + + // stop evaluate at middle + exp = parser.parse('json(x).b'); + ({path, left, error} = ExpressionFunctions.tryAccumulatePath(exp, memory)); + assert.strictEqual(path, 'b'); + + }); }); var isArraySame = (actual, expected) => { //return [isSuccess, errorMessage] diff --git a/libraries/botbuilder-lg/tests/lg.test.js b/libraries/botbuilder-lg/tests/lg.test.js index 5bcfe10630..5f5217adf7 100644 --- a/libraries/botbuilder-lg/tests/lg.test.js +++ b/libraries/botbuilder-lg/tests/lg.test.js @@ -742,4 +742,33 @@ describe('LG', function() { evaled = LGFile.evaluateTemplate('StringTemplateWithTemplateRef'); assert.strictEqual(evaled, 'hello jack , welcome. nice weather!'); }); + + it('TestMemoryAccessPath', function() { + var LGFile = LGParser.parseFile(GetExampleFilePath('MemoryAccess.lg')); + + const scope = { + myProperty: { + name: 'p1' + }, + turn: { + properties: { + p1: { + enum: 'p1enum' + } + } + } + }; + + // this evaulate will hit memory access twice + // first for "property", and get "p1", from local + // sencond for "turn.property[p1].enum" and get "p1enum" from global + var evaled = LGFile.evaluateTemplate('T1', scope); + assert.strictEqual(evaled, 'p1enum'); + + // this evaulate will hit memory access twice + // first for "myProperty.name", and get "p1", from global + // sencond for "turn.property[p1].enum" and get "p1enum" from global + evaled = LGFile.evaluateTemplate('T3', scope); + assert.strictEqual(evaled, 'p1enum'); + }); }); diff --git a/libraries/botbuilder-lg/tests/testData/examples/MemoryAccess.lg b/libraries/botbuilder-lg/tests/testData/examples/MemoryAccess.lg new file mode 100644 index 0000000000..fade009209 --- /dev/null +++ b/libraries/botbuilder-lg/tests/testData/examples/MemoryAccess.lg @@ -0,0 +1,8 @@ +# T1 +- ${T2("p1")} + +# T2(property) +- ${turn.properties[property].enum} + +# T3 +- ${turn.properties[myProperty.name].enum} \ No newline at end of file