From 4f02de8041c963fab3d9e2dc570b3bac4c3a1e5d Mon Sep 17 00:00:00 2001 From: hond Date: Wed, 6 May 2020 16:46:46 +0800 Subject: [PATCH 1/3] add more timex function --- .../src/expressionFunctions.ts | 166 ++++++++++++++++++ .../src/expressionType.ts | 9 + .../tests/badExpression.test.js | 14 ++ .../tests/expressionParser.test.js | 24 +++ 4 files changed, 213 insertions(+) diff --git a/libraries/adaptive-expressions/src/expressionFunctions.ts b/libraries/adaptive-expressions/src/expressionFunctions.ts index d186efe736..e86f4d34f8 100644 --- a/libraries/adaptive-expressions/src/expressionFunctions.ts +++ b/libraries/adaptive-expressions/src/expressionFunctions.ts @@ -816,6 +816,22 @@ export class ExpressionFunctions { } } + private static parseTimexProperty(timexExpr: any): {timexProperty: TimexProperty; error: string} { + let parsed: TimexProperty; + if (timexExpr instanceof TimexProperty) { + parsed = timexExpr; + } else if (typeof timexExpr === 'string'){ + parsed = new TimexProperty(timexExpr); + } else { + parsed = new TimexProperty(timexExpr); + if (parsed == undefined || Object.keys(parsed).length === 0) { + return {timexProperty: parsed, error: `${ timexExpr } requires a TimexProperty or a string as a argument`}; + } + } + + return {timexProperty: parsed, error: undefined}; + } + private static addOrdinal(num: number): string { let hasResult = false; let ordinalResult: string = num.toString(); @@ -2736,6 +2752,156 @@ export class ExpressionFunctions { }, ReturnType.Number, ExpressionFunctions.validateUnary), + new ExpressionEvaluator( + ExpressionType.IsDefinite, + (expr: Expression, state: any, options: Options): { value: any; error: string } => { + let parsed: TimexProperty; + let value = false; + let error: string; + let args: any []; + ({args, error} = ExpressionFunctions.evaluateChildren(expr, state, options)); + if (!error) { + ({timexProperty: parsed, error: error} = ExpressionFunctions.parseTimexProperty(args[0])); + } + + if (!error) { + value = parsed != undefined && parsed.year !== undefined && parsed.month !== undefined && parsed.dayOfMonth !== undefined; + } + + return {value, error}; + }, + ReturnType.Boolean, + ExpressionFunctions.validateUnary), + new ExpressionEvaluator( + ExpressionType.IsTime, + (expr: Expression, state: any, options: Options): { value: any; error: string } => { + let parsed: TimexProperty; + let value = false; + let error: string; + let args: any []; + ({args, error} = ExpressionFunctions.evaluateChildren(expr, state, options)); + if (!error) { + ({timexProperty: parsed, error: error} = ExpressionFunctions.parseTimexProperty(args[0])); + } + + if (parsed && !error) { + value = parsed.hour !== undefined && parsed.minute !== undefined && parsed.second !== undefined; + } + + return {value, error}; + }, + ReturnType.Boolean, + ExpressionFunctions.validateUnary), + new ExpressionEvaluator( + ExpressionType.IsDuration, + (expr: Expression, state: any, options: Options): { value: any; error: string } => { + let parsed: TimexProperty; + let value = false; + let error: string; + let args: any []; + ({args, error} = ExpressionFunctions.evaluateChildren(expr, state, options)); + if (!error) { + ({timexProperty: parsed, error: error} = ExpressionFunctions.parseTimexProperty(args[0])); + } + + if (parsed && !error) { + value = parsed.years !== undefined + || parsed.months !== undefined + || parsed.weeks !== undefined + || parsed.days !== undefined + || parsed.hours !== undefined + || parsed.minutes !== undefined + || parsed.seconds !== undefined; + } + + return {value, error}; + }, + ReturnType.Boolean, + ExpressionFunctions.validateUnary), + new ExpressionEvaluator( + ExpressionType.IsDate, + (expr: Expression, state: any, options: Options): { value: any; error: string } => { + let parsed: TimexProperty; + let value = false; + let error: string; + let args: any []; + ({args, error} = ExpressionFunctions.evaluateChildren(expr, state, options)); + if (!error) { + ({timexProperty: parsed, error: error} = ExpressionFunctions.parseTimexProperty(args[0])); + } + + if (parsed && !error) { + value = (parsed.month !== undefined && parsed.dayOfMonth !== undefined) || parsed.DayOfWeek !== undefined; + } + + return {value, error}; + }, + ReturnType.Boolean, + ExpressionFunctions.validateUnary), + new ExpressionEvaluator( + ExpressionType.IsTimeRange, + (expr: Expression, state: any, options: Options): { value: any; error: string } => { + let parsed: TimexProperty; + let value = false; + let error: string; + let args: any []; + ({args, error} = ExpressionFunctions.evaluateChildren(expr, state, options)); + if (!error) { + ({timexProperty: parsed, error: error} = ExpressionFunctions.parseTimexProperty(args[0])); + } + + if (parsed && !error) { + value = parsed.partOfDay !== undefined; + } + + return {value, error}; + }, + ReturnType.Boolean, + ExpressionFunctions.validateUnary), + new ExpressionEvaluator( + ExpressionType.IsDateRange, + (expr: Expression, state: any, options: Options): { value: any; error: string } => { + let parsed: TimexProperty; + let value = false; + let error: string; + let args: any []; + ({args, error} = ExpressionFunctions.evaluateChildren(expr, state, options)); + if (!error) { + ({timexProperty: parsed, error: error} = ExpressionFunctions.parseTimexProperty(args[0])); + } + + if (parsed && !error) { + value = (parsed.year !== undefined && parsed.dayOfMonth === undefined) || + (parsed.year !== undefined && parsed.month !== undefined && parsed.dayOfMonth === undefined) || + (parsed.month !== undefined && parsed.dayOfMonth === undefined) || + parsed.season !== undefined || parsed.weekOfYear !== undefined || parsed.weekOfMonth !== undefined; + } + + return {value, error}; + }, + ReturnType.Boolean, + ExpressionFunctions.validateUnary), + new ExpressionEvaluator( + ExpressionType.IsPresent, + (expr: Expression, state: any, options: Options): { value: any; error: string } => { + let parsed: TimexProperty; + let value = false; + let error: string; + let args: any []; + ({args, error} = ExpressionFunctions.evaluateChildren(expr, state, options)); + if (!error) { + ({timexProperty: parsed, error: error} = ExpressionFunctions.parseTimexProperty(args[0])); + } + + if (parsed && !error) { + value = parsed.now !== undefined; + } + + return {value, error}; + }, + ReturnType.Boolean, + ExpressionFunctions.validateUnary), + new ExpressionEvaluator( ExpressionType.UriHost, (expr: Expression, state: any, options: Options): { value: any; error: string } => { diff --git a/libraries/adaptive-expressions/src/expressionType.ts b/libraries/adaptive-expressions/src/expressionType.ts index b2433cdcc2..48a7470d22 100644 --- a/libraries/adaptive-expressions/src/expressionType.ts +++ b/libraries/adaptive-expressions/src/expressionType.ts @@ -85,6 +85,15 @@ export class ExpressionType { public static readonly StartOfMonth: string = 'startOfMonth'; public static readonly Ticks: string = 'ticks'; + // timex + public static readonly IsDefinite: string = 'isDefinite'; + public static readonly IsTime: string = 'isTime'; + public static readonly IsDuration: string = 'isDuration'; + public static readonly IsDate: string = 'isDate'; + public static readonly IsTimeRange: string = 'isTimeRange'; + public static readonly IsDateRange: string = 'isDateRange'; + public static readonly IsPresent: string = 'isPresent'; + // Conversions public static readonly Float: string = 'float'; public static readonly Int: string = 'int'; diff --git a/libraries/adaptive-expressions/tests/badExpression.test.js b/libraries/adaptive-expressions/tests/badExpression.test.js index 67f18edb0b..f282fc3baf 100644 --- a/libraries/adaptive-expressions/tests/badExpression.test.js +++ b/libraries/adaptive-expressions/tests/badExpression.test.js @@ -167,6 +167,20 @@ const badExpressions = 'range(one, 0)', // second param should be more than 0 // Date and time function test + 'isDefinite(12345)', // should hava a string or a TimexProperty parameter + 'isDefinite(\'world\', 123445)', // should have only one parameter + 'isTime(123445)', // should hava a string or a TimexProperty parameter + 'isTime(\'world\', 123445)', // should have only one parameter + 'isDuration(123445)', // should hava a string or a TimexProperty parameter + 'isDuration(\'world\', 123445)', // should have only one parameter + 'isDate(123445)', // should hava a string or a TimexProperty parameter + 'isDate(\'world\', 123445)', // should have only one parameter + 'isTimeRange(123445)', // should hava a string or a TimexProperty parameter + 'isTimeRange(\'world\', 123445)', // should have only one parameter + 'isDateRange(123445)', // should hava a string or a TimexProperty parameter + 'isDateRange(\'world\', 123445)', // should have only one parameter + 'isPresent(123445)', // should hava a string or a TimexProperty parameter + 'isPresent(\'world\', 123445)', // should have only one parameter 'addDays(\'errortime\', 1)',// error datetime format 'addDays(timestamp, \'hi\')',// second param should be integer 'addDays(timestamp)',// should have 2 or 3 params diff --git a/libraries/adaptive-expressions/tests/expressionParser.test.js b/libraries/adaptive-expressions/tests/expressionParser.test.js index 7e36ad5d85..701e33632b 100644 --- a/libraries/adaptive-expressions/tests/expressionParser.test.js +++ b/libraries/adaptive-expressions/tests/expressionParser.test.js @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/no-use-before-define */ /* eslint-disable @typescript-eslint/no-var-requires */ const { Expression, SimpleObjectMemory, ExpressionFunctions, Options } = require('../lib'); +var { TimexProperty } = require('@microsoft/recognizers-text-data-types-timex-expression'); const assert = require('assert'); const moment = require('moment'); @@ -405,6 +406,23 @@ const dataSource = [ // Otherwise exceptions will be thrown out // All the output timestamp strings are in ISO format of YYYY-MM-DDTHH:mm:ss.sssZ // Init dateTime: 2018-03-15T13:00:00:111Z + ['isDefinite(\'helloworld\')', false], + ['isDefinite(\'2012-12-21\')', true], + ['isDefinite(\'xxxx-12-21\')', false], + ['isDefinite(validFullDateTimex)', true], + ['isDefinite(invalidFullDateTimex)', false], + ['isTime(validHourTimex)', true], + ['isTime(invalidHourTimex)', false], + ['isDuration(\'PT30M\')', true], + ['isDuration(\'2012-12-21T12:30\')', false], + ['isDate(\'PT30M\')', false], + ['isDate(\'2012-12-21T12:30\')', true], + ['isTimeRange(\'PT30M\')', false], + ['isTimeRange(validTimeRange)', true], + ['isDateRange(\'PT30M\')', false], + ['isDateRange(\'2012-02\')', true], + ['isPresent(\'PT30M\')', false], + ['isPresent(validNow)', true], ['addDays(timestamp, 1)', '2018-03-16T13:00:00.111Z'], ['addDays(timestamp, 1,\'MM-dd-yy\')', '03-16-18'], ['addHours(timestamp, 1)', '2018-03-15T14:00:00.111Z'], @@ -691,6 +709,12 @@ const scope = { ], timestamp: '2018-03-15T13:00:00.111Z', notISOTimestamp: '2018-03-15T13:00:00Z', + validFullDateTimex: new TimexProperty('2020-02-20'), + invalidFullDateTimex: new TimexProperty('xxxx-02-20'), + validHourTimex: new TimexProperty('2020-02-20T07:30'), + validTimeRange: new TimexProperty({partOfDay: 'morning'}), + validNow: new TimexProperty({now: true}), + invalidHourTimex: new TimexProperty('2001-02-20'), timestampObj: new Date('2018-03-15T13:00:00.000Z'), unixTimestamp: 1521118800, user: From 8aa2573278dcfd114da8562157b16cb66829df28 Mon Sep 17 00:00:00 2001 From: Hongyang Date: Wed, 6 May 2020 19:17:30 +0800 Subject: [PATCH 2/3] fix typo --- libraries/adaptive-expressions/src/expressionFunctions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/adaptive-expressions/src/expressionFunctions.ts b/libraries/adaptive-expressions/src/expressionFunctions.ts index e86f4d34f8..8c38e81a3a 100644 --- a/libraries/adaptive-expressions/src/expressionFunctions.ts +++ b/libraries/adaptive-expressions/src/expressionFunctions.ts @@ -2831,7 +2831,7 @@ export class ExpressionFunctions { } if (parsed && !error) { - value = (parsed.month !== undefined && parsed.dayOfMonth !== undefined) || parsed.DayOfWeek !== undefined; + value = (parsed.month !== undefined && parsed.dayOfMonth !== undefined) || parsed.dayOfWeek !== undefined; } return {value, error}; From 865e16440e263ab8e59cc021a8fc70cb7ce8c4a5 Mon Sep 17 00:00:00 2001 From: Hongyang Date: Wed, 6 May 2020 19:50:48 +0800 Subject: [PATCH 3/3] fix typo --- libraries/adaptive-expressions/src/expressionFunctions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/adaptive-expressions/src/expressionFunctions.ts b/libraries/adaptive-expressions/src/expressionFunctions.ts index 8c38e81a3a..1ca730d02b 100644 --- a/libraries/adaptive-expressions/src/expressionFunctions.ts +++ b/libraries/adaptive-expressions/src/expressionFunctions.ts @@ -824,7 +824,7 @@ export class ExpressionFunctions { parsed = new TimexProperty(timexExpr); } else { parsed = new TimexProperty(timexExpr); - if (parsed == undefined || Object.keys(parsed).length === 0) { + if (parsed === undefined || Object.keys(parsed).length === 0) { return {timexProperty: parsed, error: `${ timexExpr } requires a TimexProperty or a string as a argument`}; } }