From 8a161f09a4a332af41fd73b6da6d897e1232a13c Mon Sep 17 00:00:00 2001 From: brianinoa Date: Mon, 5 Sep 2022 20:41:48 +0200 Subject: [PATCH 01/11] :sparkles: Introduce Array Extensions --- .../src/Extensions/ArrayExtensions.ts | 49 +++++++++++++++++++ .../src/Extensions/ExpressionExtension.ts | 8 ++- 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 packages/workflow/src/Extensions/ArrayExtensions.ts diff --git a/packages/workflow/src/Extensions/ArrayExtensions.ts b/packages/workflow/src/Extensions/ArrayExtensions.ts new file mode 100644 index 0000000000000..ae3fbdb99a530 --- /dev/null +++ b/packages/workflow/src/Extensions/ArrayExtensions.ts @@ -0,0 +1,49 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/unbound-method */ +/* eslint-disable @typescript-eslint/explicit-member-accessibility */ +// eslint-disable-next-line import/no-cycle +import { DateTime } from 'luxon'; +import { BaseExtension, ExtensionMethodHandler } from './Extensions'; + +// type ArrayExtensionsTypes = string[] | number[] | Date[] | undefined; +export class ArrayExtensions extends BaseExtension { + methodMapping = new Map>(); + + constructor() { + super(); + this.initializeMethodMap(); + } + + bind(mainArg: [], extraArgs?: Array | undefined) { + return Array.from(this.methodMapping).reduce((p, c) => { + const [key, method] = c; + Object.assign(p, { + [key]: () => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return method.call('', mainArg, extraArgs); + }, + }); + return p; + }, {} as object); + } + + private initializeMethodMap(): void { + this.methodMapping = new Map boolean | string | Date | number>([ + ['first', this.first], + ['last', this.last], + ['unique', this.unique], + ]); + } + + first(value: any[]): any { + return value[0]; + } + + last(value: any[]): any { + return value[value.length - 1]; + } + + unique(value: any[]): any[] { + return Array.from(new Set(value)); + } +} diff --git a/packages/workflow/src/Extensions/ExpressionExtension.ts b/packages/workflow/src/Extensions/ExpressionExtension.ts index 73994b3d52840..54147d5cd84e1 100644 --- a/packages/workflow/src/Extensions/ExpressionExtension.ts +++ b/packages/workflow/src/Extensions/ExpressionExtension.ts @@ -10,11 +10,12 @@ import * as BabelTypes from '@babel/types'; import { DateTime, Interval, Duration, DateTimeJSOptions, Zone } from 'luxon'; import { ExpressionExtensionError } from '../ExpressionError'; import { StringExtensions } from './StringExtensions'; +import { ArrayExtensions } from './ArrayExtensions'; const EXPRESSION_EXTENDER = 'extend'; const stringExtensions = new StringExtensions(); - +const arrayExtensions = new ArrayExtensions(); const EXPRESSION_EXTENSION_METHODS = [ ...stringExtensions.listMethods(), ...Object.getOwnPropertyNames(DateTime).filter((p) => { @@ -29,6 +30,7 @@ const EXPRESSION_EXTENSION_METHODS = [ ...Object.getOwnPropertyNames(Zone).filter((p) => { return typeof Zone[p as keyof typeof Zone] === 'function'; }), + ...arrayExtensions.listMethods(), 'sayHi', 'toDecimal', 'isBlank', @@ -189,6 +191,10 @@ export function extend(mainArg: unknown, ...extraArgs: unknown[]): ExtMethods { return true; }, ...stringExtensions.bind(mainArg as string, extraArgs as string[] | undefined), + ...arrayExtensions.bind( + mainArg as [], + extraArgs as Array | undefined, + ), }; return extensions; From d408195407bdcadb8dee08a2e8a0ee6414126e5e Mon Sep 17 00:00:00 2001 From: brianinoa Date: Mon, 5 Sep 2022 21:26:21 +0200 Subject: [PATCH 02/11] :zap: Fix typings --- packages/workflow/src/Extensions/ArrayExtensions.ts | 11 ++++------- .../workflow/src/Extensions/ExpressionExtension.ts | 5 +---- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/packages/workflow/src/Extensions/ArrayExtensions.ts b/packages/workflow/src/Extensions/ArrayExtensions.ts index ae3fbdb99a530..5817a6b912de1 100644 --- a/packages/workflow/src/Extensions/ArrayExtensions.ts +++ b/packages/workflow/src/Extensions/ArrayExtensions.ts @@ -2,24 +2,21 @@ /* eslint-disable @typescript-eslint/unbound-method */ /* eslint-disable @typescript-eslint/explicit-member-accessibility */ // eslint-disable-next-line import/no-cycle -import { DateTime } from 'luxon'; import { BaseExtension, ExtensionMethodHandler } from './Extensions'; -// type ArrayExtensionsTypes = string[] | number[] | Date[] | undefined; -export class ArrayExtensions extends BaseExtension { - methodMapping = new Map>(); +export class ArrayExtensions extends BaseExtension { + methodMapping = new Map>(); constructor() { super(); this.initializeMethodMap(); } - bind(mainArg: [], extraArgs?: Array | undefined) { + bind(mainArg: any[], extraArgs?: string[] | number[] | undefined) { return Array.from(this.methodMapping).reduce((p, c) => { const [key, method] = c; Object.assign(p, { [key]: () => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return method.call('', mainArg, extraArgs); }, }); @@ -28,7 +25,7 @@ export class ArrayExtensions extends BaseExtension { } private initializeMethodMap(): void { - this.methodMapping = new Map boolean | string | Date | number>([ + this.methodMapping = new Map boolean | string | Date | number>([ ['first', this.first], ['last', this.last], ['unique', this.unique], diff --git a/packages/workflow/src/Extensions/ExpressionExtension.ts b/packages/workflow/src/Extensions/ExpressionExtension.ts index 54147d5cd84e1..a61d377434a3d 100644 --- a/packages/workflow/src/Extensions/ExpressionExtension.ts +++ b/packages/workflow/src/Extensions/ExpressionExtension.ts @@ -191,10 +191,7 @@ export function extend(mainArg: unknown, ...extraArgs: unknown[]): ExtMethods { return true; }, ...stringExtensions.bind(mainArg as string, extraArgs as string[] | undefined), - ...arrayExtensions.bind( - mainArg as [], - extraArgs as Array | undefined, - ), + ...arrayExtensions.bind(mainArg as unknown[], extraArgs as string[] | undefined), }; return extensions; From 127f75e70424ec5a4e987bc212c0555c50054304 Mon Sep 17 00:00:00 2001 From: brianinoa Date: Tue, 6 Sep 2022 23:06:40 +0200 Subject: [PATCH 03/11] :recycle: Refactor Array Extensions --- .../src/Extensions/ArrayExtensions.ts | 71 +++++++++++++++++-- .../src/Extensions/ExpressionExtension.ts | 4 ++ 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/packages/workflow/src/Extensions/ArrayExtensions.ts b/packages/workflow/src/Extensions/ArrayExtensions.ts index 5817a6b912de1..1bed66afaf2fe 100644 --- a/packages/workflow/src/Extensions/ArrayExtensions.ts +++ b/packages/workflow/src/Extensions/ArrayExtensions.ts @@ -2,21 +2,23 @@ /* eslint-disable @typescript-eslint/unbound-method */ /* eslint-disable @typescript-eslint/explicit-member-accessibility */ // eslint-disable-next-line import/no-cycle +import { ExpressionError } from '../ExpressionError'; import { BaseExtension, ExtensionMethodHandler } from './Extensions'; -export class ArrayExtensions extends BaseExtension { - methodMapping = new Map>(); +export class ArrayExtensions extends BaseExtension { + methodMapping = new Map>(); constructor() { super(); this.initializeMethodMap(); } - bind(mainArg: any[], extraArgs?: string[] | number[] | undefined) { + bind(mainArg: any[], extraArgs?: number[] | string[] | boolean[] | undefined) { return Array.from(this.methodMapping).reduce((p, c) => { const [key, method] = c; Object.assign(p, { [key]: () => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return method.call('', mainArg, extraArgs); }, }); @@ -25,21 +27,82 @@ export class ArrayExtensions extends BaseExtension { } private initializeMethodMap(): void { - this.methodMapping = new Map boolean | string | Date | number>([ + this.methodMapping = new Map< + string, + ( + value: any[], + extraArgs?: number[] | string[] | boolean[] | undefined, + ) => any[] | boolean | string | Date | number + >([ + ['duplicates', this.unique], + ['isPresent', this.isPresent], + ['filter', this.filter], ['first', this.first], ['last', this.last], + ['length', this.length], + ['pluck', this.pluck], ['unique', this.unique], + ['random', this.random], + ['remove', this.unique], ]); } + filter(value: any[], extraArgs?: any[]): any[] { + if (!Array.isArray(extraArgs)) { + throw new ExpressionError('arguments must be passed to filter'); + } + const [term] = extraArgs as string[] | number[]; + return Array.isArray(value) ? value.filter((v) => v === term) : []; + } + first(value: any[]): any { return value[0]; } + isBlank(value: any[]): boolean { + return Array.isArray(value) && value.length === 0; + } + + isPresent(value: any[], extraArgs?: any[]): boolean { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + if (!Array.isArray(extraArgs)) { + throw new ExpressionError('arguments must be passed to isPresent'); + } + const [comparator] = extraArgs as string[] | number[]; + + return Array.isArray(value) && value.includes(comparator); + } + last(value: any[]): any { return value[value.length - 1]; } + length(value: any[]): number { + return Array.isArray(value) ? value.length : 0; + } + + pluck(value: any[], extraArgs: any[]): any[] { + if (!Array.isArray(extraArgs)) { + throw new ExpressionError('arguments must be passed to pluck'); + } + const fieldsToPluck = extraArgs; + return value.map((element: object) => { + const entries = Object.entries(element); + return entries.reduce((p, c) => { + const [key, val] = c as [string, Date | string | number]; + if (fieldsToPluck.includes(c)) { + Object.assign(p, { [key]: val }); + } + return p; + }, {}); + }); + } + + random(value: any[]): any { + const length = value == null ? 0 : value.length; + return length ? value[Math.floor(Math.random() * length)] : undefined; + } + unique(value: any[]): any[] { return Array.from(new Set(value)); } diff --git a/packages/workflow/src/Extensions/ExpressionExtension.ts b/packages/workflow/src/Extensions/ExpressionExtension.ts index a61d377434a3d..0babcbdc6a917 100644 --- a/packages/workflow/src/Extensions/ExpressionExtension.ts +++ b/packages/workflow/src/Extensions/ExpressionExtension.ts @@ -188,6 +188,10 @@ export function extend(mainArg: unknown, ...extraArgs: unknown[]): ExtMethods { return stringExtensions.isBlank(mainArg); } + if (Array.isArray(mainArg)) { + return arrayExtensions.isBlank(mainArg); + } + return true; }, ...stringExtensions.bind(mainArg as string, extraArgs as string[] | undefined), From abf6434038e8dac8ab7eadd958b0c9d53c9fd830 Mon Sep 17 00:00:00 2001 From: brianinoa Date: Wed, 7 Sep 2022 03:17:00 +0200 Subject: [PATCH 04/11] :recycle: Fix small issues --- packages/workflow/src/Extensions/ArrayExtensions.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/workflow/src/Extensions/ArrayExtensions.ts b/packages/workflow/src/Extensions/ArrayExtensions.ts index 1bed66afaf2fe..c66218271c656 100644 --- a/packages/workflow/src/Extensions/ArrayExtensions.ts +++ b/packages/workflow/src/Extensions/ArrayExtensions.ts @@ -51,8 +51,8 @@ export class ArrayExtensions extends BaseExtension { if (!Array.isArray(extraArgs)) { throw new ExpressionError('arguments must be passed to filter'); } - const [term] = extraArgs as string[] | number[]; - return Array.isArray(value) ? value.filter((v) => v === term) : []; + const terms = extraArgs as string[] | number[]; + return value.filter((v: string | number) => (terms as Array).includes(v)); } first(value: any[]): any { @@ -68,9 +68,10 @@ export class ArrayExtensions extends BaseExtension { if (!Array.isArray(extraArgs)) { throw new ExpressionError('arguments must be passed to isPresent'); } - const [comparator] = extraArgs as string[] | number[]; - - return Array.isArray(value) && value.includes(comparator); + const comparators = extraArgs as string[] | number[]; + return value.some((v: string | number) => { + return (comparators as Array).includes(v); + }); } last(value: any[]): any { @@ -90,7 +91,7 @@ export class ArrayExtensions extends BaseExtension { const entries = Object.entries(element); return entries.reduce((p, c) => { const [key, val] = c as [string, Date | string | number]; - if (fieldsToPluck.includes(c)) { + if (fieldsToPluck.includes(key)) { Object.assign(p, { [key]: val }); } return p; From 143f50a5329e92f5ec30b9959205d54d3869133e Mon Sep 17 00:00:00 2001 From: brianinoa Date: Mon, 5 Sep 2022 20:41:48 +0200 Subject: [PATCH 05/11] :sparkles: Introduce Array Extensions --- .../src/Extensions/ArrayExtensions.ts | 49 +++++++++++++++++++ .../src/Extensions/ExpressionExtension.ts | 8 ++- 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 packages/workflow/src/Extensions/ArrayExtensions.ts diff --git a/packages/workflow/src/Extensions/ArrayExtensions.ts b/packages/workflow/src/Extensions/ArrayExtensions.ts new file mode 100644 index 0000000000000..ae3fbdb99a530 --- /dev/null +++ b/packages/workflow/src/Extensions/ArrayExtensions.ts @@ -0,0 +1,49 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/unbound-method */ +/* eslint-disable @typescript-eslint/explicit-member-accessibility */ +// eslint-disable-next-line import/no-cycle +import { DateTime } from 'luxon'; +import { BaseExtension, ExtensionMethodHandler } from './Extensions'; + +// type ArrayExtensionsTypes = string[] | number[] | Date[] | undefined; +export class ArrayExtensions extends BaseExtension { + methodMapping = new Map>(); + + constructor() { + super(); + this.initializeMethodMap(); + } + + bind(mainArg: [], extraArgs?: Array | undefined) { + return Array.from(this.methodMapping).reduce((p, c) => { + const [key, method] = c; + Object.assign(p, { + [key]: () => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return method.call('', mainArg, extraArgs); + }, + }); + return p; + }, {} as object); + } + + private initializeMethodMap(): void { + this.methodMapping = new Map boolean | string | Date | number>([ + ['first', this.first], + ['last', this.last], + ['unique', this.unique], + ]); + } + + first(value: any[]): any { + return value[0]; + } + + last(value: any[]): any { + return value[value.length - 1]; + } + + unique(value: any[]): any[] { + return Array.from(new Set(value)); + } +} diff --git a/packages/workflow/src/Extensions/ExpressionExtension.ts b/packages/workflow/src/Extensions/ExpressionExtension.ts index 73994b3d52840..54147d5cd84e1 100644 --- a/packages/workflow/src/Extensions/ExpressionExtension.ts +++ b/packages/workflow/src/Extensions/ExpressionExtension.ts @@ -10,11 +10,12 @@ import * as BabelTypes from '@babel/types'; import { DateTime, Interval, Duration, DateTimeJSOptions, Zone } from 'luxon'; import { ExpressionExtensionError } from '../ExpressionError'; import { StringExtensions } from './StringExtensions'; +import { ArrayExtensions } from './ArrayExtensions'; const EXPRESSION_EXTENDER = 'extend'; const stringExtensions = new StringExtensions(); - +const arrayExtensions = new ArrayExtensions(); const EXPRESSION_EXTENSION_METHODS = [ ...stringExtensions.listMethods(), ...Object.getOwnPropertyNames(DateTime).filter((p) => { @@ -29,6 +30,7 @@ const EXPRESSION_EXTENSION_METHODS = [ ...Object.getOwnPropertyNames(Zone).filter((p) => { return typeof Zone[p as keyof typeof Zone] === 'function'; }), + ...arrayExtensions.listMethods(), 'sayHi', 'toDecimal', 'isBlank', @@ -189,6 +191,10 @@ export function extend(mainArg: unknown, ...extraArgs: unknown[]): ExtMethods { return true; }, ...stringExtensions.bind(mainArg as string, extraArgs as string[] | undefined), + ...arrayExtensions.bind( + mainArg as [], + extraArgs as Array | undefined, + ), }; return extensions; From dc5dd11ec3b13ec066209953605322631549b660 Mon Sep 17 00:00:00 2001 From: brianinoa Date: Mon, 5 Sep 2022 21:26:21 +0200 Subject: [PATCH 06/11] :zap: Fix typings --- packages/workflow/src/Extensions/ArrayExtensions.ts | 11 ++++------- .../workflow/src/Extensions/ExpressionExtension.ts | 5 +---- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/packages/workflow/src/Extensions/ArrayExtensions.ts b/packages/workflow/src/Extensions/ArrayExtensions.ts index ae3fbdb99a530..5817a6b912de1 100644 --- a/packages/workflow/src/Extensions/ArrayExtensions.ts +++ b/packages/workflow/src/Extensions/ArrayExtensions.ts @@ -2,24 +2,21 @@ /* eslint-disable @typescript-eslint/unbound-method */ /* eslint-disable @typescript-eslint/explicit-member-accessibility */ // eslint-disable-next-line import/no-cycle -import { DateTime } from 'luxon'; import { BaseExtension, ExtensionMethodHandler } from './Extensions'; -// type ArrayExtensionsTypes = string[] | number[] | Date[] | undefined; -export class ArrayExtensions extends BaseExtension { - methodMapping = new Map>(); +export class ArrayExtensions extends BaseExtension { + methodMapping = new Map>(); constructor() { super(); this.initializeMethodMap(); } - bind(mainArg: [], extraArgs?: Array | undefined) { + bind(mainArg: any[], extraArgs?: string[] | number[] | undefined) { return Array.from(this.methodMapping).reduce((p, c) => { const [key, method] = c; Object.assign(p, { [key]: () => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return method.call('', mainArg, extraArgs); }, }); @@ -28,7 +25,7 @@ export class ArrayExtensions extends BaseExtension { } private initializeMethodMap(): void { - this.methodMapping = new Map boolean | string | Date | number>([ + this.methodMapping = new Map boolean | string | Date | number>([ ['first', this.first], ['last', this.last], ['unique', this.unique], diff --git a/packages/workflow/src/Extensions/ExpressionExtension.ts b/packages/workflow/src/Extensions/ExpressionExtension.ts index 54147d5cd84e1..a61d377434a3d 100644 --- a/packages/workflow/src/Extensions/ExpressionExtension.ts +++ b/packages/workflow/src/Extensions/ExpressionExtension.ts @@ -191,10 +191,7 @@ export function extend(mainArg: unknown, ...extraArgs: unknown[]): ExtMethods { return true; }, ...stringExtensions.bind(mainArg as string, extraArgs as string[] | undefined), - ...arrayExtensions.bind( - mainArg as [], - extraArgs as Array | undefined, - ), + ...arrayExtensions.bind(mainArg as unknown[], extraArgs as string[] | undefined), }; return extensions; From a744f6fc6f002dbb317aca7c6fdb2dde90a1e38e Mon Sep 17 00:00:00 2001 From: brianinoa Date: Tue, 6 Sep 2022 23:06:40 +0200 Subject: [PATCH 07/11] :recycle: Refactor Array Extensions --- .../src/Extensions/ArrayExtensions.ts | 71 +++++++++++++++++-- .../src/Extensions/ExpressionExtension.ts | 4 ++ 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/packages/workflow/src/Extensions/ArrayExtensions.ts b/packages/workflow/src/Extensions/ArrayExtensions.ts index 5817a6b912de1..1bed66afaf2fe 100644 --- a/packages/workflow/src/Extensions/ArrayExtensions.ts +++ b/packages/workflow/src/Extensions/ArrayExtensions.ts @@ -2,21 +2,23 @@ /* eslint-disable @typescript-eslint/unbound-method */ /* eslint-disable @typescript-eslint/explicit-member-accessibility */ // eslint-disable-next-line import/no-cycle +import { ExpressionError } from '../ExpressionError'; import { BaseExtension, ExtensionMethodHandler } from './Extensions'; -export class ArrayExtensions extends BaseExtension { - methodMapping = new Map>(); +export class ArrayExtensions extends BaseExtension { + methodMapping = new Map>(); constructor() { super(); this.initializeMethodMap(); } - bind(mainArg: any[], extraArgs?: string[] | number[] | undefined) { + bind(mainArg: any[], extraArgs?: number[] | string[] | boolean[] | undefined) { return Array.from(this.methodMapping).reduce((p, c) => { const [key, method] = c; Object.assign(p, { [key]: () => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return method.call('', mainArg, extraArgs); }, }); @@ -25,21 +27,82 @@ export class ArrayExtensions extends BaseExtension { } private initializeMethodMap(): void { - this.methodMapping = new Map boolean | string | Date | number>([ + this.methodMapping = new Map< + string, + ( + value: any[], + extraArgs?: number[] | string[] | boolean[] | undefined, + ) => any[] | boolean | string | Date | number + >([ + ['duplicates', this.unique], + ['isPresent', this.isPresent], + ['filter', this.filter], ['first', this.first], ['last', this.last], + ['length', this.length], + ['pluck', this.pluck], ['unique', this.unique], + ['random', this.random], + ['remove', this.unique], ]); } + filter(value: any[], extraArgs?: any[]): any[] { + if (!Array.isArray(extraArgs)) { + throw new ExpressionError('arguments must be passed to filter'); + } + const [term] = extraArgs as string[] | number[]; + return Array.isArray(value) ? value.filter((v) => v === term) : []; + } + first(value: any[]): any { return value[0]; } + isBlank(value: any[]): boolean { + return Array.isArray(value) && value.length === 0; + } + + isPresent(value: any[], extraArgs?: any[]): boolean { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + if (!Array.isArray(extraArgs)) { + throw new ExpressionError('arguments must be passed to isPresent'); + } + const [comparator] = extraArgs as string[] | number[]; + + return Array.isArray(value) && value.includes(comparator); + } + last(value: any[]): any { return value[value.length - 1]; } + length(value: any[]): number { + return Array.isArray(value) ? value.length : 0; + } + + pluck(value: any[], extraArgs: any[]): any[] { + if (!Array.isArray(extraArgs)) { + throw new ExpressionError('arguments must be passed to pluck'); + } + const fieldsToPluck = extraArgs; + return value.map((element: object) => { + const entries = Object.entries(element); + return entries.reduce((p, c) => { + const [key, val] = c as [string, Date | string | number]; + if (fieldsToPluck.includes(c)) { + Object.assign(p, { [key]: val }); + } + return p; + }, {}); + }); + } + + random(value: any[]): any { + const length = value == null ? 0 : value.length; + return length ? value[Math.floor(Math.random() * length)] : undefined; + } + unique(value: any[]): any[] { return Array.from(new Set(value)); } diff --git a/packages/workflow/src/Extensions/ExpressionExtension.ts b/packages/workflow/src/Extensions/ExpressionExtension.ts index a61d377434a3d..0babcbdc6a917 100644 --- a/packages/workflow/src/Extensions/ExpressionExtension.ts +++ b/packages/workflow/src/Extensions/ExpressionExtension.ts @@ -188,6 +188,10 @@ export function extend(mainArg: unknown, ...extraArgs: unknown[]): ExtMethods { return stringExtensions.isBlank(mainArg); } + if (Array.isArray(mainArg)) { + return arrayExtensions.isBlank(mainArg); + } + return true; }, ...stringExtensions.bind(mainArg as string, extraArgs as string[] | undefined), From d158611cdada391ff79118a0e21e7c200e1ce109 Mon Sep 17 00:00:00 2001 From: brianinoa Date: Wed, 7 Sep 2022 03:17:00 +0200 Subject: [PATCH 08/11] :recycle: Fix small issues --- packages/workflow/src/Extensions/ArrayExtensions.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/workflow/src/Extensions/ArrayExtensions.ts b/packages/workflow/src/Extensions/ArrayExtensions.ts index 1bed66afaf2fe..c66218271c656 100644 --- a/packages/workflow/src/Extensions/ArrayExtensions.ts +++ b/packages/workflow/src/Extensions/ArrayExtensions.ts @@ -51,8 +51,8 @@ export class ArrayExtensions extends BaseExtension { if (!Array.isArray(extraArgs)) { throw new ExpressionError('arguments must be passed to filter'); } - const [term] = extraArgs as string[] | number[]; - return Array.isArray(value) ? value.filter((v) => v === term) : []; + const terms = extraArgs as string[] | number[]; + return value.filter((v: string | number) => (terms as Array).includes(v)); } first(value: any[]): any { @@ -68,9 +68,10 @@ export class ArrayExtensions extends BaseExtension { if (!Array.isArray(extraArgs)) { throw new ExpressionError('arguments must be passed to isPresent'); } - const [comparator] = extraArgs as string[] | number[]; - - return Array.isArray(value) && value.includes(comparator); + const comparators = extraArgs as string[] | number[]; + return value.some((v: string | number) => { + return (comparators as Array).includes(v); + }); } last(value: any[]): any { @@ -90,7 +91,7 @@ export class ArrayExtensions extends BaseExtension { const entries = Object.entries(element); return entries.reduce((p, c) => { const [key, val] = c as [string, Date | string | number]; - if (fieldsToPluck.includes(c)) { + if (fieldsToPluck.includes(key)) { Object.assign(p, { [key]: val }); } return p; From 815ab0d3d2091233aa195c51ab51f04672360feb Mon Sep 17 00:00:00 2001 From: brianinoa Date: Sat, 10 Sep 2022 00:39:11 +0200 Subject: [PATCH 09/11] re introduce array extensions --- packages/workflow/src/Extensions/ExpressionExtension.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/workflow/src/Extensions/ExpressionExtension.ts b/packages/workflow/src/Extensions/ExpressionExtension.ts index 0eb5f24f00947..fec2d39b6b8ea 100644 --- a/packages/workflow/src/Extensions/ExpressionExtension.ts +++ b/packages/workflow/src/Extensions/ExpressionExtension.ts @@ -18,11 +18,13 @@ const EXPRESSION_EXTENDER = 'extend'; const stringExtensions = new StringExtensions(); const dateExtensions = new DateExtensions(); +const arrayExtensions = new ArrayExtensions(); const EXPRESSION_EXTENSION_METHODS = Array.from( new Set([ ...stringExtensions.listMethods(), ...dateExtensions.listMethods(), + ...arrayExtensions.listMethods(), 'toDecimal', 'isBlank', 'toLocaleString', From 49d7166f64d4b9e8c98106058ffe9be0be86e24b Mon Sep 17 00:00:00 2001 From: brianinoa Date: Sat, 10 Sep 2022 01:37:39 +0200 Subject: [PATCH 10/11] Fix scope in method bindings --- packages/workflow/src/Extensions/ArrayExtensions.ts | 2 +- packages/workflow/src/Extensions/ExpressionExtension.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/workflow/src/Extensions/ArrayExtensions.ts b/packages/workflow/src/Extensions/ArrayExtensions.ts index c66218271c656..3c21dc77f40b7 100644 --- a/packages/workflow/src/Extensions/ArrayExtensions.ts +++ b/packages/workflow/src/Extensions/ArrayExtensions.ts @@ -19,7 +19,7 @@ export class ArrayExtensions extends BaseExtension { Object.assign(p, { [key]: () => { // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return method.call('', mainArg, extraArgs); + return method.call(this, mainArg, extraArgs); }, }); return p; diff --git a/packages/workflow/src/Extensions/ExpressionExtension.ts b/packages/workflow/src/Extensions/ExpressionExtension.ts index fec2d39b6b8ea..7622b7063ebea 100644 --- a/packages/workflow/src/Extensions/ExpressionExtension.ts +++ b/packages/workflow/src/Extensions/ExpressionExtension.ts @@ -154,7 +154,10 @@ export function extend(mainArg: unknown, ...extraArgs: unknown[]): ExtMethods { new Date(mainArg as string), extraArgs as number[] | string[] | boolean[] | undefined, ), - ...arrayExtensions.bind(mainArg as unknown[], extraArgs as string[] | undefined), + ...arrayExtensions.bind( + Array.isArray(mainArg) ? mainArg : ([mainArg] as unknown[]), + extraArgs as string[] | undefined, + ), }; return extensions; From d432efbcd8caa98a7b0339f2b75e20d7d6ab161f Mon Sep 17 00:00:00 2001 From: brianinoa Date: Sat, 10 Sep 2022 01:37:58 +0200 Subject: [PATCH 11/11] :white_check_mark: Add Array Expression tests --- .../test/ExpressionExtensions.test.ts | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/packages/workflow/test/ExpressionExtensions.test.ts b/packages/workflow/test/ExpressionExtensions.test.ts index 2c606fb692e9f..196b4fbee6c6d 100644 --- a/packages/workflow/test/ExpressionExtensions.test.ts +++ b/packages/workflow/test/ExpressionExtensions.test.ts @@ -8,6 +8,7 @@ import { DateTime } from 'luxon'; import { extend } from '../src/Extensions'; import { DateExtensions } from '../src/Extensions/DateExtensions'; import { StringExtensions } from '../src/Extensions/StringExtensions'; +import { ArrayExtensions } from '../src/Extensions/ArrayExtensions'; describe('Expression Extensions', () => { describe('extend()', () => { @@ -130,5 +131,51 @@ describe('Expression Extensions', () => { new Date('2022-09-01T19:42:28.164Z'), ); }); + + const arrayExtensions = (data: any[], ...args: any[]) => { + return extend(data, ...args) as unknown as ArrayExtensions; + }; + + it('should be able to utilize array expression extension methods', () => { + expect(evaluate('={{ [1,2,3].random() }}')).not.toBeUndefined(); + + expect(evaluate('={{ [1,2,3, "imhere"].isPresent("imhere") }}')).toEqual(true); + + expect( + evaluate(`={{ [ + { value: 1, string: '1' }, + { value: 2, string: '2' }, + { value: 3, string: '3' }, + { value: 4, string: '4' }, + { value: 5, string: '5' }, + { value: 6, string: '6' } + ].pluck("value") }}`), + ).toEqual( + expect.arrayContaining([ + { value: 1 }, + { value: 2 }, + { value: 3 }, + { value: 4 }, + { value: 5 }, + { value: 6 }, + ]), + ); + + expect(evaluate('={{ ["repeat","repeat","a","b","c"].unique() }}')).toEqual( + expect.arrayContaining(['repeat', 'repeat', 'a', 'b', 'c']), + ); + + expect(evaluate('={{ [].isBlank() }}')).toEqual(arrayExtensions([]).isBlank([])); + + expect(evaluate('={{ [].length() }}')).toEqual(arrayExtensions([]).length([])); + + expect(evaluate('={{ ["repeat","repeat","a","b","c"].last() }}')).toEqual('c'); + + expect(evaluate('={{ ["repeat","repeat","a","b","c"].first() }}')).toEqual('repeat'); + + expect(evaluate('={{ ["repeat","repeat","a","b","c"].filter("repeat") }}')).toEqual( + expect.arrayContaining(['repeat', 'repeat']), + ); + }); }); });