Merge pull request #10922 from appsmithorg/chore/releaseBlockerFixes-v1.6.9
chore: releaseBlockerFixes-v1.6.9
This commit is contained in:
commit
ff8e2a64e8
|
|
@ -1,9 +1,7 @@
|
||||||
import { ReduxActionTypes, ReduxAction } from "constants/ReduxActionConstants";
|
import { ReduxActionTypes, ReduxAction } from "constants/ReduxActionConstants";
|
||||||
import { BatchAction, batchAction } from "actions/batchActions";
|
import { BatchAction, batchAction } from "actions/batchActions";
|
||||||
|
import { Diff } from "deep-diff";
|
||||||
import { DataTree } from "entities/DataTree/dataTreeFactory";
|
import { DataTree } from "entities/DataTree/dataTreeFactory";
|
||||||
import { isWidget } from "../workers/evaluationUtils";
|
|
||||||
import { MetaState } from "../reducers/entityReducers/metaReducer";
|
|
||||||
import isEmpty from "lodash/isEmpty";
|
|
||||||
|
|
||||||
export interface UpdateWidgetMetaPropertyPayload {
|
export interface UpdateWidgetMetaPropertyPayload {
|
||||||
widgetId: string;
|
widgetId: string;
|
||||||
|
|
@ -47,18 +45,15 @@ export const resetChildrenMetaProperty = (
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateMetaState = (evaluatedDataTree: DataTree) => {
|
export const updateMetaState = (
|
||||||
const updatedWidgetMetaState: MetaState = {};
|
updates: Diff<any, any>[],
|
||||||
Object.values(evaluatedDataTree).forEach((entity) => {
|
updatedDataTree: DataTree,
|
||||||
if (isWidget(entity) && entity.widgetId && !isEmpty(entity.meta)) {
|
) => {
|
||||||
updatedWidgetMetaState[entity.widgetId] = entity.meta;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: ReduxActionTypes.UPDATE_META_STATE,
|
type: ReduxActionTypes.UPDATE_META_STATE,
|
||||||
payload: {
|
payload: {
|
||||||
updatedWidgetMetaState,
|
updates,
|
||||||
|
updatedDataTree,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,8 @@ export interface ExecuteErrorPayload extends ErrorActionPayload {
|
||||||
export const urlGroupsRegexExp = /^(https?:\/{2}\S+?)(\/[\s\S]*?)?(\?(?![^{]*})[\s\S]*)?$/;
|
export const urlGroupsRegexExp = /^(https?:\/{2}\S+?)(\/[\s\S]*?)?(\?(?![^{]*})[\s\S]*)?$/;
|
||||||
|
|
||||||
export const EXECUTION_PARAM_KEY = "executionParams";
|
export const EXECUTION_PARAM_KEY = "executionParams";
|
||||||
export const EXECUTION_PARAM_REFERENCE_REGEX = /this.params/g;
|
export const EXECUTION_PARAM_REFERENCE_REGEX = /this.params|this\?.params/g;
|
||||||
|
export const THIS_DOT_PARAMS_KEY = "params";
|
||||||
|
|
||||||
export const RESP_HEADER_DATATYPE = "X-APPSMITH-DATATYPE";
|
export const RESP_HEADER_DATATYPE = "X-APPSMITH-DATATYPE";
|
||||||
export const API_REQUEST_HEADERS: APIHeaders = {
|
export const API_REQUEST_HEADERS: APIHeaders = {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,16 @@
|
||||||
import { set, cloneDeep } from "lodash";
|
import { set, cloneDeep, get } from "lodash";
|
||||||
import { createReducer } from "utils/AppsmithUtils";
|
import { createReducer } from "utils/AppsmithUtils";
|
||||||
import { UpdateWidgetMetaPropertyPayload } from "actions/metaActions";
|
import { UpdateWidgetMetaPropertyPayload } from "actions/metaActions";
|
||||||
import isObject from "lodash/isObject";
|
|
||||||
import { DataTreeWidget } from "entities/DataTree/dataTreeFactory";
|
|
||||||
import {
|
import {
|
||||||
ReduxActionTypes,
|
ReduxActionTypes,
|
||||||
ReduxAction,
|
ReduxAction,
|
||||||
WidgetReduxActionTypes,
|
WidgetReduxActionTypes,
|
||||||
} from "constants/ReduxActionConstants";
|
} from "constants/ReduxActionConstants";
|
||||||
|
import { Diff } from "deep-diff";
|
||||||
|
import produce from "immer";
|
||||||
|
import { DataTree } from "entities/DataTree/dataTreeFactory";
|
||||||
|
import { isWidget } from "../../workers/evaluationUtils";
|
||||||
|
|
||||||
export type MetaState = Record<string, Record<string, unknown>>;
|
export type MetaState = Record<string, Record<string, unknown>>;
|
||||||
|
|
||||||
|
|
@ -17,24 +20,41 @@ export const metaReducer = createReducer(initialState, {
|
||||||
[ReduxActionTypes.UPDATE_META_STATE]: (
|
[ReduxActionTypes.UPDATE_META_STATE]: (
|
||||||
state: MetaState,
|
state: MetaState,
|
||||||
action: ReduxAction<{
|
action: ReduxAction<{
|
||||||
updatedWidgetMetaState: Record<string, DataTreeWidget>;
|
updates: Diff<any, any>[];
|
||||||
|
updatedDataTree: DataTree;
|
||||||
}>,
|
}>,
|
||||||
) => {
|
) => {
|
||||||
// if metaObject is updated in dataTree we also update meta values, to keep meta state in sync.
|
const { updatedDataTree, updates } = action.payload;
|
||||||
const newMetaState = cloneDeep(state);
|
|
||||||
const { updatedWidgetMetaState } = action.payload;
|
|
||||||
|
|
||||||
Object.entries(updatedWidgetMetaState).forEach(
|
// if metaObject is updated in dataTree we also update meta values, to keep meta state in sync.
|
||||||
([entityWidgetId, entityMetaState]) => {
|
const newMetaState = produce(state, (draftMetaState) => {
|
||||||
if (isObject(newMetaState[entityWidgetId])) {
|
if (updates.length) {
|
||||||
Object.keys(newMetaState[entityWidgetId]).forEach((key) => {
|
updates.forEach((update) => {
|
||||||
if (key in entityMetaState) {
|
// if meta field is updated in the dataTree then update metaReducer values.
|
||||||
newMetaState[entityWidgetId][key] = entityMetaState[key];
|
if (
|
||||||
|
update.kind === "E" &&
|
||||||
|
update.path?.length &&
|
||||||
|
update.path?.length > 1 &&
|
||||||
|
update.path[1] === "meta"
|
||||||
|
) {
|
||||||
|
// path eg: Input1.meta.defaultText
|
||||||
|
const entity = get(updatedDataTree, update.path[0]);
|
||||||
|
const metaPropertyPath = update.path.slice(2);
|
||||||
|
if (
|
||||||
|
isWidget(entity) &&
|
||||||
|
entity.widgetId &&
|
||||||
|
metaPropertyPath.length
|
||||||
|
) {
|
||||||
|
set(
|
||||||
|
draftMetaState,
|
||||||
|
[entity.widgetId, ...metaPropertyPath],
|
||||||
|
update.rhs,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
},
|
}
|
||||||
);
|
});
|
||||||
return newMetaState;
|
return newMetaState;
|
||||||
},
|
},
|
||||||
[ReduxActionTypes.SET_META_PROP]: (
|
[ReduxActionTypes.SET_META_PROP]: (
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ function* evaluateTreeSaga(
|
||||||
PerformanceTransactionName.SET_EVALUATED_TREE,
|
PerformanceTransactionName.SET_EVALUATED_TREE,
|
||||||
);
|
);
|
||||||
|
|
||||||
yield put(updateMetaState(dataTree));
|
yield put(updateMetaState(updates, dataTree));
|
||||||
|
|
||||||
const updatedDataTree = yield select(getDataTree);
|
const updatedDataTree = yield select(getDataTree);
|
||||||
log.debug({ jsUpdates: jsUpdates });
|
log.debug({ jsUpdates: jsUpdates });
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ import {
|
||||||
migrateTableSanitizeColumnKeys,
|
migrateTableSanitizeColumnKeys,
|
||||||
isSortableMigration,
|
isSortableMigration,
|
||||||
migrateTableWidgetIconButtonVariant,
|
migrateTableWidgetIconButtonVariant,
|
||||||
migrateTableWidgetNumericColumnName,
|
|
||||||
} from "./migrations/TableWidget";
|
} from "./migrations/TableWidget";
|
||||||
import { migrateTextStyleFromTextWidget } from "./migrations/TextWidgetReplaceTextStyle";
|
import { migrateTextStyleFromTextWidget } from "./migrations/TextWidgetReplaceTextStyle";
|
||||||
import { DATA_BIND_REGEX_GLOBAL } from "constants/BindingsConstants";
|
import { DATA_BIND_REGEX_GLOBAL } from "constants/BindingsConstants";
|
||||||
|
|
@ -1039,7 +1038,10 @@ export const transformDSL = (
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentDSL.version === 50) {
|
if (currentDSL.version === 50) {
|
||||||
currentDSL = migrateTableWidgetNumericColumnName(currentDSL);
|
/*
|
||||||
|
* We're skipping this to fix a bad table migration - migrateTableWidgetNumericColumnName
|
||||||
|
* it overwrites the computedValue of the table columns
|
||||||
|
*/
|
||||||
currentDSL.version = LATEST_PAGE_VERSION;
|
currentDSL.version = LATEST_PAGE_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -490,6 +490,9 @@ export const migrateTableWidgetIconButtonVariant = (currentDSL: DSLWidget) => {
|
||||||
return currentDSL;
|
return currentDSL;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DO NOT USE THIS. it overwrites conputedValues of the Table Columns
|
||||||
|
*/
|
||||||
export const migrateTableWidgetNumericColumnName = (currentDSL: DSLWidget) => {
|
export const migrateTableWidgetNumericColumnName = (currentDSL: DSLWidget) => {
|
||||||
currentDSL.children = currentDSL.children?.map((child: WidgetProps) => {
|
currentDSL.children = currentDSL.children?.map((child: WidgetProps) => {
|
||||||
if (child.type === "TABLE_WIDGET") {
|
if (child.type === "TABLE_WIDGET") {
|
||||||
|
|
|
||||||
109
app/client/src/workers/DataTreeEvaluator.test.ts
Normal file
109
app/client/src/workers/DataTreeEvaluator.test.ts
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
import DataTreeEvaluator from "./DataTreeEvaluator";
|
||||||
|
|
||||||
|
describe("DataTreeEvaluator", () => {
|
||||||
|
let dataTreeEvaluator: DataTreeEvaluator;
|
||||||
|
beforeAll(() => {
|
||||||
|
dataTreeEvaluator = new DataTreeEvaluator({});
|
||||||
|
});
|
||||||
|
describe("evaluateActionBindings", () => {
|
||||||
|
it("handles this.params.property", () => {
|
||||||
|
const result = dataTreeEvaluator.evaluateActionBindings(
|
||||||
|
[
|
||||||
|
"(function() { return this.params.property })()",
|
||||||
|
"(() => { return this.params.property })()",
|
||||||
|
'this.params.property || "default value"',
|
||||||
|
'this.params.property1 || "default value"',
|
||||||
|
],
|
||||||
|
{
|
||||||
|
property: "my value",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
expect(result).toStrictEqual([
|
||||||
|
"my value",
|
||||||
|
"my value",
|
||||||
|
"my value",
|
||||||
|
"default value",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("handles this?.params.property", () => {
|
||||||
|
const result = dataTreeEvaluator.evaluateActionBindings(
|
||||||
|
[
|
||||||
|
"(() => { return this?.params.property })()",
|
||||||
|
"(function() { return this?.params.property })()",
|
||||||
|
'this?.params.property || "default value"',
|
||||||
|
'this?.params.property1 || "default value"',
|
||||||
|
],
|
||||||
|
{
|
||||||
|
property: "my value",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
expect(result).toStrictEqual([
|
||||||
|
"my value",
|
||||||
|
"my value",
|
||||||
|
"my value",
|
||||||
|
"default value",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("handles this?.params?.property", () => {
|
||||||
|
const result = dataTreeEvaluator.evaluateActionBindings(
|
||||||
|
[
|
||||||
|
"(() => { return this?.params?.property })()",
|
||||||
|
"(function() { return this?.params?.property })()",
|
||||||
|
'this?.params?.property || "default value"',
|
||||||
|
'this?.params?.property1 || "default value"',
|
||||||
|
],
|
||||||
|
{
|
||||||
|
property: "my value",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
expect(result).toStrictEqual([
|
||||||
|
"my value",
|
||||||
|
"my value",
|
||||||
|
"my value",
|
||||||
|
"default value",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("handles executionParams.property", () => {
|
||||||
|
const result = dataTreeEvaluator.evaluateActionBindings(
|
||||||
|
[
|
||||||
|
"(function() { return executionParams.property })()",
|
||||||
|
"(() => { return executionParams.property })()",
|
||||||
|
'executionParams.property || "default value"',
|
||||||
|
'executionParams.property1 || "default value"',
|
||||||
|
],
|
||||||
|
{
|
||||||
|
property: "my value",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
expect(result).toStrictEqual([
|
||||||
|
"my value",
|
||||||
|
"my value",
|
||||||
|
"my value",
|
||||||
|
"default value",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("handles executionParams?.property", () => {
|
||||||
|
const result = dataTreeEvaluator.evaluateActionBindings(
|
||||||
|
[
|
||||||
|
"(function() { return executionParams?.property })()",
|
||||||
|
"(() => { return executionParams?.property })()",
|
||||||
|
'executionParams?.property || "default value"',
|
||||||
|
'executionParams?.property1 || "default value"',
|
||||||
|
],
|
||||||
|
{
|
||||||
|
property: "my value",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
expect(result).toStrictEqual([
|
||||||
|
"my value",
|
||||||
|
"my value",
|
||||||
|
"my value",
|
||||||
|
"default value",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -55,11 +55,13 @@ import toposort from "toposort";
|
||||||
import {
|
import {
|
||||||
EXECUTION_PARAM_KEY,
|
EXECUTION_PARAM_KEY,
|
||||||
EXECUTION_PARAM_REFERENCE_REGEX,
|
EXECUTION_PARAM_REFERENCE_REGEX,
|
||||||
|
THIS_DOT_PARAMS_KEY,
|
||||||
} from "constants/AppsmithActionConstants/ActionConstants";
|
} from "constants/AppsmithActionConstants/ActionConstants";
|
||||||
import { DATA_BIND_REGEX } from "constants/BindingsConstants";
|
import { DATA_BIND_REGEX } from "constants/BindingsConstants";
|
||||||
import evaluateSync, {
|
import evaluateSync, {
|
||||||
createGlobalData,
|
createGlobalData,
|
||||||
EvalResult,
|
EvalResult,
|
||||||
|
EvaluateContext,
|
||||||
EvaluationScriptType,
|
EvaluationScriptType,
|
||||||
getScriptToEval,
|
getScriptToEval,
|
||||||
evaluateAsync,
|
evaluateAsync,
|
||||||
|
|
@ -609,12 +611,19 @@ export default class DataTreeEvaluator {
|
||||||
entity.bindingPaths[propertyPath] ||
|
entity.bindingPaths[propertyPath] ||
|
||||||
EvaluationSubstitutionType.TEMPLATE;
|
EvaluationSubstitutionType.TEMPLATE;
|
||||||
|
|
||||||
|
const contextData: EvaluateContext = {};
|
||||||
|
if (isAction(entity)) {
|
||||||
|
contextData.thisContext = {
|
||||||
|
params: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
evalPropertyValue = this.getDynamicValue(
|
evalPropertyValue = this.getDynamicValue(
|
||||||
unEvalPropertyValue,
|
unEvalPropertyValue,
|
||||||
currentTree,
|
currentTree,
|
||||||
resolvedFunctions,
|
resolvedFunctions,
|
||||||
evaluationSubstitutionType,
|
evaluationSubstitutionType,
|
||||||
|
contextData,
|
||||||
undefined,
|
undefined,
|
||||||
fullPropertyPath,
|
fullPropertyPath,
|
||||||
);
|
);
|
||||||
|
|
@ -764,6 +773,7 @@ export default class DataTreeEvaluator {
|
||||||
data: DataTree,
|
data: DataTree,
|
||||||
resolvedFunctions: Record<string, any>,
|
resolvedFunctions: Record<string, any>,
|
||||||
evaluationSubstitutionType: EvaluationSubstitutionType,
|
evaluationSubstitutionType: EvaluationSubstitutionType,
|
||||||
|
contextData?: EvaluateContext,
|
||||||
callBackData?: Array<any>,
|
callBackData?: Array<any>,
|
||||||
fullPropertyPath?: string,
|
fullPropertyPath?: string,
|
||||||
) {
|
) {
|
||||||
|
|
@ -792,6 +802,7 @@ export default class DataTreeEvaluator {
|
||||||
toBeSentForEval,
|
toBeSentForEval,
|
||||||
data,
|
data,
|
||||||
resolvedFunctions,
|
resolvedFunctions,
|
||||||
|
contextData,
|
||||||
callBackData,
|
callBackData,
|
||||||
);
|
);
|
||||||
if (fullPropertyPath && result.errors.length) {
|
if (fullPropertyPath && result.errors.length) {
|
||||||
|
|
@ -864,10 +875,17 @@ export default class DataTreeEvaluator {
|
||||||
js: string,
|
js: string,
|
||||||
data: DataTree,
|
data: DataTree,
|
||||||
resolvedFunctions: Record<string, any>,
|
resolvedFunctions: Record<string, any>,
|
||||||
|
contextData?: EvaluateContext,
|
||||||
callbackData?: Array<any>,
|
callbackData?: Array<any>,
|
||||||
): EvalResult {
|
): EvalResult {
|
||||||
try {
|
try {
|
||||||
return evaluateSync(js, data, resolvedFunctions, callbackData);
|
return evaluateSync(
|
||||||
|
js,
|
||||||
|
data,
|
||||||
|
resolvedFunctions,
|
||||||
|
contextData,
|
||||||
|
callbackData,
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return {
|
return {
|
||||||
result: undefined,
|
result: undefined,
|
||||||
|
|
@ -1555,24 +1573,26 @@ export default class DataTreeEvaluator {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace any reference of 'this.params' to 'executionParams' (backwards compatibility)
|
return bindings.map((binding) => {
|
||||||
const bindingsForExecutionParams: string[] = bindings.map(
|
// Replace any reference of 'this.params' to 'executionParams' (backwards compatibility)
|
||||||
(binding: string) =>
|
// also helps with dealing with IIFE which are normal functions (not arrow)
|
||||||
binding.replace(EXECUTION_PARAM_REFERENCE_REGEX, EXECUTION_PARAM_KEY),
|
// because normal functions won't retain 'this' context (when executed elsewhere)
|
||||||
);
|
const replacedBinding = binding.replace(
|
||||||
|
EXECUTION_PARAM_REFERENCE_REGEX,
|
||||||
const dataTreeWithExecutionParams = Object.assign({}, this.evalTree, {
|
EXECUTION_PARAM_KEY,
|
||||||
[EXECUTION_PARAM_KEY]: evaluatedExecutionParams,
|
);
|
||||||
});
|
return this.getDynamicValue(
|
||||||
|
`{{${replacedBinding}}}`,
|
||||||
return bindingsForExecutionParams.map((binding) =>
|
this.evalTree,
|
||||||
this.getDynamicValue(
|
|
||||||
`{{${binding}}}`,
|
|
||||||
dataTreeWithExecutionParams,
|
|
||||||
this.resolvedFunctions,
|
this.resolvedFunctions,
|
||||||
EvaluationSubstitutionType.TEMPLATE,
|
EvaluationSubstitutionType.TEMPLATE,
|
||||||
),
|
// params can be accessed via "this.params" or "executionParams"
|
||||||
);
|
{
|
||||||
|
thisContext: { [THIS_DOT_PARAMS_KEY]: evaluatedExecutionParams },
|
||||||
|
globalContext: { [EXECUTION_PARAM_KEY]: evaluatedExecutionParams },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
clearErrors() {
|
clearErrors() {
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,9 @@ describe("evaluateSync", () => {
|
||||||
triggerPaths: {},
|
triggerPaths: {},
|
||||||
validationPaths: {},
|
validationPaths: {},
|
||||||
logBlackList: {},
|
logBlackList: {},
|
||||||
|
overridingPropertyPaths: {},
|
||||||
|
privateWidgets: {},
|
||||||
|
propertyOverrideDependency: {},
|
||||||
};
|
};
|
||||||
const dataTree: DataTree = {
|
const dataTree: DataTree = {
|
||||||
Input1: widget,
|
Input1: widget,
|
||||||
|
|
@ -75,7 +78,7 @@ describe("evaluateSync", () => {
|
||||||
const result = wrongJS
|
const result = wrongJS
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
closedFunction()
|
closedFunction.call(THIS_CONTEXT)
|
||||||
`,
|
`,
|
||||||
severity: "error",
|
severity: "error",
|
||||||
originalBinding: "wrongJS",
|
originalBinding: "wrongJS",
|
||||||
|
|
@ -89,7 +92,7 @@ describe("evaluateSync", () => {
|
||||||
const result = wrongJS
|
const result = wrongJS
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
closedFunction()
|
closedFunction.call(THIS_CONTEXT)
|
||||||
`,
|
`,
|
||||||
severity: "error",
|
severity: "error",
|
||||||
originalBinding: "wrongJS",
|
originalBinding: "wrongJS",
|
||||||
|
|
@ -108,7 +111,7 @@ describe("evaluateSync", () => {
|
||||||
const result = {}.map()
|
const result = {}.map()
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
closedFunction()
|
closedFunction.call(THIS_CONTEXT)
|
||||||
`,
|
`,
|
||||||
severity: "error",
|
severity: "error",
|
||||||
originalBinding: "{}.map()",
|
originalBinding: "{}.map()",
|
||||||
|
|
@ -135,7 +138,7 @@ describe("evaluateSync", () => {
|
||||||
const result = setTimeout(() => {}, 100)
|
const result = setTimeout(() => {}, 100)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
closedFunction()
|
closedFunction.call(THIS_CONTEXT)
|
||||||
`,
|
`,
|
||||||
severity: "error",
|
severity: "error",
|
||||||
originalBinding: "setTimeout(() => {}, 100)",
|
originalBinding: "setTimeout(() => {}, 100)",
|
||||||
|
|
@ -151,7 +154,7 @@ describe("evaluateSync", () => {
|
||||||
it("evaluates functions with callback data", () => {
|
it("evaluates functions with callback data", () => {
|
||||||
const js = "(arg1, arg2) => arg1.value + arg2";
|
const js = "(arg1, arg2) => arg1.value + arg2";
|
||||||
const callbackData = [{ value: "test" }, "1"];
|
const callbackData = [{ value: "test" }, "1"];
|
||||||
const response = evaluate(js, dataTree, {}, callbackData);
|
const response = evaluate(js, dataTree, {}, {}, callbackData);
|
||||||
expect(response.result).toBe("test1");
|
expect(response.result).toBe("test1");
|
||||||
});
|
});
|
||||||
it("handles EXPRESSIONS with new lines", () => {
|
it("handles EXPRESSIONS with new lines", () => {
|
||||||
|
|
@ -165,22 +168,38 @@ describe("evaluateSync", () => {
|
||||||
});
|
});
|
||||||
it("handles TRIGGERS with new lines", () => {
|
it("handles TRIGGERS with new lines", () => {
|
||||||
let js = "\n";
|
let js = "\n";
|
||||||
let response = evaluate(js, dataTree, {}, undefined);
|
let response = evaluate(js, dataTree, {}, undefined, undefined);
|
||||||
expect(response.errors.length).toBe(0);
|
expect(response.errors.length).toBe(0);
|
||||||
|
|
||||||
js = "\n\n\n";
|
js = "\n\n\n";
|
||||||
response = evaluate(js, dataTree, {}, undefined);
|
response = evaluate(js, dataTree, {}, undefined, undefined);
|
||||||
expect(response.errors.length).toBe(0);
|
expect(response.errors.length).toBe(0);
|
||||||
});
|
});
|
||||||
it("handles ANONYMOUS_FUNCTION with new lines", () => {
|
it("handles ANONYMOUS_FUNCTION with new lines", () => {
|
||||||
let js = "\n";
|
let js = "\n";
|
||||||
let response = evaluate(js, dataTree, {}, undefined);
|
let response = evaluate(js, dataTree, {}, undefined, undefined);
|
||||||
expect(response.errors.length).toBe(0);
|
expect(response.errors.length).toBe(0);
|
||||||
|
|
||||||
js = "\n\n\n";
|
js = "\n\n\n";
|
||||||
response = evaluate(js, dataTree, {}, undefined);
|
response = evaluate(js, dataTree, {}, undefined, undefined);
|
||||||
expect(response.errors.length).toBe(0);
|
expect(response.errors.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
it("has access to this context", () => {
|
||||||
|
const js = "this.contextVariable";
|
||||||
|
const thisContext = { contextVariable: "test" };
|
||||||
|
const response = evaluate(js, dataTree, {}, { thisContext });
|
||||||
|
expect(response.result).toBe("test");
|
||||||
|
// there should not be any error when accessing "this" variables
|
||||||
|
expect(response.errors).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("has access to additional global context", () => {
|
||||||
|
const js = "contextVariable";
|
||||||
|
const globalContext = { contextVariable: "test" };
|
||||||
|
const response = evaluate(js, dataTree, {}, { globalContext });
|
||||||
|
expect(response.result).toBe("test");
|
||||||
|
expect(response.errors).toHaveLength(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("evaluateAsync", () => {
|
describe("evaluateAsync", () => {
|
||||||
|
|
@ -256,7 +275,7 @@ describe("isFunctionAsync", () => {
|
||||||
if (typeof testFunc === "string") {
|
if (typeof testFunc === "string") {
|
||||||
testFunc = eval(testFunc);
|
testFunc = eval(testFunc);
|
||||||
}
|
}
|
||||||
const actual = isFunctionAsync(testFunc, {});
|
const actual = isFunctionAsync(testFunc, {}, {});
|
||||||
expect(actual).toBe(testCase.expected);
|
expect(actual).toBe(testCase.expected);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -34,12 +34,12 @@ export const EvaluationScripts: Record<EvaluationScriptType, string> = {
|
||||||
const result = ${ScriptTemplate}
|
const result = ${ScriptTemplate}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
closedFunction()
|
closedFunction.call(THIS_CONTEXT)
|
||||||
`,
|
`,
|
||||||
[EvaluationScriptType.ANONYMOUS_FUNCTION]: `
|
[EvaluationScriptType.ANONYMOUS_FUNCTION]: `
|
||||||
function callback (script) {
|
function callback (script) {
|
||||||
const userFunction = script;
|
const userFunction = script;
|
||||||
const result = userFunction?.apply(self, ARGUMENTS);
|
const result = userFunction?.apply(THIS_CONTEXT, ARGUMENTS);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
callback(${ScriptTemplate})
|
callback(${ScriptTemplate})
|
||||||
|
|
@ -49,7 +49,7 @@ export const EvaluationScripts: Record<EvaluationScriptType, string> = {
|
||||||
const result = await ${ScriptTemplate};
|
const result = await ${ScriptTemplate};
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
closedFunction();
|
closedFunction.call(THIS_CONTEXT);
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -102,6 +102,18 @@ export const createGlobalData = (
|
||||||
const GLOBAL_DATA: Record<string, any> = {};
|
const GLOBAL_DATA: Record<string, any> = {};
|
||||||
///// Adding callback data
|
///// Adding callback data
|
||||||
GLOBAL_DATA.ARGUMENTS = evalArguments;
|
GLOBAL_DATA.ARGUMENTS = evalArguments;
|
||||||
|
//// Adding contextual data not part of data tree
|
||||||
|
GLOBAL_DATA.THIS_CONTEXT = {};
|
||||||
|
if (context) {
|
||||||
|
if (context.thisContext) {
|
||||||
|
GLOBAL_DATA.THIS_CONTEXT = context.thisContext;
|
||||||
|
}
|
||||||
|
if (context.globalContext) {
|
||||||
|
Object.entries(context.globalContext).forEach(([key, value]) => {
|
||||||
|
GLOBAL_DATA[key] = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
//// Add internal functions to dataTree;
|
//// Add internal functions to dataTree;
|
||||||
const dataTreeWithFunctions = enhanceDataTreeWithFunctions(
|
const dataTreeWithFunctions = enhanceDataTreeWithFunctions(
|
||||||
dataTree,
|
dataTree,
|
||||||
|
|
@ -134,9 +146,13 @@ export function sanitizeScript(js: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Define a context just for this script
|
/** Define a context just for this script
|
||||||
|
* thisContext will define it on the `this`
|
||||||
|
* globalContext will define it globally
|
||||||
* requestId is used for completing promises
|
* requestId is used for completing promises
|
||||||
*/
|
*/
|
||||||
export type EvaluateContext = {
|
export type EvaluateContext = {
|
||||||
|
thisContext?: Record<string, any>;
|
||||||
|
globalContext?: Record<string, any>;
|
||||||
requestId?: string;
|
requestId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -172,6 +188,7 @@ export default function evaluateSync(
|
||||||
userScript: string,
|
userScript: string,
|
||||||
dataTree: DataTree,
|
dataTree: DataTree,
|
||||||
resolvedFunctions: Record<string, any>,
|
resolvedFunctions: Record<string, any>,
|
||||||
|
context?: EvaluateContext,
|
||||||
evalArguments?: Array<any>,
|
evalArguments?: Array<any>,
|
||||||
): EvalResult {
|
): EvalResult {
|
||||||
return (function() {
|
return (function() {
|
||||||
|
|
@ -181,7 +198,7 @@ export default function evaluateSync(
|
||||||
const GLOBAL_DATA: Record<string, any> = createGlobalData(
|
const GLOBAL_DATA: Record<string, any> = createGlobalData(
|
||||||
dataTree,
|
dataTree,
|
||||||
resolvedFunctions,
|
resolvedFunctions,
|
||||||
undefined,
|
context,
|
||||||
evalArguments,
|
evalArguments,
|
||||||
);
|
);
|
||||||
GLOBAL_DATA.ALLOW_ASYNC = false;
|
GLOBAL_DATA.ALLOW_ASYNC = false;
|
||||||
|
|
|
||||||
|
|
@ -805,10 +805,11 @@ export const overrideWidgetProperties = (
|
||||||
const overridingPropertyPaths =
|
const overridingPropertyPaths =
|
||||||
entity.overridingPropertyPaths[propertyPath];
|
entity.overridingPropertyPaths[propertyPath];
|
||||||
|
|
||||||
overridingPropertyPaths.forEach((overriddenPropertyKey) => {
|
overridingPropertyPaths.forEach((overriddenPropertyPath) => {
|
||||||
|
const overriddenPropertyPathArray = overriddenPropertyPath.split(".");
|
||||||
_.set(
|
_.set(
|
||||||
currentTree,
|
currentTree,
|
||||||
`${entity.widgetName}.${overriddenPropertyKey}`,
|
[entity.widgetName, ...overriddenPropertyPathArray],
|
||||||
clonedValue,
|
clonedValue,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
@ -824,9 +825,10 @@ export const overrideWidgetProperties = (
|
||||||
const defaultValue = entity[propertyOverridingKeyMap.DEFAULT];
|
const defaultValue = entity[propertyOverridingKeyMap.DEFAULT];
|
||||||
const clonedDefaultValue = cloneDeep(defaultValue);
|
const clonedDefaultValue = cloneDeep(defaultValue);
|
||||||
if (defaultValue !== undefined) {
|
if (defaultValue !== undefined) {
|
||||||
|
const propertyPathArray = propertyPath.split(".");
|
||||||
_.set(
|
_.set(
|
||||||
currentTree,
|
currentTree,
|
||||||
`${entity.widgetName}.${propertyPath}`,
|
[entity.widgetName, ...propertyPathArray],
|
||||||
clonedDefaultValue,
|
clonedDefaultValue,
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -803,7 +803,7 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
|
||||||
};
|
};
|
||||||
if (config.params?.fnString && isString(config.params?.fnString)) {
|
if (config.params?.fnString && isString(config.params?.fnString)) {
|
||||||
try {
|
try {
|
||||||
const { result } = evaluate(config.params.fnString, {}, {}, [
|
const { result } = evaluate(config.params.fnString, {}, {}, undefined, [
|
||||||
value,
|
value,
|
||||||
props,
|
props,
|
||||||
_,
|
_,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user