From 1933173fa6fec523c9eef7851c3b460dd633bd1c Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Thu, 10 Nov 2022 16:11:52 -0500 Subject: [PATCH 01/36] WIP --- package-lock.json | 13 +++ package.json | 1 + src/expression-lang/.#GroupByLocal.ts | 1 + src/expression-lang/EXPR.spec.ts | 146 ++++++++++++++++++++++++++ src/expression-lang/EXPR.ts | 92 ++++++++++++++++ src/expression-lang/sheetInterpret.ts | 56 ++++++++++ 6 files changed, 309 insertions(+) create mode 120000 src/expression-lang/.#GroupByLocal.ts create mode 100644 src/expression-lang/EXPR.spec.ts create mode 100644 src/expression-lang/EXPR.ts create mode 100644 src/expression-lang/sheetInterpret.ts diff --git a/package-lock.json b/package-lock.json index 1bb8b16..1505cb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "devDependencies": { "@flatfile/configure": "^0.4.2", + "@flatfile/expression-lang": "^0.0.2", "@flatfile/hooks": "^1.2.0", "@types/jest": "^28.1.4", "@types/lodash": "^4.14.186", @@ -683,6 +684,12 @@ "remeda": "^0.0.35" } }, + "node_modules/@flatfile/expression-lang": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@flatfile/expression-lang/-/expression-lang-0.0.2.tgz", + "integrity": "sha512-UIfkHh3rvCXlk5HYfIq7SGQHFi+/SOizbr4ipWjHItog/K0tMheoy5s7tVuV1jgqo5MS074aoJec9wBZsiLMmg==", + "dev": true + }, "node_modules/@flatfile/hooks": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@flatfile/hooks/-/hooks-1.2.0.tgz", @@ -6492,6 +6499,12 @@ "remeda": "^0.0.35" } }, + "@flatfile/expression-lang": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@flatfile/expression-lang/-/expression-lang-0.0.2.tgz", + "integrity": "sha512-UIfkHh3rvCXlk5HYfIq7SGQHFi+/SOizbr4ipWjHItog/K0tMheoy5s7tVuV1jgqo5MS074aoJec9wBZsiLMmg==", + "dev": true + }, "@flatfile/hooks": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@flatfile/hooks/-/hooks-1.2.0.tgz", diff --git a/package.json b/package.json index 4fb788b..3bb1563 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "devDependencies": { "@flatfile/configure": "^0.4.2", "@flatfile/hooks": "^1.2.0", + "@flatfile/expression-lang": "^0.0.2", "node-fetch": "^3.2.10", "@types/jest": "^28.1.4", "@types/lodash": "^4.14.186", diff --git a/src/expression-lang/.#GroupByLocal.ts b/src/expression-lang/.#GroupByLocal.ts new file mode 120000 index 0000000..6b2fa61 --- /dev/null +++ b/src/expression-lang/.#GroupByLocal.ts @@ -0,0 +1 @@ +paddy@Paddys-MacBook-Pro.local.599 \ No newline at end of file diff --git a/src/expression-lang/EXPR.spec.ts b/src/expression-lang/EXPR.spec.ts new file mode 100644 index 0000000..6ba24f6 --- /dev/null +++ b/src/expression-lang/EXPR.spec.ts @@ -0,0 +1,146 @@ +import { FlatfileRecord } from '@flatfile/hooks' +import { sheetInterpret } from './sheetInterpret' +import { + When, + Error, + Val, + Group, + Match, + ImplicitGreaterThan, + GroupConstraintItem, + Count, + MatchResult, + GreaterThan, + Unless, + Debug, + ValidateWhen +} from './EXPR' + +describe('VExpression Tests ->', () => { + test('Simple test', () => { + const valFunc = ValidateWhen(GreaterThan(Val(), 5), Error('val greater than 5')) + expect(valFunc(3)).toStrictEqual([]) + expect(valFunc(7)).toMatchObject([ + { level: 'error', message: 'val greater than 5' }, + ]) + }) + + test('Implicit Greater Than test', () => { + const valFunc = When(ImplicitGreaterThan(5), Error('val greater than 5')) + expect(valFunc(3)).toStrictEqual([]) + expect(valFunc(7)).toMatchObject([ + { level: 'error', message: 'val greater than 5' }, + ]) + }) +}) + +// [WholeGroup(), Unless(GreaterThan(Count(Match({'RowType':'Header'}, Group())), 0), ErrorC("Group must contain a Header row"))], +// [WholeGroup(), Unless(GreaterThan(Count(Match({'RowType':'Item'}, Group())), 0), ErrorC("Group must contain a Item row"))], +// [Match({'RowType':'Header'}, Group()), When(GreaterThan(Count(MatchResult()), 1), ErrorC("Group must contain only a single Header row"))], + +describe('GroupConstraint Tests ->', () => { + const getRecs = () => [ + new FlatfileRecord({ + rawData: { + name: 'Paddy', + age: 40, + job: 'eng', + weight: 190, + eyeColor: 'green', + }, + rowId: 1, + }), + new FlatfileRecord({ + rawData: { + name: 'Cliff', + age: 86, + job: 'ret', + weight: 160, + eyeColor: 'gray_', + }, + rowId: 2, + }), + new FlatfileRecord({ + rawData: { + name: 'Odin_', + age: 3, + job: 'kid', + weight: 30, + eyeColor: 'blue_', + }, + rowId: 3, + }), + new FlatfileRecord({ + rawData: { + name: 'Kay__', + age: 77, + job: 'ret', + weight: 160, + eyeColor: 'green', + }, + rowId: 4, + }), + new FlatfileRecord({ + rawData: { + name: 'Sarah', + age: 8, + job: 'kid', + weight: 60, + eyeColor: 'green', + }, + rowId: 5, + }), + ] + + test('Match', () => { + const recs = getRecs() + const matchResult = sheetInterpret( + Match({ name: 'Paddy' }, recs) + ) as any[] + expect(matchResult.length).toBe(1) + expect(matchResult[0].value).toMatchObject({ age: 40, name: 'Paddy' }) + + const matchResult2 = sheetInterpret( + Match({ name: 'no name' }, recs) + ) as any[] + expect(matchResult2).toStrictEqual([]) + }) + + + test('GroupConstraint', () => { + const recs = getRecs() + const greenEyes = sheetInterpret(Match({ eyeColor: 'green' }, recs), {}) + const retireds = sheetInterpret(Match({ job: 'ret' }, recs), {}) + + const gcResult = sheetInterpret( + GroupConstraintItem( + Group(), + Unless( + GreaterThan(Count(Match({ job: 'kid' }, MatchResult())), 0), + Error('No Kids') + ), + 'name', + greenEyes + ), + { group: greenEyes } + ) as FlatfileRecord[] + expect(gcResult[0].toJSON()['info']).toStrictEqual([]) + + const gcResult2 = sheetInterpret( + GroupConstraintItem( + Group(), + Unless( + GreaterThan(Count(Match({ job: 'kid' }, MatchResult())), 0), + Error('No Kids') + ), + 'name', + retireds + ), + {} + ) as FlatfileRecord[] + expect(gcResult2[0].toJSON()['info'][0]).toMatchObject({ + field: 'name', + message: 'No Kids', + }) + }) +}) diff --git a/src/expression-lang/EXPR.ts b/src/expression-lang/EXPR.ts new file mode 100644 index 0000000..0f90227 --- /dev/null +++ b/src/expression-lang/EXPR.ts @@ -0,0 +1,92 @@ +import { makeInterpreter, NestedIns } from '@flatfile/expression-lang' +export const Add = (...args: any) => ['+', ...args] +export const Subtract = (...args: any) => ['-', ...args] +export const Mult = (...args: any) => ['*', ...args] +export const Div = (...args: any) => ['/', ...args] +export const Mod = (a: any, b: any) => ['mod', a, b] + +//Comparisons +export const GreaterThan = (a: any, b: any) => ['>', a, b] +export const GT = GreaterThan + +export const LessThan = (a: any, b: any) => ['<', a, b] +export const LT = LessThan + +export const GreaterThanEqual = (a: any, b: any) => ['>=', a, b] +export const GTE = GreaterThanEqual + +export const LessThanEqual = (a: any, b: any) => ['<', a, b] +export const LTE = LessThanEqual + +export const Equal = (a: any, b: any) => ['equal', a, b] + +export const Between = (a: any, test: any, b: any) => [ + 'and', + ['<', a, test], + ['<', test, b], +] + +//Math +export const Abs = (a: any) => ['abs', a] +export const Min = (...args: any) => ['min', ...args] +export const Max = (...args: any) => ['max', ...args] +export const Round = (...args: any) => ['round', ...args] + +//logic +export const Not = (a: any) => ['not', a] +export const And = (...args: any) => ['and', ...args] +export const Or = (...args: any) => ['or', ...args] // returns the first true element + + +export const Count = (expr: NestedIns) => ['count', expr] +export const NotEqual = (a: any, b: any) => ['neq', a, b] +export const When = (predicate: any, expr: any) => ['when', predicate, expr] +export const Unless = (predicate: any, expr: any) => [ + 'when', + ['not', predicate], + expr, +] + + + +export const Error = (message: string) => ['error', message] +export const Group = () => ['variable', 'group'] +export const Val = () => ['variable', 'val'] +export const MatchResult = () => ['variable', 'matchResult'] + +export const Match = (matchSpec: any, recordGrouping: any) => [ + 'match', + matchSpec, + recordGrouping, +] +export const ImplicitGreaterThan = (comparand: any) => ['>', Val(), comparand] +export const GroupConstraintItem = ( + rowFilterExpr: NestedIns, + actionExpr: NestedIns, + origField: string, + group: NestedIns = ['variable', 'group'] +) => { + return [ + 'groupConstraintRow', + ['quote', rowFilterExpr], + ['quote', actionExpr], + origField, + group, + ] +} +export const Debug = (expr: NestedIns) => ['debug', expr] + +const simpleInterpret = makeInterpreter({}) +export const ValidateWhen = (predicate: any, expr: any) => { + return (val: any) => { + return simpleInterpret(['when', predicate, expr], { val: val }) + } +} +export const ValidateUnless = (predicate: any, expr: any) => { + return (val: any) => { + return simpleInterpret(['when', ['not', predicate], expr], { val: val }) + } +} + + + diff --git a/src/expression-lang/sheetInterpret.ts b/src/expression-lang/sheetInterpret.ts new file mode 100644 index 0000000..7aafb95 --- /dev/null +++ b/src/expression-lang/sheetInterpret.ts @@ -0,0 +1,56 @@ +import { makeInterpreter, NestedIns } from '@flatfile/expression-lang' +import { TRecordStageLevel, Message } from '@flatfile/configure' +import { FlatfileRecord } from '@flatfile/hooks' +import * as _ from 'lodash' + +//I would love message to be able to accept some type of format string +const error = (message: string, stage: TRecordStageLevel = 'validate') => { + // I don't like returning a list here, not sure where to deal with scalar/list + return [new Message(message, 'error', stage)] +} + +const match = (matchSpec: object, records: FlatfileRecord[]) => { + return _.filter(records, (rec: FlatfileRecord) => + _.isMatch(rec.originalValue, matchSpec) + ) +} + +const groupConstraintRow = ( + rowFilterExpr: NestedIns, + actionExpr: NestedIns, + origField: string, + group: any +) => { + // how to pass along variables from where this is evaluated??? + const appliccableRows = sheetInterpret(rowFilterExpr, { + group, + }) as FlatfileRecord[] + //some typeguard here + if (Array.isArray(appliccableRows) && appliccableRows.length > 0) { + const messagesToApply = sheetInterpret(actionExpr, { + group, + matchResult: appliccableRows, + }) as Message[] + if (Array.isArray(messagesToApply)) { + appliccableRows.map((record: FlatfileRecord) => { + messagesToApply.map((m) => { + record.pushInfoMessage(origField, m.message, m.level, m.stage) + }) + }) + } + } + return appliccableRows +} + +export const debug = (expr: NestedIns) => { + console.log('debug', expr) + return expr +} + +export const sheetInterpret = makeInterpreter({ + error, + match, + groupConstraintRow, + debug, +}) + From 63046b2a9b2e2e5d60fcec794cc4f6227ce8e8b3 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Thu, 10 Nov 2022 16:17:44 -0500 Subject: [PATCH 02/36] WIP --- src/expression-lang/EXPR.spec.ts | 2 +- src/expression-lang/sheetInterpret.ts | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/expression-lang/EXPR.spec.ts b/src/expression-lang/EXPR.spec.ts index 6ba24f6..75b4227 100644 --- a/src/expression-lang/EXPR.spec.ts +++ b/src/expression-lang/EXPR.spec.ts @@ -26,7 +26,7 @@ describe('VExpression Tests ->', () => { }) test('Implicit Greater Than test', () => { - const valFunc = When(ImplicitGreaterThan(5), Error('val greater than 5')) + const valFunc = ValidateWhen(ImplicitGreaterThan(5), Error('val greater than 5')) expect(valFunc(3)).toStrictEqual([]) expect(valFunc(7)).toMatchObject([ { level: 'error', message: 'val greater than 5' }, diff --git a/src/expression-lang/sheetInterpret.ts b/src/expression-lang/sheetInterpret.ts index 7aafb95..2b44946 100644 --- a/src/expression-lang/sheetInterpret.ts +++ b/src/expression-lang/sheetInterpret.ts @@ -1,8 +1,15 @@ import { makeInterpreter, NestedIns } from '@flatfile/expression-lang' -import { TRecordStageLevel, Message } from '@flatfile/configure' +import { Message } from '@flatfile/configure' import { FlatfileRecord } from '@flatfile/hooks' import * as _ from 'lodash' +export type TRecordStageLevel = + | 'compute' + | 'validate' + | 'apply' + | 'other' + + //I would love message to be able to accept some type of format string const error = (message: string, stage: TRecordStageLevel = 'validate') => { // I don't like returning a list here, not sure where to deal with scalar/list @@ -34,7 +41,8 @@ const groupConstraintRow = ( if (Array.isArray(messagesToApply)) { appliccableRows.map((record: FlatfileRecord) => { messagesToApply.map((m) => { - record.pushInfoMessage(origField, m.message, m.level, m.stage) + //@ts-ignore + record.pushInfoMessage(origField, m.message, m.level, 'validate') }) }) } From 2cdfdc60a17b6b1cb14ae5e6bba6378f3fdbc19f Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Thu, 10 Nov 2022 17:38:37 -0500 Subject: [PATCH 03/36] feat: initial add of narrative ExpressionLang explanation --- docs/Expression.md | 119 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 docs/Expression.md diff --git a/docs/Expression.md b/docs/Expression.md new file mode 100644 index 0000000..0d0690a --- /dev/null +++ b/docs/Expression.md @@ -0,0 +1,119 @@ +# The expression language by example + +The expression language is the flatfile creation that allows concise code to be evaluated with the same syntax, whether that code is executing in a test in node, in a datahook in a validate function, or on our server for a sheetCompute. + +Let's dive in + +``` +When(GreaterThan(Val(), 5), Error(" val is greater than 5")) +``` + +What's going on there... a lot + +`Val()` is a special function, that references a variable for this interpret context.. more on that later. +We'll start from the inside `GreaterThan(Val(), 5)` runs `Val()` and returns true or false if it is greater or less than 5. + +Let me explain a simpler expression first +``` +When(true, Error(" val is greater than 5") +``` +`When` is a conditional, based on the value of the first argument, it will conditionally return the expression in the second argument. + +This all seems complex and a long way of saying +`if(val > 5) {return error("val greater than 5");}` + +The magic happens with this, because we aren't actually executing the code immediately. We can execute the code immmediately, or we can send that same parse tree to the server and execute it there. + +for a `validate` hook we execute it immediately, and `Val()` is the value being validated. + +For a sheetCompute, or groupConstraint, we send the parse tree to the server for execution there. + +# The expression language for validate Field hooks + +The easiest place to use the expression language is for `validate` field hooks. + +let's take the above example and put it in a test Sheet +``` +const SimpleSheet = new Sheet( + 'SimpleSheet', + {age: NumberField({validate: VWhen(LessThan(Val(), 21), Error("too young to drink"))}, +) +``` + +note, when used in a `validate` function, `VWhen` instead of `EWhen` must be used. `VWhen` returns a function that accepts a value and calls the validate function on the expression, making `Val()` a valid way of accessing the argument for `validate`. + +# GroupByField +``` +const ItemSummary = new Sheet( + 'ItemSummary', + { + orderID: NumberField({}), //parent item + itemId: NumberField({}), + price: NumberField({}), + orderTotal: GroupByField('orderId', compute: Sum(GetColumn('price', Group()))) + } +) +``` + +this sheet looks fairly straight forward until we get to GroupByField. + +the first argument is the column to group on +`compute` for GroupByField will be interpreted on the Flatfile server, once per group, with all relevant rows exposed as `Group()`. `GetColumn` returns a list of values for the column from the set sent in. `Sum` returns the sum of values passed in + + +# GroupConstraintSet +``` +const MixedRowSheet = new Sheet( + 'MixedRows', + { + parentId: NumberField({}), + rowType: TextField({}), //can be header or item + colForHeader: TextField({}), // required per header row + colForItem: NumberField({}), //unique per parentId for rowType = item + //the following field is just a placeholder to recieve errors + validityErrors: GroupByField('parentId', compute: + GroupConstraintSet( + [Group(), When(Equal(Count(Match({'rowType':'header'}), Group())), 0), + Error("At least 1 rowType='header' required")], + [Group(), When(Equal(Count(Match({'rowType':'item'}), MatchResult())), 0), + Error("At least 1 rowType='item' required")], + [Match({'rowType':'item'}), + Unless(Equal(Count(MatchResult()), Count(Uniq(GetColumn('colForItem', MatchResult())))), + Error("colForItem must be unique across parentId"))])) + } +) +``` + + +Wow, a lot going on there +`GroupConstraintSet` -- take arguments as (applicableSet, condition), add all Messages together and apply to field. + +note we use `When` here to differentiate from `ValidateWhen`. Still not sure how to handle this naming collision. + +for the first argument +``` + [Group(), EWhen(Equal(Count(Match({'rowType':'header'}), Group())), 0), + Error("At least 1 rowType='header' required")], +``` +this will match each row in Group with `rowType`=`'header'` and count them. if the count is 0, add an Error message of "header required". + + +``` + [Group(), EWhen(Equal(Count(Match({'rowType':'item'}), MatchResult())), 0), + Error("At least 1 rowType='item' required")], +``` +the second argument does much the same for rowType. note `MatchResult()` which is the same as the condition used as the first argument of the array + + +``` + [Match({'rowType':'item'}), + Unless(Equal(Count(MatchResult()), Count(Uniq(GetColumn('colForItem', MatchResult())))), + Error("colForItem must be unique across parentId"))])) +``` +the third argument only applies to rows where `rowType`=`'item'`. this enforces that `colForItem` is unique within the group. + + + + + + From 5f5dfad91512ea2d06e25a69c2f80b189b71009f Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Thu, 10 Nov 2022 19:33:00 -0500 Subject: [PATCH 04/36] feat: WIP two small fies --- docs/Expression.md | 6 +++--- src/expression-lang/EXPR.ts | 5 ++++- src/expression-lang/sheetInterpret.ts | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/Expression.md b/docs/Expression.md index 0d0690a..96d316d 100644 --- a/docs/Expression.md +++ b/docs/Expression.md @@ -40,7 +40,7 @@ const SimpleSheet = new Sheet( ) ``` -note, when used in a `validate` function, `VWhen` instead of `EWhen` must be used. `VWhen` returns a function that accepts a value and calls the validate function on the expression, making `Val()` a valid way of accessing the argument for `validate`. +note, when used in a `validate` function, `ValidateVWhen` instead of `When` must be used. `ValidateWhen` returns a function that accepts a value and calls the validate function on the expression, making `Val()` a valid way of accessing the argument for `validate`. # GroupByField ``` @@ -92,14 +92,14 @@ note we use `When` here to differentiate from `ValidateWhen`. Still not sure ho for the first argument ``` - [Group(), EWhen(Equal(Count(Match({'rowType':'header'}), Group())), 0), + [Group(), When(Equal(Count(Match({'rowType':'header'}), Group())), 0), Error("At least 1 rowType='header' required")], ``` this will match each row in Group with `rowType`=`'header'` and count them. if the count is 0, add an Error message of "header required". ``` - [Group(), EWhen(Equal(Count(Match({'rowType':'item'}), MatchResult())), 0), + [Group(), When(Equal(Count(Match({'rowType':'item'}), MatchResult())), 0), Error("At least 1 rowType='item' required")], ``` the second argument does much the same for rowType. note `MatchResult()` which is the same as the condition used as the first argument of the array diff --git a/src/expression-lang/EXPR.ts b/src/expression-lang/EXPR.ts index 0f90227..0f8db6c 100644 --- a/src/expression-lang/EXPR.ts +++ b/src/expression-lang/EXPR.ts @@ -1,4 +1,5 @@ import { makeInterpreter, NestedIns } from '@flatfile/expression-lang' +import { error } from './sheetInterpret' export const Add = (...args: any) => ['+', ...args] export const Subtract = (...args: any) => ['-', ...args] export const Mult = (...args: any) => ['*', ...args] @@ -74,9 +75,11 @@ export const GroupConstraintItem = ( group, ] } + + export const Debug = (expr: NestedIns) => ['debug', expr] -const simpleInterpret = makeInterpreter({}) +const simpleInterpret = makeInterpreter({error}) export const ValidateWhen = (predicate: any, expr: any) => { return (val: any) => { return simpleInterpret(['when', predicate, expr], { val: val }) diff --git a/src/expression-lang/sheetInterpret.ts b/src/expression-lang/sheetInterpret.ts index 2b44946..56d8c8d 100644 --- a/src/expression-lang/sheetInterpret.ts +++ b/src/expression-lang/sheetInterpret.ts @@ -11,7 +11,7 @@ export type TRecordStageLevel = //I would love message to be able to accept some type of format string -const error = (message: string, stage: TRecordStageLevel = 'validate') => { +export const error = (message: string, stage: TRecordStageLevel = 'validate') => { // I don't like returning a list here, not sure where to deal with scalar/list return [new Message(message, 'error', stage)] } From f54a0f40bf64cb8357c2c63bbada6b6b481a1cfb Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Fri, 11 Nov 2022 05:41:40 -0500 Subject: [PATCH 05/36] feat: better names for validate functions --- src/expression-lang/EXPR.spec.ts | 15 +++++++------ src/expression-lang/EXPR.ts | 37 ++++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/src/expression-lang/EXPR.spec.ts b/src/expression-lang/EXPR.spec.ts index 75b4227..197b649 100644 --- a/src/expression-lang/EXPR.spec.ts +++ b/src/expression-lang/EXPR.spec.ts @@ -6,19 +6,20 @@ import { Val, Group, Match, - ImplicitGreaterThan, + ImplicitLessThan, GroupConstraintItem, Count, MatchResult, GreaterThan, Unless, Debug, - ValidateWhen + ErrorWhen, + ErrorUnless } from './EXPR' describe('VExpression Tests ->', () => { test('Simple test', () => { - const valFunc = ValidateWhen(GreaterThan(Val(), 5), Error('val greater than 5')) + const valFunc = ErrorWhen(GreaterThan(Val(), 5), 'val greater than 5') expect(valFunc(3)).toStrictEqual([]) expect(valFunc(7)).toMatchObject([ { level: 'error', message: 'val greater than 5' }, @@ -26,10 +27,10 @@ describe('VExpression Tests ->', () => { }) test('Implicit Greater Than test', () => { - const valFunc = ValidateWhen(ImplicitGreaterThan(5), Error('val greater than 5')) - expect(valFunc(3)).toStrictEqual([]) - expect(valFunc(7)).toMatchObject([ - { level: 'error', message: 'val greater than 5' }, + const valFunc = ErrorUnless(ImplicitLessThan(5), 'val less than 5') + expect(valFunc(7)).toStrictEqual([]) + expect(valFunc(3)).toMatchObject([ + { level: 'error', message: 'val less than 5' }, ]) }) }) diff --git a/src/expression-lang/EXPR.ts b/src/expression-lang/EXPR.ts index 0f8db6c..5893c02 100644 --- a/src/expression-lang/EXPR.ts +++ b/src/expression-lang/EXPR.ts @@ -61,6 +61,8 @@ export const Match = (matchSpec: any, recordGrouping: any) => [ recordGrouping, ] export const ImplicitGreaterThan = (comparand: any) => ['>', Val(), comparand] +export const ImplicitLessThan = (comparand: any) => ['>', Val(), comparand] + export const GroupConstraintItem = ( rowFilterExpr: NestedIns, actionExpr: NestedIns, @@ -80,16 +82,47 @@ export const GroupConstraintItem = ( export const Debug = (expr: NestedIns) => ['debug', expr] const simpleInterpret = makeInterpreter({error}) + export const ValidateWhen = (predicate: any, expr: any) => { return (val: any) => { return simpleInterpret(['when', predicate, expr], { val: val }) } } -export const ValidateUnless = (predicate: any, expr: any) => { + +export const ErrorWhen = (predicate: any, errString: string) => { + return (val: any) => { + return simpleInterpret(['when', predicate, ['error', errString]], { val: val }) + } +} + +export const ErrorUnless = (predicate: any, errString: string) => { + return (val: any) => { + return simpleInterpret(['when', ['not', predicate], ['error', errString]], { val: val }) + } +} + + +export const WarnWhen = (predicate: any, errString: string) => { + return (val: any) => { + return simpleInterpret(['when', predicate, ['warn', errString]], { val: val }) + } +} + +export const WarnUnless = (predicate: any, errString: string) => { return (val: any) => { - return simpleInterpret(['when', ['not', predicate], expr], { val: val }) + return simpleInterpret(['unless', ['not', predicate], ['warn', errString]], { val: val }) } } +export const InfoWhen = (predicate: any, errString: string) => { + return (val: any) => { + return simpleInterpret(['when', predicate, ['info', errString]], { val: val }) + } +} +export const InfoUnless = (predicate: any, errString: string) => { + return (val: any) => { + return simpleInterpret(['when', ['not', predicate], ['info', errString]], { val: val }) + } +} From d6504edc6e61a0839f9bd109aadfb70a3bb78c3b Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Fri, 11 Nov 2022 05:49:25 -0500 Subject: [PATCH 06/36] updated docs to reflect 'ErrorWhen' and other MessageConditional functions --- docs/Expression.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/Expression.md b/docs/Expression.md index 96d316d..441e6a2 100644 --- a/docs/Expression.md +++ b/docs/Expression.md @@ -36,11 +36,12 @@ let's take the above example and put it in a test Sheet ``` const SimpleSheet = new Sheet( 'SimpleSheet', - {age: NumberField({validate: VWhen(LessThan(Val(), 21), Error("too young to drink"))}, + {age: NumberField({validate: ErrorWhen(LessThan(Val(), 21), "too young to drink")}, ) ``` -note, when used in a `validate` function, `ValidateVWhen` instead of `When` must be used. `ValidateWhen` returns a function that accepts a value and calls the validate function on the expression, making `Val()` a valid way of accessing the argument for `validate`. + +note, when used in a `validate` function, there are special MessageConditionals `ErrorWhen`,`ErrorUnless`, `WarnWhen`, `WarnUnless`, `InfoWhen`, `InfoUnless` that should be used. `ErrorWhen` returns a function that accepts a value and calls the validate function on the expression, making `Val()` a valid way of accessing the argument for `validate`. # GroupByField ``` From f20dc5f0e49ac2865bb9a1b741c74a6ebed04e1e Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Tue, 15 Nov 2022 07:07:34 -0500 Subject: [PATCH 07/36] chore: jest now searches examples directory --- jest.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jest.config.js b/jest.config.js index 997df40..f5c3e51 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,5 +1,5 @@ module.exports = { - roots: ['/src'], + roots: ['/src', '/examples'], testEnvironment: 'node', transform: { '^.+\\.tsx?$': 'ts-jest', From 4dbb90fdfac6694a6e10c96096da782e6658a18f Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Tue, 15 Nov 2022 07:41:35 -0500 Subject: [PATCH 08/36] feat: updates to expression lang --- src/expression-lang/EXPR.ts | 8 +++++--- src/expression-lang/sheetInterpret.ts | 7 +++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/expression-lang/EXPR.ts b/src/expression-lang/EXPR.ts index 5893c02..25ac44f 100644 --- a/src/expression-lang/EXPR.ts +++ b/src/expression-lang/EXPR.ts @@ -1,5 +1,7 @@ import { makeInterpreter, NestedIns } from '@flatfile/expression-lang' -import { error } from './sheetInterpret' +import { error, warn, info, debug } from './sheetInterpret' +import { Message } from '@flatfile/configure' + export const Add = (...args: any) => ['+', ...args] export const Subtract = (...args: any) => ['-', ...args] export const Mult = (...args: any) => ['*', ...args] @@ -81,7 +83,7 @@ export const GroupConstraintItem = ( export const Debug = (expr: NestedIns) => ['debug', expr] -const simpleInterpret = makeInterpreter({error}) +const simpleInterpret = makeInterpreter({error, warn, info, debug}) export const ValidateWhen = (predicate: any, expr: any) => { return (val: any) => { @@ -91,7 +93,7 @@ export const ValidateWhen = (predicate: any, expr: any) => { export const ErrorWhen = (predicate: any, errString: string) => { return (val: any) => { - return simpleInterpret(['when', predicate, ['error', errString]], { val: val }) + return simpleInterpret(['when', predicate, ['error', errString]], { val: val }) as Message[] } } diff --git a/src/expression-lang/sheetInterpret.ts b/src/expression-lang/sheetInterpret.ts index 56d8c8d..2c5d08d 100644 --- a/src/expression-lang/sheetInterpret.ts +++ b/src/expression-lang/sheetInterpret.ts @@ -15,6 +15,13 @@ export const error = (message: string, stage: TRecordStageLevel = 'validate') => // I don't like returning a list here, not sure where to deal with scalar/list return [new Message(message, 'error', stage)] } +export const warn = (message: string, stage: TRecordStageLevel = 'validate') => { + return [new Message(message, 'warn', stage)] +} +export const info = (message: string, stage: TRecordStageLevel = 'validate') => { + return [new Message(message, 'info', stage)] +} + const match = (matchSpec: object, records: FlatfileRecord[]) => { return _.filter(records, (rec: FlatfileRecord) => From fbcb4ca24f92cbb6c30480832bbe3e71454d0ab3 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Tue, 15 Nov 2022 07:42:46 -0500 Subject: [PATCH 09/36] feat: sheetTester that cna test for info messages --- src/utils/testing/SheetTester.ts | 61 +++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/src/utils/testing/SheetTester.ts b/src/utils/testing/SheetTester.ts index e30aefb..6f3acb9 100644 --- a/src/utils/testing/SheetTester.ts +++ b/src/utils/testing/SheetTester.ts @@ -1,6 +1,5 @@ import _ from 'lodash' - -import { FlatfileRecords, FlatfileSession, IPayload } from '@flatfile/hooks' +import { IRecordInfo, TRecordData, TPrimitive, FlatfileRecords, FlatfileSession, IPayload } from '@flatfile/hooks' import { Workbook } from '@flatfile/configure' export class SheetTester { @@ -97,14 +96,66 @@ export class SheetTester { return transform(pkey, value) } - public async testRecord(recordBatch: {}) { - const transformedRecords = await this.transformRecords([recordBatch]) + public async testRecord(record: {}) { + const transformedRecords = await this.transformRecords([record]) return transformedRecords.records[0].value } - public async testRecords(recordBatch: any[]) { + public async testRecords(recordBatch: Record[]) { const transformedRecords = await this.transformRecords(recordBatch) return transformedRecords.records.map((r) => r.value) } + public async testMessage(record: {}) { + const transformedRecords = await this.transformRecords([record]) + return transformedRecords.records.map((r) => r.toJSON().info)[0] + } + public async testMessages(recordBatch: Record[]) { + const transformedRecords = await this.transformRecords(recordBatch) + return transformedRecords.records.map((r) => r.toJSON().info) + } + +} + +// export interface InfoObj { +// field: string +// message: string +// level: TRecordStageLevel +// stage: 'validate' | 'compute' +// } + +export type InfoObj = IRecordInfo, string | number> + +export const removeUndefineds = (obj:Record) => _.pickBy(obj, _.identity) +export const matchMessages = (messages:InfoObj[], field?:string, message?:string, level?:string): false| any[] => { + + const results = _.filter(messages, removeUndefineds({field,message,level})) + if (results.length > 0) { + return results + } + return false } + +export const matchSingleMessage = ( + messages:InfoObj[], field?:string, message?:string, level?:string): false| any => { + const results = matchMessages(messages, field, message, level) + if (results === false) { + return false + } + if (results.length === 1) { + return results[0] + } + if (results.length > 1) { + throw new Error("more than one message returned") + } + if (results.length === 0) { + //unreachable + return false + } + //unreachable + return false +} + +//use the match functions like +// const res = await testSheet.testMessage(inputRow) +// expect(matchSingleMessage(res, 'numField', 'more than 5', 'error')).toBeTruthy() From 52a9ca60544bc5f0d391af6c64fefebf98da5240 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Tue, 15 Nov 2022 07:43:14 -0500 Subject: [PATCH 10/36] feat: testing expression language on an actual sheet --- examples/features/ValidateSheet.spec.ts | 37 +++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 examples/features/ValidateSheet.spec.ts diff --git a/examples/features/ValidateSheet.spec.ts b/examples/features/ValidateSheet.spec.ts new file mode 100644 index 0000000..61dee2b --- /dev/null +++ b/examples/features/ValidateSheet.spec.ts @@ -0,0 +1,37 @@ +import { Sheet, NumberField, Workbook } from '@flatfile/configure' +import { SheetTester, matchMessages, matchSingleMessage } from '../../src/utils/testing/SheetTester' +import * as EXPR from '../../src/expression-lang/EXPR' +const [ErrorWhen, Val, GreaterThan] = [EXPR.ErrorWhen, EXPR.Val, EXPR.GreaterThan] + + +// note sheet must have same name as key in workbook it is shared as +const SubSheet = new Sheet( + 'SubSheet', + {numField: NumberField({validate: ErrorWhen(GreaterThan(Val(), 5), "more than 5")})}) + + +const TestWorkbook = new Workbook({ + name: `Test Workbook`, + namespace: 'test', + // saving SubSheet to workbook under key SubSheet + sheets: { SubSheet }, +}) + +describe('Workbook tests ->', () => { + // here we use Sheet tester + const testSheet = new SheetTester(TestWorkbook, 'SubSheet') + test('ErrorWhen ', async () => { + // for this inputRow + const inputRow = { numField: 6} + // we expect this output row + const res = await testSheet.testMessage(inputRow) + expect(matchSingleMessage(res, 'numField', 'more than 5', 'error')).toBeTruthy() + // console.log("res", res) + // console.log("matchMessages", matchMessages(res, 'numField')) + //console.log("matchSingleMessage", + + //call the expectation here + //expect(res).toMatchObject(expectedOutputRow) + }) + +}) From be77d85741157f321ab1e7857912f3d97aabfde3 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Tue, 15 Nov 2022 17:28:51 -0500 Subject: [PATCH 11/36] chore: finished typing fixes on validate functions --- src/expression-lang/EXPR.ts | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/expression-lang/EXPR.ts b/src/expression-lang/EXPR.ts index 25ac44f..c744592 100644 --- a/src/expression-lang/EXPR.ts +++ b/src/expression-lang/EXPR.ts @@ -85,12 +85,6 @@ export const Debug = (expr: NestedIns) => ['debug', expr] const simpleInterpret = makeInterpreter({error, warn, info, debug}) -export const ValidateWhen = (predicate: any, expr: any) => { - return (val: any) => { - return simpleInterpret(['when', predicate, expr], { val: val }) - } -} - export const ErrorWhen = (predicate: any, errString: string) => { return (val: any) => { return simpleInterpret(['when', predicate, ['error', errString]], { val: val }) as Message[] @@ -99,32 +93,32 @@ export const ErrorWhen = (predicate: any, errString: string) => { export const ErrorUnless = (predicate: any, errString: string) => { return (val: any) => { - return simpleInterpret(['when', ['not', predicate], ['error', errString]], { val: val }) + return simpleInterpret(['when', ['not', predicate], ['error', errString]], { val: val }) as Message[] } } export const WarnWhen = (predicate: any, errString: string) => { return (val: any) => { - return simpleInterpret(['when', predicate, ['warn', errString]], { val: val }) + return simpleInterpret(['when', predicate, ['warn', errString]], { val: val }) as Message[] } } export const WarnUnless = (predicate: any, errString: string) => { return (val: any) => { - return simpleInterpret(['unless', ['not', predicate], ['warn', errString]], { val: val }) + return simpleInterpret(['unless', ['not', predicate], ['warn', errString]], { val: val }) as Message[] } } export const InfoWhen = (predicate: any, errString: string) => { return (val: any) => { - return simpleInterpret(['when', predicate, ['info', errString]], { val: val }) + return simpleInterpret(['when', predicate, ['info', errString]], { val: val }) as Message[] } } export const InfoUnless = (predicate: any, errString: string) => { return (val: any) => { - return simpleInterpret(['when', ['not', predicate], ['info', errString]], { val: val }) + return simpleInterpret(['when', ['not', predicate], ['info', errString]], { val: val }) as Message[] } } From 89736bd7bd09ab34a7e1402234be557c1ce12a96 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Mon, 21 Nov 2022 18:31:08 -0500 Subject: [PATCH 12/36] removed trash file --- src/expression-lang/.#GroupByLocal.ts | 1 - 1 file changed, 1 deletion(-) delete mode 120000 src/expression-lang/.#GroupByLocal.ts diff --git a/src/expression-lang/.#GroupByLocal.ts b/src/expression-lang/.#GroupByLocal.ts deleted file mode 120000 index 6b2fa61..0000000 --- a/src/expression-lang/.#GroupByLocal.ts +++ /dev/null @@ -1 +0,0 @@ -paddy@Paddys-MacBook-Pro.local.599 \ No newline at end of file From 22086ba52c3c8a8b0c7739aa0ab78902e3ac616e Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Mon, 21 Nov 2022 21:25:20 -0500 Subject: [PATCH 13/36] WIP --- examples/features/GroupByField.spec.ts | 163 ++++++++++++++++++++++++ examples/features/ValidateSheet.spec.ts | 6 - package-lock.json | 14 +- package.json | 2 +- src/utils/testing/SheetTester.ts | 31 ++++- 5 files changed, 199 insertions(+), 17 deletions(-) create mode 100644 examples/features/GroupByField.spec.ts diff --git a/examples/features/GroupByField.spec.ts b/examples/features/GroupByField.spec.ts new file mode 100644 index 0000000..f378778 --- /dev/null +++ b/examples/features/GroupByField.spec.ts @@ -0,0 +1,163 @@ +//import { Sheet, Workbook } from '@flatfile/configure' +import { TextField, NumberField, GroupByField, Sheet, Workbook } from '@flatfile/configure' +import { SheetTester, matchMessages, matchSingleMessage } from '../../src/utils/testing/SheetTester' +//import { WorkbookTester } from '../../ddl/WorkbookTester' + +const CountSheet = new Sheet( + 'CountSheet', + { + category: TextField({}), + count_of_instances: GroupByField( + ['category'], + ['count', ['variable', 'group']] + )}) + +describe('SampleGroupByField ->', () => { + const TestSchema = new WorkbookTester( + { + category: TextField({}), + count_of_instances: GroupByField( + ['category'], + ['count', ['variable', 'group']] + ), + // Count(Group()) + }, + {} + ) + test('GroupByField works properly with count', async () => { + await TestSchema.checkRowResult({ + rawData: { category: 'apple_', count_of_instances: '_' }, + expectedOutput: { category: 'apple_', count_of_instances: 1 }, + }) + }) + test('GroupByField works properly with count - multiple rows', async () => { + await TestSchema.checkRows( + [ + { category: 'apple_', count_of_instances: '_' }, + { category: 'orange', count_of_instances: '_' }, + { category: 'apple_', count_of_instances: '_' }, + ], + [ + { category: 'apple_', count_of_instances: 2 }, + { category: 'orange', count_of_instances: 1 }, + { category: 'apple_', count_of_instances: 2 }, + ] + ) + }) +}) + + + +const grps = [ + { name: 'Paddy', age: 40, job: 'eng', weight: 190, eyeColor: 'green', age_sum: '0' }, + { name: 'Cliff', age: 86, job: 'ret', weight: 160, eyeColor: 'gray_', age_sum: '0' }, + { name: 'Odin_', age: 3., job: 'kid', weight: 30., eyeColor: 'blue_', age_sum: '0' }, + { name: 'Kay__', age: 77, job: 'ret', weight: 160, eyeColor: 'green', age_sum: '0' }, + { name: 'Sarah', age: 8., job: 'kid', weight: 60., eyeColor: 'green', age_sum: '0' }] + +describe('SampleGroupBy sum ->', () => { + const TestSchema = new WorkbookTester( + { + job: TextField(), + age: NumberField(), + age_sum: GroupByField( + ['job'], + ['sumField', ['variable', 'group'], 'age'] + ), + }, + {} + ) + test('GroupByField works properly with sum - multiple rows', async () => { + await TestSchema.checkRows(grps, + [{ name: 'Paddy', age: 40, job: 'eng', weight: 190, eyeColor: 'green', age_sum: 40 }, + { name: 'Cliff', age: 86, job: 'ret', weight: 160, eyeColor: 'gray_', age_sum: 163 }, + { name: 'Odin_', age: 3., job: 'kid', weight: 30., eyeColor: 'blue_', age_sum: 11 }, + { name: 'Kay__', age: 77, job: 'ret', weight: 160, eyeColor: 'green', age_sum: 163 }, + { name: 'Sarah', age: 8., job: 'kid', weight: 60., eyeColor: 'green', age_sum: 11 }] + ) + }) +}) + + +const PeopleSheet = new Sheet('People', + { + job: TextField(), + age: NumberField(), + age_sum: GroupByField( + ['job'], + ['groupConstraintRow', + ['quote', ['variable', 'group']], + ['quote', ['when', ['not', ['>', ['count', ['match', {job:'kid'}, ['variable', 'group']]], 0 ]], + ['error', 'No Kids']]], + 'name', + ['variable', 'group']]), +}) + + +describe('SampleGroupBy groupConstraint ->', () => { + const TestSchema = new WorkbookTester( + { + job: TextField(), + age: NumberField(), + age_sum: GroupByField( + ['job'], + ['groupConstraintRow', + ['quote', ['variable', 'group']], + ['quote', ['when', ['not', ['>', ['count', ['match', {job:'kid'}, ['variable', 'group']]], 0 ]], + ['error', 'No Kids']]], + 'name', + ['variable', 'group']]), + }, + {} + ) + test('GroupByField works properly with sum - multiple rows', async () => { + //await TestSchema.checkRows(grps, + const res = await TestSchema.runRowResult(grps) + expect(res[0].info[0]).toMatchObject({ + field: 'name', + message: 'No Kids', + }) + expect(res[2].info).toStrictEqual([]) + }) +}) + +describe('SampleGroupBy groupConstraint and Comp ->', () => { + const TestSchema = new WorkbookTester( + { + job: TextField(), + age: NumberField(), + age_sum: GroupByField( + ['job'], + ['do', + ['groupConstraintRow', + ['quote', ['variable', 'group']], + ['quote', ['when', ['not', ['>', ['count', ['match', {job:'kid'}, ['variable', 'group']]], 0 ]], + ['error', 'No Kids']]], + 'name', + ['variable', 'group']], + ['sumField', ['variable', 'group'], 'age']] + ), + }, + {} + ) + test('GroupByField works properly with groupconstraint and sum - multiple rows', async () => { + //await TestSchema.checkRows(grps, + const res = await TestSchema.runRowResult(grps) + // console.log(res[0].info) + // console.log(res[2].info) + expect(res[0].info[0]).toMatchObject({ + field: 'name', + message: 'No Kids', + }) + expect(res[2].info).toStrictEqual([]) + + await TestSchema.checkRows(grps, + [{ name: 'Paddy', age: 40, job: 'eng', weight: 190, eyeColor: 'green', age_sum: 40 }, + { name: 'Cliff', age: 86, job: 'ret', weight: 160, eyeColor: 'gray_', age_sum: 163 }, + { name: 'Odin_', age: 3., job: 'kid', weight: 30., eyeColor: 'blue_', age_sum: 11 }, + { name: 'Kay__', age: 77, job: 'ret', weight: 160, eyeColor: 'green', age_sum: 163 }, + { name: 'Sarah', age: 8., job: 'kid', weight: 60., eyeColor: 'green', age_sum: 11 }] + ) + }) +}) + diff --git a/examples/features/ValidateSheet.spec.ts b/examples/features/ValidateSheet.spec.ts index 61dee2b..c64a9ab 100644 --- a/examples/features/ValidateSheet.spec.ts +++ b/examples/features/ValidateSheet.spec.ts @@ -26,12 +26,6 @@ describe('Workbook tests ->', () => { // we expect this output row const res = await testSheet.testMessage(inputRow) expect(matchSingleMessage(res, 'numField', 'more than 5', 'error')).toBeTruthy() - // console.log("res", res) - // console.log("matchMessages", matchMessages(res, 'numField')) - //console.log("matchSingleMessage", - - //call the expectation here - //expect(res).toMatchObject(expectedOutputRow) }) }) diff --git a/package-lock.json b/package-lock.json index 1505cb1..619cf36 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.4", "license": "MIT", "devDependencies": { - "@flatfile/configure": "^0.4.2", + "@flatfile/configure": "^0.4.7", "@flatfile/expression-lang": "^0.0.2", "@flatfile/hooks": "^1.2.0", "@types/jest": "^28.1.4", @@ -671,9 +671,9 @@ } }, "node_modules/@flatfile/configure": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@flatfile/configure/-/configure-0.4.2.tgz", - "integrity": "sha512-U0+jSGSVKDwIfXRkMgT229SQ9tiAsmQNhjnU0yI3gxyKnZILJhixpgresLH9lb1VWPXkROQ693BniKOtwpkQ0w==", + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@flatfile/configure/-/configure-0.4.7.tgz", + "integrity": "sha512-f7i/sXvJAWzHsrG7sHZAseJ5sDjZSCrbwvWs+k94D2pxmX7DQ1PE8UaLr77dHwiqSldy7HYUg3YIx28oUGZ82A==", "dev": true, "dependencies": { "@flatfile/orm": "*", @@ -6486,9 +6486,9 @@ } }, "@flatfile/configure": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@flatfile/configure/-/configure-0.4.2.tgz", - "integrity": "sha512-U0+jSGSVKDwIfXRkMgT229SQ9tiAsmQNhjnU0yI3gxyKnZILJhixpgresLH9lb1VWPXkROQ693BniKOtwpkQ0w==", + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@flatfile/configure/-/configure-0.4.7.tgz", + "integrity": "sha512-f7i/sXvJAWzHsrG7sHZAseJ5sDjZSCrbwvWs+k94D2pxmX7DQ1PE8UaLr77dHwiqSldy7HYUg3YIx28oUGZ82A==", "dev": true, "requires": { "@flatfile/orm": "*", diff --git a/package.json b/package.json index 3bb1563..d3a66d1 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "test": "jest --runInBand --detectOpenHandles --forceExit --passWithNoTests" }, "devDependencies": { - "@flatfile/configure": "^0.4.2", + "@flatfile/configure": "^0.4.7", "@flatfile/hooks": "^1.2.0", "@flatfile/expression-lang": "^0.0.2", "node-fetch": "^3.2.10", diff --git a/src/utils/testing/SheetTester.ts b/src/utils/testing/SheetTester.ts index 6f3acb9..f815d6a 100644 --- a/src/utils/testing/SheetTester.ts +++ b/src/utils/testing/SheetTester.ts @@ -1,6 +1,25 @@ import _ from 'lodash' import { IRecordInfo, TRecordData, TPrimitive, FlatfileRecords, FlatfileSession, IPayload } from '@flatfile/hooks' -import { Workbook } from '@flatfile/configure' +import { NumberField, Sheet, TextField, Workbook } from '@flatfile/configure' +import { sheetInterpret } from '../../expression-lang/sheetInterpret' + +const localSheetCompute = ( + sheet: Sheet, + records: FlatfileRecords +) => { + const possibleSheetCompute = sheet.getSheetCompute() + if (possibleSheetCompute === undefined) { + return records + } else { + //@ts-ignore + const afterSheetCompute = sheetInterpret(possibleSheetCompute.sheetCompute, { + sheet, + modifiedRecords: records, + }) + return afterSheetCompute + } +} + export class SheetTester { public workbook @@ -50,7 +69,10 @@ export class SheetTester { const inputRecords = new FlatfileRecords(iRaw) await this.workbook.processRecords(inputRecords, session) - return inputRecords + + const sheet = this.workbook.options.sheets[this.sheetName] + return localSheetCompute(sheet, inputRecords) + //return inputRecords } public async transformField( @@ -98,20 +120,23 @@ export class SheetTester { public async testRecord(record: {}) { const transformedRecords = await this.transformRecords([record]) + //@ts-ignore return transformedRecords.records[0].value } public async testRecords(recordBatch: Record[]) { const transformedRecords = await this.transformRecords(recordBatch) - + //@ts-ignore return transformedRecords.records.map((r) => r.value) } public async testMessage(record: {}) { const transformedRecords = await this.transformRecords([record]) + //@ts-ignore return transformedRecords.records.map((r) => r.toJSON().info)[0] } public async testMessages(recordBatch: Record[]) { const transformedRecords = await this.transformRecords(recordBatch) + //@ts-ignore return transformedRecords.records.map((r) => r.toJSON().info) } From 68a7ffd9e09d4f2893a6a08b2ca09101666d19e1 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Tue, 22 Nov 2022 06:34:51 -0500 Subject: [PATCH 14/36] first working sheetcompute test in -starter --- examples/features/GroupByField.spec.ts | 30 ++++++++--------- src/expression-lang/sheetInterpret.ts | 46 +++++++++++++++++++++++++- src/utils/testing/SheetTester.ts | 5 ++- 3 files changed, 62 insertions(+), 19 deletions(-) diff --git a/examples/features/GroupByField.spec.ts b/examples/features/GroupByField.spec.ts index f378778..bdd379e 100644 --- a/examples/features/GroupByField.spec.ts +++ b/examples/features/GroupByField.spec.ts @@ -11,32 +11,25 @@ const CountSheet = new Sheet( ['category'], ['count', ['variable', 'group']] )}) +const CountBook = new Workbook({name: 't', namespace: 't', sheets: {CountSheet}}) describe('SampleGroupByField ->', () => { - const TestSchema = new WorkbookTester( - { - category: TextField({}), - count_of_instances: GroupByField( - ['category'], - ['count', ['variable', 'group']] - ), - // Count(Group()) - }, - {} - ) + const testSheet = new SheetTester(CountBook, 'CountSheet') test('GroupByField works properly with count', async () => { - await TestSchema.checkRowResult({ - rawData: { category: 'apple_', count_of_instances: '_' }, - expectedOutput: { category: 'apple_', count_of_instances: 1 }, + const res = await testSheet.testRecord({category: 'apple_', count_of_instances: '_' }) + expect(res).toStrictEqual({ category: 'apple_', count_of_instances: 1 }) }) - }) + test('GroupByField works properly with count - multiple rows', async () => { - await TestSchema.checkRows( + const res = await testSheet.testRecords( [ { category: 'apple_', count_of_instances: '_' }, { category: 'orange', count_of_instances: '_' }, { category: 'apple_', count_of_instances: '_' }, - ], + ]) + + expect(res).toStrictEqual( + [ { category: 'apple_', count_of_instances: 2 }, { category: 'orange', count_of_instances: 1 }, @@ -46,6 +39,8 @@ describe('SampleGroupByField ->', () => { }) }) +/* + const grps = [ @@ -161,3 +156,4 @@ describe('SampleGroupBy groupConstraint and Comp ->', () => { }) }) +*/ diff --git a/src/expression-lang/sheetInterpret.ts b/src/expression-lang/sheetInterpret.ts index 2c5d08d..4a2a8dc 100644 --- a/src/expression-lang/sheetInterpret.ts +++ b/src/expression-lang/sheetInterpret.ts @@ -1,6 +1,7 @@ import { makeInterpreter, NestedIns } from '@flatfile/expression-lang' import { Message } from '@flatfile/configure' -import { FlatfileRecord } from '@flatfile/hooks' +import { FlatfileRecord, FlatfileRecords } from '@flatfile/hooks' +import { Sheet } from '@flatfile/configure' import * as _ from 'lodash' export type TRecordStageLevel = @@ -29,6 +30,42 @@ const match = (matchSpec: object, records: FlatfileRecord[]) => { ) } + + + +const groupByCompute = ( + gbArgs: any, + sheet: Sheet, + records: FlatfileRecords +) => { + const { groupBy, expression, destination } = gbArgs + const recs = records.records + const groups: Record = _.groupBy(recs, (rec) => + rec.get(groupBy) + ) + + _.forEach(groups, (group: FlatfileRecord[], gbKey) => { + const res = simpleInterpret(expression, { sheet, group }) + for (const rec of group) { + //@ts-ignore + rec.set(destination, res) + } + }) + return records +} + + +const sumField = (records: FlatfileRecord[], field: string) => { + //@ts-ignore + const allVals = records.map((rec) => rec.get(field)) + const presentVals = _.remove(allVals) + //@ts-ignore + const numberVals = presentVals.map((val:string|number) => parseFloat(val)) + const sum_ = numberVals.reduce((a,b) => a+b) + return sum_ +} + + const groupConstraintRow = ( rowFilterExpr: NestedIns, actionExpr: NestedIns, @@ -57,14 +94,21 @@ const groupConstraintRow = ( return appliccableRows } + export const debug = (expr: NestedIns) => { console.log('debug', expr) return expr } +const do_ = (...exprs: any) => exprs[exprs.length -1] + +//@ts-ignore +const simpleInterpret = makeInterpreter({sumField, groupConstraintRow, error, match, 'do': do_}) + export const sheetInterpret = makeInterpreter({ error, match, + groupByCompute, groupConstraintRow, debug, }) diff --git a/src/utils/testing/SheetTester.ts b/src/utils/testing/SheetTester.ts index f815d6a..7aa15c0 100644 --- a/src/utils/testing/SheetTester.ts +++ b/src/utils/testing/SheetTester.ts @@ -7,6 +7,7 @@ const localSheetCompute = ( sheet: Sheet, records: FlatfileRecords ) => { + const possibleSheetCompute = sheet.getSheetCompute() if (possibleSheetCompute === undefined) { return records @@ -24,12 +25,14 @@ const localSheetCompute = ( export class SheetTester { public workbook public sheetName + private rawSheetName private testSession: IPayload constructor( public readonly passedWorkbook: Workbook, public readonly passedSheetName: string ) { this.sheetName = `${passedWorkbook.options.namespace}/${passedSheetName}` + this.rawSheetName = passedSheetName this.workbook = passedWorkbook this.testSession = { schemaSlug: '', @@ -70,7 +73,7 @@ export class SheetTester { await this.workbook.processRecords(inputRecords, session) - const sheet = this.workbook.options.sheets[this.sheetName] + const sheet = this.workbook.options.sheets[this.rawSheetName] return localSheetCompute(sheet, inputRecords) //return inputRecords } From 435f3454e14c4f8594dd69a243b07bc6e9ed19aa Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Tue, 22 Nov 2022 06:38:22 -0500 Subject: [PATCH 15/36] WIP --- examples/features/GroupByField.spec.ts | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/examples/features/GroupByField.spec.ts b/examples/features/GroupByField.spec.ts index bdd379e..b8bcd04 100644 --- a/examples/features/GroupByField.spec.ts +++ b/examples/features/GroupByField.spec.ts @@ -39,7 +39,7 @@ describe('SampleGroupByField ->', () => { }) }) -/* + @@ -50,8 +50,9 @@ const grps = [ { name: 'Kay__', age: 77, job: 'ret', weight: 160, eyeColor: 'green', age_sum: '0' }, { name: 'Sarah', age: 8., job: 'kid', weight: 60., eyeColor: 'green', age_sum: '0' }] -describe('SampleGroupBy sum ->', () => { - const TestSchema = new WorkbookTester( + +const JobAgeSheet = new Sheet( + 'JobAgeSheet', { job: TextField(), age: NumberField(), @@ -59,11 +60,15 @@ describe('SampleGroupBy sum ->', () => { ['job'], ['sumField', ['variable', 'group'], 'age'] ), - }, - {} - ) + } +) +const JABook = new Workbook({name: 't', namespace: 't', sheets: {JobAgeSheet}}) + +describe('SampleGroupBy sum ->', () => { + const testSheet = new SheetTester(JABook, 'JobAgeSheet') test('GroupByField works properly with sum - multiple rows', async () => { - await TestSchema.checkRows(grps, + const res = await testSheet.testRecords(grps) + expect(res).toStrictEqual( [{ name: 'Paddy', age: 40, job: 'eng', weight: 190, eyeColor: 'green', age_sum: 40 }, { name: 'Cliff', age: 86, job: 'ret', weight: 160, eyeColor: 'gray_', age_sum: 163 }, { name: 'Odin_', age: 3., job: 'kid', weight: 30., eyeColor: 'blue_', age_sum: 11 }, @@ -73,7 +78,7 @@ describe('SampleGroupBy sum ->', () => { }) }) - +/* const PeopleSheet = new Sheet('People', { job: TextField(), @@ -156,4 +161,5 @@ describe('SampleGroupBy groupConstraint and Comp ->', () => { }) }) + */ From 606544a22456578e50bb564f6da914fe5c1c74af Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Tue, 22 Nov 2022 06:42:19 -0500 Subject: [PATCH 16/36] WIP --- examples/features/GroupByField.spec.ts | 28 +++++++------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/examples/features/GroupByField.spec.ts b/examples/features/GroupByField.spec.ts index b8bcd04..0bb05c6 100644 --- a/examples/features/GroupByField.spec.ts +++ b/examples/features/GroupByField.spec.ts @@ -78,7 +78,7 @@ describe('SampleGroupBy sum ->', () => { }) }) -/* + const PeopleSheet = new Sheet('People', { job: TextField(), @@ -92,35 +92,21 @@ const PeopleSheet = new Sheet('People', 'name', ['variable', 'group']]), }) - +const PeopleBook = new Workbook({name: 't', namespace: 't', sheets: {PeopleSheet}}) describe('SampleGroupBy groupConstraint ->', () => { - const TestSchema = new WorkbookTester( - { - job: TextField(), - age: NumberField(), - age_sum: GroupByField( - ['job'], - ['groupConstraintRow', - ['quote', ['variable', 'group']], - ['quote', ['when', ['not', ['>', ['count', ['match', {job:'kid'}, ['variable', 'group']]], 0 ]], - ['error', 'No Kids']]], - 'name', - ['variable', 'group']]), - }, - {} - ) + const testSheet = new SheetTester(PeopleBook, 'PeopleSheet') test('GroupByField works properly with sum - multiple rows', async () => { - //await TestSchema.checkRows(grps, - const res = await TestSchema.runRowResult(grps) - expect(res[0].info[0]).toMatchObject({ + const res = await testSheet.testMessages(grps) + expect(res[0][0]).toMatchObject({ field: 'name', message: 'No Kids', }) - expect(res[2].info).toStrictEqual([]) + expect(res[2]).toStrictEqual([]) }) }) +/* describe('SampleGroupBy groupConstraint and Comp ->', () => { const TestSchema = new WorkbookTester( { From 94f89580c0e3066404c094bcbd793c1d82d918fd Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Tue, 22 Nov 2022 06:47:10 -0500 Subject: [PATCH 17/36] all tests converted and pass --- examples/features/GroupByField.spec.ts | 58 +++++++++++++------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/examples/features/GroupByField.spec.ts b/examples/features/GroupByField.spec.ts index 0bb05c6..852f35d 100644 --- a/examples/features/GroupByField.spec.ts +++ b/examples/features/GroupByField.spec.ts @@ -106,38 +106,43 @@ describe('SampleGroupBy groupConstraint ->', () => { }) }) -/* -describe('SampleGroupBy groupConstraint and Comp ->', () => { - const TestSchema = new WorkbookTester( - { - job: TextField(), - age: NumberField(), - age_sum: GroupByField( - ['job'], - ['do', - ['groupConstraintRow', - ['quote', ['variable', 'group']], - ['quote', ['when', ['not', ['>', ['count', ['match', {job:'kid'}, ['variable', 'group']]], 0 ]], +const BothSheet = new Sheet( + 'BothSheet', + { + job: TextField(), + age: NumberField(), + age_sum: GroupByField( + ['job'], + ['do', + ['groupConstraintRow', + ['quote', ['variable', 'group']], + ['quote', ['when', ['not', ['>', ['count', ['match', {job:'kid'}, ['variable', 'group']]], 0 ]], ['error', 'No Kids']]], - 'name', - ['variable', 'group']], - ['sumField', ['variable', 'group'], 'age']] - ), - }, - {} - ) - test('GroupByField works properly with groupconstraint and sum - multiple rows', async () => { + 'name', + ['variable', 'group']], + ['sumField', ['variable', 'group'], 'age']] + ), + } +) + +const BothBook = new Workbook({name: 't', namespace: 't', sheets: {BothSheet}}) + +describe('SampleGroupBy groupConstraint and Comp ->', () => { + const testSheet = new SheetTester(BothBook, 'BothSheet') + test('GroupByField works properly with groupconstraint and sum - messages', async () => { //await TestSchema.checkRows(grps, - const res = await TestSchema.runRowResult(grps) + const res = await testSheet.testMessages(grps) // console.log(res[0].info) // console.log(res[2].info) - expect(res[0].info[0]).toMatchObject({ + expect(res[0][0]).toMatchObject({ field: 'name', message: 'No Kids', }) - expect(res[2].info).toStrictEqual([]) - - await TestSchema.checkRows(grps, + expect(res[2]).toStrictEqual([]) + }) + test('GroupByField works properly with groupconstraint and sum - rows', async () => { + const res = await testSheet.testRecords(grps) + expect(res).toStrictEqual( [{ name: 'Paddy', age: 40, job: 'eng', weight: 190, eyeColor: 'green', age_sum: 40 }, { name: 'Cliff', age: 86, job: 'ret', weight: 160, eyeColor: 'gray_', age_sum: 163 }, { name: 'Odin_', age: 3., job: 'kid', weight: 30., eyeColor: 'blue_', age_sum: 11 }, @@ -146,6 +151,3 @@ describe('SampleGroupBy groupConstraint and Comp ->', () => { ) }) }) - - -*/ From 0693b7dc157c021ea025b4e42c7b1bafb01fa6ac Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Tue, 22 Nov 2022 08:14:03 -0500 Subject: [PATCH 18/36] all ExpressionLanguage converted to Expr --- examples/features/GroupByField.spec.ts | 103 ++++++++++++++++--------- src/expression-lang/EXPR.ts | 3 + 2 files changed, 69 insertions(+), 37 deletions(-) diff --git a/examples/features/GroupByField.spec.ts b/examples/features/GroupByField.spec.ts index 852f35d..26d3a66 100644 --- a/examples/features/GroupByField.spec.ts +++ b/examples/features/GroupByField.spec.ts @@ -1,7 +1,17 @@ -//import { Sheet, Workbook } from '@flatfile/configure' import { TextField, NumberField, GroupByField, Sheet, Workbook } from '@flatfile/configure' import { SheetTester, matchMessages, matchSingleMessage } from '../../src/utils/testing/SheetTester' -//import { WorkbookTester } from '../../ddl/WorkbookTester' +import { + Group, + SumField, + Count, + Match, + Error, + GreaterThan, + Unless, + GroupConstraintItem, + Do +} from '../../src/expression-lang/EXPR' + const CountSheet = new Sheet( 'CountSheet', @@ -9,7 +19,7 @@ const CountSheet = new Sheet( category: TextField({}), count_of_instances: GroupByField( ['category'], - ['count', ['variable', 'group']] + Count(Group()) )}) const CountBook = new Workbook({name: 't', namespace: 't', sheets: {CountSheet}}) @@ -29,7 +39,6 @@ describe('SampleGroupByField ->', () => { ]) expect(res).toStrictEqual( - [ { category: 'apple_', count_of_instances: 2 }, { category: 'orange', count_of_instances: 1 }, @@ -41,8 +50,6 @@ describe('SampleGroupByField ->', () => { - - const grps = [ { name: 'Paddy', age: 40, job: 'eng', weight: 190, eyeColor: 'green', age_sum: '0' }, { name: 'Cliff', age: 86, job: 'ret', weight: 160, eyeColor: 'gray_', age_sum: '0' }, @@ -58,43 +65,71 @@ const JobAgeSheet = new Sheet( age: NumberField(), age_sum: GroupByField( ['job'], - ['sumField', ['variable', 'group'], 'age'] + SumField(Group(), 'age') ), } ) + +const SumResults = [ + { name: 'Paddy', age: 40, job: 'eng', weight: 190, eyeColor: 'green', age_sum: 40 }, + { name: 'Cliff', age: 86, job: 'ret', weight: 160, eyeColor: 'gray_', age_sum: 163 }, + { name: 'Odin_', age: 3., job: 'kid', weight: 30., eyeColor: 'blue_', age_sum: 11 }, + { name: 'Kay__', age: 77, job: 'ret', weight: 160, eyeColor: 'green', age_sum: 163 }, + { name: 'Sarah', age: 8., job: 'kid', weight: 60., eyeColor: 'green', age_sum: 11 }] + + const JABook = new Workbook({name: 't', namespace: 't', sheets: {JobAgeSheet}}) describe('SampleGroupBy sum ->', () => { const testSheet = new SheetTester(JABook, 'JobAgeSheet') test('GroupByField works properly with sum - multiple rows', async () => { const res = await testSheet.testRecords(grps) - expect(res).toStrictEqual( - [{ name: 'Paddy', age: 40, job: 'eng', weight: 190, eyeColor: 'green', age_sum: 40 }, - { name: 'Cliff', age: 86, job: 'ret', weight: 160, eyeColor: 'gray_', age_sum: 163 }, - { name: 'Odin_', age: 3., job: 'kid', weight: 30., eyeColor: 'blue_', age_sum: 11 }, - { name: 'Kay__', age: 77, job: 'ret', weight: 160, eyeColor: 'green', age_sum: 163 }, - { name: 'Sarah', age: 8., job: 'kid', weight: 60., eyeColor: 'green', age_sum: 11 }] - ) + expect(res).toStrictEqual(SumResults) }) }) + const PeopleSheet = new Sheet('People', { job: TextField(), age: NumberField(), age_sum: GroupByField( ['job'], + GroupConstraintItem( + Group(), + Unless( + GreaterThan( + Count(Match({job:'kid'}, Group())), + 0), + Error('No Kids')), + 'name', + Group())) + +}) +const PeopleBook = new Workbook({name: 't', namespace: 't', sheets: {PeopleSheet}}) + +describe('SampleGroupBy groupConstraint ->', () => { + + test('GroupConstraintItem outputs properly', () => { + expect(GroupConstraintItem( + Group(), + Unless( + GreaterThan( + Count(Match({job:'kid'}, Group())), + 0), + Error('No Kids')), + 'name', + Group())) + .toStrictEqual( ['groupConstraintRow', ['quote', ['variable', 'group']], ['quote', ['when', ['not', ['>', ['count', ['match', {job:'kid'}, ['variable', 'group']]], 0 ]], ['error', 'No Kids']]], 'name', - ['variable', 'group']]), -}) -const PeopleBook = new Workbook({name: 't', namespace: 't', sheets: {PeopleSheet}}) - -describe('SampleGroupBy groupConstraint ->', () => { + ['variable', 'group']]) + }) + const testSheet = new SheetTester(PeopleBook, 'PeopleSheet') test('GroupByField works properly with sum - multiple rows', async () => { const res = await testSheet.testMessages(grps) @@ -113,14 +148,17 @@ const BothSheet = new Sheet( age: NumberField(), age_sum: GroupByField( ['job'], - ['do', - ['groupConstraintRow', - ['quote', ['variable', 'group']], - ['quote', ['when', ['not', ['>', ['count', ['match', {job:'kid'}, ['variable', 'group']]], 0 ]], - ['error', 'No Kids']]], - 'name', - ['variable', 'group']], - ['sumField', ['variable', 'group'], 'age']] + Do( + GroupConstraintItem( + Group(), + Unless( + GreaterThan( + Count(Match({job:'kid'}, Group())), + 0), + Error('No Kids')), + 'name', + Group()), + SumField(Group(), 'age')) ), } ) @@ -130,10 +168,7 @@ const BothBook = new Workbook({name: 't', namespace: 't', sheets: {BothSheet}}) describe('SampleGroupBy groupConstraint and Comp ->', () => { const testSheet = new SheetTester(BothBook, 'BothSheet') test('GroupByField works properly with groupconstraint and sum - messages', async () => { - //await TestSchema.checkRows(grps, const res = await testSheet.testMessages(grps) - // console.log(res[0].info) - // console.log(res[2].info) expect(res[0][0]).toMatchObject({ field: 'name', message: 'No Kids', @@ -142,12 +177,6 @@ describe('SampleGroupBy groupConstraint and Comp ->', () => { }) test('GroupByField works properly with groupconstraint and sum - rows', async () => { const res = await testSheet.testRecords(grps) - expect(res).toStrictEqual( - [{ name: 'Paddy', age: 40, job: 'eng', weight: 190, eyeColor: 'green', age_sum: 40 }, - { name: 'Cliff', age: 86, job: 'ret', weight: 160, eyeColor: 'gray_', age_sum: 163 }, - { name: 'Odin_', age: 3., job: 'kid', weight: 30., eyeColor: 'blue_', age_sum: 11 }, - { name: 'Kay__', age: 77, job: 'ret', weight: 160, eyeColor: 'green', age_sum: 163 }, - { name: 'Sarah', age: 8., job: 'kid', weight: 60., eyeColor: 'green', age_sum: 11 }] - ) + expect(res).toStrictEqual(SumResults) }) }) diff --git a/src/expression-lang/EXPR.ts b/src/expression-lang/EXPR.ts index c744592..1254487 100644 --- a/src/expression-lang/EXPR.ts +++ b/src/expression-lang/EXPR.ts @@ -80,6 +80,9 @@ export const GroupConstraintItem = ( ] } +export const SumField = (grp:any, field:string) => ['sumField', grp, field] +export const Do = (...exprs:any[]) => ['do', ...exprs] + export const Debug = (expr: NestedIns) => ['debug', expr] From 4d0a857b197793da211d77d9bb1ceae47b472f68 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Tue, 22 Nov 2022 08:20:13 -0500 Subject: [PATCH 19/36] feat: working examples of SheetTester being used with GroupByField --- examples/features/GroupByField.spec.ts | 50 +++++++++----------------- src/expression-lang/EXPR.spec.ts | 18 ++++++++++ 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/examples/features/GroupByField.spec.ts b/examples/features/GroupByField.spec.ts index 26d3a66..fda41b5 100644 --- a/examples/features/GroupByField.spec.ts +++ b/examples/features/GroupByField.spec.ts @@ -51,11 +51,11 @@ describe('SampleGroupByField ->', () => { const grps = [ - { name: 'Paddy', age: 40, job: 'eng', weight: 190, eyeColor: 'green', age_sum: '0' }, - { name: 'Cliff', age: 86, job: 'ret', weight: 160, eyeColor: 'gray_', age_sum: '0' }, - { name: 'Odin_', age: 3., job: 'kid', weight: 30., eyeColor: 'blue_', age_sum: '0' }, - { name: 'Kay__', age: 77, job: 'ret', weight: 160, eyeColor: 'green', age_sum: '0' }, - { name: 'Sarah', age: 8., job: 'kid', weight: 60., eyeColor: 'green', age_sum: '0' }] + { name: 'Paddy', age: 40, job: 'eng', weight: 190, eye_color: 'green', age_sum: '0' }, + { name: 'Cliff', age: 86, job: 'ret', weight: 160, eye_color: 'gray_', age_sum: '0' }, + { name: 'Odin_', age: 3., job: 'kid', weight: 30., eye_color: 'blue_', age_sum: '0' }, + { name: 'Kay__', age: 77, job: 'ret', weight: 160, eye_color: 'green', age_sum: '0' }, + { name: 'Sarah', age: 8., job: 'kid', weight: 60., eye_color: 'green', age_sum: '0' }] const JobAgeSheet = new Sheet( @@ -71,11 +71,11 @@ const JobAgeSheet = new Sheet( ) const SumResults = [ - { name: 'Paddy', age: 40, job: 'eng', weight: 190, eyeColor: 'green', age_sum: 40 }, - { name: 'Cliff', age: 86, job: 'ret', weight: 160, eyeColor: 'gray_', age_sum: 163 }, - { name: 'Odin_', age: 3., job: 'kid', weight: 30., eyeColor: 'blue_', age_sum: 11 }, - { name: 'Kay__', age: 77, job: 'ret', weight: 160, eyeColor: 'green', age_sum: 163 }, - { name: 'Sarah', age: 8., job: 'kid', weight: 60., eyeColor: 'green', age_sum: 11 }] + { name: 'Paddy', age: 40, job: 'eng', weight: 190, eye_color: 'green', age_sum: 40 }, + { name: 'Cliff', age: 86, job: 'ret', weight: 160, eye_color: 'gray_', age_sum: 163 }, + { name: 'Odin_', age: 3., job: 'kid', weight: 30., eye_color: 'blue_', age_sum: 11 }, + { name: 'Kay__', age: 77, job: 'ret', weight: 160, eye_color: 'green', age_sum: 163 }, + { name: 'Sarah', age: 8., job: 'kid', weight: 60., eye_color: 'green', age_sum: 11 }] const JABook = new Workbook({name: 't', namespace: 't', sheets: {JobAgeSheet}}) @@ -100,9 +100,9 @@ const PeopleSheet = new Sheet('People', Group(), Unless( GreaterThan( - Count(Match({job:'kid'}, Group())), + Count(Match({eye_color: 'blue_'}, Group())), 0), - Error('No Kids')), + Error('No Blue eyes')), 'name', Group())) @@ -111,31 +111,13 @@ const PeopleBook = new Workbook({name: 't', namespace: 't', sheets: {PeopleSheet describe('SampleGroupBy groupConstraint ->', () => { - test('GroupConstraintItem outputs properly', () => { - expect(GroupConstraintItem( - Group(), - Unless( - GreaterThan( - Count(Match({job:'kid'}, Group())), - 0), - Error('No Kids')), - 'name', - Group())) - .toStrictEqual( - ['groupConstraintRow', - ['quote', ['variable', 'group']], - ['quote', ['when', ['not', ['>', ['count', ['match', {job:'kid'}, ['variable', 'group']]], 0 ]], - ['error', 'No Kids']]], - 'name', - ['variable', 'group']]) - }) const testSheet = new SheetTester(PeopleBook, 'PeopleSheet') test('GroupByField works properly with sum - multiple rows', async () => { const res = await testSheet.testMessages(grps) expect(res[0][0]).toMatchObject({ field: 'name', - message: 'No Kids', + message: 'No Blue eyes', }) expect(res[2]).toStrictEqual([]) }) @@ -153,9 +135,9 @@ const BothSheet = new Sheet( Group(), Unless( GreaterThan( - Count(Match({job:'kid'}, Group())), + Count(Match({eye_color: 'blue_'}, Group())), 0), - Error('No Kids')), + Error('No Blue eyes')), 'name', Group()), SumField(Group(), 'age')) @@ -171,7 +153,7 @@ describe('SampleGroupBy groupConstraint and Comp ->', () => { const res = await testSheet.testMessages(grps) expect(res[0][0]).toMatchObject({ field: 'name', - message: 'No Kids', + message: 'No Blue eyes', }) expect(res[2]).toStrictEqual([]) }) diff --git a/src/expression-lang/EXPR.spec.ts b/src/expression-lang/EXPR.spec.ts index 197b649..c54c846 100644 --- a/src/expression-lang/EXPR.spec.ts +++ b/src/expression-lang/EXPR.spec.ts @@ -144,4 +144,22 @@ describe('GroupConstraint Tests ->', () => { message: 'No Kids', }) }) + test('GroupConstraintItem outputs properly', () => { + expect(GroupConstraintItem( + Group(), + Unless( + GreaterThan( + Count(Match({job:'kid'}, Group())), + 0), + Error('No Kids')), + 'name', + Group())) + .toStrictEqual( + ['groupConstraintRow', + ['quote', ['variable', 'group']], + ['quote', ['when', ['not', ['>', ['count', ['match', {job:'kid'}, ['variable', 'group']]], 0 ]], + ['error', 'No Kids']]], + 'name', + ['variable', 'group']]) + }) }) From ea1a7ca3535326f3246b83fa95de756fca3383ed Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Tue, 22 Nov 2022 10:07:49 -0500 Subject: [PATCH 20/36] added key explanation note --- examples/features/GroupByField.spec.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/features/GroupByField.spec.ts b/examples/features/GroupByField.spec.ts index fda41b5..dc10535 100644 --- a/examples/features/GroupByField.spec.ts +++ b/examples/features/GroupByField.spec.ts @@ -130,6 +130,9 @@ const BothSheet = new Sheet( age: NumberField(), age_sum: GroupByField( ['job'], + // NOTE THE USE OF DO HERE... + // Do allows multiple expressions to be executed and the result + // of the last one is returned... in this case "SumField" Do( GroupConstraintItem( Group(), From 4654b272a5ac12d9088d10ff69507e751e19e570 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Thu, 1 Dec 2022 18:39:07 -0500 Subject: [PATCH 21/36] added more tests --- examples/features/GroupByField.spec.ts | 37 ++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/examples/features/GroupByField.spec.ts b/examples/features/GroupByField.spec.ts index dc10535..c70b46f 100644 --- a/examples/features/GroupByField.spec.ts +++ b/examples/features/GroupByField.spec.ts @@ -12,6 +12,43 @@ import { Do } from '../../src/expression-lang/EXPR' +const tgrps = [ + { name: 'Odin_', age: 3., job: 'kid', weight: 30., eye_color: 'blue_', fav_group: 'Raffi', age_sum: '0' }, + { name: 'Sarah', age: 8., job: 'kid', weight: 60., eye_color: 'green', fav_group: 'Wiggles', age_sum: '0' }, + { name: 'Paddy', age: 40, job: 'eng', weight: 190, eye_color: 'green', fav_group: 'Wiggles', age_sum: '0' }, + { name: 'Kay__', age: 77, job: 'ret', weight: 160, eye_color: 'green', fav_group: 'Beach Boys', age_sum: '0' }, + { name: 'Cliff', age: 86, job: 'ret', weight: 160, eye_color: 'gray_', fav_group: 'The Stones', age_sum: '0' }, + { name: 'Franz', age: 72, job: 'ret', weight: 170, eye_color: 'blue_', fav_group: 'Beach Boys', age_sum: '0' }, +] + + +const UniquePeopleSheet = new Sheet('People', + { + job: TextField(), + age: NumberField(), + age_sum: GroupByField( + ['job'], + GroupConstraintItem( + ['nonUnique', 'fav_group'], Error('fav_group must be unique'), + 'fav_group', Group())) +}) +const UniquePeopleBook = new Workbook({name: 't', namespace: 't', sheets: {UniquePeopleSheet}}) + +describe('SampleGroupBy groupConstraint 2 ->', () => { + + + const testSheet = new SheetTester(UniquePeopleBook, 'UniquePeopleSheet') + test('GroupByField works properly with sum - multiple rows', async () => { + const res = await testSheet.testMessages(tgrps) + console.log(res) + expect(res[3][0]).toMatchObject({ + field: 'fav_group', + message: 'fav_group must be unique', + }) + expect(res[4]).toStrictEqual([]) + }) +}) + const CountSheet = new Sheet( 'CountSheet', From 8acc6fe32c21ba3c3c4b33b5eb4f263017208423 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Tue, 6 Dec 2022 11:30:51 -0500 Subject: [PATCH 22/36] chore:bumped to latest versions --- package-lock.json | 1151 +++++++++++++++++++++++---------------------- package.json | 4 +- 2 files changed, 590 insertions(+), 565 deletions(-) diff --git a/package-lock.json b/package-lock.json index 619cf36..1f50c73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,30 +51,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.4.tgz", - "integrity": "sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.5.tgz", + "integrity": "sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz", - "integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.5.tgz", + "integrity": "sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", - "@babel/helper-compilation-targets": "^7.19.3", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.3", + "@babel/generator": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-module-transforms": "^7.20.2", + "@babel/helpers": "^7.20.5", + "@babel/parser": "^7.20.5", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.3", - "@babel/types": "^7.19.3", + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -99,12 +99,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.19.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.5.tgz", - "integrity": "sha512-DxbNz9Lz4aMZ99qPpO1raTbcrI1ZeYh+9NR9qhfkQIbFtVEqotHojEBxHzmxhVONkGt6VyrqVQcgpefMy9pqcg==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", + "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", "dev": true, "dependencies": { - "@babel/types": "^7.19.4", + "@babel/types": "^7.20.5", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -127,12 +127,12 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz", - "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", + "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.19.3", + "@babel/compat-data": "^7.20.0", "@babel/helper-validator-option": "^7.18.6", "browserslist": "^4.21.3", "semver": "^6.3.0" @@ -200,40 +200,40 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz", + "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", - "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", "dev": true, "dependencies": { - "@babel/types": "^7.19.4" + "@babel/types": "^7.20.2" }, "engines": { "node": ">=6.9.0" @@ -279,14 +279,14 @@ } }, "node_modules/@babel/helpers": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.4.tgz", - "integrity": "sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw==", + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz", + "integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==", "dev": true, "dependencies": { "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.4", - "@babel/types": "^7.19.4" + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5" }, "engines": { "node": ">=6.9.0" @@ -378,9 +378,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.4.tgz", - "integrity": "sha512-qpVT7gtuOLjWeDTKLkJ6sryqLliBaFpAtGeqw5cs5giLldvh+Ch0plqnUMKoVAUS6ZEueQQiZV+p5pxtPitEsA==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", + "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -537,12 +537,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", - "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", + "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -566,19 +566,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.4.tgz", - "integrity": "sha512-w3K1i+V5u2aJUOXBFFC5pveFLmtq1s3qcdDNC2qRI6WPBQIDaKFqXxDEqDO/h1dQ3HjsZoZMyIy6jGLq0xtw+g==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", + "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.4", + "@babel/generator": "^7.20.5", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.4", - "@babel/types": "^7.19.4", + "@babel/parser": "^7.20.5", + "@babel/types": "^7.20.5", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -596,9 +596,9 @@ } }, "node_modules/@babel/types": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", - "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", + "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.19.4", @@ -616,9 +616,9 @@ "dev": true }, "node_modules/@esbuild/android-arm": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.10.tgz", - "integrity": "sha512-FNONeQPy/ox+5NBkcSbYJxoXj9GWu8gVGJTVmUyoOCKQFDTrHVKgNSzChdNt0I8Aj/iKcsDf2r9BFwv+FSNUXg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", + "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", "cpu": [ "arm" ], @@ -632,9 +632,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.10.tgz", - "integrity": "sha512-w0Ou3Z83LOYEkwaui2M8VwIp+nLi/NA60lBLMvaJ+vXVMcsARYdEzLNE7RSm4+lSg4zq4d7fAVuzk7PNQ5JFgg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", + "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", "cpu": [ "loong64" ], @@ -671,9 +671,9 @@ } }, "node_modules/@flatfile/configure": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/@flatfile/configure/-/configure-0.4.7.tgz", - "integrity": "sha512-f7i/sXvJAWzHsrG7sHZAseJ5sDjZSCrbwvWs+k94D2pxmX7DQ1PE8UaLr77dHwiqSldy7HYUg3YIx28oUGZ82A==", + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/@flatfile/configure/-/configure-0.4.8.tgz", + "integrity": "sha512-3R068RvP6TBew4YsH8C0ECe7LdzqPpauHJEo4XB+Miw6PmAlEUg9Bg/DLwaFQnIKoRCHGxfXRXXSyL1ltAfakA==", "dev": true, "dependencies": { "@flatfile/orm": "*", @@ -703,9 +703,9 @@ "dev": true }, "node_modules/@flatfile/schema": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@flatfile/schema/-/schema-0.2.1.tgz", - "integrity": "sha512-IoWrZfGG35vk2ONTBtbF8usRuf4ocQVeS7fOlLs4nP1Vr7JJFoob4D4qL1FJN3/bV7jJpiG0borl4wP5EOx8iQ==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@flatfile/schema/-/schema-0.2.3.tgz", + "integrity": "sha512-MQjvyuAHD9P9OyjYlK3oooAOAbKZQqJM1pVBYKExVUz2bLIUcFYAhGIZgcBsy/TKfn6rCr2JmbOaGWij0EyLGQ==", "dev": true, "dependencies": { "lodash": "^4.17.21", @@ -713,14 +713,14 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.10.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", - "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", + "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" @@ -1170,9 +1170,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.16", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.16.tgz", - "integrity": "sha512-LCQ+NeThyJ4k1W2d+vIKdxuSt9R3pQSZ4P92m7EakaYuXcVWbHuT5bjNcqLd4Rdgi6xYWYDvBJZJLZSLanjDcA==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "3.1.0", @@ -1215,15 +1215,15 @@ } }, "node_modules/@sinclair/typebox": { - "version": "0.24.46", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.46.tgz", - "integrity": "sha512-ng4ut1z2MCBhK/NwDVwIQp3pAUOCs/KNaW3cBxdFB2xTDrOuo1xuNmpr/9HHFhxqIvHrs1NTH3KJg6q+JSy1Kw==", + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", "dev": true }, "node_modules/@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", "dev": true, "dependencies": { "type-detect": "4.0.8" @@ -1239,9 +1239,9 @@ } }, "node_modules/@types/babel__core": { - "version": "7.1.19", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", - "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "version": "7.1.20", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", + "integrity": "sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==", "dev": true, "dependencies": { "@babel/parser": "^7.1.0", @@ -1271,9 +1271,9 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.2.tgz", - "integrity": "sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg==", + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", + "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", "dev": true, "dependencies": { "@babel/types": "^7.3.0" @@ -1323,15 +1323,15 @@ } }, "node_modules/@types/lodash": { - "version": "4.14.186", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.186.tgz", - "integrity": "sha512-eHcVlLXP0c2FlMPm56ITode2AgLMSa6aJ05JTTbYbI+7EMkCEE5qk2E41d5g2lCVTqRe0GnnRFurmlCsDODrPw==", + "version": "4.14.191", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", + "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", "dev": true }, "node_modules/@types/node": { - "version": "18.8.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.5.tgz", - "integrity": "sha512-Bq7G3AErwe5A/Zki5fdD3O6+0zDChhg671NfPjtIcbtzDNZTv4NPKMRFr7gtYPG7y+B8uTiNK4Ngd9T0FTar6Q==", + "version": "18.11.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.11.tgz", + "integrity": "sha512-KJ021B1nlQUBLopzZmPBVuGU9un7WJd/W4ya7Ih02B4Uwky5Nja0yGYav2EfYIk0RR2Q9oVhf60S2XR1BCWJ2g==", "dev": true }, "node_modules/@types/node-fetch": { @@ -1357,9 +1357,9 @@ "dev": true }, "node_modules/@types/yargs": { - "version": "17.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", - "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", + "version": "17.0.15", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.15.tgz", + "integrity": "sha512-ZHc4W2dnEQPfhn06TBEdWaiUHEZAocYaiVMfwOipY5jcJt/251wVrKCBWBetGZWO5CF8tdb7L3DmdxVlZ2BOIg==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -1372,14 +1372,14 @@ "dev": true }, "node_modules/@typescript-eslint/parser": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.40.0.tgz", - "integrity": "sha512-Ah5gqyX2ySkiuYeOIDg7ap51/b63QgWZA7w6AHtFrag7aH0lRQPbLzUjk0c9o5/KZ6JRkTTDKShL4AUrQa6/hw==", + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.45.1.tgz", + "integrity": "sha512-JQ3Ep8bEOXu16q0ztsatp/iQfDCtvap7sp/DKo7DWltUquj5AfCOpX2zSzJ8YkAVnrQNqQ5R62PBz2UtrfmCkA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.40.0", - "@typescript-eslint/types": "5.40.0", - "@typescript-eslint/typescript-estree": "5.40.0", + "@typescript-eslint/scope-manager": "5.45.1", + "@typescript-eslint/types": "5.45.1", + "@typescript-eslint/typescript-estree": "5.45.1", "debug": "^4.3.4" }, "engines": { @@ -1399,13 +1399,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.40.0.tgz", - "integrity": "sha512-d3nPmjUeZtEWRvyReMI4I1MwPGC63E8pDoHy0BnrYjnJgilBD3hv7XOiETKLY/zTwI7kCnBDf2vWTRUVpYw0Uw==", + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.45.1.tgz", + "integrity": "sha512-D6fCileR6Iai7E35Eb4Kp+k0iW7F1wxXYrOhX/3dywsOJpJAQ20Fwgcf+P/TDtvQ7zcsWsrJaglaQWDhOMsspQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.40.0", - "@typescript-eslint/visitor-keys": "5.40.0" + "@typescript-eslint/types": "5.45.1", + "@typescript-eslint/visitor-keys": "5.45.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1416,9 +1416,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.40.0.tgz", - "integrity": "sha512-V1KdQRTXsYpf1Y1fXCeZ+uhjW48Niiw0VGt4V8yzuaDTU8Z1Xl7yQDyQNqyAFcVhpYXIVCEuxSIWTsLDpHgTbw==", + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.45.1.tgz", + "integrity": "sha512-HEW3U0E5dLjUT+nk7b4lLbOherS1U4ap+b9pfu2oGsW3oPu7genRaY9dDv3nMczC1rbnRY2W/D7SN05wYoGImg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1429,13 +1429,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.40.0.tgz", - "integrity": "sha512-b0GYlDj8TLTOqwX7EGbw2gL5EXS2CPEWhF9nGJiGmEcmlpNBjyHsTwbqpyIEPVpl6br4UcBOYlcI2FJVtJkYhg==", + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.45.1.tgz", + "integrity": "sha512-76NZpmpCzWVrrb0XmYEpbwOz/FENBi+5W7ipVXAsG3OoFrQKJMiaqsBMbvGRyLtPotGqUfcY7Ur8j0dksDJDng==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.40.0", - "@typescript-eslint/visitor-keys": "5.40.0", + "@typescript-eslint/types": "5.45.1", + "@typescript-eslint/visitor-keys": "5.45.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1456,12 +1456,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.40.0.tgz", - "integrity": "sha512-ijJ+6yig+x9XplEpG2K6FUdJeQGGj/15U3S56W9IqXKJqleuD7zJ2AX/miLezwxpd7ZxDAqO87zWufKg+RPZyQ==", + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.45.1.tgz", + "integrity": "sha512-cy9ln+6rmthYWjH9fmx+5FU/JDpjQb586++x2FZlveq7GdGuLLW9a2Jcst2TGekH82bXpfmRNSwP9tyEs6RjvQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.40.0", + "@typescript-eslint/types": "5.45.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -1473,9 +1473,9 @@ } }, "node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1567,9 +1567,9 @@ "dev": true }, "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "dependencies": { "normalize-path": "^3.0.0", @@ -1839,9 +1839,9 @@ "dev": true }, "node_modules/bundle-require": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-3.1.0.tgz", - "integrity": "sha512-IIXtAO7fKcwPHNPt9kY/WNVJqy7NDy6YqJvv6ENH0TOZoJ+yjpEsn1w40WKZbR2ibfu5g1rfgJTvmFHpm5aOMA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-3.1.2.tgz", + "integrity": "sha512-Of6l6JBAxiyQ5axFxUM6dYeP/W7X2Sozeo/4EYB9sJhL+dqL7TKjg+shwxp6jlu/6ZSERfsYtIpSJ1/x3XkAEA==", "dev": true, "dependencies": { "load-tsconfig": "^0.2.0" @@ -1881,9 +1881,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001418", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz", - "integrity": "sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==", + "version": "1.0.30001436", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001436.tgz", + "integrity": "sha512-ZmWkKsnC2ifEPoWUvSAIGyOYwT+keAaaWPHiQ9DfMqS1t6tfuyFYoWR78TeZtznkEQ64+vGXH9cZrElwR2Mrxg==", "dev": true, "funding": [ { @@ -1973,10 +1973,13 @@ } }, "node_modules/ci-info": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz", - "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==", - "dev": true + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz", + "integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==", + "dev": true, + "engines": { + "node": ">=8" + } }, "node_modules/cjs-module-lexer": { "version": "1.2.2", @@ -2274,9 +2277,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.281", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.281.tgz", - "integrity": "sha512-yer0w5wCYdFoZytfmbNhwiGI/3cW06+RV7E23ln4490DVMxs7PvYpbsrSmAiBn/V6gode8wvJlST2YfWgvzWIg==", + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", "dev": true }, "node_modules/emittery": { @@ -2307,9 +2310,9 @@ } }, "node_modules/esbuild": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.10.tgz", - "integrity": "sha512-N7wBhfJ/E5fzn/SpNgX+oW2RLRjwaL8Y0ezqNqhjD6w0H2p0rDuEz2FKZqpqLnO8DCaWumKe8dsC/ljvVSSxng==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", + "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", "dev": true, "hasInstallScript": true, "bin": { @@ -2319,34 +2322,34 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.15.10", - "@esbuild/linux-loong64": "0.15.10", - "esbuild-android-64": "0.15.10", - "esbuild-android-arm64": "0.15.10", - "esbuild-darwin-64": "0.15.10", - "esbuild-darwin-arm64": "0.15.10", - "esbuild-freebsd-64": "0.15.10", - "esbuild-freebsd-arm64": "0.15.10", - "esbuild-linux-32": "0.15.10", - "esbuild-linux-64": "0.15.10", - "esbuild-linux-arm": "0.15.10", - "esbuild-linux-arm64": "0.15.10", - "esbuild-linux-mips64le": "0.15.10", - "esbuild-linux-ppc64le": "0.15.10", - "esbuild-linux-riscv64": "0.15.10", - "esbuild-linux-s390x": "0.15.10", - "esbuild-netbsd-64": "0.15.10", - "esbuild-openbsd-64": "0.15.10", - "esbuild-sunos-64": "0.15.10", - "esbuild-windows-32": "0.15.10", - "esbuild-windows-64": "0.15.10", - "esbuild-windows-arm64": "0.15.10" + "@esbuild/android-arm": "0.15.18", + "@esbuild/linux-loong64": "0.15.18", + "esbuild-android-64": "0.15.18", + "esbuild-android-arm64": "0.15.18", + "esbuild-darwin-64": "0.15.18", + "esbuild-darwin-arm64": "0.15.18", + "esbuild-freebsd-64": "0.15.18", + "esbuild-freebsd-arm64": "0.15.18", + "esbuild-linux-32": "0.15.18", + "esbuild-linux-64": "0.15.18", + "esbuild-linux-arm": "0.15.18", + "esbuild-linux-arm64": "0.15.18", + "esbuild-linux-mips64le": "0.15.18", + "esbuild-linux-ppc64le": "0.15.18", + "esbuild-linux-riscv64": "0.15.18", + "esbuild-linux-s390x": "0.15.18", + "esbuild-netbsd-64": "0.15.18", + "esbuild-openbsd-64": "0.15.18", + "esbuild-sunos-64": "0.15.18", + "esbuild-windows-32": "0.15.18", + "esbuild-windows-64": "0.15.18", + "esbuild-windows-arm64": "0.15.18" } }, "node_modules/esbuild-android-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.10.tgz", - "integrity": "sha512-UI7krF8OYO1N7JYTgLT9ML5j4+45ra3amLZKx7LO3lmLt1Ibn8t3aZbX5Pu4BjWiqDuJ3m/hsvhPhK/5Y/YpnA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", + "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", "cpu": [ "x64" ], @@ -2360,9 +2363,9 @@ } }, "node_modules/esbuild-android-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.10.tgz", - "integrity": "sha512-EOt55D6xBk5O05AK8brXUbZmoFj4chM8u3riGflLa6ziEoVvNjRdD7Cnp82NHQGfSHgYR06XsPI8/sMuA/cUwg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", + "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", "cpu": [ "arm64" ], @@ -2376,9 +2379,9 @@ } }, "node_modules/esbuild-darwin-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.10.tgz", - "integrity": "sha512-hbDJugTicqIm+WKZgp208d7FcXcaK8j2c0l+fqSJ3d2AzQAfjEYDRM3Z2oMeqSJ9uFxyj/muSACLdix7oTstRA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", + "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", "cpu": [ "x64" ], @@ -2392,9 +2395,9 @@ } }, "node_modules/esbuild-darwin-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.10.tgz", - "integrity": "sha512-M1t5+Kj4IgSbYmunf2BB6EKLkWUq+XlqaFRiGOk8bmBapu9bCDrxjf4kUnWn59Dka3I27EiuHBKd1rSO4osLFQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", + "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", "cpu": [ "arm64" ], @@ -2408,9 +2411,9 @@ } }, "node_modules/esbuild-freebsd-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.10.tgz", - "integrity": "sha512-KMBFMa7C8oc97nqDdoZwtDBX7gfpolkk6Bcmj6YFMrtCMVgoU/x2DI1p74DmYl7CSS6Ppa3xgemrLrr5IjIn0w==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", + "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", "cpu": [ "x64" ], @@ -2424,9 +2427,9 @@ } }, "node_modules/esbuild-freebsd-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.10.tgz", - "integrity": "sha512-m2KNbuCX13yQqLlbSojFMHpewbn8wW5uDS6DxRpmaZKzyq8Dbsku6hHvh2U+BcLwWY4mpgXzFUoENEf7IcioGg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", + "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", "cpu": [ "arm64" ], @@ -2440,9 +2443,9 @@ } }, "node_modules/esbuild-linux-32": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.10.tgz", - "integrity": "sha512-guXrwSYFAvNkuQ39FNeV4sNkNms1bLlA5vF1H0cazZBOLdLFIny6BhT+TUbK/hdByMQhtWQ5jI9VAmPKbVPu1w==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", + "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", "cpu": [ "ia32" ], @@ -2456,9 +2459,9 @@ } }, "node_modules/esbuild-linux-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.10.tgz", - "integrity": "sha512-jd8XfaSJeucMpD63YNMO1JCrdJhckHWcMv6O233bL4l6ogQKQOxBYSRP/XLWP+6kVTu0obXovuckJDcA0DKtQA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", + "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", "cpu": [ "x64" ], @@ -2472,9 +2475,9 @@ } }, "node_modules/esbuild-linux-arm": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.10.tgz", - "integrity": "sha512-6N8vThLL/Lysy9y4Ex8XoLQAlbZKUyExCWyayGi2KgTBelKpPgj6RZnUaKri0dHNPGgReJriKVU6+KDGQwn10A==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", + "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", "cpu": [ "arm" ], @@ -2488,9 +2491,9 @@ } }, "node_modules/esbuild-linux-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.10.tgz", - "integrity": "sha512-GByBi4fgkvZFTHFDYNftu1DQ1GzR23jws0oWyCfhnI7eMOe+wgwWrc78dbNk709Ivdr/evefm2PJiUBMiusS1A==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", + "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", "cpu": [ "arm64" ], @@ -2504,9 +2507,9 @@ } }, "node_modules/esbuild-linux-mips64le": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.10.tgz", - "integrity": "sha512-BxP+LbaGVGIdQNJUNF7qpYjEGWb0YyHVSKqYKrn+pTwH/SiHUxFyJYSP3pqkku61olQiSBnSmWZ+YUpj78Tw7Q==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", + "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", "cpu": [ "mips64el" ], @@ -2520,9 +2523,9 @@ } }, "node_modules/esbuild-linux-ppc64le": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.10.tgz", - "integrity": "sha512-LoSQCd6498PmninNgqd/BR7z3Bsk/mabImBWuQ4wQgmQEeanzWd5BQU2aNi9mBURCLgyheuZS6Xhrw5luw3OkQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", + "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", "cpu": [ "ppc64" ], @@ -2536,9 +2539,9 @@ } }, "node_modules/esbuild-linux-riscv64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.10.tgz", - "integrity": "sha512-Lrl9Cr2YROvPV4wmZ1/g48httE8z/5SCiXIyebiB5N8VT7pX3t6meI7TQVHw/wQpqP/AF4SksDuFImPTM7Z32Q==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", + "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", "cpu": [ "riscv64" ], @@ -2552,9 +2555,9 @@ } }, "node_modules/esbuild-linux-s390x": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.10.tgz", - "integrity": "sha512-ReP+6q3eLVVP2lpRrvl5EodKX7EZ1bS1/z5j6hsluAlZP5aHhk6ghT6Cq3IANvvDdscMMCB4QEbI+AjtvoOFpA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", + "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", "cpu": [ "s390x" ], @@ -2568,9 +2571,9 @@ } }, "node_modules/esbuild-netbsd-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.10.tgz", - "integrity": "sha512-iGDYtJCMCqldMskQ4eIV+QSS/CuT7xyy9i2/FjpKvxAuCzrESZXiA1L64YNj6/afuzfBe9i8m/uDkFHy257hTw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", + "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", "cpu": [ "x64" ], @@ -2584,9 +2587,9 @@ } }, "node_modules/esbuild-openbsd-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.10.tgz", - "integrity": "sha512-ftMMIwHWrnrYnvuJQRJs/Smlcb28F9ICGde/P3FUTCgDDM0N7WA0o9uOR38f5Xe2/OhNCgkjNeb7QeaE3cyWkQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", + "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", "cpu": [ "x64" ], @@ -2600,9 +2603,9 @@ } }, "node_modules/esbuild-sunos-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.10.tgz", - "integrity": "sha512-mf7hBL9Uo2gcy2r3rUFMjVpTaGpFJJE5QTDDqUFf1632FxteYANffDZmKbqX0PfeQ2XjUDE604IcE7OJeoHiyg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", + "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", "cpu": [ "x64" ], @@ -2616,9 +2619,9 @@ } }, "node_modules/esbuild-windows-32": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.10.tgz", - "integrity": "sha512-ttFVo+Cg8b5+qHmZHbEc8Vl17kCleHhLzgT8X04y8zudEApo0PxPg9Mz8Z2cKH1bCYlve1XL8LkyXGFjtUYeGg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", + "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", "cpu": [ "ia32" ], @@ -2632,9 +2635,9 @@ } }, "node_modules/esbuild-windows-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.10.tgz", - "integrity": "sha512-2H0gdsyHi5x+8lbng3hLbxDWR7mKHWh5BXZGKVG830KUmXOOWFE2YKJ4tHRkejRduOGDrBvHBriYsGtmTv3ntA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", + "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", "cpu": [ "x64" ], @@ -2648,9 +2651,9 @@ } }, "node_modules/esbuild-windows-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.10.tgz", - "integrity": "sha512-S+th4F+F8VLsHLR0zrUcG+Et4hx0RKgK1eyHc08kztmLOES8BWwMiaGdoW9hiXuzznXQ0I/Fg904MNbr11Nktw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", + "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", "cpu": [ "arm64" ], @@ -2685,14 +2688,15 @@ } }, "node_modules/eslint": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.25.0.tgz", - "integrity": "sha512-DVlJOZ4Pn50zcKW5bYH7GQK/9MsoQG2d5eDH0ebEkE8PbgzTTmtt/VTH9GGJ4BfeZCpBLqFfvsjX35UacUL83A==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", + "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", "dev": true, "dependencies": { "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.10.5", + "@humanwhocodes/config-array": "^0.11.6", "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -2708,14 +2712,14 @@ "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", - "glob-parent": "^6.0.1", + "glob-parent": "^6.0.2", "globals": "^13.15.0", - "globby": "^11.1.0", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", @@ -2801,9 +2805,9 @@ } }, "node_modules/espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", "dev": true, "dependencies": { "acorn": "^8.8.0", @@ -2979,9 +2983,9 @@ "dev": true }, "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", + "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -3082,9 +3086,9 @@ } }, "node_modules/flatfile": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/flatfile/-/flatfile-3.1.0.tgz", - "integrity": "sha512-DIllGnB377RPqyIYvkr74oMJ+tqUXzUcFSlDpVOn10n58ns96siYTwek5VvDns/R6S9+t7mxI/LCVNC0e0y5YQ==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/flatfile/-/flatfile-3.1.5.tgz", + "integrity": "sha512-8bzhqkjXajrSY6wRipqPlTXpcn6Fq5xccRMPmvxZAWmAGvRMSuXnicVUnteAfdxyNlvTVWC7ucLr/hcocgNs8w==", "dev": true, "dependencies": { "@types/node-fetch": "^2.6.2", @@ -3252,9 +3256,9 @@ } }, "node_modules/globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "version": "13.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", + "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -3378,9 +3382,9 @@ ] }, "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", + "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", "dev": true, "engines": { "node": ">= 4" @@ -3465,9 +3469,9 @@ } }, "node_modules/is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -3533,6 +3537,15 @@ "node": ">=0.12.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -3942,9 +3955,9 @@ } }, "node_modules/jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, "engines": { "node": ">=6" @@ -4203,10 +4216,14 @@ } }, "node_modules/js-sdsl": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", - "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", - "dev": true + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } }, "node_modules/js-tokens": { "version": "4.0.0", @@ -4542,9 +4559,9 @@ } }, "node_modules/node-fetch": { - "version": "3.2.10", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.10.tgz", - "integrity": "sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.0.tgz", + "integrity": "sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==", "dev": true, "dependencies": { "data-uri-to-buffer": "^4.0.0", @@ -4906,9 +4923,9 @@ } }, "node_modules/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.0.tgz", + "integrity": "sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==", "dev": true, "bin": { "prettier": "bin-prettier.js" @@ -5143,15 +5160,16 @@ } }, "node_modules/rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.6.0.tgz", + "integrity": "sha512-qCgiBeSu2/AIOKWGFMiRkjPlGlcVwxAjwpGKQZOQYng+83Hip4PjrWHm7EQX1wnrvRqfTytEihRRfLHdX+hR4g==", "dev": true, "bin": { "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=10.0.0" + "node": ">=14.18.0", + "npm": ">=8.0.0" }, "optionalDependencies": { "fsevents": "~2.3.2" @@ -5289,9 +5307,9 @@ "dev": true }, "node_modules/stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, "dependencies": { "escape-string-regexp": "^2.0.0" @@ -5388,9 +5406,9 @@ } }, "node_modules/sucrase": { - "version": "3.28.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.28.0.tgz", - "integrity": "sha512-TK9600YInjuiIhVM3729rH4ZKPOsGeyXUwY+Ugu9eilNbdTFyHr6XcAGYbRVZPDgWj6tgI7bx95aaJjHnbffag==", + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.29.0.tgz", + "integrity": "sha512-bZPAuGA5SdFHuzqIhTAqt9fvNEo9rESqXIG3oiKdF8K4UmkQxC4KlNL3lVyAErXp+mPvUqZ5l13qx6TrDIGf3A==", "dev": true, "dependencies": { "commander": "^4.0.0", @@ -5629,12 +5647,12 @@ "dev": true }, "node_modules/tsup": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/tsup/-/tsup-6.2.3.tgz", - "integrity": "sha512-J5Pu2Dx0E1wlpIEsVFv9ryzP1pZ1OYsJ2cBHZ7GrKteytNdzaSz5hmLX7/nAxtypq+jVkVvA79d7S83ETgHQ5w==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/tsup/-/tsup-6.5.0.tgz", + "integrity": "sha512-36u82r7rYqRHFkD15R20Cd4ercPkbYmuvRkz3Q1LCm5BsiFNUgpo36zbjVhCOgvjyxNBWNKHsaD5Rl8SykfzNA==", "dev": true, "dependencies": { - "bundle-require": "^3.1.0", + "bundle-require": "^3.1.2", "cac": "^6.7.12", "chokidar": "^3.5.1", "debug": "^4.3.1", @@ -5644,7 +5662,7 @@ "joycon": "^3.0.1", "postcss-load-config": "^3.0.1", "resolve-from": "^5.0.0", - "rollup": "^2.74.1", + "rollup": "^3.2.5", "source-map": "0.8.0-beta.0", "sucrase": "^3.20.3", "tree-kill": "^1.2.2" @@ -5769,9 +5787,9 @@ } }, "node_modules/typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", + "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", "dev": true, "peer": true, "bin": { @@ -5965,9 +5983,9 @@ } }, "node_modules/yargs": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", - "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", "dev": true, "dependencies": { "cliui": "^8.0.1", @@ -5976,7 +5994,7 @@ "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" + "yargs-parser": "^21.1.1" }, "engines": { "node": ">=12" @@ -6025,27 +6043,27 @@ } }, "@babel/compat-data": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.4.tgz", - "integrity": "sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.5.tgz", + "integrity": "sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==", "dev": true }, "@babel/core": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz", - "integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.5.tgz", + "integrity": "sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==", "dev": true, "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", - "@babel/helper-compilation-targets": "^7.19.3", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.3", + "@babel/generator": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-module-transforms": "^7.20.2", + "@babel/helpers": "^7.20.5", + "@babel/parser": "^7.20.5", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.3", - "@babel/types": "^7.19.3", + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -6062,12 +6080,12 @@ } }, "@babel/generator": { - "version": "7.19.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.5.tgz", - "integrity": "sha512-DxbNz9Lz4aMZ99qPpO1raTbcrI1ZeYh+9NR9qhfkQIbFtVEqotHojEBxHzmxhVONkGt6VyrqVQcgpefMy9pqcg==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", + "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", "dev": true, "requires": { - "@babel/types": "^7.19.4", + "@babel/types": "^7.20.5", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -6086,12 +6104,12 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz", - "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", + "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", "dev": true, "requires": { - "@babel/compat-data": "^7.19.3", + "@babel/compat-data": "^7.20.0", "@babel/helper-validator-option": "^7.18.6", "browserslist": "^4.21.3", "semver": "^6.3.0" @@ -6140,34 +6158,34 @@ } }, "@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz", + "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==", "dev": true, "requires": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.2" } }, "@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", "dev": true }, "@babel/helper-simple-access": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", - "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", "dev": true, "requires": { - "@babel/types": "^7.19.4" + "@babel/types": "^7.20.2" } }, "@babel/helper-split-export-declaration": { @@ -6198,14 +6216,14 @@ "dev": true }, "@babel/helpers": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.4.tgz", - "integrity": "sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw==", + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz", + "integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==", "dev": true, "requires": { "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.4", - "@babel/types": "^7.19.4" + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5" } }, "@babel/highlight": { @@ -6278,9 +6296,9 @@ } }, "@babel/parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.4.tgz", - "integrity": "sha512-qpVT7gtuOLjWeDTKLkJ6sryqLliBaFpAtGeqw5cs5giLldvh+Ch0plqnUMKoVAUS6ZEueQQiZV+p5pxtPitEsA==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", + "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -6392,12 +6410,12 @@ } }, "@babel/plugin-syntax-typescript": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", - "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", + "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.19.0" } }, "@babel/template": { @@ -6412,19 +6430,19 @@ } }, "@babel/traverse": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.4.tgz", - "integrity": "sha512-w3K1i+V5u2aJUOXBFFC5pveFLmtq1s3qcdDNC2qRI6WPBQIDaKFqXxDEqDO/h1dQ3HjsZoZMyIy6jGLq0xtw+g==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", + "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", "dev": true, "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.4", + "@babel/generator": "^7.20.5", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.4", - "@babel/types": "^7.19.4", + "@babel/parser": "^7.20.5", + "@babel/types": "^7.20.5", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -6438,9 +6456,9 @@ } }, "@babel/types": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", - "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", + "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", "dev": true, "requires": { "@babel/helper-string-parser": "^7.19.4", @@ -6455,16 +6473,16 @@ "dev": true }, "@esbuild/android-arm": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.10.tgz", - "integrity": "sha512-FNONeQPy/ox+5NBkcSbYJxoXj9GWu8gVGJTVmUyoOCKQFDTrHVKgNSzChdNt0I8Aj/iKcsDf2r9BFwv+FSNUXg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", + "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", "dev": true, "optional": true }, "@esbuild/linux-loong64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.10.tgz", - "integrity": "sha512-w0Ou3Z83LOYEkwaui2M8VwIp+nLi/NA60lBLMvaJ+vXVMcsARYdEzLNE7RSm4+lSg4zq4d7fAVuzk7PNQ5JFgg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", + "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", "dev": true, "optional": true }, @@ -6486,9 +6504,9 @@ } }, "@flatfile/configure": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/@flatfile/configure/-/configure-0.4.7.tgz", - "integrity": "sha512-f7i/sXvJAWzHsrG7sHZAseJ5sDjZSCrbwvWs+k94D2pxmX7DQ1PE8UaLr77dHwiqSldy7HYUg3YIx28oUGZ82A==", + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/@flatfile/configure/-/configure-0.4.8.tgz", + "integrity": "sha512-3R068RvP6TBew4YsH8C0ECe7LdzqPpauHJEo4XB+Miw6PmAlEUg9Bg/DLwaFQnIKoRCHGxfXRXXSyL1ltAfakA==", "dev": true, "requires": { "@flatfile/orm": "*", @@ -6518,9 +6536,9 @@ "dev": true }, "@flatfile/schema": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@flatfile/schema/-/schema-0.2.1.tgz", - "integrity": "sha512-IoWrZfGG35vk2ONTBtbF8usRuf4ocQVeS7fOlLs4nP1Vr7JJFoob4D4qL1FJN3/bV7jJpiG0borl4wP5EOx8iQ==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@flatfile/schema/-/schema-0.2.3.tgz", + "integrity": "sha512-MQjvyuAHD9P9OyjYlK3oooAOAbKZQqJM1pVBYKExVUz2bLIUcFYAhGIZgcBsy/TKfn6rCr2JmbOaGWij0EyLGQ==", "dev": true, "requires": { "lodash": "^4.17.21", @@ -6528,14 +6546,14 @@ } }, "@humanwhocodes/config-array": { - "version": "0.10.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", - "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", + "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "minimatch": "^3.0.5" } }, "@humanwhocodes/module-importer": { @@ -6883,9 +6901,9 @@ "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.16", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.16.tgz", - "integrity": "sha512-LCQ+NeThyJ4k1W2d+vIKdxuSt9R3pQSZ4P92m7EakaYuXcVWbHuT5bjNcqLd4Rdgi6xYWYDvBJZJLZSLanjDcA==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "requires": { "@jridgewell/resolve-uri": "3.1.0", @@ -6919,15 +6937,15 @@ } }, "@sinclair/typebox": { - "version": "0.24.46", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.46.tgz", - "integrity": "sha512-ng4ut1z2MCBhK/NwDVwIQp3pAUOCs/KNaW3cBxdFB2xTDrOuo1xuNmpr/9HHFhxqIvHrs1NTH3KJg6q+JSy1Kw==", + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", "dev": true }, "@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", "dev": true, "requires": { "type-detect": "4.0.8" @@ -6943,9 +6961,9 @@ } }, "@types/babel__core": { - "version": "7.1.19", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", - "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "version": "7.1.20", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", + "integrity": "sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -6975,9 +6993,9 @@ } }, "@types/babel__traverse": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.2.tgz", - "integrity": "sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg==", + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", + "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", "dev": true, "requires": { "@babel/types": "^7.3.0" @@ -7027,15 +7045,15 @@ } }, "@types/lodash": { - "version": "4.14.186", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.186.tgz", - "integrity": "sha512-eHcVlLXP0c2FlMPm56ITode2AgLMSa6aJ05JTTbYbI+7EMkCEE5qk2E41d5g2lCVTqRe0GnnRFurmlCsDODrPw==", + "version": "4.14.191", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", + "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", "dev": true }, "@types/node": { - "version": "18.8.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.5.tgz", - "integrity": "sha512-Bq7G3AErwe5A/Zki5fdD3O6+0zDChhg671NfPjtIcbtzDNZTv4NPKMRFr7gtYPG7y+B8uTiNK4Ngd9T0FTar6Q==", + "version": "18.11.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.11.tgz", + "integrity": "sha512-KJ021B1nlQUBLopzZmPBVuGU9un7WJd/W4ya7Ih02B4Uwky5Nja0yGYav2EfYIk0RR2Q9oVhf60S2XR1BCWJ2g==", "dev": true }, "@types/node-fetch": { @@ -7061,9 +7079,9 @@ "dev": true }, "@types/yargs": { - "version": "17.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", - "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", + "version": "17.0.15", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.15.tgz", + "integrity": "sha512-ZHc4W2dnEQPfhn06TBEdWaiUHEZAocYaiVMfwOipY5jcJt/251wVrKCBWBetGZWO5CF8tdb7L3DmdxVlZ2BOIg==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -7076,41 +7094,41 @@ "dev": true }, "@typescript-eslint/parser": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.40.0.tgz", - "integrity": "sha512-Ah5gqyX2ySkiuYeOIDg7ap51/b63QgWZA7w6AHtFrag7aH0lRQPbLzUjk0c9o5/KZ6JRkTTDKShL4AUrQa6/hw==", + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.45.1.tgz", + "integrity": "sha512-JQ3Ep8bEOXu16q0ztsatp/iQfDCtvap7sp/DKo7DWltUquj5AfCOpX2zSzJ8YkAVnrQNqQ5R62PBz2UtrfmCkA==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.40.0", - "@typescript-eslint/types": "5.40.0", - "@typescript-eslint/typescript-estree": "5.40.0", + "@typescript-eslint/scope-manager": "5.45.1", + "@typescript-eslint/types": "5.45.1", + "@typescript-eslint/typescript-estree": "5.45.1", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.40.0.tgz", - "integrity": "sha512-d3nPmjUeZtEWRvyReMI4I1MwPGC63E8pDoHy0BnrYjnJgilBD3hv7XOiETKLY/zTwI7kCnBDf2vWTRUVpYw0Uw==", + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.45.1.tgz", + "integrity": "sha512-D6fCileR6Iai7E35Eb4Kp+k0iW7F1wxXYrOhX/3dywsOJpJAQ20Fwgcf+P/TDtvQ7zcsWsrJaglaQWDhOMsspQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.40.0", - "@typescript-eslint/visitor-keys": "5.40.0" + "@typescript-eslint/types": "5.45.1", + "@typescript-eslint/visitor-keys": "5.45.1" } }, "@typescript-eslint/types": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.40.0.tgz", - "integrity": "sha512-V1KdQRTXsYpf1Y1fXCeZ+uhjW48Niiw0VGt4V8yzuaDTU8Z1Xl7yQDyQNqyAFcVhpYXIVCEuxSIWTsLDpHgTbw==", + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.45.1.tgz", + "integrity": "sha512-HEW3U0E5dLjUT+nk7b4lLbOherS1U4ap+b9pfu2oGsW3oPu7genRaY9dDv3nMczC1rbnRY2W/D7SN05wYoGImg==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.40.0.tgz", - "integrity": "sha512-b0GYlDj8TLTOqwX7EGbw2gL5EXS2CPEWhF9nGJiGmEcmlpNBjyHsTwbqpyIEPVpl6br4UcBOYlcI2FJVtJkYhg==", + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.45.1.tgz", + "integrity": "sha512-76NZpmpCzWVrrb0XmYEpbwOz/FENBi+5W7ipVXAsG3OoFrQKJMiaqsBMbvGRyLtPotGqUfcY7Ur8j0dksDJDng==", "dev": true, "requires": { - "@typescript-eslint/types": "5.40.0", - "@typescript-eslint/visitor-keys": "5.40.0", + "@typescript-eslint/types": "5.45.1", + "@typescript-eslint/visitor-keys": "5.45.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -7119,19 +7137,19 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.40.0.tgz", - "integrity": "sha512-ijJ+6yig+x9XplEpG2K6FUdJeQGGj/15U3S56W9IqXKJqleuD7zJ2AX/miLezwxpd7ZxDAqO87zWufKg+RPZyQ==", + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.45.1.tgz", + "integrity": "sha512-cy9ln+6rmthYWjH9fmx+5FU/JDpjQb586++x2FZlveq7GdGuLLW9a2Jcst2TGekH82bXpfmRNSwP9tyEs6RjvQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.40.0", + "@typescript-eslint/types": "5.45.1", "eslint-visitor-keys": "^3.3.0" } }, "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true }, "acorn-jsx": { @@ -7192,9 +7210,9 @@ "dev": true }, "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -7384,9 +7402,9 @@ "dev": true }, "bundle-require": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-3.1.0.tgz", - "integrity": "sha512-IIXtAO7fKcwPHNPt9kY/WNVJqy7NDy6YqJvv6ENH0TOZoJ+yjpEsn1w40WKZbR2ibfu5g1rfgJTvmFHpm5aOMA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-3.1.2.tgz", + "integrity": "sha512-Of6l6JBAxiyQ5axFxUM6dYeP/W7X2Sozeo/4EYB9sJhL+dqL7TKjg+shwxp6jlu/6ZSERfsYtIpSJ1/x3XkAEA==", "dev": true, "requires": { "load-tsconfig": "^0.2.0" @@ -7411,9 +7429,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001418", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz", - "integrity": "sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==", + "version": "1.0.30001436", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001436.tgz", + "integrity": "sha512-ZmWkKsnC2ifEPoWUvSAIGyOYwT+keAaaWPHiQ9DfMqS1t6tfuyFYoWR78TeZtznkEQ64+vGXH9cZrElwR2Mrxg==", "dev": true }, "case-anything": { @@ -7466,9 +7484,9 @@ } }, "ci-info": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz", - "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz", + "integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==", "dev": true }, "cjs-module-lexer": { @@ -7685,9 +7703,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.4.281", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.281.tgz", - "integrity": "sha512-yer0w5wCYdFoZytfmbNhwiGI/3cW06+RV7E23ln4490DVMxs7PvYpbsrSmAiBn/V6gode8wvJlST2YfWgvzWIg==", + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", "dev": true }, "emittery": { @@ -7712,172 +7730,172 @@ } }, "esbuild": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.10.tgz", - "integrity": "sha512-N7wBhfJ/E5fzn/SpNgX+oW2RLRjwaL8Y0ezqNqhjD6w0H2p0rDuEz2FKZqpqLnO8DCaWumKe8dsC/ljvVSSxng==", - "dev": true, - "requires": { - "@esbuild/android-arm": "0.15.10", - "@esbuild/linux-loong64": "0.15.10", - "esbuild-android-64": "0.15.10", - "esbuild-android-arm64": "0.15.10", - "esbuild-darwin-64": "0.15.10", - "esbuild-darwin-arm64": "0.15.10", - "esbuild-freebsd-64": "0.15.10", - "esbuild-freebsd-arm64": "0.15.10", - "esbuild-linux-32": "0.15.10", - "esbuild-linux-64": "0.15.10", - "esbuild-linux-arm": "0.15.10", - "esbuild-linux-arm64": "0.15.10", - "esbuild-linux-mips64le": "0.15.10", - "esbuild-linux-ppc64le": "0.15.10", - "esbuild-linux-riscv64": "0.15.10", - "esbuild-linux-s390x": "0.15.10", - "esbuild-netbsd-64": "0.15.10", - "esbuild-openbsd-64": "0.15.10", - "esbuild-sunos-64": "0.15.10", - "esbuild-windows-32": "0.15.10", - "esbuild-windows-64": "0.15.10", - "esbuild-windows-arm64": "0.15.10" + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", + "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.15.18", + "@esbuild/linux-loong64": "0.15.18", + "esbuild-android-64": "0.15.18", + "esbuild-android-arm64": "0.15.18", + "esbuild-darwin-64": "0.15.18", + "esbuild-darwin-arm64": "0.15.18", + "esbuild-freebsd-64": "0.15.18", + "esbuild-freebsd-arm64": "0.15.18", + "esbuild-linux-32": "0.15.18", + "esbuild-linux-64": "0.15.18", + "esbuild-linux-arm": "0.15.18", + "esbuild-linux-arm64": "0.15.18", + "esbuild-linux-mips64le": "0.15.18", + "esbuild-linux-ppc64le": "0.15.18", + "esbuild-linux-riscv64": "0.15.18", + "esbuild-linux-s390x": "0.15.18", + "esbuild-netbsd-64": "0.15.18", + "esbuild-openbsd-64": "0.15.18", + "esbuild-sunos-64": "0.15.18", + "esbuild-windows-32": "0.15.18", + "esbuild-windows-64": "0.15.18", + "esbuild-windows-arm64": "0.15.18" } }, "esbuild-android-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.10.tgz", - "integrity": "sha512-UI7krF8OYO1N7JYTgLT9ML5j4+45ra3amLZKx7LO3lmLt1Ibn8t3aZbX5Pu4BjWiqDuJ3m/hsvhPhK/5Y/YpnA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", + "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", "dev": true, "optional": true }, "esbuild-android-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.10.tgz", - "integrity": "sha512-EOt55D6xBk5O05AK8brXUbZmoFj4chM8u3riGflLa6ziEoVvNjRdD7Cnp82NHQGfSHgYR06XsPI8/sMuA/cUwg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", + "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", "dev": true, "optional": true }, "esbuild-darwin-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.10.tgz", - "integrity": "sha512-hbDJugTicqIm+WKZgp208d7FcXcaK8j2c0l+fqSJ3d2AzQAfjEYDRM3Z2oMeqSJ9uFxyj/muSACLdix7oTstRA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", + "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", "dev": true, "optional": true }, "esbuild-darwin-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.10.tgz", - "integrity": "sha512-M1t5+Kj4IgSbYmunf2BB6EKLkWUq+XlqaFRiGOk8bmBapu9bCDrxjf4kUnWn59Dka3I27EiuHBKd1rSO4osLFQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", + "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", "dev": true, "optional": true }, "esbuild-freebsd-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.10.tgz", - "integrity": "sha512-KMBFMa7C8oc97nqDdoZwtDBX7gfpolkk6Bcmj6YFMrtCMVgoU/x2DI1p74DmYl7CSS6Ppa3xgemrLrr5IjIn0w==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", + "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", "dev": true, "optional": true }, "esbuild-freebsd-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.10.tgz", - "integrity": "sha512-m2KNbuCX13yQqLlbSojFMHpewbn8wW5uDS6DxRpmaZKzyq8Dbsku6hHvh2U+BcLwWY4mpgXzFUoENEf7IcioGg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", + "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", "dev": true, "optional": true }, "esbuild-linux-32": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.10.tgz", - "integrity": "sha512-guXrwSYFAvNkuQ39FNeV4sNkNms1bLlA5vF1H0cazZBOLdLFIny6BhT+TUbK/hdByMQhtWQ5jI9VAmPKbVPu1w==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", + "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", "dev": true, "optional": true }, "esbuild-linux-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.10.tgz", - "integrity": "sha512-jd8XfaSJeucMpD63YNMO1JCrdJhckHWcMv6O233bL4l6ogQKQOxBYSRP/XLWP+6kVTu0obXovuckJDcA0DKtQA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", + "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", "dev": true, "optional": true }, "esbuild-linux-arm": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.10.tgz", - "integrity": "sha512-6N8vThLL/Lysy9y4Ex8XoLQAlbZKUyExCWyayGi2KgTBelKpPgj6RZnUaKri0dHNPGgReJriKVU6+KDGQwn10A==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", + "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", "dev": true, "optional": true }, "esbuild-linux-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.10.tgz", - "integrity": "sha512-GByBi4fgkvZFTHFDYNftu1DQ1GzR23jws0oWyCfhnI7eMOe+wgwWrc78dbNk709Ivdr/evefm2PJiUBMiusS1A==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", + "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", "dev": true, "optional": true }, "esbuild-linux-mips64le": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.10.tgz", - "integrity": "sha512-BxP+LbaGVGIdQNJUNF7qpYjEGWb0YyHVSKqYKrn+pTwH/SiHUxFyJYSP3pqkku61olQiSBnSmWZ+YUpj78Tw7Q==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", + "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", "dev": true, "optional": true }, "esbuild-linux-ppc64le": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.10.tgz", - "integrity": "sha512-LoSQCd6498PmninNgqd/BR7z3Bsk/mabImBWuQ4wQgmQEeanzWd5BQU2aNi9mBURCLgyheuZS6Xhrw5luw3OkQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", + "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", "dev": true, "optional": true }, "esbuild-linux-riscv64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.10.tgz", - "integrity": "sha512-Lrl9Cr2YROvPV4wmZ1/g48httE8z/5SCiXIyebiB5N8VT7pX3t6meI7TQVHw/wQpqP/AF4SksDuFImPTM7Z32Q==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", + "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", "dev": true, "optional": true }, "esbuild-linux-s390x": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.10.tgz", - "integrity": "sha512-ReP+6q3eLVVP2lpRrvl5EodKX7EZ1bS1/z5j6hsluAlZP5aHhk6ghT6Cq3IANvvDdscMMCB4QEbI+AjtvoOFpA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", + "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", "dev": true, "optional": true }, "esbuild-netbsd-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.10.tgz", - "integrity": "sha512-iGDYtJCMCqldMskQ4eIV+QSS/CuT7xyy9i2/FjpKvxAuCzrESZXiA1L64YNj6/afuzfBe9i8m/uDkFHy257hTw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", + "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", "dev": true, "optional": true }, "esbuild-openbsd-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.10.tgz", - "integrity": "sha512-ftMMIwHWrnrYnvuJQRJs/Smlcb28F9ICGde/P3FUTCgDDM0N7WA0o9uOR38f5Xe2/OhNCgkjNeb7QeaE3cyWkQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", + "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", "dev": true, "optional": true }, "esbuild-sunos-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.10.tgz", - "integrity": "sha512-mf7hBL9Uo2gcy2r3rUFMjVpTaGpFJJE5QTDDqUFf1632FxteYANffDZmKbqX0PfeQ2XjUDE604IcE7OJeoHiyg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", + "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", "dev": true, "optional": true }, "esbuild-windows-32": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.10.tgz", - "integrity": "sha512-ttFVo+Cg8b5+qHmZHbEc8Vl17kCleHhLzgT8X04y8zudEApo0PxPg9Mz8Z2cKH1bCYlve1XL8LkyXGFjtUYeGg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", + "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", "dev": true, "optional": true }, "esbuild-windows-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.10.tgz", - "integrity": "sha512-2H0gdsyHi5x+8lbng3hLbxDWR7mKHWh5BXZGKVG830KUmXOOWFE2YKJ4tHRkejRduOGDrBvHBriYsGtmTv3ntA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", + "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", "dev": true, "optional": true }, "esbuild-windows-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.10.tgz", - "integrity": "sha512-S+th4F+F8VLsHLR0zrUcG+Et4hx0RKgK1eyHc08kztmLOES8BWwMiaGdoW9hiXuzznXQ0I/Fg904MNbr11Nktw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", + "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", "dev": true, "optional": true }, @@ -7894,14 +7912,15 @@ "dev": true }, "eslint": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.25.0.tgz", - "integrity": "sha512-DVlJOZ4Pn50zcKW5bYH7GQK/9MsoQG2d5eDH0ebEkE8PbgzTTmtt/VTH9GGJ4BfeZCpBLqFfvsjX35UacUL83A==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", + "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", "dev": true, "requires": { "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.10.5", + "@humanwhocodes/config-array": "^0.11.6", "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -7917,14 +7936,14 @@ "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", - "glob-parent": "^6.0.1", + "glob-parent": "^6.0.2", "globals": "^13.15.0", - "globby": "^11.1.0", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", @@ -7980,9 +7999,9 @@ "dev": true }, "espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", "dev": true, "requires": { "acorn": "^8.8.0", @@ -8111,9 +8130,9 @@ "dev": true }, "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", + "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -8183,9 +8202,9 @@ } }, "flatfile": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/flatfile/-/flatfile-3.1.0.tgz", - "integrity": "sha512-DIllGnB377RPqyIYvkr74oMJ+tqUXzUcFSlDpVOn10n58ns96siYTwek5VvDns/R6S9+t7mxI/LCVNC0e0y5YQ==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/flatfile/-/flatfile-3.1.5.tgz", + "integrity": "sha512-8bzhqkjXajrSY6wRipqPlTXpcn6Fq5xccRMPmvxZAWmAGvRMSuXnicVUnteAfdxyNlvTVWC7ucLr/hcocgNs8w==", "dev": true, "requires": { "@types/node-fetch": "^2.6.2", @@ -8304,9 +8323,9 @@ } }, "globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "version": "13.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", + "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -8389,9 +8408,9 @@ "dev": true }, "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", + "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", "dev": true }, "import-fresh": { @@ -8452,9 +8471,9 @@ } }, "is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, "requires": { "has": "^1.0.3" @@ -8499,6 +8518,12 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, "is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -8799,9 +8824,9 @@ } }, "jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, "requires": {} }, @@ -9009,9 +9034,9 @@ "dev": true }, "js-sdsl": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", - "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", "dev": true }, "js-tokens": { @@ -9265,9 +9290,9 @@ "dev": true }, "node-fetch": { - "version": "3.2.10", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.10.tgz", - "integrity": "sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.0.tgz", + "integrity": "sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==", "dev": true, "requires": { "data-uri-to-buffer": "^4.0.0", @@ -9515,9 +9540,9 @@ "dev": true }, "prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.0.tgz", + "integrity": "sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==", "dev": true }, "pretty-format": { @@ -9672,9 +9697,9 @@ } }, "rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.6.0.tgz", + "integrity": "sha512-qCgiBeSu2/AIOKWGFMiRkjPlGlcVwxAjwpGKQZOQYng+83Hip4PjrWHm7EQX1wnrvRqfTytEihRRfLHdX+hR4g==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -9766,9 +9791,9 @@ "dev": true }, "stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, "requires": { "escape-string-regexp": "^2.0.0" @@ -9840,9 +9865,9 @@ "dev": true }, "sucrase": { - "version": "3.28.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.28.0.tgz", - "integrity": "sha512-TK9600YInjuiIhVM3729rH4ZKPOsGeyXUwY+Ugu9eilNbdTFyHr6XcAGYbRVZPDgWj6tgI7bx95aaJjHnbffag==", + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.29.0.tgz", + "integrity": "sha512-bZPAuGA5SdFHuzqIhTAqt9fvNEo9rESqXIG3oiKdF8K4UmkQxC4KlNL3lVyAErXp+mPvUqZ5l13qx6TrDIGf3A==", "dev": true, "requires": { "commander": "^4.0.0", @@ -10007,12 +10032,12 @@ "dev": true }, "tsup": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/tsup/-/tsup-6.2.3.tgz", - "integrity": "sha512-J5Pu2Dx0E1wlpIEsVFv9ryzP1pZ1OYsJ2cBHZ7GrKteytNdzaSz5hmLX7/nAxtypq+jVkVvA79d7S83ETgHQ5w==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/tsup/-/tsup-6.5.0.tgz", + "integrity": "sha512-36u82r7rYqRHFkD15R20Cd4ercPkbYmuvRkz3Q1LCm5BsiFNUgpo36zbjVhCOgvjyxNBWNKHsaD5Rl8SykfzNA==", "dev": true, "requires": { - "bundle-require": "^3.1.0", + "bundle-require": "^3.1.2", "cac": "^6.7.12", "chokidar": "^3.5.1", "debug": "^4.3.1", @@ -10022,7 +10047,7 @@ "joycon": "^3.0.1", "postcss-load-config": "^3.0.1", "resolve-from": "^5.0.0", - "rollup": "^2.74.1", + "rollup": "^3.2.5", "source-map": "0.8.0-beta.0", "sucrase": "^3.20.3", "tree-kill": "^1.2.2" @@ -10102,9 +10127,9 @@ "dev": true }, "typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", + "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", "dev": true, "peer": true }, @@ -10245,9 +10270,9 @@ "dev": true }, "yargs": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", - "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", "dev": true, "requires": { "cliui": "^8.0.1", @@ -10256,7 +10281,7 @@ "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" + "yargs-parser": "^21.1.1" } }, "yargs-parser": { diff --git a/package.json b/package.json index 5d3d901..cfe6f3e 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,8 @@ "test": "jest --runInBand --detectOpenHandles --forceExit --passWithNoTests" }, "devDependencies": { - "flatfile": "^3.1.0", - "@flatfile/configure": "^0.4.7", + "flatfile": "^3.1.5", + "@flatfile/configure": "^0.4.8", "@flatfile/hooks": "^1.2.0", "@flatfile/expression-lang": "^0.0.2", "node-fetch": "^3.2.10", From 61327467f812a1106b1bf92f57a6e955cf1ce38e Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Fri, 16 Dec 2022 14:15:21 -0500 Subject: [PATCH 23/36] non-unique works --- examples/features/GroupByField.spec.ts | 2 +- src/expression-lang/sheetInterpret.ts | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/examples/features/GroupByField.spec.ts b/examples/features/GroupByField.spec.ts index c70b46f..172682f 100644 --- a/examples/features/GroupByField.spec.ts +++ b/examples/features/GroupByField.spec.ts @@ -29,7 +29,7 @@ const UniquePeopleSheet = new Sheet('People', age_sum: GroupByField( ['job'], GroupConstraintItem( - ['nonUnique', 'fav_group'], Error('fav_group must be unique'), + ['nonUnique', 'fav_group', ['variable', 'group']], Error('fav_group must be unique'), 'fav_group', Group())) }) const UniquePeopleBook = new Workbook({name: 't', namespace: 't', sheets: {UniquePeopleSheet}}) diff --git a/src/expression-lang/sheetInterpret.ts b/src/expression-lang/sheetInterpret.ts index 4a2a8dc..8209ab8 100644 --- a/src/expression-lang/sheetInterpret.ts +++ b/src/expression-lang/sheetInterpret.ts @@ -30,6 +30,19 @@ const match = (matchSpec: object, records: FlatfileRecord[]) => { ) } +const nonUnique = (column:string, records: FlatfileRecord[]) => { + const groups = _.groupBy(records, (rec) => + rec.get(column)) + //_.forEach(groups, (group: FlatfileRecord[], gbKey) => { + const groupSets = _.map(groups, (group: FlatfileRecord[]) => group) + const nonUniqueSets = _.filter(groupSets, + (groupedBy:FlatfileRecord[]) => { + if (groupedBy.length > 1) { + return true} + return false}) + return _.flatten(nonUniqueSets) +} + @@ -103,13 +116,14 @@ export const debug = (expr: NestedIns) => { const do_ = (...exprs: any) => exprs[exprs.length -1] //@ts-ignore -const simpleInterpret = makeInterpreter({sumField, groupConstraintRow, error, match, 'do': do_}) +const simpleInterpret = makeInterpreter({sumField, groupConstraintRow, nonUnique, error, match, 'do': do_}) export const sheetInterpret = makeInterpreter({ error, match, groupByCompute, groupConstraintRow, + nonUnique, debug, }) From 2e47a6f7926f5699f51235ecffb9f6c2a01094fb Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Tue, 20 Dec 2022 11:44:11 -0500 Subject: [PATCH 24/36] added NonUnique EXPR --- examples/features/GroupByField.spec.ts | 6 ++- src/expression-lang/EXPR.ts | 2 +- src/index.ts | 70 ++++++++++++++++++++------ 3 files changed, 61 insertions(+), 17 deletions(-) diff --git a/examples/features/GroupByField.spec.ts b/examples/features/GroupByField.spec.ts index 172682f..c6e19f0 100644 --- a/examples/features/GroupByField.spec.ts +++ b/examples/features/GroupByField.spec.ts @@ -9,7 +9,8 @@ import { GreaterThan, Unless, GroupConstraintItem, - Do + Do, + NonUnique } from '../../src/expression-lang/EXPR' const tgrps = [ @@ -29,7 +30,8 @@ const UniquePeopleSheet = new Sheet('People', age_sum: GroupByField( ['job'], GroupConstraintItem( - ['nonUnique', 'fav_group', ['variable', 'group']], Error('fav_group must be unique'), + NonUnique('fav_group', Group()), + Error('fav_group must be unique'), 'fav_group', Group())) }) const UniquePeopleBook = new Workbook({name: 't', namespace: 't', sheets: {UniquePeopleSheet}}) diff --git a/src/expression-lang/EXPR.ts b/src/expression-lang/EXPR.ts index 1254487..21f151d 100644 --- a/src/expression-lang/EXPR.ts +++ b/src/expression-lang/EXPR.ts @@ -50,7 +50,7 @@ export const Unless = (predicate: any, expr: any) => [ expr, ] - +export const NonUnique = (column:string, group:NestedIns) => ['nonUnique', column, group] export const Error = (message: string) => ['error', message] export const Group = () => ['variable', 'group'] diff --git a/src/index.ts b/src/index.ts index 07927ee..6da78f6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,23 @@ +import { + TextField, + NumberField, + GroupByField, + Sheet, + Workbook, + Portal +} from '@flatfile/configure' +import { + Group, + SumField, + Count, + Match, + Error, + GreaterThan, + Unless, + GroupConstraintItem, + Do +} from './expression-lang/EXPR' + /** * This is a scaffold for defining a Workbook with Sheets and Portals. * Test this scaffold using the sample file in examples/sample-uploads/my-sheet-sample.csv. @@ -5,13 +25,6 @@ * See examples/workbooks/FullExample.ts for a full, working example of a Workbook. */ -import { - NumberField, - Portal, - Sheet, - TextField, - Workbook, -} from '@flatfile/configure' /** * Sheets @@ -24,6 +37,37 @@ const MySheet = new Sheet('MySheet', { age: NumberField(), }) +const BothSheet = new Sheet( + 'BothSheet', + { + name: TextField(), + eye_color: TextField(), + job: TextField(), + age: NumberField(), + age_sum: GroupByField( + ['job'], + // NOTE THE USE OF DO HERE... + // Do allows multiple expressions to be executed and the result + // of the last one is returned... in this case "SumField" + Do( + GroupConstraintItem( + Group(), + Unless( + GreaterThan( + Count(Match({eye_color: 'blue_'}, Group())), + 0), + Error('No Blue eyes')), + 'name', + Group()), + SumField(Group(), 'age')) + ), + } +) + + + + + /** * Portals * Define your Portals here, or import them: @@ -31,15 +75,13 @@ const MySheet = new Sheet('MySheet', { */ const MyPortal = new Portal({ name: 'MyPortal', - sheet: 'MySheet', + sheet: 'BothSheet', }) // Workbook - Update to reference your Workbook with Sheet(s) and Portal(s) -export default new Workbook({ - name: 'MyWorkbook', - namespace: 'my-workbook', +//export default new Workbook({ +export default new Workbook({name: 't', namespace: 't', sheets: {BothSheet}, + // name: 'MyWorkbook', + // namespace: 'my-workbook', portals: [MyPortal], - sheets: { - MySheet, - }, }) From 18757a418b7bd8f996424deca64e4f024e5dd568 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Wed, 21 Dec 2022 14:37:41 -0500 Subject: [PATCH 25/36] updated the argument so that it's always 'funcname', 'rowset', extra conditions' --- examples/features/GroupByField.spec.ts | 6 +++--- src/expression-lang/EXPR.spec.ts | 12 ++++++------ src/expression-lang/EXPR.ts | 6 +++--- src/expression-lang/sheetInterpret.ts | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/features/GroupByField.spec.ts b/examples/features/GroupByField.spec.ts index c6e19f0..e7475fd 100644 --- a/examples/features/GroupByField.spec.ts +++ b/examples/features/GroupByField.spec.ts @@ -30,7 +30,7 @@ const UniquePeopleSheet = new Sheet('People', age_sum: GroupByField( ['job'], GroupConstraintItem( - NonUnique('fav_group', Group()), + NonUnique(Group(), 'fav_group'), Error('fav_group must be unique'), 'fav_group', Group())) }) @@ -139,7 +139,7 @@ const PeopleSheet = new Sheet('People', Group(), Unless( GreaterThan( - Count(Match({eye_color: 'blue_'}, Group())), + Count(Match(Group(), {eye_color: 'blue_'})), 0), Error('No Blue eyes')), 'name', @@ -177,7 +177,7 @@ const BothSheet = new Sheet( Group(), Unless( GreaterThan( - Count(Match({eye_color: 'blue_'}, Group())), + Count(Match(Group(), {eye_color: 'blue_'})), 0), Error('No Blue eyes')), 'name', diff --git a/src/expression-lang/EXPR.spec.ts b/src/expression-lang/EXPR.spec.ts index c54c846..ed6a0ac 100644 --- a/src/expression-lang/EXPR.spec.ts +++ b/src/expression-lang/EXPR.spec.ts @@ -96,7 +96,7 @@ describe('GroupConstraint Tests ->', () => { test('Match', () => { const recs = getRecs() const matchResult = sheetInterpret( - Match({ name: 'Paddy' }, recs) + Match(recs, { name: 'Paddy' }) ) as any[] expect(matchResult.length).toBe(1) expect(matchResult[0].value).toMatchObject({ age: 40, name: 'Paddy' }) @@ -110,14 +110,14 @@ describe('GroupConstraint Tests ->', () => { test('GroupConstraint', () => { const recs = getRecs() - const greenEyes = sheetInterpret(Match({ eyeColor: 'green' }, recs), {}) + const greenEyes = sheetInterpret(Match(recs, { eyeColor: 'green' }), {}) const retireds = sheetInterpret(Match({ job: 'ret' }, recs), {}) const gcResult = sheetInterpret( GroupConstraintItem( Group(), Unless( - GreaterThan(Count(Match({ job: 'kid' }, MatchResult())), 0), + GreaterThan(Count(Match(MatchResult(), { job: 'kid' })), 0), Error('No Kids') ), 'name', @@ -131,7 +131,7 @@ describe('GroupConstraint Tests ->', () => { GroupConstraintItem( Group(), Unless( - GreaterThan(Count(Match({ job: 'kid' }, MatchResult())), 0), + GreaterThan(Count(Match(MatchResult(), { job: 'kid' })), 0), Error('No Kids') ), 'name', @@ -149,7 +149,7 @@ describe('GroupConstraint Tests ->', () => { Group(), Unless( GreaterThan( - Count(Match({job:'kid'}, Group())), + Count(Match(Group(), {job:'kid'})), 0), Error('No Kids')), 'name', @@ -157,7 +157,7 @@ describe('GroupConstraint Tests ->', () => { .toStrictEqual( ['groupConstraintRow', ['quote', ['variable', 'group']], - ['quote', ['when', ['not', ['>', ['count', ['match', {job:'kid'}, ['variable', 'group']]], 0 ]], + ['quote', ['when', ['not', ['>', ['count', ['match', ['variable', 'group'], {job:'kid'}]], 0 ]], ['error', 'No Kids']]], 'name', ['variable', 'group']]) diff --git a/src/expression-lang/EXPR.ts b/src/expression-lang/EXPR.ts index 21f151d..a5848cf 100644 --- a/src/expression-lang/EXPR.ts +++ b/src/expression-lang/EXPR.ts @@ -50,17 +50,17 @@ export const Unless = (predicate: any, expr: any) => [ expr, ] -export const NonUnique = (column:string, group:NestedIns) => ['nonUnique', column, group] +export const NonUnique = (group:NestedIns, column:string) => ['nonUnique', group, column] export const Error = (message: string) => ['error', message] export const Group = () => ['variable', 'group'] export const Val = () => ['variable', 'val'] export const MatchResult = () => ['variable', 'matchResult'] -export const Match = (matchSpec: any, recordGrouping: any) => [ +export const Match = (recordGrouping: any, matchSpec: any) => [ 'match', - matchSpec, recordGrouping, + matchSpec ] export const ImplicitGreaterThan = (comparand: any) => ['>', Val(), comparand] export const ImplicitLessThan = (comparand: any) => ['>', Val(), comparand] diff --git a/src/expression-lang/sheetInterpret.ts b/src/expression-lang/sheetInterpret.ts index 8209ab8..b93695f 100644 --- a/src/expression-lang/sheetInterpret.ts +++ b/src/expression-lang/sheetInterpret.ts @@ -24,13 +24,13 @@ export const info = (message: string, stage: TRecordStageLevel = 'validate') => } -const match = (matchSpec: object, records: FlatfileRecord[]) => { +const match = (records: FlatfileRecord[], matchSpec: object) => { return _.filter(records, (rec: FlatfileRecord) => _.isMatch(rec.originalValue, matchSpec) ) } -const nonUnique = (column:string, records: FlatfileRecord[]) => { +const nonUnique = (records: FlatfileRecord[], column:string) => { const groups = _.groupBy(records, (rec) => rec.get(column)) //_.forEach(groups, (group: FlatfileRecord[], gbKey) => { From 15ee8f062572c85e0ae180245861fc5a6a746cdd Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Thu, 22 Dec 2022 11:30:28 -0500 Subject: [PATCH 26/36] added a complex unique test --- examples/features/complexUnique.spec.ts | 67 +++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 examples/features/complexUnique.spec.ts diff --git a/examples/features/complexUnique.spec.ts b/examples/features/complexUnique.spec.ts new file mode 100644 index 0000000..2329e53 --- /dev/null +++ b/examples/features/complexUnique.spec.ts @@ -0,0 +1,67 @@ +import { TextField, NumberField, GroupByField, Sheet, Workbook } from '@flatfile/configure' +import { SheetTester, matchMessages, matchSingleMessage } from '../../src/utils/testing/SheetTester' +import { + Group, + And, + Count, + Match, + Error, + GreaterThan, + When, + GroupConstraintItem, + +} from '../../src/expression-lang/EXPR' + +//any name that occurs with a job of 'kid', must be unique across the entire sheet +const tgrps = [ + { name: 'Odin_', job: 'kid', f:''}, //0 + { name: 'Odin_', job: 'ret', f:''}, //1 + { name: 'Sarah', job: 'kid', f:''}, //2 + { name: 'Paddy', job: 'eng', f:''}, + { name: 'Paddy', job: 'ret', f:''}, //4 + { name: 'Franz', job: 'ret', f:''}, + { name: 'Franz', job: 'ret', f:''}, //6 + { name: 'Kay__', job: 'ret', f:''}, + { name: 'Cliff', job: 'ret', f:''}, //8 +] + +const UniquePeopleSheet = new Sheet('People', + { + job: TextField(), + name: TextField(), + f: GroupByField( + ['name'], + GroupConstraintItem( + Group(), + When( + And( + GreaterThan(Count(Match(Group(), {job:'kid'})), 0), + GreaterThan(Count(Group()), 1)), + Error("name appears in row with 'kid', and other rows too")), + 'name')) +}) + +const UniquePeopleBook = new Workbook({name: 't', namespace: 't', sheets: {UniquePeopleSheet}}) + +describe('SampleGroupBy groupConstraint 2 ->', () => { + + + const testSheet = new SheetTester(UniquePeopleBook, 'UniquePeopleSheet') + test('GroupByField works properly with sum - multiple rows', async () => { + const res = await testSheet.testMessages(tgrps) + expect(res[0][0]).toMatchObject({ + field: 'name', + message: "name appears in row with 'kid', and other rows too", + }) + expect(res[1][0]).toMatchObject({ + field: 'name', + message: "name appears in row with 'kid', and other rows too", + }) + + expect(res[3]).toStrictEqual([]) + expect(res[4]).toStrictEqual([]) + expect(res[5]).toStrictEqual([]) + expect(res[6]).toStrictEqual([]) + }) +}) + From 4aced6a563eb3dd00d268faa4324d1170d16483a Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Wed, 28 Dec 2022 14:42:56 -0500 Subject: [PATCH 27/36] example sheet with SumField --- examples/sample-uploads/job-age-sample.csv | 6 ++++ examples/workbooks/GroupByBook.ts | 41 ++++++++++++++++++++++ src/utils/testing/SheetTester.ts | 1 - 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 examples/sample-uploads/job-age-sample.csv create mode 100644 examples/workbooks/GroupByBook.ts diff --git a/examples/sample-uploads/job-age-sample.csv b/examples/sample-uploads/job-age-sample.csv new file mode 100644 index 0000000..cfec826 --- /dev/null +++ b/examples/sample-uploads/job-age-sample.csv @@ -0,0 +1,6 @@ +name,job,age,age_sum +Paddy,eng,40,_ +Cliff,ret,86,_ +Odin_,kid,3,_ +Kay__,ret,77,_ +Sarah,kid,8,_ diff --git a/examples/workbooks/GroupByBook.ts b/examples/workbooks/GroupByBook.ts new file mode 100644 index 0000000..7a08ae1 --- /dev/null +++ b/examples/workbooks/GroupByBook.ts @@ -0,0 +1,41 @@ +import { + Group, + SumField, +} from '../../src/expression-lang/EXPR' +import { + NumberField, + Sheet, + TextField, + GroupByField, + Workbook, + Portal, + Sheet, +} from '@flatfile/configure' + + +const JobAgeSheet = new Sheet( + 'JobAgeSheet', + { + job: TextField(), + age: NumberField(), + age_sum: GroupByField( + ['job'], + SumField(Group(), 'age') + ), + } +) + + +const JobAgePortal = new Portal({ + name: 'JobAgePortal', + sheet: 'JobAgeSheet' +}) + +export default new Workbook({ + name: 'GroupByWorkbook', + namespace: 'basic', + sheets: { + JobAgeSheet + }, + portals: [JobAgePortal], +}) diff --git a/src/utils/testing/SheetTester.ts b/src/utils/testing/SheetTester.ts index 8e56a33..9799488 100644 --- a/src/utils/testing/SheetTester.ts +++ b/src/utils/testing/SheetTester.ts @@ -2,7 +2,6 @@ import _ from 'lodash' import { IRecordInfo, TRecordData, TPrimitive, FlatfileRecords, FlatfileSession, IPayload } from '@flatfile/hooks' import { NumberField, Sheet, TextField, Workbook } from '@flatfile/configure' import { sheetInterpret } from '../../expression-lang/sheetInterpret' -import { Workbook } from '@flatfile/configure' const localSheetCompute = ( sheet: Sheet, records: FlatfileRecords From 17d1e5696f026fba9d307688986557f6f88455a5 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Thu, 29 Dec 2022 17:10:44 -0500 Subject: [PATCH 28/36] WIP, sample deploy showing row being returned by GroupConstraintItem --- examples/sample-uploads/job-age-sample.csv | 13 +++---- examples/workbooks/GroupByBook.ts | 41 +++++++++++++++++++--- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/examples/sample-uploads/job-age-sample.csv b/examples/sample-uploads/job-age-sample.csv index cfec826..18d4a33 100644 --- a/examples/sample-uploads/job-age-sample.csv +++ b/examples/sample-uploads/job-age-sample.csv @@ -1,6 +1,7 @@ -name,job,age,age_sum -Paddy,eng,40,_ -Cliff,ret,86,_ -Odin_,kid,3,_ -Kay__,ret,77,_ -Sarah,kid,8,_ +name,job,age,age_sum,eye_color +Paddy,eng,40,_,green +Cliff,ret,86,_,gray_ +Odin_,kid,3,_,blue_ +Kay__,ret,77,_,green +Sarah,kid,8,_,green +Stacy,kid,,_,gray_ diff --git a/examples/workbooks/GroupByBook.ts b/examples/workbooks/GroupByBook.ts index 7a08ae1..5afd57a 100644 --- a/examples/workbooks/GroupByBook.ts +++ b/examples/workbooks/GroupByBook.ts @@ -1,6 +1,12 @@ import { Group, SumField, + GroupConstraintItem, + Unless, + GreaterThan, + Count, + Match, + Error } from '../../src/expression-lang/EXPR' import { NumberField, @@ -9,7 +15,6 @@ import { GroupByField, Workbook, Portal, - Sheet, } from '@flatfile/configure' @@ -24,18 +29,44 @@ const JobAgeSheet = new Sheet( ), } ) - - const JobAgePortal = new Portal({ name: 'JobAgePortal', sheet: 'JobAgeSheet' }) + + +const PeopleSheet = new Sheet('People', + { + name: TextField(), + job: TextField(), + eye_color: TextField(), + age_sum: GroupByField( + ['job'], + GroupConstraintItem( + Group(), + Unless( + GreaterThan( + Count(Match(Group(), {eye_color: 'blue_'})), + 0), + Error('No Blue eyes')), + 'name', + Group())) +}) + +const PeoplePortal = new Portal({ + name: 'PeoplePortal', + sheet: 'PeopleSheet' +}) + + export default new Workbook({ name: 'GroupByWorkbook', namespace: 'basic', sheets: { - JobAgeSheet + JobAgeSheet, + PeopleSheet }, - portals: [JobAgePortal], + portals: [JobAgePortal, PeoplePortal], }) + From bfef5caad896c8b43af821c13f1125f4141e2406 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Tue, 3 Jan 2023 13:32:30 -0500 Subject: [PATCH 29/36] WIP --- examples/features/GroupByField.spec.ts | 4 ++-- examples/workbooks/GroupByBook.ts | 25 +++++++++++++++---------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/examples/features/GroupByField.spec.ts b/examples/features/GroupByField.spec.ts index e7475fd..dac1370 100644 --- a/examples/features/GroupByField.spec.ts +++ b/examples/features/GroupByField.spec.ts @@ -135,7 +135,7 @@ const PeopleSheet = new Sheet('People', age: NumberField(), age_sum: GroupByField( ['job'], - GroupConstraintItem( + Do(GroupConstraintItem( Group(), Unless( GreaterThan( @@ -143,7 +143,7 @@ const PeopleSheet = new Sheet('People', 0), Error('No Blue eyes')), 'name', - Group())) + Group()), "22222" ) }) const PeopleBook = new Workbook({name: 't', namespace: 't', sheets: {PeopleSheet}}) diff --git a/examples/workbooks/GroupByBook.ts b/examples/workbooks/GroupByBook.ts index 5afd57a..281b975 100644 --- a/examples/workbooks/GroupByBook.ts +++ b/examples/workbooks/GroupByBook.ts @@ -6,7 +6,8 @@ import { GreaterThan, Count, Match, - Error + Error, + Do } from '../../src/expression-lang/EXPR' import { NumberField, @@ -40,18 +41,22 @@ const PeopleSheet = new Sheet('People', { name: TextField(), job: TextField(), + //foo: TextField({stageVisibility: {review:false}}), + foo: TextField({stageVisibility: {review:true}}), eye_color: TextField(), age_sum: GroupByField( ['job'], - GroupConstraintItem( - Group(), - Unless( - GreaterThan( - Count(Match(Group(), {eye_color: 'blue_'})), - 0), - Error('No Blue eyes')), - 'name', - Group())) + Do( + GroupConstraintItem( + Group(), + Unless( + GreaterThan( + Count(Match(Group(), {eye_color: 'blue_'})), + 0), + Error('No Blue eyes')), + 'name', + Group()), + "33333")) }) const PeoplePortal = new Portal({ From 6e8dc83db36b26789cc18127a50d6241fa7a056d Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Wed, 4 Jan 2023 11:32:11 -0500 Subject: [PATCH 30/36] WIP --- examples/workbooks/GroupByBook.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/examples/workbooks/GroupByBook.ts b/examples/workbooks/GroupByBook.ts index 281b975..4434a5e 100644 --- a/examples/workbooks/GroupByBook.ts +++ b/examples/workbooks/GroupByBook.ts @@ -6,9 +6,10 @@ import { GreaterThan, Count, Match, - Error, + Error as ExprError, Do } from '../../src/expression-lang/EXPR' + import { NumberField, Sheet, @@ -41,7 +42,14 @@ const PeopleSheet = new Sheet('People', { name: TextField(), job: TextField(), - //foo: TextField({stageVisibility: {review:false}}), + age: NumberField({ + validate: (val) => { + if (val > 10) { + throw new Error("too old") + } + } + } + ), foo: TextField({stageVisibility: {review:true}}), eye_color: TextField(), age_sum: GroupByField( @@ -53,7 +61,7 @@ const PeopleSheet = new Sheet('People', GreaterThan( Count(Match(Group(), {eye_color: 'blue_'})), 0), - Error('No Blue eyes')), + ExprError('No Blue eyes')), 'name', Group()), "33333")) From 959f8c8a83699d091c18cf62cb08de01dc2327a7 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Wed, 18 Jan 2023 17:33:44 -0500 Subject: [PATCH 31/36] WIP --- docs/Expression.md | 25 +++++++++++++++++++++++++ examples/features/GroupByField.spec.ts | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/docs/Expression.md b/docs/Expression.md index 441e6a2..110f460 100644 --- a/docs/Expression.md +++ b/docs/Expression.md @@ -43,7 +43,32 @@ const SimpleSheet = new Sheet( note, when used in a `validate` function, there are special MessageConditionals `ErrorWhen`,`ErrorUnless`, `WarnWhen`, `WarnUnless`, `InfoWhen`, `InfoUnless` that should be used. `ErrorWhen` returns a function that accepts a value and calls the validate function on the expression, making `Val()` a valid way of accessing the argument for `validate`. +# Expression language for sheet wide operations + +There are many operations and validations that need to be run across an entire sheet. These leverage expression language to allow declarative statements describing what you want done. GroupByField is the only way to accomplish this now. + +When thinking about using GroupByField, keep in mind the order of operations + +1. field cast +2. field compute +3. recordCompute +4. batchRecordsCompute +5. field validate +6. field egressFormat +----- Back to the server ---- +7. uniqueness checks +8. sheetCompute (groupByField) + + +Given that order of operations. Use the other hooks to prepare data for the groupByField. The other hooks are better suited to most tasks, but sheetwide operations require GroupByField. + +GroupByField is best suited for simple calculations (sum, count) and validating properties about a group. + +When developing with GroupByField, we recommend using local testing. Look at [GroupByField.spec.ts]( https://flatfile.com/docs/get-started/quickstart/) + # GroupByField + + ``` const ItemSummary = new Sheet( 'ItemSummary', diff --git a/examples/features/GroupByField.spec.ts b/examples/features/GroupByField.spec.ts index dac1370..186c2a2 100644 --- a/examples/features/GroupByField.spec.ts +++ b/examples/features/GroupByField.spec.ts @@ -143,7 +143,7 @@ const PeopleSheet = new Sheet('People', 0), Error('No Blue eyes')), 'name', - Group()), "22222" ) + Group()), "22222" )) }) const PeopleBook = new Workbook({name: 't', namespace: 't', sheets: {PeopleSheet}}) From 4408de90c5fa87eff2dfb8b67ceeda6225e17db0 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Wed, 18 Jan 2023 17:37:41 -0500 Subject: [PATCH 32/36] reduced diff to main --- src/index.ts | 70 +++++++++++----------------------------------------- 1 file changed, 14 insertions(+), 56 deletions(-) diff --git a/src/index.ts b/src/index.ts index 6da78f6..07927ee 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,23 +1,3 @@ -import { - TextField, - NumberField, - GroupByField, - Sheet, - Workbook, - Portal -} from '@flatfile/configure' -import { - Group, - SumField, - Count, - Match, - Error, - GreaterThan, - Unless, - GroupConstraintItem, - Do -} from './expression-lang/EXPR' - /** * This is a scaffold for defining a Workbook with Sheets and Portals. * Test this scaffold using the sample file in examples/sample-uploads/my-sheet-sample.csv. @@ -25,6 +5,13 @@ import { * See examples/workbooks/FullExample.ts for a full, working example of a Workbook. */ +import { + NumberField, + Portal, + Sheet, + TextField, + Workbook, +} from '@flatfile/configure' /** * Sheets @@ -37,37 +24,6 @@ const MySheet = new Sheet('MySheet', { age: NumberField(), }) -const BothSheet = new Sheet( - 'BothSheet', - { - name: TextField(), - eye_color: TextField(), - job: TextField(), - age: NumberField(), - age_sum: GroupByField( - ['job'], - // NOTE THE USE OF DO HERE... - // Do allows multiple expressions to be executed and the result - // of the last one is returned... in this case "SumField" - Do( - GroupConstraintItem( - Group(), - Unless( - GreaterThan( - Count(Match({eye_color: 'blue_'}, Group())), - 0), - Error('No Blue eyes')), - 'name', - Group()), - SumField(Group(), 'age')) - ), - } -) - - - - - /** * Portals * Define your Portals here, or import them: @@ -75,13 +31,15 @@ const BothSheet = new Sheet( */ const MyPortal = new Portal({ name: 'MyPortal', - sheet: 'BothSheet', + sheet: 'MySheet', }) // Workbook - Update to reference your Workbook with Sheet(s) and Portal(s) -//export default new Workbook({ -export default new Workbook({name: 't', namespace: 't', sheets: {BothSheet}, - // name: 'MyWorkbook', - // namespace: 'my-workbook', +export default new Workbook({ + name: 'MyWorkbook', + namespace: 'my-workbook', portals: [MyPortal], + sheets: { + MySheet, + }, }) From 4de7230aa531a903eecc7d1eae2c85b6282f3a19 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Thu, 19 Jan 2023 09:30:29 -0500 Subject: [PATCH 33/36] updating the directory structure to be more in line with main --- docs/Expression.md => examples/fields/GroupByField.README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/Expression.md => examples/fields/GroupByField.README.md (100%) diff --git a/docs/Expression.md b/examples/fields/GroupByField.README.md similarity index 100% rename from docs/Expression.md rename to examples/fields/GroupByField.README.md From 1b23b71810b419e2b618dd913b9afa5da341e6fb Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Thu, 19 Jan 2023 16:10:26 -0500 Subject: [PATCH 34/36] naming more in common with main --- examples/{features => fields}/GroupByField.spec.ts | 0 examples/{features => sheets}/ValidateSheet.spec.ts | 0 examples/{features => sheets}/complexUnique.spec.ts | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename examples/{features => fields}/GroupByField.spec.ts (100%) rename examples/{features => sheets}/ValidateSheet.spec.ts (100%) rename examples/{features => sheets}/complexUnique.spec.ts (100%) diff --git a/examples/features/GroupByField.spec.ts b/examples/fields/GroupByField.spec.ts similarity index 100% rename from examples/features/GroupByField.spec.ts rename to examples/fields/GroupByField.spec.ts diff --git a/examples/features/ValidateSheet.spec.ts b/examples/sheets/ValidateSheet.spec.ts similarity index 100% rename from examples/features/ValidateSheet.spec.ts rename to examples/sheets/ValidateSheet.spec.ts diff --git a/examples/features/complexUnique.spec.ts b/examples/sheets/complexUnique.spec.ts similarity index 100% rename from examples/features/complexUnique.spec.ts rename to examples/sheets/complexUnique.spec.ts From 0b859b8abb04c8a714e64dd51a057132061ef254 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Thu, 19 Jan 2023 19:19:29 -0500 Subject: [PATCH 35/36] updates to tests to show a demo of making an HTTP request and stuffing that value onto a field, then extracting that json value with sheet compute and using it to verify proeprties of the group --- examples/fields/GroupByField.spec.ts | 97 +++++++++++++++++++++++++-- src/expression-lang/EXPR.ts | 13 ++++ src/expression-lang/sheetInterpret.ts | 72 +++++++++++++++++++- 3 files changed, 174 insertions(+), 8 deletions(-) diff --git a/examples/fields/GroupByField.spec.ts b/examples/fields/GroupByField.spec.ts index 186c2a2..ece083c 100644 --- a/examples/fields/GroupByField.spec.ts +++ b/examples/fields/GroupByField.spec.ts @@ -10,16 +10,27 @@ import { Unless, GroupConstraintItem, Do, - NonUnique + NonUnique, + RecordPick, + Pick, + JSONLoad, + Debug, + JSONStringify, + SortedBy, + First, + Get, + Without, + StrConcat, + ArrayEquals } from '../../src/expression-lang/EXPR' const tgrps = [ - { name: 'Odin_', age: 3., job: 'kid', weight: 30., eye_color: 'blue_', fav_group: 'Raffi', age_sum: '0' }, - { name: 'Sarah', age: 8., job: 'kid', weight: 60., eye_color: 'green', fav_group: 'Wiggles', age_sum: '0' }, - { name: 'Paddy', age: 40, job: 'eng', weight: 190, eye_color: 'green', fav_group: 'Wiggles', age_sum: '0' }, - { name: 'Kay__', age: 77, job: 'ret', weight: 160, eye_color: 'green', fav_group: 'Beach Boys', age_sum: '0' }, - { name: 'Cliff', age: 86, job: 'ret', weight: 160, eye_color: 'gray_', fav_group: 'The Stones', age_sum: '0' }, - { name: 'Franz', age: 72, job: 'ret', weight: 170, eye_color: 'blue_', fav_group: 'Beach Boys', age_sum: '0' }, + { name: 'Odin_', age: 3., job: 'kid', weight: 30., eye_color: 'blue_', fav_group: 'Raffi', age_sum: '0', 'encoded_field': '' }, + { name: 'Sarah', age: 8., job: 'kid', weight: 60., eye_color: 'green', fav_group: 'Wiggles', age_sum: '0', 'encoded_field': '' }, + { name: 'Paddy', age: 40, job: 'eng', weight: 190, eye_color: 'green', fav_group: 'Wiggles', age_sum: '0', 'encoded_field': '' }, + { name: 'Kay__', age: 77, job: 'ret', weight: 160, eye_color: 'green', fav_group: 'Beach Boys', age_sum: '0', 'encoded_field': '' }, + { name: 'Cliff', age: 86, job: 'ret', weight: 160, eye_color: 'gray_', fav_group: 'The Stones', age_sum: '0', 'encoded_field': '' }, + { name: 'Franz', age: 72, job: 'ret', weight: 170, eye_color: 'blue_', fav_group: 'Beach Boys', age_sum: '0', 'encoded_field': '' } ] @@ -204,3 +215,75 @@ describe('SampleGroupBy groupConstraint and Comp ->', () => { expect(res).toStrictEqual(SumResults) }) }) + + + +const UnpackSheet = new Sheet( + 'UnpackSheet', + { + job: TextField(), + name: TextField(), + encoded_field: TextField({}), + age_sum: GroupByField( + ['job'], + GroupConstraintItem( + Group(), + Unless( + ArrayEquals( + SortedBy(Pick(First( + SortedBy(JSONLoad( + RecordPick(Group(), 'encoded_field', JSON.stringify({timestamp:'2000'}))), + 'timestamp', 'desc')), 'names')), + SortedBy(RecordPick(Group(), 'name')) + ), + Error( + //@ts-ignore + StrConcat( + Without( + SortedBy(Pick(First( + SortedBy(JSONLoad( + RecordPick(Group(), 'encoded_field', JSON.stringify({timestamp:'2000'}))), + 'timestamp', 'desc')), 'names')), + RecordPick(Group(), 'name')), + " is missing from the group") + )), + 'name', + Group()) +)}, + { + batchRecordsCompute: async (records) => { + // this batchRecordsCompute is supposed to mock making an HTTP request and setting it on fields + const rec1 = records.records[0]; + rec1.set('encoded_field', + JSON.stringify({timestamp: new Date(), names:["Odin_", "Sarah"]})) + const rec2 = records.records[2]; + //note Maire is an engineer that isn't present in the dataset + rec2.set('encoded_field', + JSON.stringify({timestamp: new Date(), names:["Paddy", "Maire"]})) + + } + } +) + +const UnpackBook = new Workbook({name: 't', namespace: 't', sheets: {UnpackSheet}}) + +describe('Unpack example ->', () => { +const tgrps = [ + { name: 'Odin_', job: 'kid', age_sum: '0', 'encoded_field': '' }, + { name: 'Sarah', job: 'kid', age_sum: '0', 'encoded_field': '' }, + { name: 'Paddy', job: 'eng', age_sum: '0', 'encoded_field': '' }, +] + + + const testSheet = new SheetTester(UnpackBook, 'UnpackSheet') + test('GroupByField works properly with sum - multiple rows', async () => { + const res = await testSheet.testMessages(tgrps) + + expect(res[0]).toStrictEqual([]) + expect(res[2][0]).toMatchObject({ + field: 'name', + message: "Maire is missing from the group", + }) + }) +}) + diff --git a/src/expression-lang/EXPR.ts b/src/expression-lang/EXPR.ts index a5848cf..f6b9caa 100644 --- a/src/expression-lang/EXPR.ts +++ b/src/expression-lang/EXPR.ts @@ -86,6 +86,19 @@ export const Do = (...exprs:any[]) => ['do', ...exprs] export const Debug = (expr: NestedIns) => ['debug', expr] +export const RecordPick = (recordGroup:any, fieldName:any, defaultVal:any = undefined ) => + ['recordPick', recordGroup, fieldName, defaultVal] +export const Pick = (objs:any, fieldName:any) => ['pick', objs, fieldName] +export const JSONLoad = (str:any) => ['JSONLoad', str] +export const JSONStringify = (obj:any) => ['JSONStringify', obj] +export const SortedBy = (objs:any, field:any=undefined, direction:string='asc') => ['sortedBy', objs, field, direction] +export const First = (objs:any) => ['first', objs] +export const Get = (rec:any, field:any, defaultVal:any=undefined) => ['get', rec, field, defaultVal] +export const Without = (minuend:any, subtrahend:any) => ['without', minuend, subtrahend] +export const StrConcat = (a:any, b:any) => ['strConcat', a, b] +export const ArrayEquals = (a:any, b:any) => ['arrayEquals', a, b] + + const simpleInterpret = makeInterpreter({error, warn, info, debug}) export const ErrorWhen = (predicate: any, errString: string) => { diff --git a/src/expression-lang/sheetInterpret.ts b/src/expression-lang/sheetInterpret.ts index b93695f..53f476d 100644 --- a/src/expression-lang/sheetInterpret.ts +++ b/src/expression-lang/sheetInterpret.ts @@ -108,6 +108,66 @@ const groupConstraintRow = ( } +/* +RecordPick - takes a recordGroup and field name, returns a list of values for that field +Pick - takes a list of objects and a field name, returns a list of values for that field +JSONLoad - calls JSON.parse on a string returns the object +SortedBy - takes an array of objects, sorts them by field name +First - returns the first element of an array +Get - returns a field from an object +Without - performs set diff on two lists of primitives +strConcat - concatates objects/strings into a string +ArrayEquals - verifies that two arrays are equal (edited) +*/ + +const recordPick = (records:FlatfileRecord[], fieldName:string, defaultVal:any=undefined ) => { + return records.map((rec) => { + const v = rec.get(fieldName) + if( v === null) { + return defaultVal + } + return v + }) +} + +const pick = (objs:Record[], fieldName:string ) => { + if(!_.isArray(objs)) { + //once again a hack + return objs[fieldName] + } + return objs.map((o) => o[fieldName]) +} + +const JSONLoad = (str:string) => { + try { + if (_.isArray(str)) { + //this is a hack + //@ts-ignore + return str.map(JSON.parse) + } + return JSON.parse(str) + } + catch (e:any) {return {}} +} + +const JSONStringify = (obj:any) => JSON.stringify(obj) + +//@ts-ignore +const sortedBy = (objs:Record[], field:string, direction:string) => _.orderBy(objs, [field], [direction]) + +const first = (objs:any[]) => objs[0] + +const get = (rec:FlatfileRecord, field:string, defaultVal:any=undefined) => { + try { + rec.get(field) + } catch (e:any) { + return defaultVal + } +} +const without = (full:any[], subtrahend:any[]) => _.without(full, ...subtrahend) +const strConcat = (a:any, b:any) => a.toString() + b.toString() +const arrayEquals = _.isEqual + export const debug = (expr: NestedIns) => { console.log('debug', expr) return expr @@ -116,7 +176,13 @@ export const debug = (expr: NestedIns) => { const do_ = (...exprs: any) => exprs[exprs.length -1] //@ts-ignore -const simpleInterpret = makeInterpreter({sumField, groupConstraintRow, nonUnique, error, match, 'do': do_}) +const simpleInterpret = makeInterpreter({ + sumField, groupConstraintRow, nonUnique, error, match, 'do': do_, + recordPick, pick, JSONLoad, JSONStringify, sortedBy, first, + //@ts-ignore + get, + debug, + without, strConcat, arrayEquals }) export const sheetInterpret = makeInterpreter({ error, @@ -125,5 +191,9 @@ export const sheetInterpret = makeInterpreter({ groupConstraintRow, nonUnique, debug, + recordPick, pick, JSONLoad, JSONStringify, sortedBy, first, + //@ts-ignore + get, + without, strConcat, arrayEquals }) From 44d8172ed77240dcaad89ff9328c21e679b75401 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Thu, 19 Jan 2023 19:28:22 -0500 Subject: [PATCH 36/36] added Uniq --- src/expression-lang/EXPR.ts | 1 + src/expression-lang/sheetInterpret.ts | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/expression-lang/EXPR.ts b/src/expression-lang/EXPR.ts index f6b9caa..0751621 100644 --- a/src/expression-lang/EXPR.ts +++ b/src/expression-lang/EXPR.ts @@ -97,6 +97,7 @@ export const Get = (rec:any, field:any, defaultVal:any=undefined) => ['get', rec export const Without = (minuend:any, subtrahend:any) => ['without', minuend, subtrahend] export const StrConcat = (a:any, b:any) => ['strConcat', a, b] export const ArrayEquals = (a:any, b:any) => ['arrayEquals', a, b] +export const Uniq = (objs:any) => ['uniq', objs] const simpleInterpret = makeInterpreter({error, warn, info, debug}) diff --git a/src/expression-lang/sheetInterpret.ts b/src/expression-lang/sheetInterpret.ts index 53f476d..b9dba40 100644 --- a/src/expression-lang/sheetInterpret.ts +++ b/src/expression-lang/sheetInterpret.ts @@ -165,6 +165,7 @@ const get = (rec:FlatfileRecord, field:string, defaultVal:any=undefined) => } } const without = (full:any[], subtrahend:any[]) => _.without(full, ...subtrahend) +const uniq = (full:any[]) => _.uniq(full) const strConcat = (a:any, b:any) => a.toString() + b.toString() const arrayEquals = _.isEqual @@ -181,7 +182,7 @@ const simpleInterpret = makeInterpreter({ recordPick, pick, JSONLoad, JSONStringify, sortedBy, first, //@ts-ignore get, - debug, + debug, uniq, without, strConcat, arrayEquals }) export const sheetInterpret = makeInterpreter({ @@ -193,7 +194,7 @@ export const sheetInterpret = makeInterpreter({ debug, recordPick, pick, JSONLoad, JSONStringify, sortedBy, first, //@ts-ignore - get, + get, uniq, without, strConcat, arrayEquals })