mirror of
https://github.com/divkit/divkit.git
synced 2026-05-07 20:02:32 +00:00
Initial funcs support
commit_hash:78f512cfc76f18e5db8b956eaa1703e4b23e07ca
This commit is contained in:
@@ -32,9 +32,9 @@ import type { CustomFunctions } from './funcs/customFuncs';
|
||||
|
||||
export type VariablesMap = Map<string, VariableInstance>;
|
||||
|
||||
export type EvalTypes = 'string' | 'number' | 'integer' | 'boolean' | 'color' | 'url' | 'datetime' | 'dict' | 'array';
|
||||
export type EvalTypes = 'string' | 'number' | 'integer' | 'boolean' | 'color' | 'url' | 'datetime' | 'dict' | 'array' | 'function';
|
||||
|
||||
export type EvalTypesWithoutDatetime = 'string' | 'number' | 'integer' | 'boolean' | 'color' | 'url' | 'dict' | 'array';
|
||||
export type EvalTypesWithoutDatetime = 'string' | 'number' | 'integer' | 'boolean' | 'color' | 'url' | 'dict' | 'array' | 'function';
|
||||
|
||||
export interface EvalValueBase {
|
||||
type: string;
|
||||
@@ -86,8 +86,13 @@ export interface ArrayValue extends EvalValueBase {
|
||||
value: unknown[];
|
||||
}
|
||||
|
||||
export interface FuncValue extends EvalValueBase {
|
||||
type: 'function';
|
||||
value: Func[];
|
||||
}
|
||||
|
||||
export type EvalValue = StringValue | UrlValue | ColorValue | NumberValue | IntegerValue |
|
||||
BooleanValue | DatetimeValue | DictValue | ArrayValue;
|
||||
BooleanValue | DatetimeValue | DictValue | ArrayValue | FuncValue;
|
||||
|
||||
export interface EvalError {
|
||||
type: 'error';
|
||||
@@ -463,7 +468,7 @@ function evalCallExpression(ctx: EvalContext, expr: CallExpression): EvalValue {
|
||||
const builtInFindRes = findBestMatchedFunc(funcs, funcName, args);
|
||||
|
||||
// Assign errors only there is no match error in user defined funcs
|
||||
if ('func' in builtInFindRes || !findRes) {
|
||||
if ('func' in builtInFindRes || !findRes || findRes.type === 'missing') {
|
||||
findRes = builtInFindRes;
|
||||
}
|
||||
}
|
||||
@@ -566,6 +571,14 @@ function evalMethodExpression(ctx: EvalContext, expr: MethodExpression): EvalVal
|
||||
|
||||
function evalVariable(ctx: EvalContext, expr: Variable): EvalValue {
|
||||
const varName = expr.id.name;
|
||||
const customFuncs = ctx.customFunctions?.get(varName);
|
||||
if (customFuncs) {
|
||||
return {
|
||||
type: 'function',
|
||||
value: customFuncs
|
||||
};
|
||||
}
|
||||
|
||||
const variable = ctx.variables.get(varName);
|
||||
|
||||
if (variable) {
|
||||
|
||||
@@ -59,6 +59,7 @@ export function customFunctionWrap(fn: DivFunction): Func {
|
||||
let ast: Node | undefined;
|
||||
|
||||
return {
|
||||
name: fn.name,
|
||||
args: fn.arguments.map(it => {
|
||||
return {
|
||||
type: it.type
|
||||
@@ -74,6 +75,9 @@ export function customFunctionWrap(fn: DivFunction): Func {
|
||||
|
||||
const vars: VariablesMap = new Map();
|
||||
args.forEach((arg, index) => {
|
||||
if (arg.type === 'function') {
|
||||
throw new Error('Incorrect argument type: function');
|
||||
}
|
||||
const instance = createConstVariable(fn.arguments[index].name, arg.type, arg.value);
|
||||
// DatetimeVariable doesnt exist right know, but works fine
|
||||
vars.set(instance.getName(), instance as Variable);
|
||||
|
||||
@@ -9,6 +9,7 @@ export type FuncArg = EvalTypes | {
|
||||
}
|
||||
|
||||
export interface Func {
|
||||
name?: string;
|
||||
args: FuncArg[];
|
||||
cb(ctx: EvalContext, ...args: EvalValue[]): EvalValue;
|
||||
}
|
||||
|
||||
@@ -105,6 +105,12 @@ class ExpressionBinding {
|
||||
usedVars: res.usedVars
|
||||
};
|
||||
}
|
||||
if (result.type === 'function') {
|
||||
return {
|
||||
result: `<${result.value[0]?.name || 'Function'}>` as T,
|
||||
usedVars: res.usedVars
|
||||
};
|
||||
}
|
||||
if (!keepComplex && (result.type === 'array' || result.type === 'dict')) {
|
||||
try {
|
||||
return {
|
||||
|
||||
@@ -60,6 +60,8 @@ export function valToString(val: EvalValue, stringifyComplex: boolean): string {
|
||||
return '<dict>';
|
||||
} else if (val.type === 'array') {
|
||||
return '<array>';
|
||||
} else if (val.type === 'function') {
|
||||
return val.value[0].name || 'Function';
|
||||
}
|
||||
|
||||
// For purpose when new eval value types will be added
|
||||
@@ -186,6 +188,10 @@ export function convertJsValueToDivKit(
|
||||
val: unknown,
|
||||
evalType: EvalTypesWithoutDatetime
|
||||
): EvalValue {
|
||||
if (evalType === 'function') {
|
||||
throw new Error('Cannot convert function');
|
||||
}
|
||||
|
||||
const jsType = EVAL_TYPE_TO_JS_TYPE[evalType];
|
||||
|
||||
let type: string = typeof val;
|
||||
|
||||
@@ -9,6 +9,8 @@ import { evalExpression, type EvalResult } from '../../src/expressions/eval';
|
||||
import { transformColorValue, valToString } from '../../src/expressions/utils';
|
||||
import { parse } from '../../src/expressions/expressions';
|
||||
import { createVariable } from '../../src/expressions/variable';
|
||||
import { customFunctionWrap, type CustomFunctions } from '../../src/expressions/funcs/customFuncs';
|
||||
import type { DivFunction } from '../../typings/common';
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
@@ -46,6 +48,7 @@ function convertVals(val: EvalResult) {
|
||||
|
||||
function runCase(item: any) {
|
||||
const vars = new Map();
|
||||
const customFunctions: CustomFunctions = new Map();
|
||||
if (item.variables) {
|
||||
for (const variable of item.variables) {
|
||||
let value;
|
||||
@@ -89,6 +92,14 @@ function runCase(item: any) {
|
||||
vars.set(variable.name, createVariable(variable.name, variable.type, value));
|
||||
}
|
||||
}
|
||||
if (item.functions) {
|
||||
for (const func of item.functions) {
|
||||
const fn = func as DivFunction;
|
||||
const list = customFunctions.get(fn.name) || [];
|
||||
list.push(customFunctionWrap(fn));
|
||||
customFunctions.set(fn.name, list);
|
||||
}
|
||||
}
|
||||
let ast;
|
||||
try {
|
||||
ast = parse(item.expression, {
|
||||
@@ -105,7 +116,7 @@ function runCase(item: any) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
const res = evalExpression(vars, undefined, undefined, ast, {
|
||||
const res = evalExpression(vars, customFunctions, undefined, ast, {
|
||||
weekStartDay: item.platform_specific?.web?.weekStartDay || 0
|
||||
});
|
||||
if (item.expected.value !== '' || res.result.type !== 'error') {
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
}
|
||||
],
|
||||
"platforms": [
|
||||
"ios"
|
||||
"ios",
|
||||
"web"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -51,7 +52,8 @@
|
||||
}
|
||||
],
|
||||
"platforms": [
|
||||
"ios"
|
||||
"ios",
|
||||
"web"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -74,7 +76,9 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"platforms": []
|
||||
"platforms": [
|
||||
"web"
|
||||
]
|
||||
},
|
||||
{
|
||||
"expression": "@{toString(myFunction)}",
|
||||
@@ -96,7 +100,9 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"platforms": []
|
||||
"platforms": [
|
||||
"web"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user