Skip to content

Commit

Permalink
port: Register missingProperties custom function to get all variables…
Browse files Browse the repository at this point in the history
… the template contains (#3885)

* init

* init

* fix issue

* fix API extractor error

* fix

* fix comments

* fix test:compat

Co-authored-by: Josh Gummersall <jgummersall@microsoft.com>
  • Loading branch information
Danieladu and Josh Gummersall committed Aug 2, 2021
1 parent fe1757a commit 3e2beae
Show file tree
Hide file tree
Showing 18 changed files with 476 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,10 @@ describe('ActionTests', function () {
await TestUtils.runTestScript(resourceExplorer, 'Action_SetProperties');
});

it('MissingProperty', async () => {
await TestUtils.runTestScript(resourceExplorer, 'Action_MissingProperty');
});

it('SetProperty', async () => {
await TestUtils.runTestScript(resourceExplorer, 'Action_SetProperty');
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
{
"$schema": "../../../tests.schema",
"$kind": "Microsoft.Test.Script",
"dialog": {
"$kind": "Microsoft.AdaptiveDialog",
"id": "planningTest",
"generator": "main.lg",
"triggers": [
{
"$kind": "Microsoft.OnBeginDialog",
"actions": [
{
"$kind": "Microsoft.SetProperty",
"property": "user.missingProperties",
"value": "=missingProperties('${dialog.first} and ${dialog.second}')"
},
{
"$kind": "Microsoft.Foreach",
"itemsProperty": "user.missingProperties",
"actions": [
{
"$kind": "Microsoft.IfCondition",
"condition": "empty(getProperty(dialog.foreach.value))",
"actions": [
{
"$kind": "Microsoft.TextInput",
"property": "=dialog.foreach.value",
"prompt": "Hello, please input ${dialog.foreach.value}"
}
]
}
]
},
{
"$kind": "Microsoft.SendActivity",
"activity": "You finish all slot filling. And get result: ${dialog.first} and ${dialog.second}"
},
{
"$kind": "Microsoft.SetProperty",
"property": "user.missingProperties",
"value": "=missingProperties('${nameAndAge()}')"
},
{
"$kind": "Microsoft.Foreach",
"itemsProperty": "user.missingProperties",
"actions": [
{
"$kind": "Microsoft.IfCondition",
"condition": "empty(getProperty(dialog.foreach.value))",
"actions": [
{
"$kind": "Microsoft.TextInput",
"property": "=dialog.foreach.value",
"prompt": "Hello, please input ${dialog.foreach.value}"
}
]
}
]
},
{
"$kind": "Microsoft.SendActivity",
"activity": "You finish all slot filling. And get result: ${nameAndAge()}"
},
{
"$kind": "Microsoft.SetProperty",
"property": "user.missingProperties",
"value": "=missingProperties('${nameAndAge()}')"
},
{
"$kind": "Microsoft.SendActivity",
"activity": "${count(user.missingProperties)}"
},
{
"$kind": "Microsoft.BeginDialog",
"options": {},
"dialog": {
"$kind": "Microsoft.AdaptiveDialog",
"generator": "sub.lg",
"triggers": [
{
"$kind": "Microsoft.OnBeginDialog",
"actions": [
{
"$kind": "Microsoft.SetProperty",
"property": "user.missingProperties",
"value": "=missingProperties('${showPetName()}')"
},
{
"$kind": "Microsoft.SendActivity",
"activity": "${count(user.missingProperties)}"
}
]
}
]
}
},
{
"$kind": "Microsoft.SetProperty",
"property": "user.missingProperties",
"value": "=missingProperties('${nameAndAge()}')"
},
{
"$kind": "Microsoft.SendActivity",
"activity": "${count(user.missingProperties)}"
}
]
}
]
},
"script": [
{
"$kind": "Microsoft.Test.UserConversationUpdate"
},
{
"$kind": "Microsoft.Test.AssertReply",
"text": "Hello, please input dialog.first"
},
{
"$kind": "Microsoft.Test.UserSays",
"text": "1"
},
{
"$kind": "Microsoft.Test.AssertReply",
"text": "Hello, please input dialog.second"
},
{
"$kind": "Microsoft.Test.UserSays",
"text": "2"
},
{
"$kind": "Microsoft.Test.AssertReply",
"text": "You finish all slot filling. And get result: 1 and 2"
},
{
"$kind": "Microsoft.Test.AssertReply",
"text": "Hello, please input user.name"
},
{
"$kind": "Microsoft.Test.UserSays",
"text": "Jack"
},
{
"$kind": "Microsoft.Test.AssertReply",
"text": "Hello, please input user.age"
},
{
"$kind": "Microsoft.Test.UserSays",
"text": "20"
},
{
"$kind": "Microsoft.Test.AssertReply",
"text": "You finish all slot filling. And get result: my name is Jack and my age is 20"
},
{
"$kind": "Microsoft.Test.AssertReply",
"text": "2"
},
{
"$kind": "Microsoft.Test.AssertReply",
"text": "1"
},
{
"$kind": "Microsoft.Test.AssertReply",
"text": "2"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@

# length
- length in main

# nameAndAge
- my name is ${user.name} and my age is ${user.age}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# showPetName
- the pet's name is ${petName}
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@ import { Headers as Headers_2 } from 'node-fetch';
import { ImportResolverDelegate } from 'botbuilder-lg';
import { IntExpression } from 'adaptive-expressions';
import { ListStyle } from 'botbuilder-dialogs';
import { MemoryInterface } from 'adaptive-expressions';
import { ModelResult } from 'botbuilder-dialogs';
import { NumberExpression } from 'adaptive-expressions';
import { ObjectExpression } from 'adaptive-expressions';
import { Options } from 'adaptive-expressions';
import { PromptOptions } from 'botbuilder-dialogs';
import { Recognizer } from 'botbuilder-dialogs';
import { RecognizerConfiguration } from 'botbuilder-dialogs';
Expand Down Expand Up @@ -1364,6 +1366,7 @@ export class LanguageGenerationBotComponent extends BotComponent {
// @public
export interface LanguageGenerator<T = unknown, D = Record<string, unknown>> {
generate(dialogContext: DialogContext, template: string, data: D): Promise<T>;
missingProperties(dialogContext: DialogContext, template: string, state?: MemoryInterface, options?: Options): string[];
}

// @public
Expand Down Expand Up @@ -1445,6 +1448,12 @@ export class MentionEntityRecognizer extends TextEntityRecognizer {
protected _recognize(text: string, culture: string): ModelResult[];
}

// @public
export class MissingPropertiesFunction extends ExpressionEvaluator {
constructor(context: DialogContext);
static readonly functionName = "missingProperties";
}

// @public (undocumented)
export class MostSpecificSelector extends TriggerSelector implements MostSpecificSelectorConfiguration {
// (undocumented)
Expand Down Expand Up @@ -1480,6 +1489,8 @@ export abstract class MultiLanguageGeneratorBase<T = unknown, D extends Record<s
// (undocumented)
getConverter(property: keyof MultiLanguageGeneratorBaseConfiguration): Converter | ConverterFactory;
languagePolicy: LanguagePolicy;
// (undocumented)
missingProperties(dialogContext: DialogContext, template: string, state?: MemoryInterface, options?: Options): string[];
abstract tryGetGenerator(dialogContext: DialogContext, locale: string): {
exist: boolean;
result: LanguageGenerator<T, D>;
Expand Down Expand Up @@ -2328,7 +2339,8 @@ export class TemplateEngineLanguageGenerator<T = unknown, D extends Record<strin
generate(dialogContext: DialogContext, template: string, data: D): Promise<T>;
// (undocumented)
id: string;
}
missingProperties(dialogContext: DialogContext, template: string, _state?: MemoryInterface, _options?: Options): string[];
}

// @public (undocumented)
export interface TemplateEngineLanguageGeneratorConfiguration {
Expand Down
3 changes: 2 additions & 1 deletion libraries/botbuilder-dialogs-adaptive/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
"botbuilder-dialogs-declarative": "4.1.6",
"botbuilder-lg": "4.1.6",
"lodash": "^4.17.21",
"node-fetch": "^2.6.0"
"node-fetch": "^2.6.0",
"uuid": "^8.3.2"
},
"devDependencies": {
"@microsoft/recognizers-text": "~1.1.4",
Expand Down
7 changes: 6 additions & 1 deletion libraries/botbuilder-dialogs-adaptive/src/adaptiveDialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* Licensed under the MIT License.
*/

import { BoolExpression, BoolExpressionConverter, IntExpression } from 'adaptive-expressions';
import { BoolExpression, BoolExpressionConverter, Expression, IntExpression } from 'adaptive-expressions';
import {
Activity,
ActivityTypes,
Expand Down Expand Up @@ -48,6 +48,7 @@ import { EntityAssignment } from './entityAssignment';
import { EntityAssignmentComparer } from './entityAssignmentComparer';
import { EntityAssignments } from './entityAssignments';
import { EntityInfo, NormalizedEntityInfos } from './entityInfo';
import { MissingPropertiesFunction } from './functions';
import { LanguageGenerator } from './languageGenerator';
import { languageGeneratorKey } from './languageGeneratorExtensions';
import { BoolProperty } from './properties';
Expand Down Expand Up @@ -775,6 +776,10 @@ export class AdaptiveDialog<O extends object = {}> extends DialogContainer<O> im
protected onSetScopedServices(dialogContext: DialogContext): void {
if (this.generator) {
dialogContext.services.set(languageGeneratorKey, this.generator);
Expression.functions.set(
MissingPropertiesFunction.functionName,
new MissingPropertiesFunction(dialogContext)
);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@

export * from './hasPendingActionsFunction';
export * from './isDialogActiveFunction';
export * from './missingPropertiesFunction';
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* @module botbuilder-dialogs-adaptive
*/
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/

import {
Expression,
ExpressionEvaluator,
FunctionUtils,
MemoryInterface,
Options,
ReturnType,
ValueWithError,
} from 'adaptive-expressions';
import { LanguageGenerator } from '../languageGenerator';

import { DialogContext, DialogStateManager } from 'botbuilder-dialogs';
/**
* Defines missingProperties(template) expression function.
* This expression will get all variables the template contains.
*
* @example missingProperties('${a} ${b}')
*/
export class MissingPropertiesFunction extends ExpressionEvaluator {
/**
* Function identifier name.
*/
public static readonly functionName = 'missingProperties'; // `name` is reserved in JavaScript.

private static readonly generatorPath = 'dialogclass.generator';

private static dialogContext: DialogContext;

/**
* Intializes a new instance of the [MissingProperties](xref:botbuilder-dialogs-adaptive.MissingProperties) class.
*
* @param context dialog context.
*/
public constructor(context: DialogContext) {
super(
MissingPropertiesFunction.functionName,
MissingPropertiesFunction.function,
ReturnType.Array,
FunctionUtils.validateUnaryString
);

MissingPropertiesFunction.dialogContext = context;
}

private static function(expression: Expression, state: MemoryInterface, options: Options): ValueWithError {
const { args, error } = FunctionUtils.evaluateChildren(expression, state, options);
if (error != null) {
return { value: undefined, error };
}

const templateBody = args[0].toString();

const generator = (state as DialogStateManager).getValue<LanguageGenerator>(MissingPropertiesFunction.generatorPath);
if (generator) {
return {
value: generator.missingProperties(
MissingPropertiesFunction.dialogContext,
templateBody,
state,
options
),
error: undefined,
};
}
return { value: undefined, error: undefined };
}
}
Loading

0 comments on commit 3e2beae

Please sign in to comment.