Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const validateExpressions: ValidateFunc = (
let errorMessage = '';
let warningMessage = '';
try {
newCache[value] = cache?.[value] ? cache[value] : checkExpression(value, required);
newCache[value] = cache?.[value] ? cache[value] : checkExpression(value, required, types);
errorMessage = checkReturnType(newCache[value], types);
} catch (error) {
//change the missing custom function error to warning
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
import { Diagnostic, LgFile, LuFile, DialogSetting, SchemaDefinitions, MicrosoftIDialog } from '@bfc/shared';
import { ReturnType } from 'adaptive-expressions';

//this is used to change the type like 'integer', 'boolean' to expression parse return type
//the expression return type is number and can do bitwise to check if the type is match.
export const StringMapExpressionType = {
number: ReturnType.Number,
string: ReturnType.String,
boolean: ReturnType.Boolean,
object: ReturnType.Object,
array: ReturnType.Array,
integer: ReturnType.Number,
all: ReturnType.Number + ReturnType.String + ReturnType.Boolean + ReturnType.Object + ReturnType.Array,
};

export type ExpressionParseResult = { [content: string]: number };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT License.

import values from 'lodash/values';
import { FieldNames } from '@bfc/shared';
import { FieldNames, JSONSchema7 } from '@bfc/shared';

import { StringMapExpressionType } from './types';

Expand Down Expand Up @@ -41,23 +41,73 @@ export function findRequiredProperties(schema: any): { [key: string]: boolean }
return required;
}

export function findTypes(schema: any): number[] {
/*
case:
json field type is string;
the $role is expression;
there is no oneOf;

we don't know which return type is correct,
so we think the expression support all return types.

case:
the $role is expression;
the oneOf has some normal types and there is no expression in oneOf

the return type is one of the types in oneOf filed.

case:
the $role is expression;
the oneOf has some normal types and there is a expression role in oneOf

the filed maybe a string expression and the expression return type is one of the types in oneOf filed besides the type with expression role.
*/
/**
* this function will find the expression types from schema,
* and switch them to the type of Expression's return type,
* the type in schema is like 'integer', 'boolean',
* but the Expression's return type is number:
* ReturnType {
Boolean = 1,
Number = 2,
Object = 4,
String = 8,
Array = 16,
}
* if the Expression parse return type is 5. it means the expresion return maybe boolean or object.
* then we can use the schema type to do bitwise to check if the type is match.
*
* @param schema dialog's filed schema from client's merged schema(sdk.schema)
* @returns the list of type (switch the string type to the expression type).
*/
export const findTypes = (schema: JSONSchema7): number[] => {
if (!schema) return [];
let types: number[] = [];
if (schema.type) {
if (Array.isArray(schema.type)) {
types = schema.type.map((item: string) => StringMapExpressionType[item]);
} else {
types.push(StringMapExpressionType[schema.type]);
}
} else if (schema.oneOf) {
types = schema.oneOf.reduce((result: string[], item) => {
if (StringMapExpressionType[item.type]) {
result.push(StringMapExpressionType[item.type]);

if (schema.type === 'string' && schema.$role === 'expression') {
return [StringMapExpressionType.all];
}

if (schema.type && Array.isArray(schema.type)) {
types = schema.type.map((item: string) => StringMapExpressionType[item]);
}

if (schema.oneOf) {
types = schema.oneOf?.reduce((result: number[], item) => {
if (item.$role === 'expression') return result;

if (item.type) {
if (Array.isArray(item.type)) {
result.push(...item.type.map((i: string) => StringMapExpressionType[i]));
} else {
result.push(StringMapExpressionType[item.type]);
}
}

return result;
}, []);
if (types.length === 0) types.push(StringMapExpressionType.all);
}

return Array.from(new Set<number>(types));
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,18 @@ export const addReturnType = (currentType: number, newType: number) => {
return currentType | newType;
};

export const checkStringExpression = (exp: string): number => {
//StringExpression always assumes string interpolation unless prefixed with =, producing a string
if (exp.trim().startsWith('=')) {
return Expression.parse(exp.trim().substring(1)).returnType;
export const checkStringExpression = (exp: string, isStringType: boolean): number => {
const origin = exp.trim();

//no need to do parse if the string expression doesn't start with '='
if (!origin.startsWith('=') && isStringType) {
return ReturnType.String;
}

return ReturnType.String;
return Expression.parse(origin.substring(1)).returnType;
};

export const checkExpression = (exp: any, required: boolean): number => {
export const checkExpression = (exp: any, required: boolean, types: number[]): number => {
if ((exp === undefined || '') && required) {
throw new Error(EMPTY);
}
Expand All @@ -53,7 +55,7 @@ export const checkExpression = (exp: any, required: boolean): number => {
break;
}
case 'string': {
returnType = checkStringExpression(exp);
returnType = checkStringExpression(exp, types.length === 1 && types[0] === ReturnType.String);
break;
}
default:
Expand Down